@adhdev/daemon-core 0.9.82-rc.93 → 0.9.82-rc.95

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.mjs CHANGED
@@ -4640,6 +4640,9 @@ var init_provider_cli_adapter = __esm({
4640
4640
  idleFinishCandidate = null;
4641
4641
  finishRetryTimer = null;
4642
4642
  finishRetryCount = 0;
4643
+ pendingOutboundQueue = [];
4644
+ pendingOutboundFlushTimer = null;
4645
+ pendingOutboundFlushInFlight = false;
4643
4646
  // Resize redraw suppression
4644
4647
  resizeSuppressUntil = 0;
4645
4648
  // Debug: status transition history
@@ -5660,6 +5663,7 @@ ${lastSnapshot}`;
5660
5663
  this.activeModal = null;
5661
5664
  this.setStatus("idle", "response_finished");
5662
5665
  this.onStatusChange?.();
5666
+ this.schedulePendingOutboundFlush();
5663
5667
  }
5664
5668
  maybeCommitVisibleIdleTranscript(session, parsedMessages) {
5665
5669
  const allowImmediateScriptIdleCommit = this.provider.allowInputDuringGeneration === true;
@@ -5680,6 +5684,7 @@ ${lastSnapshot}`;
5680
5684
  this.activeModal = null;
5681
5685
  this.setStatus("idle", "script_idle_commit");
5682
5686
  this.onStatusChange?.();
5687
+ this.schedulePendingOutboundFlush();
5683
5688
  this.recordTrace("script_idle_commit", {
5684
5689
  messageCount: parsedMessages.length,
5685
5690
  lastAssistant: summarizeCliTraceText(visibleAssistant.content, 320)
@@ -5862,6 +5867,14 @@ ${lastSnapshot}`;
5862
5867
  messages: [],
5863
5868
  workingDir: this.workingDir,
5864
5869
  activeModal: effectiveModal,
5870
+ pendingOutboundCount: this.pendingOutboundQueue.length,
5871
+ pendingOutboundMessages: this.pendingOutboundQueue.map((message) => ({
5872
+ id: message.id,
5873
+ role: message.role,
5874
+ content: message.content,
5875
+ queuedAt: message.queuedAt,
5876
+ source: message.source
5877
+ })),
5865
5878
  errorMessage: this.parseErrorMessage || void 0,
5866
5879
  errorReason: this.parseErrorMessage ? "parse_error" : void 0,
5867
5880
  ...bufferState ? { bufferState } : {}
@@ -6158,6 +6171,90 @@ ${lastSnapshot}`;
6158
6171
  ), 50);
6159
6172
  }
6160
6173
  async sendMessage(text) {
6174
+ await this.sendMessageNow(text, true);
6175
+ }
6176
+ enqueuePendingOutboundMessage(text, reason) {
6177
+ const content = String(text || "");
6178
+ const duplicate = this.pendingOutboundQueue.some((message2) => message2.content === content);
6179
+ if (duplicate) {
6180
+ this.recordTrace("send_message_queued_duplicate_suppressed", {
6181
+ reason,
6182
+ queueLength: this.pendingOutboundQueue.length,
6183
+ text: summarizeCliTraceText(content, 500)
6184
+ });
6185
+ return;
6186
+ }
6187
+ const queuedAt = Date.now();
6188
+ const message = {
6189
+ id: `${queuedAt}:${this.pendingOutboundQueue.length}:${Math.random().toString(36).slice(2, 10)}`,
6190
+ role: "user",
6191
+ content,
6192
+ queuedAt,
6193
+ source: "sendMessage"
6194
+ };
6195
+ this.pendingOutboundQueue.push(message);
6196
+ this.recordTrace("send_message_queued", {
6197
+ reason,
6198
+ queueLength: this.pendingOutboundQueue.length,
6199
+ queuedAt,
6200
+ text: summarizeCliTraceText(content, 500)
6201
+ });
6202
+ LOG.info("CLI", `[${this.cliType}] queued outbound message while busy (${reason}); queue=${this.pendingOutboundQueue.length}`);
6203
+ this.onStatusChange?.();
6204
+ }
6205
+ shouldQueuePendingOutboundMessage(parsedStatusBeforeSend = null) {
6206
+ if (this.provider.allowInputDuringGeneration === true) return null;
6207
+ if (this.hasActionableApproval()) return null;
6208
+ const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
6209
+ if (parsedSessionStatus === "idle" && this.parsedStatusHasFinalAssistantMessage(parsedStatusBeforeSend)) return null;
6210
+ if (this.currentStatus === "generating") return "current_status_generating";
6211
+ if (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating") {
6212
+ const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
6213
+ const parsedHasActionableModal = Boolean(
6214
+ parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
6215
+ );
6216
+ const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
6217
+ return terminalLooksIdle ? null : `parsed_status_${parsedSessionStatus}`;
6218
+ }
6219
+ if (this.isWaitingForResponse && this.currentTurnScope) return "active_turn_in_progress";
6220
+ return null;
6221
+ }
6222
+ schedulePendingOutboundFlush(delayMs = 0) {
6223
+ if (this.pendingOutboundFlushTimer) clearTimeout(this.pendingOutboundFlushTimer);
6224
+ this.pendingOutboundFlushTimer = setTimeout(() => {
6225
+ this.pendingOutboundFlushTimer = null;
6226
+ void this.flushPendingOutboundQueue();
6227
+ }, Math.max(0, delayMs));
6228
+ }
6229
+ async flushPendingOutboundQueue() {
6230
+ if (this.pendingOutboundFlushInFlight || this.pendingOutboundQueue.length === 0) return;
6231
+ if (this.currentStatus !== "idle" || this.isWaitingForResponse || this.hasActionableApproval()) return;
6232
+ this.pendingOutboundFlushInFlight = true;
6233
+ try {
6234
+ while (this.pendingOutboundQueue.length > 0) {
6235
+ if (this.currentStatus !== "idle" || this.isWaitingForResponse || this.hasActionableApproval()) break;
6236
+ const next = this.pendingOutboundQueue[0];
6237
+ this.recordTrace("send_message_queue_flush", {
6238
+ id: next.id,
6239
+ queuedAt: next.queuedAt,
6240
+ queueLength: this.pendingOutboundQueue.length,
6241
+ text: summarizeCliTraceText(next.content, 500)
6242
+ });
6243
+ try {
6244
+ await this.sendMessageNow(next.content, false);
6245
+ this.pendingOutboundQueue.shift();
6246
+ this.onStatusChange?.();
6247
+ } catch (error) {
6248
+ LOG.warn("CLI", `[${this.cliType}] queued outbound flush failed: ${error?.message || error}`);
6249
+ this.schedulePendingOutboundFlush(1e3);
6250
+ break;
6251
+ }
6252
+ }
6253
+ } finally {
6254
+ this.pendingOutboundFlushInFlight = false;
6255
+ }
6256
+ }
6257
+ async sendMessageNow(text, allowQueue) {
6161
6258
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
6162
6259
  const allowInputDuringGeneration = this.provider.allowInputDuringGeneration === true;
6163
6260
  const allowInterventionPrompt = allowInputDuringGeneration && this.isWaitingForResponse && !this.hasActionableApproval();
@@ -6168,6 +6265,18 @@ ${lastSnapshot}`;
6168
6265
  await new Promise((resolve16) => setTimeout(resolve16, 50));
6169
6266
  }
6170
6267
  }
6268
+ const parsedStatusBeforeSend = !allowInputDuringGeneration ? (() => {
6269
+ try {
6270
+ return this.getScriptParsedStatus?.() || null;
6271
+ } catch {
6272
+ return null;
6273
+ }
6274
+ })() : null;
6275
+ const queueReason = this.shouldQueuePendingOutboundMessage(parsedStatusBeforeSend);
6276
+ if (allowQueue && queueReason) {
6277
+ this.enqueuePendingOutboundMessage(text, queueReason);
6278
+ return;
6279
+ }
6171
6280
  if (!allowInterventionPrompt) {
6172
6281
  await this.waitForInteractivePrompt();
6173
6282
  }
@@ -6180,13 +6289,6 @@ ${lastSnapshot}`;
6180
6289
  }
6181
6290
  }
6182
6291
  if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
6183
- const parsedStatusBeforeSend = !allowInputDuringGeneration ? (() => {
6184
- try {
6185
- return this.getScriptParsedStatus?.() || null;
6186
- } catch {
6187
- return null;
6188
- }
6189
- })() : null;
6190
6292
  const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
6191
6293
  if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
6192
6294
  const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
@@ -6195,11 +6297,19 @@ ${lastSnapshot}`;
6195
6297
  );
6196
6298
  const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
6197
6299
  if (!terminalLooksIdle) {
6300
+ if (allowQueue) {
6301
+ this.enqueuePendingOutboundMessage(text, `parsed_status_${parsedSessionStatus}`);
6302
+ return;
6303
+ }
6198
6304
  throw new Error(`${this.cliName} is still processing the previous prompt`);
6199
6305
  }
6200
6306
  }
6201
6307
  if (this.isWaitingForResponse && !allowInputDuringGeneration) {
6202
6308
  if (!this.clearStaleIdleResponseGuard("send_message_guard") && !this.clearParsedIdleResponseGuard("send_message_parsed_idle_guard", parsedStatusBeforeSend)) {
6309
+ if (allowQueue) {
6310
+ this.enqueuePendingOutboundMessage(text, "waiting_for_response");
6311
+ return;
6312
+ }
6203
6313
  throw new Error(`${this.cliName} is still processing the previous prompt`);
6204
6314
  }
6205
6315
  }
@@ -6434,6 +6544,12 @@ ${lastSnapshot}`;
6434
6544
  this.pendingTerminalQueryTail = "";
6435
6545
  this.ptyOutputChunks = [];
6436
6546
  this.finishRetryCount = 0;
6547
+ if (this.pendingOutboundFlushTimer) {
6548
+ clearTimeout(this.pendingOutboundFlushTimer);
6549
+ this.pendingOutboundFlushTimer = null;
6550
+ }
6551
+ this.pendingOutboundQueue = [];
6552
+ this.pendingOutboundFlushInFlight = false;
6437
6553
  if (this.ptyProcess) {
6438
6554
  this.ptyProcess.write("");
6439
6555
  setTimeout(() => {
@@ -6457,6 +6573,12 @@ ${lastSnapshot}`;
6457
6573
  this.pendingTerminalQueryTail = "";
6458
6574
  this.ptyOutputChunks = [];
6459
6575
  this.finishRetryCount = 0;
6576
+ if (this.pendingOutboundFlushTimer) {
6577
+ clearTimeout(this.pendingOutboundFlushTimer);
6578
+ this.pendingOutboundFlushTimer = null;
6579
+ }
6580
+ this.pendingOutboundQueue = [];
6581
+ this.pendingOutboundFlushInFlight = false;
6460
6582
  if (this.ptyProcess) {
6461
6583
  try {
6462
6584
  if (typeof this.ptyProcess.detach === "function") {
@@ -6496,6 +6618,12 @@ ${lastSnapshot}`;
6496
6618
  this.finishRetryTimer = null;
6497
6619
  }
6498
6620
  this.finishRetryCount = 0;
6621
+ if (this.pendingOutboundFlushTimer) {
6622
+ clearTimeout(this.pendingOutboundFlushTimer);
6623
+ this.pendingOutboundFlushTimer = null;
6624
+ }
6625
+ this.pendingOutboundQueue = [];
6626
+ this.pendingOutboundFlushInFlight = false;
6499
6627
  this.resetTerminalScreen();
6500
6628
  this.ptyProcess?.clearBuffer?.();
6501
6629
  this.onStatusChange?.();
@@ -6622,6 +6750,14 @@ ${lastSnapshot}`;
6622
6750
  rawBufferPreview: this.accumulatedRawBuffer.slice(-1e3),
6623
6751
  sanitizedRawPreview: sanitizeTerminalText(this.accumulatedRawBuffer).slice(-1e3),
6624
6752
  responseBuffer: this.responseBuffer.slice(-1e3),
6753
+ pendingOutboundQueue: this.pendingOutboundQueue.map((message) => ({
6754
+ id: message.id,
6755
+ role: message.role,
6756
+ content: message.content,
6757
+ queuedAt: message.queuedAt,
6758
+ source: message.source
6759
+ })),
6760
+ pendingOutboundCount: this.pendingOutboundQueue.length,
6625
6761
  lastOutputAt: this.lastOutputAt,
6626
6762
  lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
6627
6763
  lastScreenChangeAt: this.lastScreenChangeAt,
@@ -15729,7 +15865,7 @@ var RECENT_SEND_WINDOW_MS = 1200;
15729
15865
  var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
15730
15866
  var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
15731
15867
  var CLI_NATIVE_HISTORY_FRESH_MS = 5 * 6e4;
15732
- var CLI_NATIVE_TRANSCRIPT_PROVIDERS = /* @__PURE__ */ new Set(["codex-cli", "claude-cli"]);
15868
+ var CLI_NATIVE_TRANSCRIPT_PROVIDERS = /* @__PURE__ */ new Set(["codex-cli", "claude-cli", "hermes-cli"]);
15733
15869
  var recentSendByTarget = /* @__PURE__ */ new Map();
15734
15870
  function getCurrentProviderType(h, fallback = "") {
15735
15871
  return h.currentSession?.providerType || h.currentProviderType || fallback;
@@ -16784,7 +16920,7 @@ async function handleReadChat(h, args) {
16784
16920
  returnedStatus: String(returnedStatus || ""),
16785
16921
  selectedMessageSource: messageSource.selected,
16786
16922
  messageSource,
16787
- shouldPreferAdapterMessages: supportsCliNativeTranscript(providerType, provider) && messageSource.selected !== "native-history",
16923
+ shouldPreferAdapterMessages: supportsCliNativeTranscript(providerType, provider) && isNativeSourceCanonicalHistory(provider?.canonicalHistory) && messageSource.selected !== "native-history" && typeof messageSource.fallbackReason === "string" && messageSource.fallbackReason.startsWith("native_history_") && messageSource.fallbackReason !== "native_history_not_checked" && !(selectedTranscriptAuthority === "provider" && selectedCoverage === "full"),
16788
16924
  parsedMsgCount: parsedRecord.messages.length,
16789
16925
  returnedMsgCount: selectedMessages.length
16790
16926
  },
@@ -21923,10 +22059,14 @@ function detectExplicitProviderSessionId(provider, args) {
21923
22059
  }
21924
22060
  const subcommands = resume?.sessionIdFromSubcommand;
21925
22061
  if (Array.isArray(subcommands) && subcommands.length > 0) {
22062
+ const hasResumeSubcommand = args.some((arg) => subcommands.includes(arg));
21926
22063
  const subcommandSessionId = readSubcommandSessionId(args, subcommands);
21927
22064
  if (subcommandSessionId) {
21928
22065
  return { providerSessionId: subcommandSessionId, launchMode: "resume" };
21929
22066
  }
22067
+ if (hasResumeSubcommand) {
22068
+ return { launchMode: "resume" };
22069
+ }
21930
22070
  }
21931
22071
  return { launchMode: "manual" };
21932
22072
  }
@@ -21950,6 +22090,12 @@ function resolveCliSessionBinding(provider, normalizedType, cliArgs, requestedRe
21950
22090
  launchMode: explicit.launchMode
21951
22091
  };
21952
22092
  }
22093
+ if (explicit.launchMode === "resume") {
22094
+ return {
22095
+ cliArgs: baseArgs,
22096
+ launchMode: "resume"
22097
+ };
22098
+ }
21953
22099
  if (explicit.launchMode === "manual" && hasArg(baseArgs || [], ["--session-id"])) {
21954
22100
  return {
21955
22101
  cliArgs: baseArgs,
@@ -22614,18 +22760,6 @@ Run 'adhdev doctor' for detailed diagnostics.`
22614
22760
  } else if (currentStatus === "starting") {
22615
22761
  currentStatus = getEffectiveAgentSendStatus(adapter);
22616
22762
  }
22617
- if (BUSY_AGENT_STATUSES.has(currentStatus)) {
22618
- return {
22619
- success: false,
22620
- code: "agent_runtime_busy",
22621
- reason: "agent_runtime_busy",
22622
- retryable: true,
22623
- retryRecommended: true,
22624
- status: currentStatus,
22625
- targetSessionId: args?.targetSessionId,
22626
- error: `CLI agent '${agentType}' is currently ${currentStatus}; retry after the current turn finishes.`
22627
- };
22628
- }
22629
22763
  const input = normalizeInputEnvelope(args?.input ? { input: args.input } : args);
22630
22764
  const provider = this.providerLoader.resolve(agentType) || this.providerLoader.getMeta(agentType);
22631
22765
  if (provider?.category === "acp") {
@@ -22636,7 +22770,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
22636
22770
  const message = input.textFallback;
22637
22771
  if (!message) throw new Error("message required for send_chat");
22638
22772
  await adapter.sendMessage(message);
22639
- return { success: true, status: "generating" };
22773
+ return {
22774
+ success: true,
22775
+ status: BUSY_AGENT_STATUSES.has(currentStatus) ? currentStatus : "generating",
22776
+ ...BUSY_AGENT_STATUSES.has(currentStatus) ? { queued: true, queuedReason: "agent_runtime_busy" } : {}
22777
+ };
22640
22778
  } else if (action === "clear_history") {
22641
22779
  if (typeof adapter.clearHistory === "function") adapter.clearHistory();
22642
22780
  return { success: true, cleared: true };