@adhdev/daemon-core 0.9.76-rc.55 → 0.9.76-rc.57

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/dist/types.d.ts CHANGED
@@ -42,6 +42,15 @@ export interface ChatMessage {
42
42
  /** Optional: fiber metadata */
43
43
  _type?: string;
44
44
  _sub?: string;
45
+ /** Transcript visibility/audience contract for separating chat-visible content from internal/debug runtime rows. */
46
+ visibility?: 'visible' | 'user' | 'chat' | 'hidden' | 'debug' | 'internal' | (string & {});
47
+ transcriptVisibility?: 'visible' | 'user' | 'chat' | 'hidden' | 'debug' | 'internal' | (string & {});
48
+ audience?: 'chat' | 'debug' | 'trace' | 'internal' | (string & {});
49
+ source?: 'assistant_text' | 'tool_call' | 'terminal_command' | 'runtime_activity' | 'runtime_status' | 'provider_chrome' | 'control' | (string & {});
50
+ userFacing?: boolean;
51
+ internal?: boolean;
52
+ isInternal?: boolean;
53
+ debug?: boolean;
45
54
  /** Meta information for thought/terminal logs etc */
46
55
  meta?: {
47
56
  label?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.76-rc.55",
3
+ "version": "0.9.76-rc.57",
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",
@@ -320,19 +320,23 @@ function buildReadChatCommandResult(payload: Record<string, any>, args: any): Co
320
320
  const visibleMessages = filterUserFacingChatMessages(messages);
321
321
  const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
322
322
  const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
323
- const nextDebugReadChat = {
324
- ...(debugReadChat || {}),
325
- fullMsgCount: messages.length,
326
- visibleMsgCount: visibleMessages.length,
327
- hiddenMsgCount,
328
- returnedMsgCount: sync.messages.length,
329
- };
323
+ const returnedDebugReadChat = debugReadChat
324
+ ? {
325
+ ...debugReadChat,
326
+ fullMsgCount: typeof debugReadChat.fullMsgCount === 'number'
327
+ ? debugReadChat.fullMsgCount
328
+ : messages.length,
329
+ visibleMsgCount: visibleMessages.length,
330
+ hiddenMsgCount,
331
+ returnedMsgCount: sync.messages.length,
332
+ }
333
+ : undefined;
330
334
  return {
331
335
  success: true,
332
336
  ...validatedPayload,
333
337
  messages: sync.messages,
334
338
  totalMessages: sync.totalMessages,
335
- debugReadChat: nextDebugReadChat,
339
+ ...(returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}),
336
340
  };
337
341
  }
338
342
 
@@ -145,8 +145,8 @@ const WORKFLOW_SECTION = `## Orchestration Workflow
145
145
  b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
146
146
  c. If no session exists, call \`mesh_launch_session\` to start one.
147
147
  d. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
148
- 4. **Monitor** — Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
149
- 5. **Verify** — When a task reports completion, call \`mesh_git_status\` to verify changes were made.
148
+ 4. **Monitor** — Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly just because the delegated session has not produced a final assistant message yet; tool/terminal activity means work may still be in progress. Use at most one compact \`mesh_read_chat\` check after a completion/approval signal, an explicit user status request, or a real timeout/stall. Handle approvals via \`mesh_approve\`.
149
+ 5. **Verify** — When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
150
150
  6. **Checkpoint** — Call \`mesh_checkpoint\` to save the work.
151
151
  7. **Clean up** — Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
152
152
  8. **Report** — Summarize what was done, what changed, and any issues.`;
@@ -163,7 +163,7 @@ function buildRulesSection(coordinatorCliType?: string): string {
163
163
  - **Respect explicit provider requests.** If the user names an agent/provider, pass the matching provider type to \`mesh_launch_session\`: Hermes → \`hermes-cli\`, Claude Code/Claude → \`claude-cli\`, Codex → \`codex-cli\`, Gemini → \`gemini-cli\`. Never substitute \`claude-cli\` just because the coordinator itself is Claude Code.
164
164
  - **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
165
165
  - **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
166
- - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
166
+ - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed. Never launch a duplicate session or second worker solely because \`mesh_read_chat\` has no final assistant message while the delegated session is still showing tool/terminal activity.
167
167
  - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
168
168
  - **Keep the user informed.** Report progress after each delegation round — one or two sentences, not a narration.
169
169
  - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
@@ -179,25 +179,51 @@ function readMessageMeta(message: ChatMessage): Record<string, unknown> | null {
179
179
  : null;
180
180
  }
181
181
 
182
- function isExplicitlyHiddenFromTranscript(meta: Record<string, unknown> | null): boolean {
183
- if (!meta) return false;
184
- const visibility = typeof meta.transcriptVisibility === 'string'
185
- ? meta.transcriptVisibility.trim().toLowerCase()
186
- : '';
187
- return visibility === 'hidden'
188
- || visibility === 'debug'
189
- || meta.internal === true
190
- || meta.debug === true
191
- || meta.statusOnly === true
192
- || meta.controlOnly === true;
182
+ function readStringField(value: unknown): string {
183
+ return typeof value === 'string' ? value.trim().toLowerCase() : '';
184
+ }
185
+
186
+ function readVisibilityField(message: ChatMessage, meta: Record<string, unknown> | null): string {
187
+ const record = message as ChatMessage & Record<string, unknown>;
188
+ return readStringField(record.visibility ?? record.transcriptVisibility ?? meta?.visibility ?? meta?.transcriptVisibility);
193
189
  }
194
190
 
195
- function isExplicitlyVisibleInTranscript(meta: Record<string, unknown> | null): boolean {
196
- if (!meta) return false;
197
- const visibility = typeof meta.transcriptVisibility === 'string'
198
- ? meta.transcriptVisibility.trim().toLowerCase()
199
- : '';
200
- return visibility === 'visible' || meta.userFacing === true;
191
+ function isExplicitlyHiddenFromTranscript(message: ChatMessage, meta: Record<string, unknown> | null): boolean {
192
+ 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 {
218
+ 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;
201
227
  }
202
228
 
203
229
  /**
@@ -212,8 +238,8 @@ function isExplicitlyVisibleInTranscript(meta: Record<string, unknown> | null):
212
238
  export function isUserFacingChatMessage(message: ChatMessage | null | undefined): boolean {
213
239
  if (!message) return false;
214
240
  const meta = readMessageMeta(message);
215
- if (isExplicitlyHiddenFromTranscript(meta)) return false;
216
- if (isExplicitlyVisibleInTranscript(meta)) return true;
241
+ if (isExplicitlyHiddenFromTranscript(message, meta)) return false;
242
+ if (isExplicitlyVisibleInTranscript(message, meta)) return true;
217
243
 
218
244
  const role = typeof message.role === 'string' ? message.role.trim().toLowerCase() : '';
219
245
  const kind = resolveChatMessageKind(message);
@@ -25,7 +25,7 @@ import { formatAutoApprovalMessage, pickApprovalButton } from './approval-utils.
25
25
  import { getCliScriptCommand, parseCliScriptResult } from './cli-script-results.js';
26
26
  import { mergeProviderPatchState, resolveProviderStateSurface } from './provider-patch-state.js';
27
27
  import { normalizeProviderSessionId } from './provider-session-id.js';
28
- import { buildChatMessage, buildRuntimeSystemChatMessage, normalizeChatMessages, resolveChatMessageKind } from './chat-message-normalization.js';
28
+ import { buildChatMessage, buildRuntimeSystemChatMessage, isUserFacingChatMessage, normalizeChatMessages, resolveChatMessageKind } from './chat-message-normalization.js';
29
29
 
30
30
  type PersistableCliHistoryMessage = {
31
31
  role: string;
@@ -1031,14 +1031,11 @@ export class CliProviderInstance implements ProviderInstance {
1031
1031
  const getRole = (message: ChatMessage): string => typeof message.role === 'string'
1032
1032
  ? message.role.trim().toLowerCase()
1033
1033
  : '';
1034
- const isAutoApprovalRuntimeOverlay = (entry: MergeEntry): boolean => {
1034
+ const isRuntimeOverlay = (entry: MergeEntry): boolean => {
1035
1035
  if (entry.source !== 'runtime') return false;
1036
1036
  const key = typeof entry.runtimeKey === 'string' ? entry.runtimeKey.trim().toLowerCase() : '';
1037
1037
  if (key.startsWith('auto_approval:')) return true;
1038
- const content = typeof entry.message.content === 'string'
1039
- ? entry.message.content.trim().toLowerCase()
1040
- : flattenContent(entry.message.content).trim().toLowerCase();
1041
- return content.startsWith('auto-approved:');
1038
+ return !isUserFacingChatMessage(entry.message);
1042
1039
  };
1043
1040
  const shouldKeepParsedBeforeUntimedRuntime = (message: ChatMessage): boolean => {
1044
1041
  const role = getRole(message);
@@ -1059,7 +1056,7 @@ export class CliProviderInstance implements ProviderInstance {
1059
1056
  if (a.source !== b.source && aTime !== bTime) {
1060
1057
  const parsedEntry = a.source === 'parsed' ? a : b.source === 'parsed' ? b : null;
1061
1058
  const runtimeEntry = a.source === 'runtime' ? a : b.source === 'runtime' ? b : null;
1062
- if (parsedEntry && runtimeEntry && isAutoApprovalRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
1059
+ if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
1063
1060
  if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
1064
1061
  return a.source === 'parsed' ? -1 : 1;
1065
1062
  }
@@ -1072,8 +1069,8 @@ export class CliProviderInstance implements ProviderInstance {
1072
1069
  // do not carry timestamps on parsed messages. In that case there is no safe
1073
1070
  // clock basis for interleaving timestamped runtime/system messages into the
1074
1071
  // provider transcript. Keep user prompts before runtime overlays, but do not
1075
- // let timed runtime/system overlays become the final chat turns after an
1076
- // untimed parsed assistant transcript.
1072
+ // let timed runtime/system/tool/internal overlays become the final chat turns
1073
+ // after an untimed parsed assistant transcript.
1077
1074
  return a.index - b.index;
1078
1075
  })
1079
1076
  .map((entry) => entry.message));
@@ -77,6 +77,14 @@ function validateMessage(message: unknown, source: string, index: number): ChatM
77
77
  if (typeof message.senderName === 'string') normalized.senderName = message.senderName
78
78
  if (typeof (message as any)._type === 'string') normalized._type = (message as any)._type
79
79
  if (typeof (message as any)._sub === 'string') normalized._sub = (message as any)._sub
80
+ if (typeof (message as any).visibility === 'string') normalized.visibility = (message as any).visibility
81
+ if (typeof (message as any).transcriptVisibility === 'string') normalized.transcriptVisibility = (message as any).transcriptVisibility
82
+ if (typeof (message as any).audience === 'string') normalized.audience = (message as any).audience
83
+ if (typeof (message as any).source === 'string') normalized.source = (message as any).source
84
+ if (typeof (message as any).userFacing === 'boolean') normalized.userFacing = (message as any).userFacing
85
+ if (typeof (message as any).internal === 'boolean') normalized.internal = (message as any).internal
86
+ if (typeof (message as any).isInternal === 'boolean') normalized.isInternal = (message as any).isInternal
87
+ if (typeof (message as any).debug === 'boolean') normalized.debug = (message as any).debug
80
88
 
81
89
  return normalized
82
90
  }
package/src/types.ts CHANGED
@@ -49,6 +49,15 @@ export interface ChatMessage {
49
49
  /** Optional: fiber metadata */
50
50
  _type?: string;
51
51
  _sub?: string;
52
+ /** Transcript visibility/audience contract for separating chat-visible content from internal/debug runtime rows. */
53
+ visibility?: 'visible' | 'user' | 'chat' | 'hidden' | 'debug' | 'internal' | (string & {});
54
+ transcriptVisibility?: 'visible' | 'user' | 'chat' | 'hidden' | 'debug' | 'internal' | (string & {});
55
+ audience?: 'chat' | 'debug' | 'trace' | 'internal' | (string & {});
56
+ source?: 'assistant_text' | 'tool_call' | 'terminal_command' | 'runtime_activity' | 'runtime_status' | 'provider_chrome' | 'control' | (string & {});
57
+ userFacing?: boolean;
58
+ internal?: boolean;
59
+ isInternal?: boolean;
60
+ debug?: boolean;
52
61
  /** Meta information for thought/terminal logs etc */
53
62
  meta?: { label?: string; isRunning?: boolean } | Record<string, any>;
54
63
  /** Sender name for shared sessions */