@adhdev/daemon-core 0.9.82-rc.192 → 0.9.82-rc.194

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.
@@ -84,6 +84,7 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
84
84
  duplicateRefineTerminalEvent?: undefined;
85
85
  duplicateApproval?: undefined;
86
86
  duplicateCompletion?: undefined;
87
+ duplicateStopped?: undefined;
87
88
  error?: undefined;
88
89
  bufferedForGeneratingCoordinator?: undefined;
89
90
  } | {
@@ -96,6 +97,7 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
96
97
  duplicateRefineTerminalEvent?: undefined;
97
98
  duplicateApproval?: undefined;
98
99
  duplicateCompletion?: undefined;
100
+ duplicateStopped?: undefined;
99
101
  error?: undefined;
100
102
  bufferedForGeneratingCoordinator?: undefined;
101
103
  } | {
@@ -108,6 +110,7 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
108
110
  terminalLedgerKind?: undefined;
109
111
  duplicateApproval?: undefined;
110
112
  duplicateCompletion?: undefined;
113
+ duplicateStopped?: undefined;
111
114
  error?: undefined;
112
115
  bufferedForGeneratingCoordinator?: undefined;
113
116
  } | {
@@ -120,6 +123,7 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
120
123
  terminalLedgerKind?: undefined;
121
124
  duplicateRefineTerminalEvent?: undefined;
122
125
  duplicateCompletion?: undefined;
126
+ duplicateStopped?: undefined;
123
127
  error?: undefined;
124
128
  bufferedForGeneratingCoordinator?: undefined;
125
129
  } | {
@@ -132,6 +136,7 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
132
136
  terminalLedgerKind?: undefined;
133
137
  duplicateRefineTerminalEvent?: undefined;
134
138
  duplicateApproval?: undefined;
139
+ duplicateStopped?: undefined;
135
140
  error?: undefined;
136
141
  bufferedForGeneratingCoordinator?: undefined;
137
142
  } | {
@@ -144,6 +149,20 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
144
149
  terminalLedgerKind?: undefined;
145
150
  duplicateRefineTerminalEvent?: undefined;
146
151
  duplicateApproval?: undefined;
152
+ duplicateStopped?: undefined;
153
+ error?: undefined;
154
+ bufferedForGeneratingCoordinator?: undefined;
155
+ } | {
156
+ success: boolean;
157
+ forwarded: number;
158
+ suppressed: boolean;
159
+ duplicateStopped: boolean;
160
+ intentionalCleanupStop?: undefined;
161
+ terminalLedgerEvidence?: undefined;
162
+ terminalLedgerKind?: undefined;
163
+ duplicateRefineTerminalEvent?: undefined;
164
+ duplicateApproval?: undefined;
165
+ duplicateCompletion?: undefined;
147
166
  error?: undefined;
148
167
  bufferedForGeneratingCoordinator?: undefined;
149
168
  } | {
@@ -156,6 +175,7 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
156
175
  duplicateRefineTerminalEvent?: undefined;
157
176
  duplicateApproval?: undefined;
158
177
  duplicateCompletion?: undefined;
178
+ duplicateStopped?: undefined;
159
179
  error?: undefined;
160
180
  bufferedForGeneratingCoordinator?: undefined;
161
181
  } | {
@@ -169,6 +189,7 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
169
189
  duplicateRefineTerminalEvent?: undefined;
170
190
  duplicateApproval?: undefined;
171
191
  duplicateCompletion?: undefined;
192
+ duplicateStopped?: undefined;
172
193
  error?: undefined;
173
194
  } | {
174
195
  success: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.192",
3
+ "version": "0.9.82-rc.194",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -534,7 +534,7 @@ export class CliStateEngine {
534
534
  const recentInteractiveActivity = this.hasRecentInteractiveActivity(snap, now);
535
535
  LOG.debug(
536
536
  'CLI',
537
- `[${this.provider.type}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope?.prompt || '').slice(0, 140)} status=${String(status || '')} parsedStatus=${String(parsedStatus || '')} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify((lastParsedAssistant?.content || '').slice(0, 120)).slice(0, 160)} responseBuffer=${JSON.stringify((snap.responseBuffer || '').slice(0, 160)).slice(0, 220)}`
537
+ `[${this.provider.type}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope?.prompt || '').slice(0, 140)} status=${String(status || '')} parsedStatus=${String(parsedStatus || '')} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify((lastParsedAssistant?.content || '').slice(0, 120)).slice(0, 160)} responseBuffer=${JSON.stringify((snap.responseBuffer || '').slice(0, 160)).slice(0, 220)} recentActivity=${recentInteractiveActivity}`
538
538
  );
539
539
 
540
540
  // recent_activity_hold protects an in-flight user turn from a false
@@ -544,11 +544,21 @@ export class CliStateEngine {
544
544
  // produced the startup status flip the user reported
545
545
  // (generating → idle → generating → idle within the first few seconds
546
546
  // of claude-cli launch).
547
+ //
548
+ // When isWaitingForResponse=true and a currentTurnScope is alive, a
549
+ // PTY quiet period (>statusActivityHold ms without output) does NOT
550
+ // mean the response is done — claude-cli regularly pauses 2s+ between
551
+ // chunks during parsing/generation. recentInteractiveActivity going
552
+ // false during such a pause was the root cause of false-idle
553
+ // regressions. We hold generating whenever an active response turn is
554
+ // in flight (unconditionally, not just when there was recent output).
555
+ // The real completion gate is applyIdle's idleFinishCandidate +
556
+ // idleFinish timeout, which requires stable quiet AND a parsed
557
+ // assistant message.
547
558
  const shouldHoldGenerating = status === 'idle'
548
559
  && this.isWaitingForResponse
549
560
  && !!this.currentTurnScope
550
561
  && !modal
551
- && recentInteractiveActivity
552
562
  && !(parsedStatus === 'idle' && !!lastParsedAssistant);
553
563
 
554
564
  if (shouldHoldGenerating) { this.applyHoldGenerating(ctx); return; }
@@ -1631,6 +1631,22 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
1631
1631
  return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
1632
1632
  }
1633
1633
  }
1634
+ if (args.event === 'agent:stopped' && eventSessionId) {
1635
+ const duplicateStopped = isDuplicateMeshCompletionEvent({
1636
+ meshId: args.meshId,
1637
+ event: args.event,
1638
+ sessionId: eventSessionId,
1639
+ providerType: readNonEmptyString(args.metadataEvent.providerType) || undefined,
1640
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
1641
+ timestamp: eventTimestamp,
1642
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
1643
+ coordinatorDaemonId: workerCoordinatorDaemonId || undefined,
1644
+ });
1645
+ if (duplicateStopped) {
1646
+ LOG.info('MeshEvents', `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
1647
+ return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
1648
+ }
1649
+ }
1634
1650
 
1635
1651
  // ── Task Queue & Ledger ──
1636
1652
  // Helpers that keep queue and direct-dispatch status transitions symmetric.
@@ -602,6 +602,16 @@ export class CliProviderInstance implements ProviderInstance {
602
602
  if (externalNativeFinal && isCliGeneratingLikeStatus(visibleStatus)) {
603
603
  visibleStatus = 'idle';
604
604
  }
605
+ // Adapter raw status can lag behind parsed/native evidence: if the spec driver
606
+ // has not yet emitted a state_changed(idle) event but the parsed transcript
607
+ // already shows a final assistant turn, treat the session as idle so that
608
+ // getState() agrees with what detectStatusTransition already recorded via
609
+ // lastStatus. Without this guard, getState() returns 'generating' even after
610
+ // the instance's lastStatus has flipped to 'idle', causing the dashboard to
611
+ // show a perpetual generating spinner.
612
+ if (isCliGeneratingLikeStatus(visibleStatus) && this.lastStatus === 'idle') {
613
+ visibleStatus = 'idle';
614
+ }
605
615
  const runtime = this.adapter.getRuntimeMetadata();
606
616
  this.maybeAppendRuntimeRecoveryMessage(runtime);
607
617
  let parsedMessages = Array.isArray(parsedStatus?.messages)
@@ -1263,6 +1273,9 @@ export class CliProviderInstance implements ProviderInstance {
1263
1273
  LOG.info('CLI', `[${this.type}] external transcript probe: msgCount=${probe.msgCount} lastRole=${probe.lastRole || 'none'} lastKind=${probe.lastKind || 'none'} contentLen=${probe.contentLen} sourceMtime=${probe.sourceMtimeMs ?? 'unknown'} mtimeAge=${probe.mtimeAgeMs ?? 'unknown'}ms`);
1264
1274
  pending.loggedTranscriptProbe = true;
1265
1275
  }
1276
+ if (this.type === 'antigravity-cli') {
1277
+ return null;
1278
+ }
1266
1279
  return { reason: 'missing_final_assistant', terminal: true, allowTimeout: allowMissingAssistantTimeout };
1267
1280
  }
1268
1281
  // SpecCliAdapter never populates parsed.messages — chat history flows
@@ -1637,6 +1650,9 @@ export class CliProviderInstance implements ProviderInstance {
1637
1650
  },
1638
1651
  });
1639
1652
  this.generatingStartedAt = 0;
1653
+ // Cancel any pending debounce flush — monitor already fired completion.
1654
+ if (this.completedDebounceTimer) { clearTimeout(this.completedDebounceTimer); this.completedDebounceTimer = null; }
1655
+ this.completedDebouncePending = null;
1640
1656
  continue;
1641
1657
  }
1642
1658
  this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
@@ -353,7 +353,10 @@ export function buildClaudeInteractiveTuiAnswerSteps(
353
353
  if (answer.selectedLabels.length !== 1) throw new Error(`Expected one selected label for ${question.questionId}`);
354
354
  const selectedIndex = question.options.findIndex(option => option.label === answer.selectedLabels[0]);
355
355
  if (selectedIndex < 0) throw new Error(`Unknown option for ${question.questionId}: ${answer.selectedLabels[0]}`);
356
- steps.push(`${'\x1b[B'.repeat(selectedIndex)}\r`);
356
+ for (let i = 0; i < selectedIndex; i += 1) {
357
+ steps.push('\x1b[B');
358
+ }
359
+ steps.push('\r');
357
360
  }
358
361
  steps.push('\r');
359
362
  return steps;