@adhdev/daemon-core 0.9.82-rc.176 → 0.9.82-rc.178

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.
@@ -102,8 +102,11 @@ export declare class CliProviderInstance implements ProviderInstance {
102
102
  dispose(): void;
103
103
  private completedDebounceTimer;
104
104
  private completedDebouncePending;
105
+ private lastExternalCompletionProbe;
105
106
  private enforceFreshSessionLaunchIfNeeded;
106
107
  private completionHasFinalAssistantMessage;
108
+ private buildExternalTranscriptProbe;
109
+ private recordPendingTranscriptProbe;
107
110
  private readExternalCompletionMessages;
108
111
  private completionFinalAssistantEvidence;
109
112
  private completionFinalSummary;
@@ -7,6 +7,7 @@ export interface NativeHistoryInput {
7
7
  workspace?: string;
8
8
  format?: string;
9
9
  watchPath?: string;
10
+ forceRefresh?: boolean;
10
11
  args?: Record<string, unknown>;
11
12
  }
12
13
  export interface NativeHistoryResult {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.176",
3
+ "version": "0.9.82-rc.178",
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",
@@ -1423,6 +1423,7 @@ function callProviderNativeHistoryRead(
1423
1423
  excludeInProgressTurn?: boolean,
1424
1424
  sessionStartedAtMs?: number,
1425
1425
  envOverrides?: Record<string, string>,
1426
+ forceRefresh?: boolean,
1426
1427
  ): ProviderNativeHistoryReadResult | null {
1427
1428
  const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, 'readSession');
1428
1429
  if (!fn) return null;
@@ -1437,7 +1438,8 @@ function callProviderNativeHistoryRead(
1437
1438
  excludeInProgressTurn: excludeInProgressTurn === true,
1438
1439
  sessionStartedAtMs,
1439
1440
  envOverrides,
1440
- args: { sessionId: normalizedSessionId, historySessionId: normalizedSessionId, workspace, excludeInProgressTurn: excludeInProgressTurn === true, sessionStartedAtMs, envOverrides },
1441
+ forceRefresh: forceRefresh === true,
1442
+ args: { sessionId: normalizedSessionId, historySessionId: normalizedSessionId, workspace, excludeInProgressTurn: excludeInProgressTurn === true, sessionStartedAtMs, envOverrides, forceRefresh: forceRefresh === true },
1441
1443
  });
1442
1444
  if (!result || typeof result !== 'object') return null;
1443
1445
  const records = normalizeProviderNativeHistoryRecords(agentType, normalizedSessionId, (result as any).messages || (result as any).records);
@@ -1462,11 +1464,12 @@ function buildNativeHistoryReadResult(
1462
1464
  excludeInProgressTurn?: boolean,
1463
1465
  sessionStartedAtMs?: number,
1464
1466
  envOverrides?: Record<string, string>,
1467
+ forceRefresh?: boolean,
1465
1468
  ): ProviderNativeHistoryReadResult | null {
1466
1469
  const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || '');
1467
1470
  const normalizedWorkspace = typeof workspace === 'string' ? workspace.trim() : '';
1468
1471
  if (!canonicalHistory || (!normalizedSessionId && !normalizedWorkspace) || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
1469
- return callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace, excludeInProgressTurn, sessionStartedAtMs, envOverrides);
1472
+ return callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace, excludeInProgressTurn, sessionStartedAtMs, envOverrides, forceRefresh);
1470
1473
  }
1471
1474
 
1472
1475
  function materializeNativeHistoryToMirror(
@@ -1525,6 +1528,7 @@ export function readProviderChatHistory(
1525
1528
  excludeInProgressTurn?: boolean;
1526
1529
  sessionStartedAtMs?: number;
1527
1530
  envOverrides?: Record<string, string>;
1531
+ forceRefresh?: boolean;
1528
1532
  } = {},
1529
1533
  ): {
1530
1534
  messages: HistoryMessage[];
@@ -1538,7 +1542,7 @@ export function readProviderChatHistory(
1538
1542
  unavailableReason?: string;
1539
1543
  } {
1540
1544
  if (isNativeSourceCanonicalHistory(options.canonicalHistory) && (options.historySessionId || options.workspace)) {
1541
- const nativeResult = buildNativeHistoryReadResult(agentType, options.canonicalHistory, options.scripts, options.historySessionId, options.workspace, options.excludeInProgressTurn, options.sessionStartedAtMs, options.envOverrides);
1545
+ const nativeResult = buildNativeHistoryReadResult(agentType, options.canonicalHistory, options.scripts, options.historySessionId, options.workspace, options.excludeInProgressTurn, options.sessionStartedAtMs, options.envOverrides, options.forceRefresh);
1542
1546
  if (!nativeResult) return { messages: [], hasMore: false, source: 'native-unavailable' };
1543
1547
  return {
1544
1548
  ...pageHistoryRecords(agentType, nativeResult.records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
@@ -44,6 +44,8 @@ type CompletedDebouncePending = {
44
44
  firstObservedAt: number;
45
45
  previousStatus: string;
46
46
  loggedBlockReason?: string;
47
+ loggedTranscriptProbe?: boolean;
48
+ transcriptProbeHistory?: ExternalTranscriptProbe[];
47
49
  };
48
50
 
49
51
  function isIdleStatus(value: unknown): boolean {
@@ -70,6 +72,17 @@ type CompletionFinalAssistantEvidence = {
70
72
  source: 'parsed' | 'external-native' | 'unavailable';
71
73
  };
72
74
 
75
+ type ExternalTranscriptProbe = {
76
+ readAt: number;
77
+ msgCount: number;
78
+ lastRole: string | null;
79
+ lastKind: string | null;
80
+ contentLen: number;
81
+ sourcePath: string | null;
82
+ sourceMtimeMs: number | null;
83
+ mtimeAgeMs: number | null;
84
+ };
85
+
73
86
  const COMPLETED_FINALIZATION_RETRY_MS = 1000;
74
87
  const COMPLETED_FINALIZATION_MAX_WAIT_MS = 30_000;
75
88
 
@@ -855,6 +868,7 @@ export class CliProviderInstance implements ProviderInstance {
855
868
 
856
869
  private completedDebounceTimer: NodeJS.Timeout | null = null;
857
870
  private completedDebouncePending: CompletedDebouncePending | null = null;
871
+ private lastExternalCompletionProbe: ExternalTranscriptProbe | null = null;
858
872
 
859
873
  private async enforceFreshSessionLaunchIfNeeded(): Promise<void> {
860
874
  const scriptName = getForcedNewSessionScriptName(this.provider, this.launchMode);
@@ -896,12 +910,44 @@ export class CliProviderInstance implements ProviderInstance {
896
910
  return true;
897
911
  }
898
912
 
913
+ private buildExternalTranscriptProbe(messages: unknown[], sourcePath?: string, sourceMtimeMs?: number): ExternalTranscriptProbe {
914
+ const visibleMessages = messages.filter((message: any) => isUserFacingChatMessage(message as ChatMessage));
915
+ const lastVisible = visibleMessages[visibleMessages.length - 1] as ChatMessage | undefined;
916
+ const readAt = Date.now();
917
+ const mtimeMs = Number(sourceMtimeMs) || 0;
918
+ return {
919
+ readAt,
920
+ msgCount: messages.length,
921
+ lastRole: typeof lastVisible?.role === 'string' ? lastVisible.role.trim().toLowerCase() : null,
922
+ lastKind: typeof (lastVisible as any)?.kind === 'string' ? (lastVisible as any).kind : null,
923
+ contentLen: lastVisible ? flattenContent(lastVisible.content).trim().length : 0,
924
+ sourcePath: typeof sourcePath === 'string' && sourcePath ? sourcePath : null,
925
+ sourceMtimeMs: mtimeMs || null,
926
+ mtimeAgeMs: mtimeMs ? Math.max(0, readAt - mtimeMs) : null,
927
+ };
928
+ }
929
+
930
+ private recordPendingTranscriptProbe(pending: CompletedDebouncePending): ExternalTranscriptProbe | null {
931
+ const probe = this.lastExternalCompletionProbe;
932
+ if (!probe) return null;
933
+ const history = pending.transcriptProbeHistory || [];
934
+ const last = history[history.length - 1];
935
+ if (!last || last.readAt !== probe.readAt || last.msgCount !== probe.msgCount || last.lastRole !== probe.lastRole || last.contentLen !== probe.contentLen) {
936
+ history.push(probe);
937
+ pending.transcriptProbeHistory = history.slice(-5);
938
+ }
939
+ return probe;
940
+ }
941
+
899
942
  private readExternalCompletionMessages(): unknown[] | null {
900
943
  const adapterOwnsMessagesElsewhere = (this.adapter as any)?.chatMessagesOwnedExternally === true;
901
944
  if (!adapterOwnsMessagesElsewhere) return null;
902
945
  if (!this.providerSessionId) return null;
903
946
  if (!isNativeSourceCanonicalHistory(this.provider.nativeHistory)) return null;
904
947
 
948
+ if (this.lastExternalCompletionProbe?.sourcePath) {
949
+ try { fs.statSync(this.lastExternalCompletionProbe.sourcePath); } catch { /* best-effort metadata refresh */ }
950
+ }
905
951
  const restoredHistory = readProviderChatHistory(this.type, {
906
952
  canonicalHistory: this.provider.nativeHistory,
907
953
  historySessionId: this.providerSessionId,
@@ -911,8 +957,17 @@ export class CliProviderInstance implements ProviderInstance {
911
957
  historyBehavior: this.provider.historyBehavior,
912
958
  scripts: this.provider.scripts as any,
913
959
  sessionStartedAtMs: this.startedAt,
960
+ forceRefresh: true,
914
961
  });
915
- if (restoredHistory.source !== 'provider-native') return null;
962
+ if (restoredHistory.source !== 'provider-native') {
963
+ this.lastExternalCompletionProbe = null;
964
+ return null;
965
+ }
966
+ this.lastExternalCompletionProbe = this.buildExternalTranscriptProbe(
967
+ restoredHistory.messages,
968
+ restoredHistory.sourcePath,
969
+ restoredHistory.sourceMtimeMs,
970
+ );
916
971
  return restoredHistory.messages;
917
972
  }
918
973
 
@@ -963,6 +1018,9 @@ export class CliProviderInstance implements ProviderInstance {
963
1018
  }
964
1019
 
965
1020
  const evidence = this.completionFinalAssistantEvidence(parsed?.messages);
1021
+ if (evidence.source === 'external-native') {
1022
+ this.recordPendingTranscriptProbe(args.pending);
1023
+ }
966
1024
  const visibleMessages = (Array.isArray(evidence.messages) ? evidence.messages : [])
967
1025
  .filter((message: any) => isUserFacingChatMessage(message as ChatMessage));
968
1026
  const lastVisible = visibleMessages[visibleMessages.length - 1] as ChatMessage | undefined;
@@ -994,6 +1052,7 @@ export class CliProviderInstance implements ProviderInstance {
994
1052
  pendingTimestamp: args.pending.timestamp,
995
1053
  pendingDurationSec: args.pending.duration,
996
1054
  previousBlockReason: args.pending.loggedBlockReason || null,
1055
+ transcriptProbeHistory: args.pending.transcriptProbeHistory || [],
997
1056
  };
998
1057
  }
999
1058
 
@@ -1066,6 +1125,11 @@ export class CliProviderInstance implements ProviderInstance {
1066
1125
  if (!finalAssistantEvidence.present) {
1067
1126
  if (adapterOwnsMessagesElsewhere) {
1068
1127
  if (finalAssistantEvidence.source === 'external-native') {
1128
+ const probe = this.recordPendingTranscriptProbe(pending);
1129
+ if (probe && !pending.loggedTranscriptProbe) {
1130
+ 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`);
1131
+ pending.loggedTranscriptProbe = true;
1132
+ }
1069
1133
  return { reason: 'missing_final_assistant', terminal: true };
1070
1134
  }
1071
1135
  // SpecCliAdapter never populates parsed.messages — chat history flows
@@ -29,6 +29,7 @@ export interface NativeHistoryInput {
29
29
  workspace?: string;
30
30
  format?: string;
31
31
  watchPath?: string;
32
+ forceRefresh?: boolean;
32
33
  args?: Record<string, unknown>;
33
34
  }
34
35
 
@@ -54,6 +55,9 @@ export function createNativeHistoryDispatcher(reader: ReaderId): (input: NativeH
54
55
 
55
56
  const sourcePath = resolveSourcePath(reader, workspace, sessionId);
56
57
  if (!sourcePath) return null;
58
+ if (input.forceRefresh === true || input.args?.forceRefresh === true) {
59
+ try { fs.statSync(sourcePath); } catch { /* best-effort metadata refresh */ }
60
+ }
57
61
 
58
62
  const session = readByReader(reader, sourcePath, sessionId, workspace);
59
63
  if (!session) return null;
@@ -151,7 +151,7 @@ export class SpecCliAdapter implements CliAdapter {
151
151
  activeInteractivePrompt: this.activeInteractivePrompt,
152
152
  };
153
153
  }
154
- if (/busy|generating|working|running|thinking/i.test(lc + ' ' + state.label)) {
154
+ if (lc === 'busy' || lc === 'generating') {
155
155
  return { status: 'generating', messages: [], activeModal: null, activeInteractivePrompt: this.activeInteractivePrompt };
156
156
  }
157
157
  return { status: 'idle', messages: [], activeModal: null, activeInteractivePrompt: this.activeInteractivePrompt };
@@ -301,6 +301,27 @@ export class SpecCliAdapter implements CliAdapter {
301
301
  return Promise.resolve({ ok: true, effects });
302
302
  }
303
303
  getDebugSnapshot(): unknown {
304
+ let screen = '';
305
+ let sections: Record<string, string> | undefined;
306
+ try {
307
+ screen = this.driver.snapshot();
308
+ const lines = screen.split('\n');
309
+ sections = {};
310
+ for (const sec of this.spec.layout?.sections ?? []) {
311
+ const from = (sec as any).from_top;
312
+ const fromBottom = (sec as any).from_bottom;
313
+ let start = 0;
314
+ let end = lines.length;
315
+ if (typeof from === 'number') start = Math.max(0, from);
316
+ else if (typeof fromBottom === 'number') start = Math.max(0, lines.length - fromBottom);
317
+ const until = (sec as any).until;
318
+ if (until && typeof until === 'object' && typeof until.section === 'string') {
319
+ const ref = (this.spec.layout?.sections ?? []).find((s: any) => s.id === until.section) as any;
320
+ if (ref && typeof ref.from_bottom === 'number') end = Math.max(start, lines.length - ref.from_bottom);
321
+ }
322
+ sections[(sec as any).id] = lines.slice(start, end).join('\n');
323
+ }
324
+ } catch { /* best-effort */ }
304
325
  return {
305
326
  cliType: this.cliType,
306
327
  spec_id: this.spec.id,
@@ -308,6 +329,8 @@ export class SpecCliAdapter implements CliAdapter {
308
329
  current_modal: this.latestModal,
309
330
  activeInteractivePrompt: this.activeInteractivePrompt,
310
331
  exited: this.exited,
332
+ screen,
333
+ sections,
311
334
  };
312
335
  }
313
336
  getRuntimeMetadata(): unknown {