adhdev 0.8.83 → 0.8.85

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
@@ -7162,6 +7162,7 @@ function normalizeReadChatCommandStatus(status, activeModal) {
7162
7162
  }
7163
7163
  function buildReadChatCommandResult(payload, args) {
7164
7164
  let validatedPayload;
7165
+ const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
7165
7166
  try {
7166
7167
  validatedPayload = validateReadChatResultPayload({
7167
7168
  ...payload,
@@ -7182,7 +7183,8 @@ function buildReadChatCommandResult(payload, args) {
7182
7183
  syncMode: "full",
7183
7184
  replaceFrom: 0,
7184
7185
  totalMessages: messages.length,
7185
- lastMessageSignature
7186
+ lastMessageSignature,
7187
+ ...debugReadChat ? { debugReadChat } : {}
7186
7188
  };
7187
7189
  }
7188
7190
  const sync = computeReadChatSync(messages, cursor);
@@ -7193,7 +7195,8 @@ function buildReadChatCommandResult(payload, args) {
7193
7195
  syncMode: sync.syncMode,
7194
7196
  replaceFrom: sync.replaceFrom,
7195
7197
  totalMessages: sync.totalMessages,
7196
- lastMessageSignature: sync.lastMessageSignature
7198
+ lastMessageSignature: sync.lastMessageSignature,
7199
+ ...debugReadChat ? { debugReadChat } : {}
7197
7200
  };
7198
7201
  }
7199
7202
  function didProviderConfirmSend(result) {
@@ -7284,14 +7287,33 @@ async function handleReadChat(h, args) {
7284
7287
  }
7285
7288
  }
7286
7289
  const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
7287
- const status = parsedRecord || adapter.getStatus();
7290
+ const adapterStatus = adapter.getStatus();
7291
+ const shouldPreferAdapterMessages = Array.isArray(adapterStatus.messages) && adapterStatus.messages.length > 0 && Array.isArray(parsedRecord?.messages) && adapterStatus.messages.length > parsedRecord.messages.length;
7292
+ const status = parsedRecord ? {
7293
+ ...parsedRecord,
7294
+ messages: shouldPreferAdapterMessages ? adapterStatus.messages : parsedRecord.messages,
7295
+ status: adapterStatus.status !== "idle" ? adapterStatus.status : parsedRecord.status || adapterStatus.status,
7296
+ activeModal: parsedRecord.activeModal || adapterStatus.activeModal
7297
+ } : adapterStatus;
7288
7298
  const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
7289
7299
  const providerSessionId = typeof parsedRecord?.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
7290
7300
  if (status) {
7301
+ LOG.info("Command", `[read_chat] cli-like resolved provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord?.status || "")} shouldPreferAdapterMessages=${String(shouldPreferAdapterMessages)} adapterMsgCount=${Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0} parsedMsgCount=${Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0} returnedMsgCount=${Array.isArray(status.messages) ? status.messages.length : 0}`);
7291
7302
  return buildReadChatCommandResult({
7292
7303
  messages: status.messages || [],
7293
7304
  status: status.status,
7294
7305
  activeModal: status.activeModal,
7306
+ debugReadChat: {
7307
+ provider: adapter.cliType,
7308
+ targetSessionId: String(args?.targetSessionId || ""),
7309
+ adapterStatus: String(adapterStatus.status || ""),
7310
+ parsedStatus: String(parsedRecord?.status || ""),
7311
+ returnedStatus: String(status.status || ""),
7312
+ shouldPreferAdapterMessages,
7313
+ adapterMsgCount: Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0,
7314
+ parsedMsgCount: Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0,
7315
+ returnedMsgCount: Array.isArray(status.messages) ? status.messages.length : 0
7316
+ },
7295
7317
  ...title ? { title } : {},
7296
7318
  ...providerSessionId ? { providerSessionId } : {}
7297
7319
  }, args);
@@ -11793,6 +11815,58 @@ var init_provider_cli_adapter = __esm({
11793
11815
  `[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
11794
11816
  );
11795
11817
  }
11818
+ clearStaleIdleResponseGuard(reason) {
11819
+ const screenText = this.terminalScreen.getText() || "";
11820
+ const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
11821
+ const blockingModal = this.activeModal || this.getStartupConfirmationModal(screenText);
11822
+ if (!this.isWaitingForResponse || this.currentStatus !== "idle" || !visibleIdlePrompt || !!blockingModal) {
11823
+ return false;
11824
+ }
11825
+ if (this.responseTimeout) {
11826
+ clearTimeout(this.responseTimeout);
11827
+ this.responseTimeout = null;
11828
+ }
11829
+ if (this.idleTimeout) {
11830
+ clearTimeout(this.idleTimeout);
11831
+ this.idleTimeout = null;
11832
+ }
11833
+ if (this.approvalExitTimeout) {
11834
+ clearTimeout(this.approvalExitTimeout);
11835
+ this.approvalExitTimeout = null;
11836
+ }
11837
+ if (this.finishRetryTimer) {
11838
+ clearTimeout(this.finishRetryTimer);
11839
+ this.finishRetryTimer = null;
11840
+ }
11841
+ this.clearIdleFinishCandidate(reason);
11842
+ this.responseBuffer = "";
11843
+ this.isWaitingForResponse = false;
11844
+ this.responseSettleIgnoreUntil = 0;
11845
+ this.submitRetryUsed = false;
11846
+ this.submitRetryPromptSnippet = "";
11847
+ this.finishRetryCount = 0;
11848
+ this.currentTurnScope = null;
11849
+ this.activeModal = null;
11850
+ this.recordTrace("stale_idle_response_cleared", {
11851
+ reason,
11852
+ screenText: summarizeCliTraceText(screenText, 240)
11853
+ });
11854
+ return true;
11855
+ }
11856
+ hasMeaningfulResponseBuffer(promptSnippet) {
11857
+ const raw = String(this.responseBuffer || "").trim();
11858
+ if (!raw) return false;
11859
+ const normalizedPrompt = compactPromptText(promptSnippet);
11860
+ if (!normalizedPrompt) return true;
11861
+ const normalizedBuffer = compactPromptText(raw);
11862
+ if (!normalizedBuffer) return false;
11863
+ if (normalizedBuffer === normalizedPrompt) return false;
11864
+ if (normalizedBuffer.startsWith(normalizedPrompt)) {
11865
+ const remainder = normalizedBuffer.slice(normalizedPrompt.length).replace(/[─═\-]+/g, "").replace(/⏵⏵accepteditson\([^)]*\)/gi, "").replace(/accepteditson\([^)]*\)/gi, "").replace(/(?:◐|◑|◒|◓|◔|◕|◉|●|·)?(?:x?high|medium|low|max)·?\/effort/gi, "").replace(/updateavailable!run:[a-z0-9:._\-/]+/gi, "").replace(/esctointerrupt/gi, "").replace(/❯/g, "").replace(/^[\s\-–—:;,.!/?]+/, "").trim();
11866
+ return remainder.length > 0;
11867
+ }
11868
+ return true;
11869
+ }
11796
11870
  evaluateSettled() {
11797
11871
  const now = Date.now();
11798
11872
  if (this.submitPendingUntil > now || this.responseSettleIgnoreUntil > now) {
@@ -11825,7 +11899,11 @@ var init_provider_cli_adapter = __esm({
11825
11899
  scope: this.currentTurnScope,
11826
11900
  lastOutputAt: this.lastOutputAt
11827
11901
  }) : [];
11902
+ if (this.maybeCommitVisibleIdleTranscript(parsedTranscript)) {
11903
+ return;
11904
+ }
11828
11905
  const lastParsedAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
11906
+ const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet || this.currentTurnScope?.prompt || "");
11829
11907
  this.recordTrace("settled", {
11830
11908
  tail: summarizeCliTraceText(tail, 500),
11831
11909
  screenText: summarizeCliTraceText(screenText, 1200),
@@ -11843,6 +11921,24 @@ var init_provider_cli_adapter = __esm({
11843
11921
  scope: this.currentTurnScope
11844
11922
  })
11845
11923
  });
11924
+ if (this.currentTurnScope && !lastParsedAssistant && !this.submitRetryUsed && this.ptyProcess && this.currentStatus !== "waiting_approval" && promptLikelyVisible(screenText, normalizedPromptSnippet) && !this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) {
11925
+ this.submitRetryUsed = true;
11926
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
11927
+ LOG.info("CLI", `[${this.cliType}] Retrying submit key from settled parser (no assistant yet)`);
11928
+ this.recordTrace("submit_write", {
11929
+ mode: "settled_retry",
11930
+ sendKey: this.sendKey,
11931
+ screenText: summarizeCliTraceText(screenText, 500)
11932
+ });
11933
+ this.ptyProcess.write(this.sendKey);
11934
+ if (this.settleTimer) clearTimeout(this.settleTimer);
11935
+ this.settleTimer = setTimeout(() => {
11936
+ this.settleTimer = null;
11937
+ this.settledBuffer = this.recentOutputBuffer;
11938
+ this.evaluateSettled();
11939
+ }, this.timeouts.outputSettle + 150);
11940
+ return;
11941
+ }
11846
11942
  if (this.currentTurnScope && !lastParsedAssistant) {
11847
11943
  LOG.info(
11848
11944
  "CLI",
@@ -11885,7 +11981,15 @@ var init_provider_cli_adapter = __esm({
11885
11981
  }
11886
11982
  const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
11887
11983
  const statusActivityHoldMs = this.getStatusActivityHoldMs();
11888
- const shouldHoldGenerating = scriptStatus === "idle" && this.isWaitingForResponse && !modal && recentInteractiveActivity;
11984
+ const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
11985
+ const visibleAssistantCandidate = this.looksLikeVisibleAssistantCandidate(screenText);
11986
+ if (this.currentTurnScope && this.cliType === "claude-cli") {
11987
+ LOG.info(
11988
+ "CLI",
11989
+ `[${this.cliType}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} scriptStatus=${String(scriptStatus || "")} parsedStatus=${String(parsedTranscript?.status || "")} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify(summarizeCliTraceText(lastParsedAssistant?.content || "", 120)).slice(0, 160)} visibleIdlePrompt=${String(visibleIdlePrompt)} visibleAssistantCandidate=${String(visibleAssistantCandidate)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 160)).slice(0, 220)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 160)).slice(0, 220)}`
11990
+ );
11991
+ }
11992
+ const shouldHoldGenerating = scriptStatus === "idle" && this.isWaitingForResponse && !modal && recentInteractiveActivity && !(visibleIdlePrompt && visibleAssistantCandidate);
11889
11993
  if (shouldHoldGenerating) {
11890
11994
  this.clearIdleFinishCandidate("hold_generating_recent_activity");
11891
11995
  this.setStatus("generating", "recent_activity_hold");
@@ -11916,8 +12020,8 @@ var init_provider_cli_adapter = __esm({
11916
12020
  if (scriptStatus === "waiting_approval") {
11917
12021
  this.clearIdleFinishCandidate("waiting_approval");
11918
12022
  const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
11919
- const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
11920
- if ((inCooldown || visibleIdlePrompt) && !modal) {
12023
+ const visibleIdlePrompt2 = this.looksLikeVisibleIdlePrompt(screenText);
12024
+ if ((inCooldown || visibleIdlePrompt2) && !modal) {
11921
12025
  if (this.approvalExitTimeout) {
11922
12026
  clearTimeout(this.approvalExitTimeout);
11923
12027
  this.approvalExitTimeout = null;
@@ -11989,7 +12093,7 @@ var init_provider_cli_adapter = __esm({
11989
12093
  this.lastApprovalResolvedAt = Date.now();
11990
12094
  }
11991
12095
  if (this.isWaitingForResponse) {
11992
- const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
12096
+ const visibleIdlePrompt2 = this.looksLikeVisibleIdlePrompt(screenText);
11993
12097
  const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
11994
12098
  const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
11995
12099
  const hasAssistantTurn = !!lastParsedAssistant;
@@ -11997,12 +12101,12 @@ var init_provider_cli_adapter = __esm({
11997
12101
  const idleFinishConfirmMs = this.getIdleFinishConfirmMs();
11998
12102
  const idleQuietThresholdMs = Math.max(idleFinishConfirmMs, this.timeouts.outputSettle);
11999
12103
  const idleStableThresholdMs = idleFinishConfirmMs;
12000
- const idleReady = visibleIdlePrompt && !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleStableThresholdMs;
12104
+ const idleReady = visibleIdlePrompt2 && !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleStableThresholdMs;
12001
12105
  const candidate = this.idleFinishCandidate;
12002
12106
  const candidateQuiet = !!candidate && candidate.responseEpoch === this.responseEpoch && candidate.lastOutputAt === this.lastOutputAt && candidate.lastScreenChangeAt === this.lastScreenChangeAt && assistantLength >= candidate.assistantLength && now - candidate.armedAt >= idleFinishConfirmMs;
12003
12107
  const canFinishImmediately = idleReady && candidateQuiet;
12004
12108
  this.recordTrace("idle_decision", {
12005
- visibleIdlePrompt,
12109
+ visibleIdlePrompt: visibleIdlePrompt2,
12006
12110
  quietForMs,
12007
12111
  screenStableMs,
12008
12112
  hasAssistantTurn,
@@ -12122,6 +12226,70 @@ var init_provider_cli_adapter = __esm({
12122
12226
  this.setStatus("idle", "response_finished");
12123
12227
  this.onStatusChange?.();
12124
12228
  }
12229
+ maybeCommitVisibleIdleTranscript(parsed, options) {
12230
+ const allowImmediateScriptIdleCommit = this.provider.allowInputDuringGeneration === true;
12231
+ if (!allowImmediateScriptIdleCommit) return false;
12232
+ if (!parsed || !Array.isArray(parsed.messages) || parsed.status !== "idle" || !this.isWaitingForResponse || !this.currentTurnScope || this.activeModal || parsed.activeModal) {
12233
+ return false;
12234
+ }
12235
+ if (options?.requireVisibleAssistantCandidate) {
12236
+ const candidateText = options.screenText || this.terminalScreen.getText() || "";
12237
+ if (!this.looksLikeVisibleAssistantCandidate(candidateText)) {
12238
+ return false;
12239
+ }
12240
+ }
12241
+ const hydratedForIdleCommit = normalizeCliParsedMessages(parsed.messages, {
12242
+ committedMessages: this.committedMessages,
12243
+ scope: this.currentTurnScope,
12244
+ lastOutputAt: this.lastOutputAt
12245
+ });
12246
+ const visibleAssistant = [...hydratedForIdleCommit].reverse().find((message) => message.role === "assistant" && message.content.trim());
12247
+ if (!visibleAssistant) return false;
12248
+ this.committedMessages = hydratedForIdleCommit;
12249
+ const promptForTrim = this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages);
12250
+ if (promptForTrim) {
12251
+ const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
12252
+ if (lastAssistantForTrim) {
12253
+ lastAssistantForTrim.content = trimPromptEchoPrefix(lastAssistantForTrim.content, promptForTrim);
12254
+ }
12255
+ }
12256
+ if (this.responseTimeout) {
12257
+ clearTimeout(this.responseTimeout);
12258
+ this.responseTimeout = null;
12259
+ }
12260
+ if (this.idleTimeout) {
12261
+ clearTimeout(this.idleTimeout);
12262
+ this.idleTimeout = null;
12263
+ }
12264
+ if (this.approvalExitTimeout) {
12265
+ clearTimeout(this.approvalExitTimeout);
12266
+ this.approvalExitTimeout = null;
12267
+ }
12268
+ if (this.submitRetryTimer) {
12269
+ clearTimeout(this.submitRetryTimer);
12270
+ this.submitRetryTimer = null;
12271
+ }
12272
+ if (this.finishRetryTimer) {
12273
+ clearTimeout(this.finishRetryTimer);
12274
+ this.finishRetryTimer = null;
12275
+ }
12276
+ this.syncMessageViews();
12277
+ this.responseBuffer = "";
12278
+ this.isWaitingForResponse = false;
12279
+ this.responseSettleIgnoreUntil = 0;
12280
+ this.submitRetryUsed = false;
12281
+ this.submitRetryPromptSnippet = "";
12282
+ this.finishRetryCount = 0;
12283
+ this.currentTurnScope = null;
12284
+ this.activeModal = null;
12285
+ this.setStatus("idle", "script_idle_commit");
12286
+ this.onStatusChange?.();
12287
+ this.recordTrace("script_idle_commit", {
12288
+ messageCount: this.committedMessages.length,
12289
+ lastAssistant: summarizeCliTraceText(visibleAssistant.content, 320)
12290
+ });
12291
+ return true;
12292
+ }
12125
12293
  commitCurrentTranscript() {
12126
12294
  const parsed = this.parseCurrentTranscript(
12127
12295
  this.committedMessages,
@@ -12143,6 +12311,12 @@ var init_provider_cli_adapter = __esm({
12143
12311
  }
12144
12312
  this.syncMessageViews();
12145
12313
  const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
12314
+ if (this.currentTurnScope) {
12315
+ LOG.info(
12316
+ "CLI",
12317
+ `[${this.cliType}] commitCurrentTranscript committedMessages=${this.committedMessages.length} finalLastAssistant=${JSON.stringify(summarizeCliTraceText(lastAssistant?.content || "", 220)).slice(0, 260)}`
12318
+ );
12319
+ }
12146
12320
  this.recordTrace("commit_transcript", {
12147
12321
  parsedStatus: parsed.status || null,
12148
12322
  messageCount: this.committedMessages.length,
@@ -12162,11 +12336,18 @@ var init_provider_cli_adapter = __esm({
12162
12336
  `[${this.cliType}] Commit without assistant turn: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
12163
12337
  );
12164
12338
  }
12339
+ const hasAssistant = !!lastAssistant;
12165
12340
  return {
12166
- hasAssistant: !!lastAssistant,
12341
+ hasAssistant,
12167
12342
  assistantContent: lastAssistant?.content || ""
12168
12343
  };
12169
12344
  }
12345
+ if (this.currentTurnScope) {
12346
+ LOG.info(
12347
+ "CLI",
12348
+ `[${this.cliType}] commitCurrentTranscript parsed.messages=none responseBufferLen=${this.responseBuffer.length} accumulatedBufferLen=${this.accumulatedBuffer.length} parsedStatus=${parsed?.status || "-"} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
12349
+ );
12350
+ }
12170
12351
  return {
12171
12352
  hasAssistant: false,
12172
12353
  assistantContent: ""
@@ -12252,19 +12433,25 @@ var init_provider_cli_adapter = __esm({
12252
12433
  this.currentTurnScope,
12253
12434
  screenText
12254
12435
  );
12255
- const shouldPreferCommittedMessages = !this.currentTurnScope && this.currentStatus === "idle" && !this.activeModal;
12436
+ if (this.maybeCommitVisibleIdleTranscript(parsed)) {
12437
+ return this.getScriptParsedStatus();
12438
+ }
12439
+ const shouldPreferCommittedMessages = !this.currentTurnScope && !this.activeModal && this.currentStatus === "idle";
12256
12440
  let result;
12257
12441
  if (parsed && Array.isArray(parsed.messages)) {
12258
- const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => buildChatMessage({
12259
- ...message,
12260
- id: message.id || `msg_${index}`,
12261
- index: typeof message.index === "number" ? message.index : index,
12262
- receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
12263
- })) : hydrateCliParsedMessages(parsed.messages, {
12442
+ const parsedHydratedMessages = hydrateCliParsedMessages(parsed.messages, {
12264
12443
  committedMessages: this.committedMessages,
12265
12444
  scope: this.currentTurnScope,
12266
12445
  lastOutputAt: this.lastOutputAt
12267
12446
  });
12447
+ const committedHydratedMessages = this.committedMessages.map((message, index) => buildChatMessage({
12448
+ ...message,
12449
+ id: message.id || `msg_${index}`,
12450
+ index: typeof message.index === "number" ? message.index : index,
12451
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
12452
+ }));
12453
+ const shouldPreferCommittedHistoryReplay = !this.currentTurnScope && !this.activeModal && committedHydratedMessages.length > parsedHydratedMessages.length;
12454
+ const hydratedMessages = shouldPreferCommittedMessages || shouldPreferCommittedHistoryReplay ? committedHydratedMessages : parsedHydratedMessages;
12268
12455
  result = {
12269
12456
  id: parsed.id || "cli_session",
12270
12457
  status: parsed.status || this.currentStatus,
@@ -12288,6 +12475,23 @@ var init_provider_cli_adapter = __esm({
12288
12475
  activeModal: this.activeModal
12289
12476
  };
12290
12477
  }
12478
+ const hasVisibleAssistantMessage = Array.isArray(result?.messages) && result.messages.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
12479
+ const shouldClampStaleGeneratingToIdle = result?.status === "generating" && this.currentStatus === "idle" && !this.currentTurnScope && !result?.activeModal && hasVisibleAssistantMessage;
12480
+ if (shouldClampStaleGeneratingToIdle) {
12481
+ result = {
12482
+ ...result,
12483
+ status: "idle",
12484
+ messages: Array.isArray(result.messages) ? result.messages.map((message) => {
12485
+ if (message?.role !== "assistant" || !message?.meta?.streaming) return message;
12486
+ const nextMeta = { ...message.meta || {} };
12487
+ delete nextMeta.streaming;
12488
+ return {
12489
+ ...message,
12490
+ ...Object.keys(nextMeta).length > 0 ? { meta: nextMeta } : { meta: void 0 }
12491
+ };
12492
+ }) : result.messages
12493
+ };
12494
+ }
12291
12495
  this.parsedStatusCache = {
12292
12496
  committedMessagesRef: this.committedMessages,
12293
12497
  responseBuffer: this.responseBuffer,
@@ -12420,9 +12624,27 @@ ${data.message || ""}`.trim();
12420
12624
  }
12421
12625
  }
12422
12626
  if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
12423
- if (this.isWaitingForResponse && !allowInputDuringGeneration) {
12627
+ const parsedStatusBeforeSend = !allowInputDuringGeneration ? (() => {
12628
+ try {
12629
+ return this.getScriptParsedStatus?.() || null;
12630
+ } catch {
12631
+ return null;
12632
+ }
12633
+ })() : null;
12634
+ const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
12635
+ const parsedMessagesBeforeSend = Array.isArray(parsedStatusBeforeSend?.messages) ? parsedStatusBeforeSend.messages.filter((message) => message && (message.role === "user" || message.role === "assistant")) : [];
12636
+ const shouldCommitParsedIdleBeforeSend = !allowInputDuringGeneration && parsedSessionStatus === "idle" && parsedMessagesBeforeSend.length > this.committedMessages.length && parsedMessagesBeforeSend.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
12637
+ if (shouldCommitParsedIdleBeforeSend) {
12638
+ this.commitCurrentTranscript();
12639
+ }
12640
+ if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
12424
12641
  throw new Error(`${this.cliName} is still processing the previous prompt`);
12425
12642
  }
12643
+ if (this.isWaitingForResponse && !allowInputDuringGeneration) {
12644
+ if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
12645
+ throw new Error(`${this.cliName} is still processing the previous prompt`);
12646
+ }
12647
+ }
12426
12648
  const blockingModal = this.activeModal || this.getStartupConfirmationModal(this.terminalScreen.getText() || "");
12427
12649
  if (blockingModal || this.currentStatus === "waiting_approval") {
12428
12650
  throw new Error(`${this.cliName} is awaiting confirmation before it can accept a prompt`);
@@ -12502,7 +12724,7 @@ ${data.message || ""}`.trim();
12502
12724
  this.submitRetryTimer = null;
12503
12725
  if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
12504
12726
  if (this.currentStatus === "waiting_approval") return;
12505
- if ((this.responseBuffer || "").trim()) return;
12727
+ if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
12506
12728
  const screenText2 = this.terminalScreen.getText();
12507
12729
  if (!promptLikelyVisible(screenText2, normalizedPromptSnippet)) return;
12508
12730
  if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText2)) return;
@@ -12539,7 +12761,7 @@ ${data.message || ""}`.trim();
12539
12761
  this.submitRetryTimer = null;
12540
12762
  if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
12541
12763
  if (this.currentStatus === "waiting_approval") return;
12542
- if ((this.responseBuffer || "").trim()) return;
12764
+ if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
12543
12765
  const screenText = this.terminalScreen.getText();
12544
12766
  if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
12545
12767
  LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
@@ -12938,6 +13160,30 @@ ${data.message || ""}`.trim();
12938
13160
  });
12939
13161
 
12940
13162
  // ../../oss/packages/daemon-core/src/providers/cli-provider-instance.ts
13163
+ function normalizePersistableCliHistoryContent(content) {
13164
+ return flattenContent(content).replace(/\s+/g, " ").trim();
13165
+ }
13166
+ function buildPersistableCliHistorySignature(message) {
13167
+ return [
13168
+ String(message.role || ""),
13169
+ String(message.kind || ""),
13170
+ String(message.senderName || ""),
13171
+ normalizePersistableCliHistoryContent(message.content)
13172
+ ].join("|");
13173
+ }
13174
+ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages) {
13175
+ if (!Array.isArray(currentMessages) || currentMessages.length === 0) return [];
13176
+ if (!Array.isArray(previousMessages) || previousMessages.length === 0) return currentMessages;
13177
+ const previousSignatures = previousMessages.map(buildPersistableCliHistorySignature);
13178
+ const currentSignatures = currentMessages.map(buildPersistableCliHistorySignature);
13179
+ let sharedPrefixLength = 0;
13180
+ while (sharedPrefixLength < previousSignatures.length && sharedPrefixLength < currentSignatures.length && previousSignatures[sharedPrefixLength] === currentSignatures[sharedPrefixLength]) {
13181
+ sharedPrefixLength += 1;
13182
+ }
13183
+ if (sharedPrefixLength === currentSignatures.length) return [];
13184
+ if (sharedPrefixLength === previousSignatures.length) return currentMessages.slice(sharedPrefixLength);
13185
+ return currentMessages;
13186
+ }
12941
13187
  function getDatabaseSync() {
12942
13188
  if (CachedDatabaseSync) return CachedDatabaseSync;
12943
13189
  const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path11.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
@@ -13036,6 +13282,7 @@ var init_cli_provider_instance = __esm({
13036
13282
  appliedEffectKeys = /* @__PURE__ */ new Set();
13037
13283
  historyWriter;
13038
13284
  runtimeMessages = [];
13285
+ lastPersistedHistoryMessages = [];
13039
13286
  instanceId;
13040
13287
  suppressIdleHistoryReplay = false;
13041
13288
  errorMessage = void 0;
@@ -13076,6 +13323,13 @@ var init_cli_provider_instance = __esm({
13076
13323
  this.providerSessionId,
13077
13324
  this.instanceId
13078
13325
  );
13326
+ this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13327
+ role: message.role,
13328
+ content: message.content,
13329
+ kind: message.kind,
13330
+ senderName: message.senderName,
13331
+ receivedAt: message.receivedAt
13332
+ }));
13079
13333
  this.suppressIdleHistoryReplay = restoredHistory.messages.length > 0;
13080
13334
  if (restoredHistory.messages.length > 0) {
13081
13335
  this.adapter.seedCommittedMessages(
@@ -13207,15 +13461,24 @@ var init_cli_provider_instance = __esm({
13207
13461
  messagesToSave = messagesToSave.slice(0, lastIdx);
13208
13462
  }
13209
13463
  }
13210
- if (!shouldSkipReplayPersist && messagesToSave.length > 0) {
13464
+ const normalizedMessagesToSave = messagesToSave.map((message) => ({
13465
+ role: message.role,
13466
+ content: flattenContent(message.content),
13467
+ kind: typeof message.kind === "string" ? message.kind : void 0,
13468
+ senderName: typeof message.senderName === "string" ? message.senderName : void 0,
13469
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
13470
+ }));
13471
+ if (!shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
13472
+ const incrementalMessages = buildIncrementalHistoryAppendMessages(this.lastPersistedHistoryMessages, normalizedMessagesToSave);
13211
13473
  this.historyWriter.appendNewMessages(
13212
13474
  this.type,
13213
- messagesToSave,
13475
+ incrementalMessages,
13214
13476
  parsedStatus?.title || dirName,
13215
13477
  this.instanceId,
13216
13478
  this.providerSessionId
13217
13479
  );
13218
13480
  }
13481
+ this.lastPersistedHistoryMessages = normalizedMessagesToSave;
13219
13482
  }
13220
13483
  this.applyProviderResponse(parsedStatus, { phase: "immediate" });
13221
13484
  const surface = resolveProviderStateSurface({
@@ -13231,7 +13494,7 @@ var init_cli_provider_instance = __esm({
13231
13494
  activeChat: {
13232
13495
  id: `${this.type}_${this.workingDir}`,
13233
13496
  title: parsedStatus?.title || dirName,
13234
- status: parseErrorMessage ? "error" : autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : parsedStatus?.status || visibleStatus,
13497
+ status: parseErrorMessage ? "error" : autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : adapterStatus.status !== "idle" ? visibleStatus : parsedStatus?.status || visibleStatus,
13235
13498
  messages: mergedMessages,
13236
13499
  activeModal: autoApproveActive ? null : parsedStatus?.activeModal ?? adapterStatus.activeModal,
13237
13500
  inputContent: ""
@@ -13463,6 +13726,7 @@ var init_cli_provider_instance = __esm({
13463
13726
  }
13464
13727
  if (data.sessionEvent === "new_session") {
13465
13728
  this.runtimeMessages = [];
13729
+ this.lastPersistedHistoryMessages = [];
13466
13730
  this.suppressIdleHistoryReplay = false;
13467
13731
  this.adapter.clearHistory();
13468
13732
  }
@@ -43924,6 +44188,13 @@ data: ${JSON.stringify(msg.data)}
43924
44188
  });
43925
44189
 
43926
44190
  // ../../oss/packages/daemon-core/src/cli-adapters/session-host-transport.ts
44191
+ function shouldResumeAttachedSession(record2) {
44192
+ if (!record2) return false;
44193
+ if (record2.lifecycle === "interrupted") return true;
44194
+ if (record2.lifecycle !== "stopped") return false;
44195
+ if (record2.meta?.restoredFromStorage === true) return true;
44196
+ return typeof record2.meta?.runtimeRecoveryState === "string" && String(record2.meta.runtimeRecoveryState).trim().length > 0;
44197
+ }
43927
44198
  var SessionHostRuntimeTransport, SessionHostPtyTransportFactory;
43928
44199
  var init_session_host_transport = __esm({
43929
44200
  "../../oss/packages/daemon-core/src/cli-adapters/session-host-transport.ts"() {
@@ -44103,7 +44374,7 @@ var init_session_host_transport = __esm({
44103
44374
  payload: {}
44104
44375
  });
44105
44376
  const existingRecord = existingRecords.success && existingRecords.result ? existingRecords.result.find((item) => item.sessionId === this.options.runtimeId) || null : null;
44106
- if (existingRecord?.lifecycle === "interrupted") {
44377
+ if (shouldResumeAttachedSession(existingRecord)) {
44107
44378
  const resumeResponse = await this.client.request({
44108
44379
  type: "resume_session",
44109
44380
  payload: {
@@ -44413,6 +44684,8 @@ var init_runtime_support = __esm({
44413
44684
  // ../../oss/packages/daemon-core/src/session-host/startup-restore-policy.js
44414
44685
  function shouldAutoRestoreHostedSessionsOnStartup(env3 = process.env) {
44415
44686
  const raw = typeof env3.ADHDEV_RESTORE_HOSTED_SESSIONS_ON_STARTUP === "string" ? env3.ADHDEV_RESTORE_HOSTED_SESSIONS_ON_STARTUP.trim().toLowerCase() : "";
44687
+ if (!raw) return true;
44688
+ if (raw === "0" || raw === "false" || raw === "no") return false;
44416
44689
  return raw === "1" || raw === "true" || raw === "yes";
44417
44690
  }
44418
44691
  var init_startup_restore_policy = __esm({
@@ -54404,7 +54677,7 @@ var init_adhdev_daemon = __esm({
54404
54677
  init_source2();
54405
54678
  init_version();
54406
54679
  init_src();
54407
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.83" });
54680
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.85" });
54408
54681
  AdhdevDaemon = class _AdhdevDaemon {
54409
54682
  localHttpServer = null;
54410
54683
  localWss = null;