@adhdev/daemon-core 0.9.76-rc.9 → 0.9.76

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.
Files changed (65) hide show
  1. package/dist/cli-adapters/provider-cli-adapter.d.ts +5 -2
  2. package/dist/cli-adapters/provider-cli-runtime.d.ts +1 -0
  3. package/dist/cli-adapters/provider-cli-shared.d.ts +24 -0
  4. package/dist/commands/chat-commands.d.ts +2 -0
  5. package/dist/commands/cli-manager.d.ts +17 -4
  6. package/dist/commands/mesh-coordinator.d.ts +2 -0
  7. package/dist/commands/router.d.ts +11 -0
  8. package/dist/config/mesh-config.d.ts +3 -0
  9. package/dist/git/git-types.d.ts +1 -1
  10. package/dist/git/git-worktree.d.ts +64 -0
  11. package/dist/git/index.d.ts +2 -0
  12. package/dist/index.d.ts +4 -4
  13. package/dist/index.js +2427 -561
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.mjs +2432 -584
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/mesh/coordinator-prompt.d.ts +1 -0
  18. package/dist/mesh/mesh-events.d.ts +18 -0
  19. package/dist/providers/chat-message-normalization.d.ts +40 -0
  20. package/dist/providers/cli-provider-instance.d.ts +7 -1
  21. package/dist/providers/contracts.d.ts +20 -1
  22. package/dist/providers/io-contracts.d.ts +17 -1
  23. package/dist/providers/provider-input-support.d.ts +18 -2
  24. package/dist/providers/provider-instance-manager.d.ts +1 -0
  25. package/dist/providers/provider-instance.d.ts +4 -0
  26. package/dist/repo-mesh-types.d.ts +34 -0
  27. package/dist/session-host/runtime-support.d.ts +2 -1
  28. package/dist/shared-types.d.ts +8 -0
  29. package/dist/types.d.ts +9 -0
  30. package/package.json +4 -5
  31. package/src/chat/subscription-updates.ts +3 -1
  32. package/src/cli-adapters/provider-cli-adapter.ts +44 -11
  33. package/src/cli-adapters/provider-cli-runtime.ts +3 -2
  34. package/src/cli-adapters/provider-cli-shared.ts +201 -15
  35. package/src/commands/chat-commands.ts +166 -16
  36. package/src/commands/cli-manager.ts +78 -5
  37. package/src/commands/handler.ts +13 -4
  38. package/src/commands/mesh-coordinator.ts +155 -5
  39. package/src/commands/router.d.ts +1 -0
  40. package/src/commands/router.ts +606 -32
  41. package/src/config/mesh-config.ts +27 -2
  42. package/src/git/git-commands.ts +5 -1
  43. package/src/git/git-types.ts +1 -0
  44. package/src/git/git-worktree.ts +214 -0
  45. package/src/git/index.ts +14 -0
  46. package/src/index.ts +20 -1
  47. package/src/mesh/coordinator-prompt.ts +36 -14
  48. package/src/mesh/mesh-events.ts +173 -42
  49. package/src/providers/acp-provider-instance.ts +118 -30
  50. package/src/providers/chat-message-normalization.ts +241 -0
  51. package/src/providers/cli-provider-instance.d.ts +2 -0
  52. package/src/providers/cli-provider-instance.ts +219 -13
  53. package/src/providers/contracts.ts +25 -1
  54. package/src/providers/io-contracts.ts +63 -5
  55. package/src/providers/provider-input-support.ts +125 -1
  56. package/src/providers/provider-instance-manager.ts +20 -1
  57. package/src/providers/provider-instance.ts +4 -0
  58. package/src/providers/provider-schema.ts +38 -8
  59. package/src/providers/read-chat-contract.ts +8 -0
  60. package/src/repo-mesh-types.ts +38 -0
  61. package/src/session-host/runtime-support.ts +55 -7
  62. package/src/shared-types.ts +8 -0
  63. package/src/status/builders.ts +5 -3
  64. package/src/status/reporter.ts +6 -0
  65. package/src/types.ts +9 -0
@@ -14,5 +14,6 @@ export interface CoordinatorPromptContext {
14
14
  mesh: LocalMeshEntry;
15
15
  status?: RepoMeshStatus;
16
16
  userInstruction?: string;
17
+ coordinatorCliType?: string;
17
18
  }
18
19
  export declare function buildCoordinatorSystemPrompt(ctx: CoordinatorPromptContext): string;
@@ -1,2 +1,20 @@
1
1
  import type { DaemonComponents } from '../boot/daemon-lifecycle.js';
2
+ export interface PendingMeshCoordinatorEvent {
3
+ event: string;
4
+ meshId: string;
5
+ nodeLabel: string;
6
+ metadataEvent: Record<string, unknown>;
7
+ queuedAt: number;
8
+ }
9
+ /** Drain and return all pending coordinator events, clearing the queue. */
10
+ export declare function drainPendingMeshCoordinatorEvents(): PendingMeshCoordinatorEvent[];
11
+ export declare function handleMeshForwardEvent(components: DaemonComponents, payload: Record<string, unknown>): {
12
+ success: boolean;
13
+ forwarded: number;
14
+ error?: undefined;
15
+ } | {
16
+ success: boolean;
17
+ error: string;
18
+ forwarded?: undefined;
19
+ };
2
20
  export declare function setupMeshEventForwarding(components: DaemonComponents): void;
@@ -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;
@@ -63,3 +88,18 @@ export declare function buildUserChatMessage<T extends Omit<ChatMessage, 'role'
63
88
  });
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[];
91
+ /**
92
+ * Shared transcript visibility protocol for all ADHDev provider chat messages.
93
+ *
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.
97
+ */
98
+ export declare function classifyChatMessageVisibility(message: ChatMessage | null | undefined): ChatMessageVisibilityClassification;
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;
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[];
@@ -4,10 +4,11 @@
4
4
  * Lifecycle layer on top of ProviderCliAdapter.
5
5
  * collectCliData() + status transition logic from daemon-status.ts moved here.
6
6
  */
7
- import { type ProviderModule } from './contracts.js';
7
+ import { type ProviderModule, type InputEnvelope } from './contracts.js';
8
8
  import type { ProviderInstance, ProviderState, InstanceContext, HotChatSessionState, SessionModalState } from './provider-instance.js';
9
9
  import { ProviderCliAdapter } from '../cli-adapters/provider-cli-adapter.js';
10
10
  import type { PtyTransportFactory } from '../cli-adapters/pty-transport.js';
11
+ import type { ChatMessage } from '../types.js';
11
12
  type PersistableCliHistoryMessage = {
12
13
  role: string;
13
14
  content: string;
@@ -15,6 +16,9 @@ type PersistableCliHistoryMessage = {
15
16
  senderName?: string;
16
17
  receivedAt?: number;
17
18
  };
19
+ export declare function buildCliStructuredInputPrompt(input: InputEnvelope, options?: {
20
+ materializeDir?: string;
21
+ }): string;
18
22
  export declare function buildIncrementalHistoryAppendMessages(previousMessages: PersistableCliHistoryMessage[], currentMessages: PersistableCliHistoryMessage[]): PersistableCliHistoryMessage[];
19
23
  export declare function getForcedNewSessionScriptName(provider: ProviderModule | undefined, launchMode: 'new' | 'resume' | 'manual'): string | null;
20
24
  export declare function waitForCliAdapterReady(adapter: {
@@ -67,6 +71,7 @@ export declare class CliProviderInstance implements ProviderInstance {
67
71
  constructor(provider: ProviderModule, workingDir: string, cliArgs?: string[], instanceId?: string, transportFactory?: PtyTransportFactory, options?: {
68
72
  providerSessionId?: string;
69
73
  launchMode?: 'new' | 'resume' | 'manual';
74
+ extraEnv?: Record<string, string>;
70
75
  onProviderSessionResolved?: (info: {
71
76
  instanceId: string;
72
77
  providerType: string;
@@ -112,6 +117,7 @@ export declare class CliProviderInstance implements ProviderInstance {
112
117
  private maybeAppendRuntimeRecoveryMessage;
113
118
  private appendRuntimeSystemMessage;
114
119
  private appendRuntimeMessage;
120
+ mergeRuntimeChatMessages(parsedMessages: ChatMessage[]): ChatMessage[];
115
121
  private mergeConversationMessages;
116
122
  private formatApprovalRequestMessage;
117
123
  private promoteProviderSessionId;
@@ -87,7 +87,7 @@ export interface ProviderEffect {
87
87
  * ContentBlock — ACP ContentBlock union type
88
88
  * Represents displayable content in messages, tool call results, etc.
89
89
  */
90
- export type ContentBlock = TextBlock | ImageBlock | AudioBlock | ResourceLinkBlock | ResourceBlock;
90
+ export type ContentBlock = TextBlock | ImageBlock | AudioBlock | VideoBlock | ResourceLinkBlock | ResourceBlock;
91
91
  /** Text content — ACP TextContent */
92
92
  export interface TextBlock {
93
93
  type: 'text';
@@ -100,6 +100,7 @@ export interface ImageBlock {
100
100
  data: string;
101
101
  mimeType: string;
102
102
  uri?: string;
103
+ alt?: string;
103
104
  annotations?: ContentAnnotations;
104
105
  }
105
106
  /** Audio content — ACP AudioContent */
@@ -107,6 +108,18 @@ export interface AudioBlock {
107
108
  type: 'audio';
108
109
  data: string;
109
110
  mimeType: string;
111
+ uri?: string;
112
+ transcript?: string;
113
+ annotations?: ContentAnnotations;
114
+ }
115
+ /** Video content — ADHDev canonical display block. ACP prompt input degrades video to resource_link/text. */
116
+ export interface VideoBlock {
117
+ type: 'video';
118
+ data?: string;
119
+ mimeType: string;
120
+ uri?: string;
121
+ transcript?: string;
122
+ posterUri?: string;
110
123
  annotations?: ContentAnnotations;
111
124
  }
112
125
  /** Resource link (file reference) — ACP ResourceLink */
@@ -487,6 +500,12 @@ export interface ProviderModule {
487
500
  input?: {
488
501
  multipart?: boolean;
489
502
  mediaTypes?: Array<'text' | 'image' | 'audio' | 'video' | 'resource'>;
503
+ strategies?: Array<{
504
+ mediaType: 'text' | 'image' | 'audio' | 'video' | 'resource';
505
+ strategies?: Array<'native' | 'native_acp' | 'resource_link' | 'text_fallback' | 'paste' | 'upload'>;
506
+ native?: boolean;
507
+ degradation?: Array<'native' | 'native_acp' | 'resource_link' | 'text_fallback' | 'paste' | 'upload'>;
508
+ }>;
490
509
  };
491
510
  output?: {
492
511
  richContent?: boolean;
@@ -1,5 +1,5 @@
1
1
  import type { ContentAnnotations } from './contracts.js';
2
- export type InputPart = TextInputPart | ImageInputPart | AudioInputPart | VideoInputPart | ResourceInputPart;
2
+ export type InputPart = TextInputPart | ImageInputPart | AudioInputPart | VideoInputPart | ResourceLinkInputPart | ResourceInputPart;
3
3
  export interface TextInputPart {
4
4
  type: 'text';
5
5
  text: string;
@@ -23,6 +23,7 @@ export interface VideoInputPart {
23
23
  mimeType: string;
24
24
  uri?: string;
25
25
  data?: string;
26
+ transcript?: string;
26
27
  posterUri?: string;
27
28
  }
28
29
  export interface ResourceInputPart {
@@ -33,6 +34,16 @@ export interface ResourceInputPart {
33
34
  text?: string;
34
35
  data?: string;
35
36
  }
37
+ export interface ResourceLinkInputPart {
38
+ type: 'resource_link';
39
+ uri: string;
40
+ name: string;
41
+ title?: string;
42
+ description?: string;
43
+ mimeType?: string;
44
+ size?: number;
45
+ annotations?: ContentAnnotations;
46
+ }
36
47
  export interface InputEnvelope {
37
48
  parts: InputPart[];
38
49
  textFallback: string;
@@ -52,6 +63,7 @@ export interface ImageMessagePart {
52
63
  mimeType: string;
53
64
  uri?: string;
54
65
  data?: string;
66
+ alt?: string;
55
67
  annotations?: ContentAnnotations;
56
68
  }
57
69
  export interface AudioMessagePart {
@@ -67,6 +79,7 @@ export interface VideoMessagePart {
67
79
  mimeType: string;
68
80
  uri?: string;
69
81
  data?: string;
82
+ transcript?: string;
70
83
  posterUri?: string;
71
84
  annotations?: ContentAnnotations;
72
85
  }
@@ -74,8 +87,11 @@ export interface ResourceLinkMessagePart {
74
87
  type: 'resource_link';
75
88
  uri: string;
76
89
  name: string;
90
+ title?: string;
91
+ description?: string;
77
92
  mimeType?: string;
78
93
  size?: number;
94
+ annotations?: ContentAnnotations;
79
95
  }
80
96
  export interface ResourceMessagePart {
81
97
  type: 'resource';
@@ -1,9 +1,25 @@
1
1
  import type { InputEnvelope, ProviderModule } from './contracts.js';
2
- type InputMediaType = 'text' | 'image' | 'audio' | 'video' | 'resource';
2
+ export type InputMediaType = 'text' | 'image' | 'audio' | 'video' | 'resource';
3
+ export type InputAttachmentStrategy = 'native' | 'native_acp' | 'resource_link' | 'text_fallback' | 'paste' | 'upload';
4
+ export interface InputMediaStrategyDescriptor {
5
+ mediaType: InputMediaType;
6
+ strategies: InputAttachmentStrategy[];
7
+ native?: boolean;
8
+ degradation?: InputAttachmentStrategy[];
9
+ }
10
+ export interface MessageInputSupport {
11
+ text: boolean;
12
+ multipart: boolean;
13
+ mediaTypes: InputMediaType[];
14
+ strategies: InputMediaStrategyDescriptor[];
15
+ }
16
+ export declare const TEXT_ONLY_MESSAGE_INPUT_SUPPORT: MessageInputSupport;
3
17
  export declare function assertTextOnlyInput(provider: Pick<ProviderModule, 'name' | 'type'> | null | undefined, input: InputEnvelope): void;
4
18
  export declare function getDeclaredProviderInputSupport(provider?: Pick<ProviderModule, 'capabilities'> | null): {
5
19
  multipart: boolean;
6
20
  mediaTypes: Set<InputMediaType>;
21
+ strategies: InputMediaStrategyDescriptor[];
7
22
  };
23
+ export declare function normalizeInputStrategyDescriptors(raw: unknown): InputMediaStrategyDescriptor[];
24
+ export declare function getEffectiveMessageInputSupport(provider?: Pick<ProviderModule, 'category' | 'capabilities'> | null, runtimeCapabilities?: Record<string, any> | null): MessageInputSupport;
8
25
  export declare function assertProviderSupportsDeclaredInput(provider: Pick<ProviderModule, 'name' | 'type' | 'capabilities'> | null | undefined, input: InputEnvelope): void;
9
- export {};
@@ -67,6 +67,7 @@ export declare class ProviderInstanceManager {
67
67
  onEvent(listener: (event: ProviderEvent & {
68
68
  providerType: string;
69
69
  }) => void): void;
70
+ emitProviderEvent(providerType: string, instanceId: string, event: ProviderEvent): void;
70
71
  private emitPendingEvents;
71
72
  /**
72
73
  * Forward event to specific Instance
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import type { ProviderModule, ProviderResumeCapability } from './contracts.js';
11
11
  import type { AcpConfigOption, AcpMode, ProviderControlSchema, ProviderSummaryMetadata, SessionCapability } from '../shared-types.js';
12
+ import type { MessageInputSupport } from './provider-input-support.js';
12
13
  import type { ChatMessage } from '../types.js';
13
14
  export type ProviderStatus = 'idle' | 'generating' | 'waiting_approval' | 'error' | 'stopped' | 'starting';
14
15
  export interface ProviderRuntimeWriteOwner {
@@ -71,6 +72,7 @@ interface ProviderStateBase {
71
72
  runtime?: ProviderRuntimeInfo;
72
73
  resume?: ProviderResumeCapability;
73
74
  sessionCapabilities?: SessionCapability[];
75
+ messageInput?: MessageInputSupport;
74
76
  /** Dynamic control current values */
75
77
  controlValues?: Record<string, string | number | boolean>;
76
78
  /** Provider-declared controls schema (from provider.controls) */
@@ -147,6 +149,8 @@ export interface InstanceContext {
147
149
  onPtyData?: (data: string) => void;
148
150
  /** Provider configvalue (resolved) */
149
151
  settings: Record<string, any>;
152
+ /** Immediate provider-originated status/event emission. Used to avoid waiting for status polling. */
153
+ emitProviderEvent?: (event: ProviderEvent) => void;
150
154
  }
151
155
  export interface ProviderInstance {
152
156
  /** Provider type */
@@ -40,6 +40,8 @@ export interface RepoMeshNode {
40
40
  status: 'enabled' | 'disabled' | 'removed';
41
41
  }
42
42
  export type RepoMeshNodeHealth = 'online' | 'offline' | 'degraded' | 'dirty' | 'wrong_branch' | 'unknown';
43
+ export type RepoMeshSessionCleanupMode = 'preserve' | 'stop' | 'delete_stopped' | 'stop_and_delete';
44
+ export type RepoMeshSpawnedSessionVisibility = 'visible' | 'hidden';
43
45
  export interface RepoMeshPolicy {
44
46
  requirePreTaskCheckpoint: boolean;
45
47
  requirePostTaskCheckpoint: boolean;
@@ -48,11 +50,37 @@ export interface RepoMeshPolicy {
48
50
  dirtyWorkspaceBehavior: 'block' | 'warn' | 'checkpoint_then_continue';
49
51
  maxParallelTasks: number;
50
52
  allowedProviders?: string[];
53
+ /**
54
+ * Whether sessions spawned by mesh/coordinator policy should auto-open as visible
55
+ * dashboard tabs or start hidden. Defaults to 'visible' to preserve existing
56
+ * watch-the-agents behavior; hidden sessions remain discoverable and manually openable.
57
+ */
58
+ spawnedSessionVisibility?: RepoMeshSpawnedSessionVisibility;
59
+ /**
60
+ * What to do with delegated session-host records for a node when it is removed.
61
+ * Defaults to 'preserve' so completed work can be reviewed later and live
62
+ * runtimes are never stopped/deleted unless the mesh owner opts in.
63
+ */
64
+ sessionCleanupOnNodeRemove?: RepoMeshSessionCleanupMode;
65
+ }
66
+ export interface RepoMeshRelatedRepo {
67
+ /** Stable display label for an explicitly configured associated checkout. */
68
+ label: string;
69
+ /** Absolute checkout/workspace path for git freshness probes. */
70
+ workspace: string;
51
71
  }
52
72
  export interface RepoMeshNodePolicy {
53
73
  readOnly?: boolean;
54
74
  canPush?: boolean;
55
75
  maxConcurrentSessions?: number;
76
+ /** Ordered provider preference used when mesh_launch_session omits an explicit type. */
77
+ providerPriority?: string[];
78
+ /**
79
+ * Optional associated/external repos that must be checked alongside this node.
80
+ * These are explicit policy/config entries only; Repo Mesh does not auto-discover
81
+ * sibling paths so freshness checks stay fail-closed and non-surprising.
82
+ */
83
+ relatedRepos?: RepoMeshRelatedRepo[];
56
84
  }
57
85
  export declare const DEFAULT_MESH_POLICY: RepoMeshPolicy;
58
86
  export interface RepoMeshNodeCapabilities {
@@ -149,6 +177,12 @@ export interface LocalMeshNodeEntry {
149
177
  policy: RepoMeshNodePolicy;
150
178
  /** For single-machine mesh: same daemon, different worktree */
151
179
  isLocalWorktree?: boolean;
180
+ /** Branch this worktree tracks (set when created via clone_mesh_node) */
181
+ worktreeBranch?: string;
182
+ /** Node ID this worktree was cloned from */
183
+ clonedFromNodeId?: string;
184
+ /** Optional associated/external repos configured as node metadata. */
185
+ relatedRepos?: RepoMeshRelatedRepo[];
152
186
  }
153
187
  export interface RepoMeshStatus {
154
188
  meshId: string;
@@ -1,8 +1,9 @@
1
- import { type SessionHostEndpoint } from '@adhdev/session-host-core';
1
+ import { type SessionHostEndpoint, type SessionHostRequestType } from '@adhdev/session-host-core';
2
2
  import type { HostedCliRuntimeDescriptor } from '../commands/cli-manager.js';
3
3
  export declare function ensureSessionHostReady(options: {
4
4
  appName?: string;
5
5
  spawnHost: () => void;
6
6
  timeoutMs?: number;
7
+ requiredRequestTypes?: readonly SessionHostRequestType[];
7
8
  }): Promise<SessionHostEndpoint>;
8
9
  export declare function listHostedCliRuntimes(endpoint: SessionHostEndpoint): Promise<HostedCliRuntimeDescriptor[]>;
@@ -240,7 +240,9 @@ export type SessionTransport = 'cdp-page' | 'cdp-webview' | 'pty' | 'acp';
240
240
  export type SessionKind = 'workspace' | 'agent';
241
241
  export type SessionCapability = 'read_chat' | 'send_message' | 'new_session' | 'list_sessions' | 'switch_session' | 'resolve_action' | 'open_panel' | 'terminal_io' | 'resize_terminal' | 'change_model' | 'set_mode' | 'set_thought_level' | 'delete_notification' | 'mark_notification_unread';
242
242
  import type { RuntimeWriteOwner, RuntimeAttachedClient, SessionStatus } from './shared-types-extra.js';
243
+ import type { MessageInputSupport } from './providers/provider-input-support.js';
243
244
  export type { RuntimeWriteOwner, RuntimeAttachedClient, SessionStatus } from './shared-types-extra.js';
245
+ export type { MessageInputSupport, InputMediaStrategyDescriptor, InputAttachmentStrategy, InputMediaType } from './providers/provider-input-support.js';
244
246
  export interface SessionEntry {
245
247
  id: string;
246
248
  parentId: string | null;
@@ -267,6 +269,8 @@ export interface SessionEntry {
267
269
  resume?: ProviderResumeCapability;
268
270
  activeChat: SessionActiveChatData | null;
269
271
  capabilities?: SessionCapability[];
272
+ /** Effective message input/media support for this session. Defaults fail-closed to text-only. */
273
+ messageInput?: MessageInputSupport;
270
274
  cdpConnected?: boolean;
271
275
  /** Dynamic control current values (generic key-value) */
272
276
  controlValues?: Record<string, string | number | boolean>;
@@ -522,6 +526,8 @@ export interface DaemonStatusEventPayload {
522
526
  timestamp: number;
523
527
  targetSessionId?: string;
524
528
  providerType?: string;
529
+ providerSessionId?: string;
530
+ workspaceName?: string;
525
531
  duration?: number;
526
532
  elapsedSec?: number;
527
533
  modalMessage?: string;
@@ -535,6 +541,8 @@ export interface DashboardStatusEventPayload {
535
541
  daemonId?: string;
536
542
  providerType?: string;
537
543
  targetSessionId?: string;
544
+ providerSessionId?: string;
545
+ workspaceName?: string;
538
546
  duration?: number;
539
547
  elapsedSec?: number;
540
548
  modalMessage?: string;
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.9",
3
+ "version": "0.9.76",
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",
@@ -50,18 +50,17 @@
50
50
  "@agentclientprotocol/sdk": "^0.16.1",
51
51
  "@xterm/xterm": "^6.0.0",
52
52
  "chalk": "^5.3.0",
53
- "chokidar": "^5.0.0",
53
+ "chokidar": "^4.0.3",
54
54
  "conf": "^13.0.0",
55
+ "js-yaml": "^4.1.1",
55
56
  "node-pty": "^1.2.0-beta.12",
56
57
  "ws": "^8.19.0"
57
58
  },
58
- "bundleDependencies": [
59
- "@adhdev/session-host-core"
60
- ],
61
59
  "optionalDependencies": {
62
60
  "@adhdev/ghostty-vt-node": "*"
63
61
  },
64
62
  "devDependencies": {
63
+ "@types/js-yaml": "^4.0.9",
65
64
  "@types/node": "^22.0.0",
66
65
  "@types/ws": "^8.18.1",
67
66
  "tsup": "^8.2.0",
@@ -8,6 +8,7 @@ import {
8
8
  buildSessionModalDeliverySignature,
9
9
  } from './chat-signatures.js'
10
10
  import { normalizeManagedStatus } from '../status/normalize.js'
11
+ import { 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 = 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'
@@ -35,6 +35,7 @@ import {
35
35
  normalizeScreenSnapshot,
36
36
  promptLikelyVisible,
37
37
  sanitizeTerminalText,
38
+ TerminalTranscriptAccumulator,
38
39
  type CliChatMessage,
39
40
  type CliProviderModule,
40
41
  type CliScriptInput,
@@ -195,8 +196,10 @@ export class ProviderCliAdapter implements CliAdapter {
195
196
  // ─── CLI Scripts (script-based parsing) ───
196
197
  private cliScripts: CliScripts;
197
198
  private runtimeSettings: Record<string, any> = {};
198
- /** Full accumulated ANSI-stripped PTY output */
199
+ /** Full accumulated rendered PTY transcript for parser/readback use */
199
200
  private accumulatedBuffer: string = '';
201
+ /** Stateful rendered transcript accumulator; raw debug remains in accumulatedRawBuffer. */
202
+ private transcriptAccumulator = new TerminalTranscriptAccumulator();
200
203
  /** Full accumulated raw PTY output (with ANSI) */
201
204
  private accumulatedRawBuffer: string = '';
202
205
  /** Current visible terminal screen snapshot */
@@ -287,6 +290,7 @@ export class ProviderCliAdapter implements CliAdapter {
287
290
 
288
291
  private resetTerminalScreen(rows?: number, cols?: number): void {
289
292
  this.terminalScreen.reset(rows, cols);
293
+ this.transcriptAccumulator.reset();
290
294
  this.lastScreenText = '';
291
295
  this.lastScreenSnapshot = '';
292
296
  this.lastScreenChangeAt = 0;
@@ -422,6 +426,7 @@ export class ProviderCliAdapter implements CliAdapter {
422
426
  provider: CliProviderModule,
423
427
  workingDir: string,
424
428
  private extraArgs: string[] = [],
429
+ private extraEnv: Record<string, string> = {},
425
430
  transportFactory: PtyTransportFactory = new NodePtyTransportFactory(),
426
431
  ) {
427
432
  this.provider = provider;
@@ -523,6 +528,7 @@ export class ProviderCliAdapter implements CliAdapter {
523
528
  runtimeSettings: this.runtimeSettings,
524
529
  workingDir: this.workingDir,
525
530
  extraArgs: this.extraArgs,
531
+ extraEnv: this.extraEnv,
526
532
  });
527
533
 
528
534
  LOG.info('CLI', `[${this.cliType}] Spawning in ${this.workingDir}`);
@@ -632,6 +638,7 @@ export class ProviderCliAdapter implements CliAdapter {
632
638
  private handleOutput(rawData: string): void {
633
639
  this.terminalScreen.write(rawData);
634
640
  const cleanData = sanitizeTerminalText(rawData);
641
+ const renderedTranscript = this.transcriptAccumulator.append(rawData);
635
642
  const now = Date.now();
636
643
  const shouldReadScreen = this.shouldReadTerminalScreenSnapshot(now);
637
644
  const screenText = shouldReadScreen ? this.readTerminalScreenText(now) : this.lastScreenText;
@@ -678,15 +685,23 @@ export class ProviderCliAdapter implements CliAdapter {
678
685
  }
679
686
  }
680
687
 
681
- // Rolling buffers
688
+ // Rolling parser/readback buffers. `accumulatedBuffer` and
689
+ // `recentOutputBuffer` intentionally use the rendered transcript state,
690
+ // not raw PTY append text, so overwritten CLI status/tool lines do not
691
+ // leak stale cells into read_chat / mesh_read_chat compact summaries.
682
692
  const prevRecentLen = this.recentOutputBuffer.length;
683
- const prevAccumulatedLen = this.accumulatedBuffer.length;
684
693
  const prevAccumulatedRawLen = this.accumulatedRawBuffer.length;
685
- this.recentOutputBuffer = appendBoundedText(this.recentOutputBuffer, cleanData, ProviderCliAdapter.MAX_RECENT_OUTPUT_BUFFER);
686
- this.accumulatedBuffer = appendBoundedText(this.accumulatedBuffer, cleanData, ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
694
+ const nextAccumulatedBuffer = renderedTranscript.length <= ProviderCliAdapter.MAX_ACCUMULATED_BUFFER
695
+ ? renderedTranscript
696
+ : renderedTranscript.slice(-ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
697
+ const nextRecentOutputBuffer = nextAccumulatedBuffer.slice(-ProviderCliAdapter.MAX_RECENT_OUTPUT_BUFFER);
698
+ this.recentOutputBuffer = nextRecentOutputBuffer;
699
+ this.accumulatedBuffer = nextAccumulatedBuffer;
687
700
  this.accumulatedRawBuffer = appendBoundedText(this.accumulatedRawBuffer, rawData, ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
688
- const droppedRecent = this.recordBoundedAppendDrop(prevRecentLen, cleanData.length, this.recentOutputBuffer.length);
689
- const droppedClean = this.recordBoundedAppendDrop(prevAccumulatedLen, cleanData.length, this.accumulatedBuffer.length);
701
+ // recentOutputBuffer is a 1000-char sliding window over accumulatedBuffer.
702
+ // Anything that doesn't fit in the window is considered dropped.
703
+ const droppedRecent = Math.max(0, renderedTranscript.length - ProviderCliAdapter.MAX_RECENT_OUTPUT_BUFFER);
704
+ const droppedClean = Math.max(0, renderedTranscript.length - this.accumulatedBuffer.length);
690
705
  const droppedRaw = this.recordBoundedAppendDrop(prevAccumulatedRawLen, rawData.length, this.accumulatedRawBuffer.length);
691
706
  this.recentOutputDroppedChars += droppedRecent;
692
707
  this.accumulatedBufferDroppedChars += droppedClean;
@@ -1855,9 +1870,13 @@ export class ProviderCliAdapter implements CliAdapter {
1855
1870
  };
1856
1871
  this.recordTrace('submit_echo_missing', diagnostic);
1857
1872
  if (this.requirePromptEchoBeforeSubmit) {
1858
- const message = `${this.cliName} prompt echo was not observed on the PTY screen before submit`;
1859
- LOG.warn('CLI', `[${this.cliType}] ${message} elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
1860
- completion.rejectOnce(new Error(message));
1873
+ // At this point the prompt text write already completed. Rejecting without
1874
+ // a submit key can leave the delegated CLI with an unsent prompt sitting at
1875
+ // the input line, which makes later coordinator sends appear stuck. Prefer a
1876
+ // guarded submit after the full echo wait; the existing stuck-submit retry
1877
+ // will send a delayed follow-up Enter if the prompt remains visible.
1878
+ LOG.warn('CLI', `[${this.cliType}] prompt echo was not observed before submit; sending guarded submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
1879
+ this.submitSendKey(state, completion);
1861
1880
  return;
1862
1881
  }
1863
1882
  LOG.warn('CLI', `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
@@ -1912,7 +1931,21 @@ export class ProviderCliAdapter implements CliAdapter {
1912
1931
  ? String(parsedStatusBeforeSend.status)
1913
1932
  : '';
1914
1933
  if (!allowInputDuringGeneration && (parsedSessionStatus === 'generating' || parsedSessionStatus === 'long_generating')) {
1915
- throw new Error(`${this.cliName} is still processing the previous prompt`);
1934
+ const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
1935
+ const parsedHasActionableModal = Boolean(
1936
+ parsedModal
1937
+ && Array.isArray(parsedModal.buttons)
1938
+ && parsedModal.buttons.some((candidate: unknown) => typeof candidate === 'string' && candidate.trim()),
1939
+ );
1940
+ const terminalLooksIdle = this.currentStatus === 'idle'
1941
+ && this.runDetectStatus(this.recentOutputBuffer) === 'idle'
1942
+ && !this.isWaitingForResponse
1943
+ && !this.currentTurnScope
1944
+ && !this.hasActionableApproval()
1945
+ && !parsedHasActionableModal;
1946
+ if (!terminalLooksIdle) {
1947
+ throw new Error(`${this.cliName} is still processing the previous prompt`);
1948
+ }
1916
1949
  }
1917
1950
  if (this.isWaitingForResponse && !allowInputDuringGeneration) {
1918
1951
  if (!this.clearStaleIdleResponseGuard('send_message_guard')) {
@@ -27,8 +27,9 @@ export function resolveCliSpawnPlan(options: {
27
27
  runtimeSettings: Record<string, any>;
28
28
  workingDir: string;
29
29
  extraArgs: string[];
30
+ extraEnv?: Record<string, string>;
30
31
  }): CliSpawnPlan {
31
- const { provider, runtimeSettings, workingDir, extraArgs } = options;
32
+ const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
32
33
  const { spawn: spawnConfig } = provider;
33
34
  const configuredCommand = typeof runtimeSettings.executablePath === 'string' && runtimeSettings.executablePath.trim()
34
35
  ? runtimeSettings.executablePath.trim()
@@ -65,7 +66,7 @@ export function resolveCliSpawnPlan(options: {
65
66
  shellArgs = allArgs;
66
67
  }
67
68
 
68
- const env = buildCliSpawnEnv(process.env, spawnConfig.env);
69
+ const env = buildCliSpawnEnv(process.env, { ...(spawnConfig.env || {}), ...(extraEnv || {}) });
69
70
  // Some CLI agents, notably Hermes, route their tools through TERMINAL_CWD
70
71
  // rather than process.cwd(). Keep the generic ADHDev launch workspace as
71
72
  // the single source of truth so PTY cwd and tool cwd cannot diverge.