@adhdev/daemon-core 0.9.76-rc.60 → 0.9.76-rc.61

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.
@@ -2,6 +2,31 @@ import type { ChatMessage } from '../types.js';
2
2
  export declare const BUILTIN_CHAT_MESSAGE_KINDS: readonly ["standard", "thought", "tool", "terminal", "system"];
3
3
  export type BuiltinChatMessageKind = typeof BUILTIN_CHAT_MESSAGE_KINDS[number];
4
4
  export type ChatMessageKind = BuiltinChatMessageKind | (string & {});
5
+ export declare const CHAT_MESSAGE_VISIBILITIES: readonly ["user", "debug", "internal", "hidden"];
6
+ export declare const CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES: readonly ["visible", "chat", "user", "debug", "internal", "hidden"];
7
+ export declare const CHAT_MESSAGE_AUDIENCES: readonly ["chat", "debug", "trace", "internal"];
8
+ export declare const CHAT_MESSAGE_SOURCES: readonly ["assistant_text", "tool_call", "terminal_command", "runtime_activity", "runtime_status", "provider_chrome", "control"];
9
+ export declare const CHAT_MESSAGE_ACTIVITY_SOURCES: readonly ["tool_call", "terminal_command", "runtime_activity"];
10
+ export declare const CHAT_MESSAGE_INTERNAL_SOURCES: readonly ["runtime_status", "provider_chrome", "control"];
11
+ export type ChatMessageVisibility = typeof CHAT_MESSAGE_VISIBILITIES[number] | (string & {});
12
+ export type ChatMessageTranscriptVisibility = typeof CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES[number] | (string & {});
13
+ export type ChatMessageAudience = typeof CHAT_MESSAGE_AUDIENCES[number] | (string & {});
14
+ export type ChatMessageSource = typeof CHAT_MESSAGE_SOURCES[number] | (string & {});
15
+ export type ChatMessageTranscriptSurface = 'chat' | 'activity' | 'internal';
16
+ export interface ChatMessageVisibilityClassification {
17
+ surface: ChatMessageTranscriptSurface;
18
+ isUserFacing: boolean;
19
+ isActivityFacing: boolean;
20
+ isInternal: boolean;
21
+ explicitUserFacing: boolean;
22
+ explicitHidden: boolean;
23
+ role: string;
24
+ kind: ChatMessageKind;
25
+ visibility: string;
26
+ transcriptVisibility: string;
27
+ audience: string;
28
+ source: string;
29
+ }
5
30
  export declare function isBuiltinChatMessageKind(kind: unknown): kind is BuiltinChatMessageKind;
6
31
  export declare function normalizeChatMessageKind(kind: unknown, role: unknown): ChatMessageKind;
7
32
  export declare function resolveChatMessageKind<T extends ChatMessage>(message: T): ChatMessageKind;
@@ -64,13 +89,17 @@ export declare function buildUserChatMessage<T extends Omit<ChatMessage, 'role'
64
89
  export declare function normalizeChatMessage<T extends ChatMessage>(message: T): T;
65
90
  export declare function normalizeChatMessages<T extends ChatMessage>(messages: T[] | null | undefined): T[];
66
91
  /**
67
- * Product chat transcript visibility contract.
92
+ * Shared transcript visibility protocol for all ADHDev provider chat messages.
68
93
  *
69
- * read_chat/debug paths may preserve every normalized message, including tool,
70
- * terminal, thought, status, and control rows. The default user-facing chat UX
71
- * should only render meaningful conversation turns unless a producer explicitly
72
- * marks a non-standard row as user-facing. This keeps internal tool/status/control
73
- * plumbing out of the ordinary transcript without matching provider-specific text.
94
+ * Producers can stamp visibility/audience/source/userFacing/internal/debug either
95
+ * at the top level or under `meta`. Consumers should use this classifier instead
96
+ * of matching command text, icons, provider names, or terminal UI fragments.
74
97
  */
98
+ export declare function classifyChatMessageVisibility(message: ChatMessage | null | undefined): ChatMessageVisibilityClassification;
75
99
  export declare function isUserFacingChatMessage(message: ChatMessage | null | undefined): boolean;
100
+ export declare function isActivityChatMessage(message: ChatMessage | null | undefined): boolean;
101
+ export declare function isInternalChatMessage(message: ChatMessage | null | undefined): boolean;
76
102
  export declare function filterUserFacingChatMessages<T extends ChatMessage>(messages: T[] | null | undefined): T[];
103
+ export declare function filterActivityChatMessages<T extends ChatMessage>(messages: T[] | null | undefined): T[];
104
+ export declare function filterInternalChatMessages<T extends ChatMessage>(messages: T[] | null | undefined): T[];
105
+ export declare function filterChatMessagesByVisibility<T extends ChatMessage>(messages: T[] | null | undefined, surface: ChatMessageTranscriptSurface): T[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.76-rc.60",
3
+ "version": "0.9.76-rc.61",
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",
@@ -8,6 +8,7 @@ import {
8
8
  buildSessionModalDeliverySignature,
9
9
  } from './chat-signatures.js'
10
10
  import { normalizeManagedStatus } from '../status/normalize.js'
11
+ import { filterUserFacingChatMessages, normalizeChatMessages } from '../providers/chat-message-normalization.js'
11
12
 
12
13
  export interface ChatTailSubscriptionCursor {
13
14
  tailLimit: number
@@ -101,7 +102,8 @@ export function prepareSessionChatTailUpdate(
101
102
  }
102
103
  }
103
104
 
104
- const messages = Array.isArray(result.messages) ? result.messages : []
105
+ const fullMessages = normalizeChatMessages(Array.isArray(result.messages) ? result.messages as any[] : [])
106
+ const messages = filterUserFacingChatMessages(fullMessages)
105
107
  const title = typeof result.title === 'string' ? result.title : undefined
106
108
  const activeModal = normalizeChatTailActiveModal(result.activeModal)
107
109
  const status = typeof result.status === 'string' ? result.status : 'idle'
package/src/index.ts CHANGED
@@ -312,10 +312,22 @@ export {
312
312
  buildUserChatMessage,
313
313
  normalizeChatMessage,
314
314
  normalizeChatMessages,
315
+ CHAT_MESSAGE_VISIBILITIES,
316
+ CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES,
317
+ CHAT_MESSAGE_AUDIENCES,
318
+ CHAT_MESSAGE_SOURCES,
319
+ CHAT_MESSAGE_ACTIVITY_SOURCES,
320
+ CHAT_MESSAGE_INTERNAL_SOURCES,
321
+ classifyChatMessageVisibility,
315
322
  isUserFacingChatMessage,
323
+ isActivityChatMessage,
324
+ isInternalChatMessage,
316
325
  filterUserFacingChatMessages,
326
+ filterActivityChatMessages,
327
+ filterInternalChatMessages,
328
+ filterChatMessagesByVisibility,
317
329
  } from './providers/chat-message-normalization.js';
318
- export type { BuiltinChatMessageKind, ChatMessageKind } from './providers/chat-message-normalization.js';
330
+ export type { BuiltinChatMessageKind, ChatMessageKind, ChatMessageVisibility, ChatMessageTranscriptVisibility, ChatMessageAudience, ChatMessageSource, ChatMessageTranscriptSurface, ChatMessageVisibilityClassification } from './providers/chat-message-normalization.js';
319
331
  export { VersionArchive, detectAllVersions } from './providers/version-archive.js';
320
332
  export type { ProviderVersionInfo, VersionHistory } from './providers/version-archive.js';
321
333
 
@@ -5,6 +5,43 @@ export const BUILTIN_CHAT_MESSAGE_KINDS = ['standard', 'thought', 'tool', 'termi
5
5
  export type BuiltinChatMessageKind = typeof BUILTIN_CHAT_MESSAGE_KINDS[number];
6
6
  export type ChatMessageKind = BuiltinChatMessageKind | (string & {});
7
7
 
8
+ export const CHAT_MESSAGE_VISIBILITIES = ['user', 'debug', 'internal', 'hidden'] as const;
9
+ export const CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES = ['visible', 'chat', 'user', 'debug', 'internal', 'hidden'] as const;
10
+ export const CHAT_MESSAGE_AUDIENCES = ['chat', 'debug', 'trace', 'internal'] as const;
11
+ export const CHAT_MESSAGE_SOURCES = [
12
+ 'assistant_text',
13
+ 'tool_call',
14
+ 'terminal_command',
15
+ 'runtime_activity',
16
+ 'runtime_status',
17
+ 'provider_chrome',
18
+ 'control',
19
+ ] as const;
20
+ export const CHAT_MESSAGE_ACTIVITY_SOURCES = ['tool_call', 'terminal_command', 'runtime_activity'] as const;
21
+ export const CHAT_MESSAGE_INTERNAL_SOURCES = ['runtime_status', 'provider_chrome', 'control'] as const;
22
+
23
+ export type ChatMessageVisibility = typeof CHAT_MESSAGE_VISIBILITIES[number] | (string & {});
24
+ export type ChatMessageTranscriptVisibility = typeof CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES[number] | (string & {});
25
+ export type ChatMessageAudience = typeof CHAT_MESSAGE_AUDIENCES[number] | (string & {});
26
+ export type ChatMessageSource = typeof CHAT_MESSAGE_SOURCES[number] | (string & {});
27
+ export type ChatMessageTranscriptSurface = 'chat' | 'activity' | 'internal';
28
+
29
+ export interface ChatMessageVisibilityClassification {
30
+ surface: ChatMessageTranscriptSurface;
31
+ isUserFacing: boolean;
32
+ isActivityFacing: boolean;
33
+ isInternal: boolean;
34
+ explicitUserFacing: boolean;
35
+ explicitHidden: boolean;
36
+ role: string;
37
+ kind: ChatMessageKind;
38
+ visibility: string;
39
+ transcriptVisibility: string;
40
+ audience: string;
41
+ source: string;
42
+ }
43
+
44
+
8
45
  const KNOWN_CHAT_MESSAGE_KINDS = new Set<string>(BUILTIN_CHAT_MESSAGE_KINDS);
9
46
  const CHAT_MESSAGE_KIND_ALIASES: Record<string, BuiltinChatMessageKind> = {
10
47
  text: 'standard',
@@ -183,71 +220,195 @@ function readStringField(value: unknown): string {
183
220
  return typeof value === 'string' ? value.trim().toLowerCase() : '';
184
221
  }
185
222
 
186
- function readVisibilityField(message: ChatMessage, meta: Record<string, unknown> | null): string {
223
+ function readRecordField(message: ChatMessage, meta: Record<string, unknown> | null, key: string): unknown {
187
224
  const record = message as ChatMessage & Record<string, unknown>;
188
- return readStringField(record.visibility ?? record.transcriptVisibility ?? meta?.visibility ?? meta?.transcriptVisibility);
225
+ return record[key] ?? meta?.[key];
226
+ }
227
+
228
+ function readVisibilityField(message: ChatMessage, meta: Record<string, unknown> | null): string {
229
+ return readStringField(readRecordField(message, meta, 'visibility'));
189
230
  }
190
231
 
191
- function isExplicitlyHiddenFromTranscript(message: ChatMessage, meta: Record<string, unknown> | null): boolean {
232
+ function readTranscriptVisibilityField(message: ChatMessage, meta: Record<string, unknown> | null): string {
192
233
  const record = message as ChatMessage & Record<string, unknown>;
193
- const visibility = readVisibilityField(message, meta);
194
- const audience = readStringField(record.audience ?? meta?.audience);
195
- const source = readStringField(record.source ?? meta?.source);
196
-
197
- return visibility === 'hidden'
198
- || visibility === 'debug'
199
- || visibility === 'internal'
200
- || audience === 'debug'
201
- || audience === 'trace'
202
- || audience === 'internal'
203
- || source === 'runtime_status'
204
- || source === 'runtime_activity'
205
- || source === 'provider_chrome'
206
- || source === 'control'
207
- || record.internal === true
208
- || record.isInternal === true
209
- || record.debug === true
210
- || meta?.internal === true
211
- || meta?.isInternal === true
212
- || meta?.debug === true
213
- || meta?.statusOnly === true
214
- || meta?.controlOnly === true;
215
- }
216
-
217
- function isExplicitlyVisibleInTranscript(message: ChatMessage, meta: Record<string, unknown> | null): boolean {
234
+ return readStringField(record.transcriptVisibility ?? meta?.transcriptVisibility ?? record.visibility ?? meta?.visibility);
235
+ }
236
+
237
+ const EXPLICIT_HIDDEN_VISIBILITIES = new Set(['hidden', 'debug', 'internal']);
238
+ const EXPLICIT_VISIBLE_VISIBILITIES = new Set(['visible', 'user', 'chat']);
239
+ const HIDDEN_AUDIENCES = new Set(['debug', 'trace', 'internal']);
240
+ const ACTIVITY_SOURCE_SET = new Set<string>(CHAT_MESSAGE_ACTIVITY_SOURCES);
241
+ const INTERNAL_SOURCE_SET = new Set<string>(CHAT_MESSAGE_INTERNAL_SOURCES);
242
+
243
+ function hasBooleanMarker(message: ChatMessage, meta: Record<string, unknown> | null, keys: string[]): boolean {
218
244
  const record = message as ChatMessage & Record<string, unknown>;
219
- const visibility = readVisibilityField(message, meta);
220
- const audience = readStringField(record.audience ?? meta?.audience);
221
- return visibility === 'visible'
222
- || visibility === 'user'
223
- || visibility === 'chat'
224
- || audience === 'chat'
225
- || record.userFacing === true
226
- || meta?.userFacing === true;
245
+ return keys.some((key) => record[key] === true || meta?.[key] === true);
246
+ }
247
+
248
+ function isActivityKind(kind: ChatMessageKind): boolean {
249
+ return kind === 'thought' || kind === 'tool' || kind === 'terminal';
250
+ }
251
+
252
+ function isOrdinaryVisibleTurn(message: ChatMessage, role: string, kind: ChatMessageKind): boolean {
253
+ if (role === 'user' || role === 'human') return kind === 'standard' || kind === '';
254
+ if (role === 'assistant') return kind === 'standard' || kind === '';
255
+ return false;
227
256
  }
228
257
 
229
258
  /**
230
- * Product chat transcript visibility contract.
259
+ * Shared transcript visibility protocol for all ADHDev provider chat messages.
231
260
  *
232
- * read_chat/debug paths may preserve every normalized message, including tool,
233
- * terminal, thought, status, and control rows. The default user-facing chat UX
234
- * should only render meaningful conversation turns unless a producer explicitly
235
- * marks a non-standard row as user-facing. This keeps internal tool/status/control
236
- * plumbing out of the ordinary transcript without matching provider-specific text.
261
+ * Producers can stamp visibility/audience/source/userFacing/internal/debug either
262
+ * at the top level or under `meta`. Consumers should use this classifier instead
263
+ * of matching command text, icons, provider names, or terminal UI fragments.
237
264
  */
238
- export function isUserFacingChatMessage(message: ChatMessage | null | undefined): boolean {
239
- if (!message) return false;
240
- const meta = readMessageMeta(message);
241
- if (isExplicitlyHiddenFromTranscript(message, meta)) return false;
242
- if (isExplicitlyVisibleInTranscript(message, meta)) return true;
265
+ export function classifyChatMessageVisibility(message: ChatMessage | null | undefined): ChatMessageVisibilityClassification {
266
+ if (!message) {
267
+ return {
268
+ surface: 'internal',
269
+ isUserFacing: false,
270
+ isActivityFacing: false,
271
+ isInternal: true,
272
+ explicitUserFacing: false,
273
+ explicitHidden: true,
274
+ role: '',
275
+ kind: 'standard',
276
+ visibility: '',
277
+ transcriptVisibility: '',
278
+ audience: '',
279
+ source: '',
280
+ };
281
+ }
243
282
 
283
+ const meta = readMessageMeta(message);
244
284
  const role = typeof message.role === 'string' ? message.role.trim().toLowerCase() : '';
245
285
  const kind = resolveChatMessageKind(message);
246
- if (role === 'user' || role === 'human') return kind === 'standard' || kind === '';
247
- if (role === 'assistant') return kind === 'standard' || kind === '';
248
- return false;
286
+ const visibility = readVisibilityField(message, meta);
287
+ const transcriptVisibility = readTranscriptVisibilityField(message, meta);
288
+ const audience = readStringField(readRecordField(message, meta, 'audience'));
289
+ const source = readStringField(readRecordField(message, meta, 'source'));
290
+ const explicitHidden = EXPLICIT_HIDDEN_VISIBILITIES.has(visibility)
291
+ || EXPLICIT_HIDDEN_VISIBILITIES.has(transcriptVisibility)
292
+ || HIDDEN_AUDIENCES.has(audience)
293
+ || hasBooleanMarker(message, meta, ['internal', 'isInternal', 'debug', 'statusOnly', 'controlOnly']);
294
+ const explicitUserFacing = EXPLICIT_VISIBLE_VISIBILITIES.has(visibility)
295
+ || EXPLICIT_VISIBLE_VISIBILITIES.has(transcriptVisibility)
296
+ || audience === 'chat'
297
+ || hasBooleanMarker(message, meta, ['userFacing']);
298
+
299
+ if (explicitHidden) {
300
+ const activityLike = isActivityKind(kind) || ACTIVITY_SOURCE_SET.has(source);
301
+ return {
302
+ surface: activityLike ? 'activity' : 'internal',
303
+ isUserFacing: false,
304
+ isActivityFacing: activityLike,
305
+ isInternal: !activityLike,
306
+ explicitUserFacing,
307
+ explicitHidden,
308
+ role,
309
+ kind,
310
+ visibility,
311
+ transcriptVisibility,
312
+ audience,
313
+ source,
314
+ };
315
+ }
316
+
317
+ if (explicitUserFacing) {
318
+ return {
319
+ surface: 'chat',
320
+ isUserFacing: true,
321
+ isActivityFacing: false,
322
+ isInternal: false,
323
+ explicitUserFacing,
324
+ explicitHidden,
325
+ role,
326
+ kind,
327
+ visibility,
328
+ transcriptVisibility,
329
+ audience,
330
+ source,
331
+ };
332
+ }
333
+
334
+ if (INTERNAL_SOURCE_SET.has(source) || role === 'system' || kind === 'system') {
335
+ return {
336
+ surface: 'internal',
337
+ isUserFacing: false,
338
+ isActivityFacing: false,
339
+ isInternal: true,
340
+ explicitUserFacing,
341
+ explicitHidden,
342
+ role,
343
+ kind,
344
+ visibility,
345
+ transcriptVisibility,
346
+ audience,
347
+ source,
348
+ };
349
+ }
350
+
351
+ if (ACTIVITY_SOURCE_SET.has(source) || isActivityKind(kind)) {
352
+ return {
353
+ surface: 'activity',
354
+ isUserFacing: false,
355
+ isActivityFacing: true,
356
+ isInternal: false,
357
+ explicitUserFacing,
358
+ explicitHidden,
359
+ role,
360
+ kind,
361
+ visibility,
362
+ transcriptVisibility,
363
+ audience,
364
+ source,
365
+ };
366
+ }
367
+
368
+ const isUserFacing = isOrdinaryVisibleTurn(message, role, kind);
369
+ return {
370
+ surface: isUserFacing ? 'chat' : 'internal',
371
+ isUserFacing,
372
+ isActivityFacing: false,
373
+ isInternal: !isUserFacing,
374
+ explicitUserFacing,
375
+ explicitHidden,
376
+ role,
377
+ kind,
378
+ visibility,
379
+ transcriptVisibility,
380
+ audience,
381
+ source,
382
+ };
383
+ }
384
+
385
+ export function isUserFacingChatMessage(message: ChatMessage | null | undefined): boolean {
386
+ return classifyChatMessageVisibility(message).isUserFacing;
387
+ }
388
+
389
+ export function isActivityChatMessage(message: ChatMessage | null | undefined): boolean {
390
+ return classifyChatMessageVisibility(message).isActivityFacing;
391
+ }
392
+
393
+ export function isInternalChatMessage(message: ChatMessage | null | undefined): boolean {
394
+ return classifyChatMessageVisibility(message).isInternal;
249
395
  }
250
396
 
251
397
  export function filterUserFacingChatMessages<T extends ChatMessage>(messages: T[] | null | undefined): T[] {
252
398
  return (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
253
399
  }
400
+
401
+ export function filterActivityChatMessages<T extends ChatMessage>(messages: T[] | null | undefined): T[] {
402
+ return (Array.isArray(messages) ? messages : []).filter((message) => isActivityChatMessage(message));
403
+ }
404
+
405
+ export function filterInternalChatMessages<T extends ChatMessage>(messages: T[] | null | undefined): T[] {
406
+ return (Array.isArray(messages) ? messages : []).filter((message) => isInternalChatMessage(message));
407
+ }
408
+
409
+ export function filterChatMessagesByVisibility<T extends ChatMessage>(
410
+ messages: T[] | null | undefined,
411
+ surface: ChatMessageTranscriptSurface,
412
+ ): T[] {
413
+ return (Array.isArray(messages) ? messages : []).filter((message) => classifyChatMessageVisibility(message).surface === surface);
414
+ }