@adhdev/daemon-core 0.9.8 → 0.9.10

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.
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import type { ProviderSummaryMetadata } from '../shared-types.js';
10
10
  import type { ChatMessageKind } from './chat-message-normalization.js';
11
+ export type ReadChatTurnStatus = 'open' | 'waiting_approval' | 'complete' | 'error';
11
12
  export interface ReadChatResult {
12
13
  messages: ChatMessage[];
13
14
  status: AgentStatus;
@@ -15,6 +16,9 @@ export interface ReadChatResult {
15
16
  /** IDE/Extension only: session info */
16
17
  id?: string;
17
18
  title?: string;
19
+ /** Authoritative transcript turn identity when available. */
20
+ currentTurnId?: string;
21
+ turnStatus?: ReadChatTurnStatus;
18
22
  /** Extension only: additional metadata */
19
23
  agentType?: string;
20
24
  agentName?: string;
@@ -2,4 +2,4 @@
2
2
  * Provider System — Public API
3
3
  */
4
4
  export { ProviderLoader } from './provider-loader.js';
5
- export type { ProviderModule, ProviderCategory, ProviderScripts, ResolvedProvider, ReadChatResult, ChatMessage, AgentStatus, ModalInfo, SendMessageResult, ListSessionsResult, SessionInfo, SwitchSessionResult, } from './contracts.js';
5
+ export type { ProviderModule, ProviderCategory, ProviderScripts, ResolvedProvider, ReadChatResult, ReadChatTurnStatus, ChatMessage, AgentStatus, ModalInfo, SendMessageResult, ListSessionsResult, SessionInfo, SwitchSessionResult, } from './contracts.js';
package/dist/types.d.ts CHANGED
@@ -20,12 +20,19 @@ export interface StatusResponse extends StatusReportPayload {
20
20
  /** System info (legacy compat) */
21
21
  system?: SystemInfo;
22
22
  }
23
+ export type ChatBubbleState = 'draft' | 'streaming' | 'final' | 'removed';
23
24
  export interface ChatMessage {
24
25
  role: string;
25
26
  /** Plain text (legacy) or canonical message parts */
26
27
  content: string | MessagePart[];
27
28
  kind?: ChatMessageKind;
28
29
  id?: string;
30
+ /** Stable daemon-owned bubble identity when available. */
31
+ bubbleId?: string;
32
+ /** Stable provider-local unit identity used to reconcile legacy providers during migration. */
33
+ providerUnitKey?: string;
34
+ /** Bubble lifecycle state for transcript-authority migration. */
35
+ bubbleState?: ChatBubbleState;
29
36
  index?: number;
30
37
  timestamp?: number;
31
38
  receivedAt?: number;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/session-host-core",
3
- "version": "0.9.8",
3
+ "version": "0.9.10",
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.8",
3
+ "version": "0.9.10",
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",
@@ -350,7 +350,7 @@ export class ProviderCliAdapter implements CliAdapter {
350
350
  private readonly sendDelayMs: number;
351
351
  private readonly sendKey: string;
352
352
  private readonly submitStrategy: 'wait_for_echo' | 'immediate';
353
- private static readonly SCRIPT_STATUS_DEBOUNCE_MS = 1000;
353
+ private static readonly SCRIPT_STATUS_DEBOUNCE_MS = 3000;
354
354
 
355
355
  constructor(
356
356
  provider: CliProviderModule,
@@ -18,6 +18,7 @@ import type { ReadChatCursor, ReadChatSyncMode, SessionTransport } from '../shar
18
18
  import { normalizeChatMessages } from '../providers/chat-message-normalization.js';
19
19
 
20
20
  const RECENT_SEND_WINDOW_MS = 1200;
21
+ export const READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25_000;
21
22
  const recentSendByTarget = new Map<string, number>();
22
23
 
23
24
  interface ApprovalSelectableInstance extends ProviderInstance {
@@ -400,7 +401,7 @@ function didProviderConfirmSend(result: any): boolean {
400
401
 
401
402
  async function readExtensionChatState(h: CommandHelpers): Promise<any | null> {
402
403
  try {
403
- const evalResult = await h.evaluateProviderScript('readChat', undefined, 50000);
404
+ const evalResult = await h.evaluateProviderScript('readChat', undefined, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
404
405
  if (!evalResult?.result) return null;
405
406
  const parsed = parseMaybeJson(evalResult.result);
406
407
  return parsed && typeof parsed === 'object' ? parsed : null;
@@ -513,7 +514,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
513
514
  ? parsedRecord.providerSessionId
514
515
  : undefined;
515
516
  if (status) {
516
- LOG.info('Command', `[read_chat] cli-like resolved provider=${adapter.cliType} target=${String(args?.targetSessionId || '')} adapterStatus=${String(adapterStatus.status || '')} parsedStatus=${String(parsedRecord?.status || '')} shouldPreferAdapterMessages=${String(shouldPreferAdapterMessages)} adapterMsgCount=${Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0} parsedMsgCount=${Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0} returnedMsgCount=${Array.isArray((status as any).messages) ? (status as any).messages.length : 0}`);
517
+ LOG.debug('Command', `[read_chat] cli-like resolved provider=${adapter.cliType} target=${String(args?.targetSessionId || '')} adapterStatus=${String(adapterStatus.status || '')} parsedStatus=${String(parsedRecord?.status || '')} shouldPreferAdapterMessages=${String(shouldPreferAdapterMessages)} adapterMsgCount=${Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0} parsedMsgCount=${Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0} returnedMsgCount=${Array.isArray((status as any).messages) ? (status as any).messages.length : 0}`);
517
518
  return buildReadChatCommandResult({
518
519
  messages: (status as any).messages || [],
519
520
  status: status.status,
@@ -540,7 +541,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
540
541
  // Extension transport: evaluateInSession
541
542
  if (isExtensionTransport(transport)) {
542
543
  try {
543
- const evalResult = await h.evaluateProviderScript('readChat', undefined, 50000);
544
+ const evalResult = await h.evaluateProviderScript('readChat', undefined, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
544
545
  if (evalResult?.result) {
545
546
  let parsed = evalResult.result;
546
547
  if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { } }
@@ -643,7 +644,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
643
644
  const script = h.getProviderScript('readChat') || h.getProviderScript('read_chat');
644
645
  if (script) {
645
646
  try {
646
- const evalResult = await h.evaluateProviderScript('readChat', undefined, 50000);
647
+ const evalResult = await h.evaluateProviderScript('readChat', undefined, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
647
648
  if (evalResult?.result) {
648
649
  let parsed: any = evalResult.result;
649
650
  if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { } }
package/src/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Core logic for daemon: CDP, Provider, IDE detection, CLI/ACP adapters and more.
5
5
  */
6
- export type { ChatMessage, ExtensionInfo, CommandResult as CoreCommandResult, ProviderConfig, DaemonEvent, StatusResponse, SystemInfo, DetectedIde, ProviderInfo, AgentEntry, } from './types.js';
6
+ export type { ChatBubbleState, ChatMessage, ExtensionInfo, CommandResult as CoreCommandResult, ProviderConfig, DaemonEvent, StatusResponse, SystemInfo, DetectedIde, ProviderInfo, AgentEntry, } from './types.js';
7
7
  export type { SessionEntry, CompactSessionEntry, CompactDaemonEntry, SessionTransport, SessionKind, SessionCapability, AgentSessionStream, ReadChatCursor, ReadChatSyncMode, ReadChatSyncResult, TransportTopic, SessionChatTailSubscriptionParams, MachineRuntimeSubscriptionParams, SessionHostDiagnosticsSubscriptionParams, SessionModalSubscriptionParams, DaemonMetadataSubscriptionParams, SessionChatTailUpdate, MachineRuntimeUpdate, SessionHostDiagnosticsUpdate, SessionModalUpdate, DaemonMetadataUpdate, TopicUpdateEnvelope, SubscribeRequest, UnsubscribeRequest, StandaloneWsStatusPayload, AvailableProviderInfo, AcpConfigOption, AcpMode, ProviderControlSchema, StatusReportPayload, MachineInfo, SessionHostDiagnosticsSnapshot, SessionHostRecord, SessionHostWriteOwner, SessionHostAttachedClient, SessionHostLogEntry, SessionHostRequestTrace, SessionHostRuntimeTransition, DetectedIdeInfo, WorkspaceEntry, ProviderSummaryItem, ProviderSummaryMetadata, ProviderState, ProviderStatus, ProviderErrorReason, ActiveChatData, IdeProviderState, CliProviderState, AcpProviderState, ExtensionProviderState, } from './shared-types.js';
8
8
  import type { RuntimeWriteOwner as _RuntimeWriteOwner } from './shared-types-extra.js';
9
9
  import type { RuntimeAttachedClient as _RuntimeAttachedClient } from './shared-types-extra.js';
@@ -65,7 +65,7 @@ export { ProviderInstanceManager } from './providers/provider-instance-manager.j
65
65
  export { IdeProviderInstance } from './providers/ide-provider-instance.js';
66
66
  export { CliProviderInstance } from './providers/cli-provider-instance.js';
67
67
  export { AcpProviderInstance } from './providers/acp-provider-instance.js';
68
- export type { ProviderModule, CdpTargetFilter, ProviderResumeCapability } from './providers/contracts.js';
68
+ export type { ProviderModule, CdpTargetFilter, ProviderResumeCapability, ReadChatTurnStatus } from './providers/contracts.js';
69
69
  export { VersionArchive, detectAllVersions } from './providers/version-archive.js';
70
70
  export type { ProviderVersionInfo, VersionHistory } from './providers/version-archive.js';
71
71
  export { DevServer } from './daemon/dev-server.js';
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@
6
6
 
7
7
  // ── Types ──
8
8
  export type {
9
+ ChatBubbleState,
9
10
  ChatMessage,
10
11
  ExtensionInfo,
11
12
  CommandResult as CoreCommandResult,
@@ -251,7 +252,7 @@ export { ProviderInstanceManager } from './providers/provider-instance-manager.j
251
252
  export { IdeProviderInstance } from './providers/ide-provider-instance.js';
252
253
  export { CliProviderInstance } from './providers/cli-provider-instance.js';
253
254
  export { AcpProviderInstance } from './providers/acp-provider-instance.js';
254
- export type { ProviderModule, CdpTargetFilter, ProviderResumeCapability, InputEnvelope, InputPart, MessagePart, ControlListResult, ControlSetResult, ControlInvokeResult } from './providers/contracts.js';
255
+ export type { ProviderModule, CdpTargetFilter, ProviderResumeCapability, InputEnvelope, InputPart, MessagePart, ReadChatTurnStatus, ControlListResult, ControlSetResult, ControlInvokeResult } from './providers/contracts.js';
255
256
  export type { ProviderSourceConfigSnapshot, ProviderSourceConfigUpdate } from './config/provider-source-config.js';
256
257
  export { parseProviderSourceConfigUpdate } from './config/provider-source-config.js';
257
258
  export { normalizeInputEnvelope, normalizeMessageParts, flattenMessageParts } from './providers/io-contracts.js';
@@ -576,7 +576,7 @@ export class CliProviderInstance implements ProviderInstance {
576
576
  }
577
577
 
578
578
  if (!this.generatingStartedAt) this.generatingStartedAt = now;
579
- // Defer the generating_started event — if idle comes back within 1s,
579
+ // Defer the generating_started event — if idle comes back within 3s,
580
580
  // the whole started→completed pair was a false positive from PTY noise
581
581
  if (this.generatingDebounceTimer) clearTimeout(this.generatingDebounceTimer);
582
582
  this.generatingDebouncePending = { chatTitle, timestamp: now };
@@ -586,7 +586,7 @@ export class CliProviderInstance implements ProviderInstance {
586
586
  this.generatingDebouncePending = null;
587
587
  }
588
588
  this.generatingDebounceTimer = null;
589
- }, 1000);
589
+ }, 3000);
590
590
  } else if (newStatus === 'waiting_approval') {
591
591
  this.suppressIdleHistoryReplay = false;
592
592
  // Flush pending generating_started if debounce still pending
@@ -626,7 +626,7 @@ export class CliProviderInstance implements ProviderInstance {
626
626
  this.generatingDebouncePending = null;
627
627
  this.generatingStartedAt = 0;
628
628
  } else {
629
- // Debounce completed — wait 2s, if still idle then emit
629
+ // Debounce completed — wait 3s, if still idle then emit
630
630
  if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
631
631
  this.completedDebouncePending = { chatTitle, duration, timestamp: now };
632
632
  this.completedDebounceTimer = setTimeout(() => {
@@ -637,7 +637,7 @@ export class CliProviderInstance implements ProviderInstance {
637
637
  this.generatingStartedAt = 0;
638
638
  }
639
639
  this.completedDebounceTimer = null;
640
- }, 2000);
640
+ }, 3000);
641
641
  }
642
642
  } else if (newStatus === 'stopped') {
643
643
  // Cancel any pending debounce
@@ -7,6 +7,7 @@
7
7
  * - User custom providers use the same contracts
8
8
  */
9
9
  import type { ProviderSummaryMetadata } from '../shared-types.js';
10
+ export type ReadChatTurnStatus = 'open' | 'waiting_approval' | 'complete' | 'error';
10
11
  export interface ReadChatResult {
11
12
  messages: ChatMessage[];
12
13
  status: AgentStatus;
@@ -14,6 +15,9 @@ export interface ReadChatResult {
14
15
  /** IDE/Extension only: session info */
15
16
  id?: string;
16
17
  title?: string;
18
+ /** Authoritative transcript turn identity when available. */
19
+ currentTurnId?: string;
20
+ turnStatus?: ReadChatTurnStatus;
17
21
  /** Extension only: additional metadata */
18
22
  agentType?: string;
19
23
  agentName?: string;
@@ -12,6 +12,8 @@
12
12
  import type { ProviderSummaryMetadata } from '../shared-types.js';
13
13
  import type { ChatMessageKind } from './chat-message-normalization.js';
14
14
 
15
+ export type ReadChatTurnStatus = 'open' | 'waiting_approval' | 'complete' | 'error';
16
+
15
17
  export interface ReadChatResult {
16
18
  messages: ChatMessage[];
17
19
  status: AgentStatus;
@@ -19,6 +21,9 @@ export interface ReadChatResult {
19
21
  /** IDE/Extension only: session info */
20
22
  id?: string;
21
23
  title?: string;
24
+ /** Authoritative transcript turn identity when available. */
25
+ currentTurnId?: string;
26
+ turnStatus?: ReadChatTurnStatus;
22
27
  /** Extension only: additional metadata */
23
28
  agentType?: string;
24
29
  agentName?: string;
@@ -8,6 +8,7 @@ export type {
8
8
  ProviderScripts,
9
9
  ResolvedProvider,
10
10
  ReadChatResult,
11
+ ReadChatTurnStatus,
11
12
  ChatMessage,
12
13
  AgentStatus,
13
14
  ModalInfo,
@@ -1,12 +1,15 @@
1
1
  import type { MessagePart, ModalInfo, ReadChatResult } from './contracts.js'
2
2
  import { normalizeMessageParts } from './contracts.js'
3
- import type { ChatMessage } from '../types.js'
3
+ import type { ChatBubbleState, ChatMessage } from '../types.js'
4
4
 
5
5
  const VALID_STATUSES = ['idle', 'generating', 'waiting_approval', 'error', 'panel_hidden', 'streaming', 'long_generating'] as const
6
6
  const VALID_ROLES = ['user', 'assistant', 'system', 'human'] as const
7
+ const VALID_BUBBLE_STATES = ['draft', 'streaming', 'final', 'removed'] as const
8
+ const VALID_TURN_STATUSES = ['open', 'waiting_approval', 'complete', 'error'] as const
7
9
 
8
10
  type ValidStatus = typeof VALID_STATUSES[number]
9
11
  type ValidRole = typeof VALID_ROLES[number]
12
+ type ValidTurnStatus = typeof VALID_TURN_STATUSES[number]
10
13
 
11
14
  function isPlainObject(value: unknown): value is Record<string, unknown> {
12
15
  return !!value && typeof value === 'object' && !Array.isArray(value)
@@ -30,6 +33,20 @@ function validateRole(role: unknown, source: string, index: number): ValidRole {
30
33
  return role as ValidRole
31
34
  }
32
35
 
36
+ function validateBubbleState(state: unknown, source: string, index: number): ChatBubbleState {
37
+ if (typeof state !== 'string' || !VALID_BUBBLE_STATES.includes(state as ChatBubbleState)) {
38
+ throw new Error(`${source}: messages[${index}].bubbleState must be one of ${VALID_BUBBLE_STATES.join(', ')}`)
39
+ }
40
+ return state as ChatBubbleState
41
+ }
42
+
43
+ function validateTurnStatus(turnStatus: unknown, source: string): ValidTurnStatus {
44
+ if (typeof turnStatus !== 'string' || !VALID_TURN_STATUSES.includes(turnStatus as ValidTurnStatus)) {
45
+ throw new Error(`${source}: turnStatus must be one of ${VALID_TURN_STATUSES.join(', ')}`)
46
+ }
47
+ return turnStatus as ValidTurnStatus
48
+ }
49
+
33
50
  function validateMessageContent(content: unknown, source: string, index: number): string | MessagePart[] {
34
51
  if (typeof content === 'string') return content
35
52
  if (Array.isArray(content)) return normalizeMessageParts(content as any)
@@ -48,6 +65,9 @@ function validateMessage(message: unknown, source: string, index: number): ChatM
48
65
 
49
66
  if (typeof message.kind === 'string') normalized.kind = message.kind as any
50
67
  if (typeof message.id === 'string') normalized.id = message.id
68
+ if (typeof message.bubbleId === 'string') normalized.bubbleId = message.bubbleId
69
+ if (typeof message.providerUnitKey === 'string') normalized.providerUnitKey = message.providerUnitKey
70
+ if (message.bubbleState !== undefined) normalized.bubbleState = validateBubbleState(message.bubbleState, source, index)
51
71
  if (isFiniteNumber(message.index)) normalized.index = message.index
52
72
  if (isFiniteNumber(message.timestamp)) normalized.timestamp = message.timestamp
53
73
  if (isFiniteNumber(message.receivedAt)) normalized.receivedAt = message.receivedAt
@@ -122,6 +142,8 @@ export function validateReadChatResultPayload(raw: unknown, source = 'read_chat'
122
142
  if (activeModal !== undefined) normalized.activeModal = activeModal
123
143
  if (typeof raw.id === 'string') normalized.id = raw.id
124
144
  if (typeof raw.title === 'string') normalized.title = raw.title
145
+ if (typeof raw.currentTurnId === 'string') normalized.currentTurnId = raw.currentTurnId
146
+ if (raw.turnStatus !== undefined) normalized.turnStatus = validateTurnStatus(raw.turnStatus, source)
125
147
  if (typeof raw.agentType === 'string') normalized.agentType = raw.agentType
126
148
  if (typeof raw.agentName === 'string') normalized.agentName = raw.agentName
127
149
  if (typeof raw.extensionId === 'string') normalized.extensionId = raw.extensionId
package/src/types.d.ts CHANGED
@@ -19,12 +19,19 @@ export interface StatusResponse extends StatusReportPayload {
19
19
  /** System info (legacy compat) */
20
20
  system?: SystemInfo;
21
21
  }
22
+ export type ChatBubbleState = 'draft' | 'streaming' | 'final' | 'removed';
22
23
  export interface ChatMessage {
23
24
  role: string;
24
25
  /** Plain text (legacy) or rich content blocks (ACP standard) */
25
26
  content: string | ContentBlock[];
26
27
  kind?: string;
27
28
  id?: string;
29
+ /** Stable daemon-owned bubble identity when available. */
30
+ bubbleId?: string;
31
+ /** Stable provider-local unit identity used to reconcile legacy providers during migration. */
32
+ providerUnitKey?: string;
33
+ /** Bubble lifecycle state for transcript-authority migration. */
34
+ bubbleState?: ChatBubbleState;
28
35
  index?: number;
29
36
  timestamp?: number;
30
37
  receivedAt?: number;
package/src/types.ts CHANGED
@@ -26,12 +26,20 @@ export interface StatusResponse extends StatusReportPayload {
26
26
 
27
27
  // ── Chat Message ──
28
28
 
29
+ export type ChatBubbleState = 'draft' | 'streaming' | 'final' | 'removed';
30
+
29
31
  export interface ChatMessage {
30
32
  role: string; // 'user' | 'assistant' | 'system' | 'human'
31
33
  /** Plain text (legacy) or canonical message parts */
32
34
  content: string | MessagePart[];
33
35
  kind?: ChatMessageKind; // built-ins: standard | thought | tool | terminal | system; custom kinds allowed
34
36
  id?: string;
37
+ /** Stable daemon-owned bubble identity when available. */
38
+ bubbleId?: string;
39
+ /** Stable provider-local unit identity used to reconcile legacy providers during migration. */
40
+ providerUnitKey?: string;
41
+ /** Bubble lifecycle state for transcript-authority migration. */
42
+ bubbleState?: ChatBubbleState;
35
43
  index?: number;
36
44
  timestamp?: number;
37
45
  receivedAt?: number;