@adhdev/daemon-core 0.8.75 → 0.8.77

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/src/index.ts CHANGED
@@ -205,6 +205,8 @@ export {
205
205
  prepareSessionChatTailUpdate,
206
206
  prepareSessionModalUpdate,
207
207
  } from './chat/subscription-updates.js';
208
+ export { runAsyncBatch } from './chat/async-batch.js';
209
+ export type { AsyncBatchOptions } from './chat/async-batch.js';
208
210
  export type {
209
211
  ChatTailSubscriptionCursor,
210
212
  PrepareSessionChatTailUpdateInput,
@@ -383,8 +383,12 @@ export class CliProviderInstance implements ProviderInstance {
383
383
  runtimeKey: runtime.runtimeKey,
384
384
  displayName: runtime.displayName,
385
385
  workspaceLabel: runtime.workspaceLabel,
386
+ lifecycle: runtime.lifecycle ?? null,
387
+ surfaceKind: runtime.surfaceKind,
386
388
  writeOwner: runtime.writeOwner || null,
387
389
  attachedClients: runtime.attachedClients || [],
390
+ restoredFromStorage: runtime.restoredFromStorage === true,
391
+ recoveryState: runtime.recoveryState ?? null,
388
392
  } : undefined,
389
393
  resume: this.provider.resume,
390
394
  controlValues: surface.controlValues,
@@ -32,8 +32,12 @@ export interface ProviderRuntimeInfo {
32
32
  runtimeKey?: string;
33
33
  displayName?: string;
34
34
  workspaceLabel?: string;
35
+ lifecycle?: string | null;
36
+ surfaceKind?: 'live_runtime' | 'recovery_snapshot' | 'inactive_record';
35
37
  writeOwner?: ProviderRuntimeWriteOwner | null;
36
38
  attachedClients?: ProviderRuntimeClient[];
39
+ restoredFromStorage?: boolean;
40
+ recoveryState?: string | null;
37
41
  }
38
42
 
39
43
  export interface ActiveChatData {
@@ -309,10 +309,14 @@ export interface SessionEntry {
309
309
  runtimeKey?: string;
310
310
  runtimeDisplayName?: string;
311
311
  runtimeWorkspaceLabel?: string;
312
+ runtimeLifecycle?: string | null;
313
+ runtimeSurfaceKind?: 'live_runtime' | 'recovery_snapshot' | 'inactive_record';
312
314
  /** CLI only: active presentation mode */
313
315
  mode?: 'terminal' | 'chat';
314
316
  runtimeWriteOwner?: RuntimeWriteOwner | null;
315
317
  runtimeAttachedClients?: RuntimeAttachedClient[];
318
+ runtimeRestoredFromStorage?: boolean;
319
+ runtimeRecoveryState?: string | null;
316
320
  resume?: ProviderResumeCapability;
317
321
  activeChat: _ActiveChatData | null;
318
322
  capabilities?: SessionCapability[];
@@ -50,7 +50,7 @@ function shouldIncludeSessionMetadata(profile: SessionEntryProfile): boolean {
50
50
  }
51
51
 
52
52
  function shouldIncludeRuntimeMetadata(profile: SessionEntryProfile): boolean {
53
- return profile !== 'live';
53
+ return true;
54
54
  }
55
55
 
56
56
  // ─── CDP Manager lookup helpers ──────────────────────
@@ -214,6 +214,33 @@ function buildExtensionAgentSession(
214
214
  };
215
215
  }
216
216
 
217
+ function shouldIncludeExtensionSession(ext: ExtensionProviderState): boolean {
218
+ const status = String(ext.status || '').trim().toLowerCase();
219
+ const hasActiveChat = !!ext.activeChat;
220
+ const hasMessages = Array.isArray(ext.activeChat?.messages) && ext.activeChat!.messages.length > 0;
221
+ const hasModal = !!ext.activeChat?.activeModal;
222
+ const hasStreams = Array.isArray((ext as any).agentStreams) && (ext as any).agentStreams.length > 0;
223
+ const hasProviderSessionId = typeof ext.providerSessionId === 'string' && ext.providerSessionId.trim().length > 0;
224
+ const hasControlValues = !!(ext.controlValues && Object.keys(ext.controlValues).length > 0);
225
+ const hasProviderControls = Array.isArray(ext.providerControls) && ext.providerControls.length > 0;
226
+ const hasOpenPanelCapability = Array.isArray(ext.sessionCapabilities) && ext.sessionCapabilities.includes('open_panel');
227
+ const hasSummaryMetadata = !!ext.summaryMetadata;
228
+ const hasError = typeof ext.errorMessage === 'string' && ext.errorMessage.trim().length > 0;
229
+ const hasInterestingStatus = !!status && !['idle', 'panel_hidden', 'disconnected', 'not_monitored'].includes(status);
230
+
231
+ return hasActiveChat
232
+ || hasMessages
233
+ || hasModal
234
+ || hasStreams
235
+ || hasProviderSessionId
236
+ || hasControlValues
237
+ || hasProviderControls
238
+ || hasOpenPanelCapability
239
+ || hasSummaryMetadata
240
+ || hasError
241
+ || hasInterestingStatus;
242
+ }
243
+
217
244
  function buildCliSession(state: CliProviderState, options: SessionEntryBuildOptions): SessionEntry {
218
245
  const profile = options.profile || 'full';
219
246
  const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
@@ -239,8 +266,12 @@ function buildCliSession(state: CliProviderState, options: SessionEntryBuildOpti
239
266
  runtimeKey: state.runtime?.runtimeKey,
240
267
  runtimeDisplayName: state.runtime?.displayName,
241
268
  runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
269
+ runtimeLifecycle: state.runtime?.lifecycle ?? null,
270
+ runtimeSurfaceKind: state.runtime?.surfaceKind,
242
271
  runtimeWriteOwner: state.runtime?.writeOwner || null,
243
272
  runtimeAttachedClients: state.runtime?.attachedClients || [],
273
+ runtimeRestoredFromStorage: state.runtime?.restoredFromStorage === true,
274
+ runtimeRecoveryState: state.runtime?.recoveryState ?? null,
244
275
  }),
245
276
  mode: state.mode,
246
277
  resume: state.resume,
@@ -305,6 +336,7 @@ export function buildSessionEntries(
305
336
  for (const state of ideStates) {
306
337
  sessions.push(buildIdeWorkspaceSession(state, cdpManagers, options));
307
338
  for (const ext of state.extensions as ExtensionProviderState[]) {
339
+ if (!shouldIncludeExtensionSession(ext)) continue;
308
340
  sessions.push(buildExtensionAgentSession(state, ext, options));
309
341
  }
310
342
  }
@@ -1,3 +1,5 @@
1
+ import { getSessionHostSurfaceKind } from '../session-host/runtime-surface.js';
2
+
1
3
  export const DEFAULT_ACTIVE_CHAT_POLL_STATUSES = new Set([
2
4
  'generating',
3
5
  'waiting_approval',
@@ -6,10 +8,16 @@ export const DEFAULT_ACTIVE_CHAT_POLL_STATUSES = new Set([
6
8
 
7
9
  export const DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS = 8_000;
8
10
 
11
+ const LIVE_RUNTIME_LIFECYCLES = new Set(['starting', 'running', 'stopping', 'interrupted']);
12
+
9
13
  export interface HotChatSessionLike {
10
14
  id?: string | null;
11
15
  status?: unknown;
12
16
  lastMessageAt?: unknown;
17
+ runtimeLifecycle?: unknown;
18
+ runtimeSurfaceKind?: unknown;
19
+ runtimeRestoredFromStorage?: unknown;
20
+ runtimeRecoveryState?: unknown;
13
21
  }
14
22
 
15
23
  function parseMessageTimestamp(value: unknown): number {
@@ -21,6 +29,27 @@ function parseMessageTimestamp(value: unknown): number {
21
29
  return 0;
22
30
  }
23
31
 
32
+ function isDefinitelyNonLiveRuntimeSession(session: HotChatSessionLike): boolean {
33
+ const surfaceKind = String(session?.runtimeSurfaceKind || '').trim();
34
+ if (surfaceKind === 'live_runtime') return false;
35
+ if (surfaceKind === 'recovery_snapshot') return true;
36
+ if (surfaceKind === 'inactive_record') return false;
37
+
38
+ const lifecycle = String(session?.runtimeLifecycle || '').trim();
39
+ if (lifecycle && LIVE_RUNTIME_LIFECYCLES.has(lifecycle)) return false;
40
+
41
+ const inferredSurfaceKind = getSessionHostSurfaceKind({
42
+ lifecycle: lifecycle || null,
43
+ meta: {
44
+ restoredFromStorage: session?.runtimeRestoredFromStorage === true,
45
+ ...(session?.runtimeRecoveryState ? { runtimeRecoveryState: session.runtimeRecoveryState } : {}),
46
+ },
47
+ });
48
+ if (inferredSurfaceKind === 'recovery_snapshot') return true;
49
+
50
+ return false;
51
+ }
52
+
24
53
  export function classifyHotChatSessionsForSubscriptionFlush(
25
54
  sessions: HotChatSessionLike[],
26
55
  previousHotSessionIds: ReadonlySet<string>,
@@ -39,10 +68,15 @@ export function classifyHotChatSessionsForSubscriptionFlush(
39
68
  );
40
69
  const activeStatuses = options.activeStatuses ?? DEFAULT_ACTIVE_CHAT_POLL_STATUSES;
41
70
  const active = new Set<string>();
71
+ const excluded = new Set<string>();
42
72
 
43
73
  for (const session of sessions) {
44
74
  const sessionId = typeof session?.id === 'string' ? session.id : '';
45
75
  if (!sessionId) continue;
76
+ if (isDefinitelyNonLiveRuntimeSession(session)) {
77
+ excluded.add(sessionId);
78
+ continue;
79
+ }
46
80
 
47
81
  const status = String(session?.status || '').toLowerCase();
48
82
  const lastMessageAt = parseMessageTimestamp(session?.lastMessageAt);
@@ -54,7 +88,7 @@ export function classifyHotChatSessionsForSubscriptionFlush(
54
88
  }
55
89
 
56
90
  const finalizing = new Set(
57
- Array.from(previousHotSessionIds).filter((sessionId) => !active.has(sessionId)),
91
+ Array.from(previousHotSessionIds).filter((sessionId) => !active.has(sessionId) && !excluded.has(sessionId)),
58
92
  );
59
93
 
60
94
  return { active, finalizing };