@adhdev/daemon-core 0.9.31 → 0.9.32

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.
@@ -85,6 +85,7 @@ export declare class ProviderLoader {
85
85
  probeStarts?: string[];
86
86
  });
87
87
  private log;
88
+ private debugLog;
88
89
  /**
89
90
  * User override root (~/.adhdev/providers by default).
90
91
  */
@@ -15,6 +15,7 @@ export declare function classifyHotChatSessionsForSubscriptionFlush(sessions: Ho
15
15
  now?: number;
16
16
  recentMessageGraceMs?: number;
17
17
  activeStatuses?: ReadonlySet<string>;
18
+ activeSessionIds?: ReadonlySet<string>;
18
19
  }): {
19
20
  active: Set<string>;
20
21
  finalizing: Set<string>;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/session-host-core",
3
- "version": "0.9.31",
3
+ "version": "0.9.32",
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.9.31",
3
+ "version": "0.9.32",
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",
@@ -282,6 +282,7 @@ export class ProviderCliAdapter implements CliAdapter {
282
282
  private static readonly STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS = 1000;
283
283
  private static readonly SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
284
284
  private static readonly MAX_TRACE_ENTRIES = 250;
285
+ private static readonly PARSE_MESSAGE_TAIL_LIMIT = 100;
285
286
 
286
287
  private readonly providerResolutionMeta: ProviderResolutionMeta;
287
288
  private static readonly FINISH_RETRY_DELAY_MS = 300;
@@ -333,6 +334,42 @@ export class ProviderCliAdapter implements CliAdapter {
333
334
  return null;
334
335
  }
335
336
 
337
+ private selectParseBaseMessages(baseMessages: CliChatMessage[]): CliChatMessage[] {
338
+ if (baseMessages.length <= ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
339
+ return baseMessages.slice(-ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
340
+ }
341
+
342
+ private messagesComparable(left: any, right: any): boolean {
343
+ if (!left || !right) return false;
344
+ if ((left.role || '') !== (right.role || '')) return false;
345
+ const leftText = normalizeComparableTranscriptText(left.content);
346
+ const rightText = normalizeComparableTranscriptText(right.content);
347
+ return !!leftText && leftText === rightText;
348
+ }
349
+
350
+ private stitchParsedMessagesWithCommittedBase(
351
+ parsedMessages: any[],
352
+ fullBaseMessages: CliChatMessage[],
353
+ parseBaseMessages: CliChatMessage[],
354
+ ): any[] {
355
+ if (!Array.isArray(parsedMessages) || parsedMessages.length === 0) return parsedMessages;
356
+ if (fullBaseMessages.length <= parseBaseMessages.length) return parsedMessages;
357
+
358
+ const parsedFirst = parsedMessages[0];
359
+ const fullFirst = fullBaseMessages[0];
360
+ if (parsedMessages.length >= fullBaseMessages.length && this.messagesComparable(parsedFirst, fullFirst)) {
361
+ return parsedMessages;
362
+ }
363
+
364
+ const tailFirst = parseBaseMessages[0];
365
+ if (tailFirst && this.messagesComparable(parsedFirst, tailFirst)) {
366
+ const prefixLength = fullBaseMessages.length - parseBaseMessages.length;
367
+ return [...fullBaseMessages.slice(0, prefixLength), ...parsedMessages];
368
+ }
369
+
370
+ return [...fullBaseMessages, ...parsedMessages];
371
+ }
372
+
336
373
  private getIdleFinishConfirmMs(): number {
337
374
  return this.timeouts.idleFinishConfirm;
338
375
  }
@@ -1044,7 +1081,7 @@ export class ProviderCliAdapter implements CliAdapter {
1044
1081
  if (!this.applyPendingScriptStatusDebounce(ctx)) return;
1045
1082
 
1046
1083
  const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
1047
- LOG.info(
1084
+ LOG.debug(
1048
1085
  'CLI',
1049
1086
  `[${this.cliType}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope?.prompt || '').slice(0, 140)} status=${String(status || '')} parsedStatus=${String(parsedStatus || '')} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify(summarizeCliTraceText(lastParsedAssistant?.content || '', 120)).slice(0, 160)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 160)).slice(0, 220)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 160)).slice(0, 220)}`
1050
1087
  );
@@ -1439,18 +1476,26 @@ export class ProviderCliAdapter implements CliAdapter {
1439
1476
  try {
1440
1477
  const screenText = this.terminalScreen.getText();
1441
1478
  const tail = this.recentOutputBuffer.slice(-500);
1479
+ const parseBaseMessages = this.selectParseBaseMessages(this.committedMessages);
1442
1480
  const input = buildCliParseInput({
1443
1481
  accumulatedBuffer: this.accumulatedBuffer,
1444
1482
  accumulatedRawBuffer: this.accumulatedRawBuffer,
1445
1483
  recentOutputBuffer: this.recentOutputBuffer,
1446
1484
  terminalScreenText: screenText,
1447
- baseMessages: this.committedMessages,
1485
+ baseMessages: parseBaseMessages,
1448
1486
  partialResponse: this.responseBuffer,
1449
1487
  isWaitingForResponse: this.isWaitingForResponse,
1450
1488
  scope: this.currentTurnScope,
1451
1489
  runtimeSettings: this.runtimeSettings,
1452
1490
  });
1453
1491
  const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
1492
+ if (session && typeof session === 'object' && Array.isArray(session.messages)) {
1493
+ session.messages = this.stitchParsedMessagesWithCommittedBase(
1494
+ session.messages,
1495
+ this.committedMessages,
1496
+ parseBaseMessages,
1497
+ );
1498
+ }
1454
1499
  this.parseErrorMessage = null;
1455
1500
  return session && typeof session === 'object' ? session : null;
1456
1501
  } catch (e: any) {
@@ -1871,12 +1916,13 @@ export class ProviderCliAdapter implements CliAdapter {
1871
1916
  }
1872
1917
  try {
1873
1918
  const screenText = typeof screenTextOverride === 'string' ? screenTextOverride : this.terminalScreen.getText();
1919
+ const parseBaseMessages = this.selectParseBaseMessages(baseMessages);
1874
1920
  const input = buildCliParseInput({
1875
1921
  accumulatedBuffer: this.accumulatedBuffer,
1876
1922
  accumulatedRawBuffer: this.accumulatedRawBuffer,
1877
1923
  recentOutputBuffer: this.recentOutputBuffer,
1878
1924
  terminalScreenText: screenText,
1879
- baseMessages,
1925
+ baseMessages: parseBaseMessages,
1880
1926
  partialResponse,
1881
1927
  isWaitingForResponse: this.isWaitingForResponse,
1882
1928
  scope,
@@ -1888,6 +1934,11 @@ export class ProviderCliAdapter implements CliAdapter {
1888
1934
  }
1889
1935
  const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
1890
1936
  if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
1937
+ normalizedParsed.messages = this.stitchParsedMessagesWithCommittedBase(
1938
+ normalizedParsed.messages,
1939
+ baseMessages,
1940
+ parseBaseMessages,
1941
+ );
1891
1942
  this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
1892
1943
  }
1893
1944
  this.parseErrorMessage = null;
@@ -175,19 +175,18 @@ export function daemonLog(category: string, msg: string, level: LogLevel = 'info
175
175
  const label = LEVEL_LABEL[level];
176
176
  const line = `[${ts()}] [${label}] [${category}] ${msg}`;
177
177
 
178
- // Always record to file (including DEBUG)
178
+ // Apply the active log level consistently to console, file, and the remote ring buffer.
179
+ // Debug hot paths are useful when explicitly enabled, but should not inflate normal-mode logs.
180
+ if (!shouldOutput) return;
181
+
179
182
  writeToFile(line);
180
183
 
181
- // Always save to ring buffer (for remote transmission)
182
184
  ringBuffer.push({ ts: Date.now(), level, category, message: msg });
183
185
  if (ringBuffer.length > RING_BUFFER_SIZE) {
184
186
  ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
185
187
  }
186
188
 
187
- // Apply filter to console output
188
- if (shouldOutput) {
189
- origConsoleLog(line);
190
- }
189
+ origConsoleLog(line);
191
190
  }
192
191
 
193
192
  // ─── Convenience API ────────────────────────────────
@@ -199,6 +199,10 @@ export class ProviderLoader {
199
199
  this.logFn(`[ProviderLoader] ${msg}`);
200
200
  }
201
201
 
202
+ private debugLog(msg: string): void {
203
+ LOG.debug('Provider', `[ProviderLoader] ${msg}`);
204
+ }
205
+
202
206
  // ─── Public API ────────────────────────────────
203
207
 
204
208
  /**
@@ -892,7 +896,7 @@ export class ProviderLoader {
892
896
  const loaded = this.loadScriptsFromDir(type, entry.scriptDir);
893
897
  if (loaded) {
894
898
  resolved.scripts = loaded;
895
- this.log(` [compatibility] ${type} v${currentVersion} → ${entry.scriptDir}`);
899
+ this.debugLog(` [compatibility] ${type} v${currentVersion} → ${entry.scriptDir}`);
896
900
  resolved._resolvedScriptDir = entry.scriptDir;
897
901
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
898
902
  if (providerDir) {
@@ -912,7 +916,7 @@ export class ProviderLoader {
912
916
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
913
917
  if (loaded) {
914
918
  resolved.scripts = loaded;
915
- this.log(` [compatibility] ${type} v${currentVersion} → default: ${base.defaultScriptDir}`);
919
+ this.debugLog(` [compatibility] ${type} v${currentVersion} → default: ${base.defaultScriptDir}`);
916
920
  resolved._resolvedScriptDir = base.defaultScriptDir;
917
921
  resolved._resolvedScriptsSource = 'defaultScriptDir:version_miss';
918
922
  if (providerDir) {
@@ -955,7 +959,7 @@ export class ProviderLoader {
955
959
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
956
960
  if (loaded) {
957
961
  resolved.scripts = loaded;
958
- this.log(` [compatibility] ${type} no version detected → default: ${base.defaultScriptDir}`);
962
+ this.debugLog(` [compatibility] ${type} no version detected → default: ${base.defaultScriptDir}`);
959
963
  resolved._resolvedScriptDir = base.defaultScriptDir;
960
964
  resolved._resolvedScriptsSource = 'defaultScriptDir:no_version';
961
965
  if (providerDir) {
@@ -59,6 +59,7 @@ export function classifyHotChatSessionsForSubscriptionFlush(
59
59
  now?: number;
60
60
  recentMessageGraceMs?: number;
61
61
  activeStatuses?: ReadonlySet<string>;
62
+ activeSessionIds?: ReadonlySet<string>;
62
63
  } = {},
63
64
  ): { active: Set<string>; finalizing: Set<string> } {
64
65
  const now = options.now ?? Date.now();
@@ -69,6 +70,7 @@ export function classifyHotChatSessionsForSubscriptionFlush(
69
70
  : DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS,
70
71
  );
71
72
  const activeStatuses = options.activeStatuses ?? DEFAULT_ACTIVE_CHAT_POLL_STATUSES;
73
+ const activeSessionIds = options.activeSessionIds ?? new Set<string>();
72
74
  const active = new Set<string>();
73
75
  const excluded = new Set<string>();
74
76
 
@@ -79,6 +81,10 @@ export function classifyHotChatSessionsForSubscriptionFlush(
79
81
  excluded.add(sessionId);
80
82
  continue;
81
83
  }
84
+ if (activeSessionIds.has(sessionId)) {
85
+ active.add(sessionId);
86
+ continue;
87
+ }
82
88
 
83
89
  const status = String(session?.status || '').toLowerCase();
84
90
  const unread = session?.unread === true;