@adhdev/daemon-core 0.8.88 → 0.8.90

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/session-host-core",
3
- "version": "0.8.88",
3
+ "version": "0.8.90",
4
4
  "description": "ADHDev local session host core \u2014 session registry, protocol, buffers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.8.88",
3
+ "version": "0.8.90",
4
4
  "description": "ADHDev daemon core \u2014 CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -677,6 +677,7 @@ export class ProviderCliAdapter implements CliAdapter {
677
677
  private looksLikeClaudeGeneratingLine(line: string): boolean {
678
678
  const trimmed = String(line || '').trim();
679
679
  if (!trimmed) return false;
680
+ if (/^⏵⏵\s+accept edits on/i.test(trimmed)) return false;
680
681
  if (/esc to (cancel|interrupt|stop)/i.test(trimmed)) return true;
681
682
  if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+\s+\S+.*\b(?:thinking|thought for \d+s?)\b/i.test(trimmed)) return true;
682
683
  if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+\s+[A-Z][A-Za-z-]{3,}ing\b.*(?:…|\.{3})/u.test(trimmed)) return true;
@@ -804,9 +805,7 @@ export class ProviderCliAdapter implements CliAdapter {
804
805
  const buttons = Array.isArray(modal.buttons) ? modal.buttons : [];
805
806
  if (buttons.length !== 1) return false;
806
807
  const buttonLabel = String(buttons[0] || '').trim();
807
- const modalText = `${modal.message || ''} ${buttonLabel}`.trim();
808
- return looksLikeConfirmOnlyLabel(buttonLabel)
809
- || /Quick safety check|project trust|trust (?:this project|the contents of this directory|the files in this folder)|Enter to confirm/i.test(modalText);
808
+ return looksLikeConfirmOnlyLabel(buttonLabel);
810
809
  }
811
810
 
812
811
  private async waitForInteractivePrompt(maxWaitMs = 5000): Promise<void> {
@@ -1051,7 +1050,8 @@ export class ProviderCliAdapter implements CliAdapter {
1051
1050
  && this.isWaitingForResponse
1052
1051
  && !modal
1053
1052
  && recentInteractiveActivity
1054
- && !(visibleIdlePrompt && visibleAssistantCandidate);
1053
+ && !(visibleIdlePrompt && visibleAssistantCandidate)
1054
+ && !(parsedTranscript?.status === 'idle' && !!lastParsedAssistant);
1055
1055
 
1056
1056
  if (shouldHoldGenerating) {
1057
1057
  this.clearIdleFinishCandidate('hold_generating_recent_activity');
@@ -1463,14 +1463,24 @@ export class ProviderCliAdapter implements CliAdapter {
1463
1463
  }
1464
1464
  }
1465
1465
 
1466
+ private projectEffectiveStatus(startupModal: { message: string; buttons: string[] } | null = null): CliSessionStatus['status'] {
1467
+ if (this.parseErrorMessage) return 'error';
1468
+ if (startupModal) return 'waiting_approval';
1469
+ if (this.isWaitingForResponse && this.currentTurnScope && this.currentStatus === 'idle') return 'generating';
1470
+ return this.currentStatus;
1471
+ }
1472
+
1466
1473
  // ─── Public API (CliAdapter) ───────────────────
1467
1474
 
1468
1475
  getStatus(): CliSessionStatus {
1476
+ const screenText = this.terminalScreen.getText() || '';
1477
+ const startupModal = this.startupParseGate ? this.getStartupConfirmationModal(screenText) : null;
1478
+ const effectiveStatus = this.projectEffectiveStatus(startupModal);
1469
1479
  return {
1470
- status: this.parseErrorMessage ? 'error' : this.currentStatus,
1480
+ status: effectiveStatus,
1471
1481
  messages: [...this.committedMessages],
1472
1482
  workingDir: this.workingDir,
1473
- activeModal: this.activeModal,
1483
+ activeModal: startupModal || this.activeModal,
1474
1484
  errorMessage: this.parseErrorMessage || undefined,
1475
1485
  errorReason: this.parseErrorMessage ? 'parse_error' : undefined,
1476
1486
  };
@@ -1551,12 +1561,21 @@ export class ProviderCliAdapter implements CliAdapter {
1551
1561
  : message.timestamp,
1552
1562
  }));
1553
1563
  const parsedLastAssistant = [...parsedHydratedMessages].reverse().find((message) => message.role === 'assistant' && typeof message.content === 'string' && message.content.trim());
1564
+ const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
1554
1565
  const shouldAdoptParsedIdleReplay =
1555
1566
  !this.currentTurnScope
1556
1567
  && !this.activeModal
1557
- && this.currentStatus === 'idle'
1568
+ && !!parsedLastAssistant
1558
1569
  && parsedHydratedMessages.length > committedHydratedMessages.length
1559
- && !!parsedLastAssistant;
1570
+ && (
1571
+ this.currentStatus === 'idle'
1572
+ || (
1573
+ this.currentStatus === 'generating'
1574
+ && this.isWaitingForResponse
1575
+ && parsed.status === 'idle'
1576
+ && visibleIdlePrompt
1577
+ )
1578
+ );
1560
1579
  if (shouldAdoptParsedIdleReplay) {
1561
1580
  this.committedMessages = normalizeCliParsedMessages(parsed.messages, {
1562
1581
  committedMessages: this.committedMessages,
@@ -1564,6 +1583,18 @@ export class ProviderCliAdapter implements CliAdapter {
1564
1583
  lastOutputAt: this.lastOutputAt,
1565
1584
  });
1566
1585
  this.syncMessageViews();
1586
+ if (this.currentStatus !== 'idle' || this.isWaitingForResponse) {
1587
+ this.responseBuffer = '';
1588
+ this.isWaitingForResponse = false;
1589
+ this.responseSettleIgnoreUntil = 0;
1590
+ this.submitRetryUsed = false;
1591
+ this.submitRetryPromptSnippet = '';
1592
+ this.finishRetryCount = 0;
1593
+ this.currentTurnScope = null;
1594
+ this.activeModal = null;
1595
+ this.setStatus('idle', 'parsed_idle_replay_commit');
1596
+ this.onStatusChange?.();
1597
+ }
1567
1598
  }
1568
1599
  const effectiveCommittedHydratedMessages = shouldAdoptParsedIdleReplay
1569
1600
  ? this.committedMessages.map((message, index) => buildChatMessage({
@@ -2160,8 +2191,9 @@ export class ProviderCliAdapter implements CliAdapter {
2160
2191
  }
2161
2192
 
2162
2193
  resolveModal(buttonIndex: number): void {
2163
- if (!this.ptyProcess || (this.currentStatus !== 'waiting_approval' && !this.activeModal)) return;
2164
- const modal = this.activeModal;
2194
+ const screenText = this.terminalScreen.getText() || '';
2195
+ const modal = this.activeModal || this.getStartupConfirmationModal(screenText);
2196
+ if (!this.ptyProcess || ((this.currentStatus !== 'waiting_approval') && !modal)) return;
2165
2197
  this.clearIdleFinishCandidate('resolve_modal');
2166
2198
  this.recordTrace('resolve_modal', {
2167
2199
  buttonIndex,
@@ -2176,7 +2208,10 @@ export class ProviderCliAdapter implements CliAdapter {
2176
2208
  }
2177
2209
  this.setStatus('generating', 'approval_resolved');
2178
2210
  this.onStatusChange?.();
2179
- if (this.shouldResolveModalWithEnter(modal, buttonIndex)) {
2211
+ const startupTrustModal = /Quick safety check|project trust|Confirm Claude Code project trust|trust (?:this project|the contents of this directory|the files in this folder)/i.test(String(modal?.message || ''));
2212
+ if (startupTrustModal && buttonIndex in this.approvalKeys) {
2213
+ this.ptyProcess.write(`${this.approvalKeys[buttonIndex]}\r`);
2214
+ } else if (this.shouldResolveModalWithEnter(modal, buttonIndex)) {
2180
2215
  this.ptyProcess.write('\r');
2181
2216
  } else if (buttonIndex in this.approvalKeys) {
2182
2217
  this.ptyProcess.write(this.approvalKeys[buttonIndex]);
@@ -2198,20 +2233,24 @@ export class ProviderCliAdapter implements CliAdapter {
2198
2233
  }
2199
2234
 
2200
2235
  getDebugState(): Record<string, any> {
2236
+ const screenText = sanitizeTerminalText(this.terminalScreen.getText());
2237
+ const startupModal = this.startupParseGate ? this.getStartupConfirmationModal(screenText) : null;
2238
+ const effectiveStatus = this.projectEffectiveStatus(startupModal);
2239
+ const effectiveReady = this.ready || !!startupModal;
2201
2240
  return {
2202
2241
  type: this.cliType,
2203
2242
  name: this.cliName,
2204
2243
  providerResolution: this.providerResolutionMeta,
2205
- status: this.currentStatus,
2206
- ready: this.ready,
2244
+ status: effectiveStatus,
2245
+ ready: effectiveReady,
2207
2246
  startupParseGate: this.startupParseGate,
2208
2247
  spawnAt: this.spawnAt,
2209
2248
  workingDir: this.workingDir,
2210
- messages: this.messages.slice(-20),
2211
- committedMessages: this.committedMessages.slice(-20),
2212
- structuredMessages: this.structuredMessages.slice(-20),
2249
+ messages: this.messages,
2250
+ committedMessages: this.committedMessages,
2251
+ structuredMessages: this.structuredMessages,
2213
2252
  messageCount: this.committedMessages.length,
2214
- screenText: sanitizeTerminalText(this.terminalScreen.getText()).slice(-4000),
2253
+ screenText: screenText.slice(-4000),
2215
2254
  currentTurnScope: this.currentTurnScope,
2216
2255
  startupBuffer: this.startupBuffer.slice(-4000),
2217
2256
  recentOutputBuffer: this.recentOutputBuffer.slice(-500),
@@ -2226,7 +2265,7 @@ export class ProviderCliAdapter implements CliAdapter {
2226
2265
  lastScreenChangeAt: this.lastScreenChangeAt,
2227
2266
  lastScreenSnapshot: this.lastScreenSnapshot.slice(-500),
2228
2267
  isWaitingForResponse: this.isWaitingForResponse,
2229
- activeModal: this.activeModal,
2268
+ activeModal: startupModal || this.activeModal,
2230
2269
  lastApprovalResolvedAt: this.lastApprovalResolvedAt,
2231
2270
  sendDelayMs: this.sendDelayMs,
2232
2271
  sendKey: this.sendKey,
@@ -139,10 +139,10 @@ export function buildCliParseInput(options: {
139
139
  runtimeSettings,
140
140
  } = options;
141
141
  const buffer = scope
142
- ? (sliceFromOffset(accumulatedBuffer, scope.bufferStart) || accumulatedBuffer)
142
+ ? sliceFromOffset(accumulatedBuffer, scope.bufferStart)
143
143
  : accumulatedBuffer;
144
144
  const rawBuffer = scope
145
- ? (sliceFromOffset(accumulatedRawBuffer, scope.rawBufferStart) || accumulatedRawBuffer)
145
+ ? sliceFromOffset(accumulatedRawBuffer, scope.rawBufferStart)
146
146
  : accumulatedRawBuffer;
147
147
  const screenText = terminalScreenText;
148
148
  const recentBuffer = buffer.slice(-1000) || recentOutputBuffer;
@@ -189,10 +189,10 @@ export function buildCliTraceParseSnapshot(options: {
189
189
  }): Record<string, any> {
190
190
  const { accumulatedBuffer, accumulatedRawBuffer, responseBuffer, partialResponse, scope } = options;
191
191
  const scopedBuffer = scope
192
- ? (sliceFromOffset(accumulatedBuffer, scope.bufferStart) || accumulatedBuffer)
192
+ ? sliceFromOffset(accumulatedBuffer, scope.bufferStart)
193
193
  : accumulatedBuffer;
194
194
  const scopedRawBuffer = scope
195
- ? (sliceFromOffset(accumulatedRawBuffer, scope.rawBufferStart) || accumulatedRawBuffer)
195
+ ? sliceFromOffset(accumulatedRawBuffer, scope.rawBufferStart)
196
196
  : accumulatedRawBuffer;
197
197
  return {
198
198
  currentTurnScope: scope || null,