@adhdev/daemon-core 0.8.35 → 0.8.37

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.
@@ -33,6 +33,179 @@ export interface AgentSessionStream {
33
33
  buttons: string[];
34
34
  } | null;
35
35
  }
36
+ export type ReadChatSyncMode = 'full' | 'append' | 'replace_tail' | 'noop';
37
+ export interface ReadChatCursor {
38
+ knownMessageCount?: number;
39
+ lastMessageSignature?: string;
40
+ tailLimit?: number;
41
+ }
42
+ export interface ReadChatSyncResult {
43
+ messages: ChatMessage[];
44
+ status: string;
45
+ title?: string;
46
+ activeModal?: {
47
+ message: string;
48
+ buttons: string[];
49
+ } | null;
50
+ syncMode: ReadChatSyncMode;
51
+ replaceFrom: number;
52
+ totalMessages: number;
53
+ lastMessageSignature: string;
54
+ }
55
+ export interface SessionHostAttachedClient {
56
+ clientId: string;
57
+ type: string;
58
+ readOnly: boolean;
59
+ attachedAt: number;
60
+ lastSeenAt: number;
61
+ }
62
+ export interface SessionHostWriteOwner {
63
+ clientId: string;
64
+ ownerType: 'agent' | 'user';
65
+ acquiredAt: number;
66
+ }
67
+ export interface SessionHostRecord {
68
+ sessionId: string;
69
+ runtimeKey: string;
70
+ displayName: string;
71
+ workspaceLabel: string;
72
+ providerType: string;
73
+ workspace: string;
74
+ lifecycle: 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'interrupted';
75
+ writeOwner: SessionHostWriteOwner | null;
76
+ attachedClients: SessionHostAttachedClient[];
77
+ osPid?: number;
78
+ lastActivityAt: number;
79
+ createdAt: number;
80
+ startedAt?: number;
81
+ meta?: Record<string, unknown>;
82
+ }
83
+ export interface SessionHostLogEntry {
84
+ timestamp: number;
85
+ level: 'debug' | 'info' | 'warn' | 'error';
86
+ message: string;
87
+ sessionId?: string;
88
+ }
89
+ export interface SessionHostRequestTrace {
90
+ timestamp: number;
91
+ requestId: string;
92
+ type: string;
93
+ sessionId?: string;
94
+ clientId?: string;
95
+ success: boolean;
96
+ durationMs: number;
97
+ error?: string;
98
+ }
99
+ export interface SessionHostRuntimeTransition {
100
+ timestamp: number;
101
+ sessionId: string;
102
+ action: string;
103
+ lifecycle?: string;
104
+ detail?: string;
105
+ success?: boolean;
106
+ error?: string;
107
+ }
108
+ export interface SessionHostDiagnosticsSnapshot {
109
+ hostStartedAt: number;
110
+ endpoint: string;
111
+ runtimeCount: number;
112
+ sessions?: SessionHostRecord[];
113
+ recentLogs: SessionHostLogEntry[];
114
+ recentRequests: SessionHostRequestTrace[];
115
+ recentTransitions: SessionHostRuntimeTransition[];
116
+ }
117
+ export type TransportTopic = 'session.chat_tail' | 'machine.runtime' | 'session_host.diagnostics' | 'session.modal' | 'daemon.metadata';
118
+ export interface SessionChatTailSubscriptionParams extends ReadChatCursor {
119
+ targetSessionId: string;
120
+ historySessionId?: string;
121
+ }
122
+ export interface MachineRuntimeSubscriptionParams {
123
+ intervalMs?: number;
124
+ }
125
+ export interface SessionModalSubscriptionParams {
126
+ targetSessionId: string;
127
+ }
128
+ export interface DaemonMetadataSubscriptionParams {
129
+ includeSessions?: boolean;
130
+ }
131
+ export interface SessionHostDiagnosticsSubscriptionParams {
132
+ includeSessions?: boolean;
133
+ limit?: number;
134
+ intervalMs?: number;
135
+ }
136
+ export interface SessionChatTailUpdate extends ReadChatSyncResult {
137
+ topic: 'session.chat_tail';
138
+ key: string;
139
+ sessionId: string;
140
+ historySessionId?: string;
141
+ seq: number;
142
+ timestamp: number;
143
+ }
144
+ export interface MachineRuntimeUpdate {
145
+ topic: 'machine.runtime';
146
+ key: string;
147
+ machine: MachineInfo;
148
+ seq: number;
149
+ timestamp: number;
150
+ }
151
+ export interface SessionHostDiagnosticsUpdate {
152
+ topic: 'session_host.diagnostics';
153
+ key: string;
154
+ diagnostics: SessionHostDiagnosticsSnapshot;
155
+ seq: number;
156
+ timestamp: number;
157
+ }
158
+ export interface SessionModalUpdate {
159
+ topic: 'session.modal';
160
+ key: string;
161
+ sessionId: string;
162
+ status: string;
163
+ title?: string;
164
+ modalMessage?: string;
165
+ modalButtons?: string[];
166
+ seq: number;
167
+ timestamp: number;
168
+ }
169
+ export interface DaemonMetadataUpdate {
170
+ topic: 'daemon.metadata';
171
+ key: string;
172
+ daemonId: string;
173
+ status: StatusReportPayload;
174
+ userName?: string;
175
+ seq: number;
176
+ timestamp: number;
177
+ }
178
+ export interface TopicUpdateEnvelopeMap {
179
+ 'session.chat_tail': SessionChatTailUpdate;
180
+ 'machine.runtime': MachineRuntimeUpdate;
181
+ 'session_host.diagnostics': SessionHostDiagnosticsUpdate;
182
+ 'session.modal': SessionModalUpdate;
183
+ 'daemon.metadata': DaemonMetadataUpdate;
184
+ }
185
+ export type TopicUpdateEnvelope = TopicUpdateEnvelopeMap[TransportTopic];
186
+ export interface SubscribeRequestMap {
187
+ 'session.chat_tail': SessionChatTailSubscriptionParams;
188
+ 'machine.runtime': MachineRuntimeSubscriptionParams;
189
+ 'session_host.diagnostics': SessionHostDiagnosticsSubscriptionParams;
190
+ 'session.modal': SessionModalSubscriptionParams;
191
+ 'daemon.metadata': DaemonMetadataSubscriptionParams;
192
+ }
193
+ export type SubscribeRequest = {
194
+ [K in TransportTopic]: {
195
+ type: 'subscribe';
196
+ topic: K;
197
+ key: string;
198
+ params: SubscribeRequestMap[K];
199
+ };
200
+ }[TransportTopic];
201
+ export type UnsubscribeRequest = {
202
+ [K in TransportTopic]: {
203
+ type: 'unsubscribe';
204
+ topic: K;
205
+ key: string;
206
+ };
207
+ }[TransportTopic];
208
+ export type StandaloneWsStatusPayload = StatusReportPayload;
36
209
  export type SessionTransport = 'cdp-page' | 'cdp-webview' | 'pty' | 'acp';
37
210
  export type SessionKind = 'workspace' | 'agent';
38
211
  export type SessionCapability = 'read_chat' | 'send_message' | 'new_session' | 'list_sessions' | 'switch_session' | 'resolve_action' | 'terminal_io' | 'resize_terminal' | 'change_model' | 'set_mode' | 'set_thought_level';
@@ -42,13 +215,13 @@ export interface SessionEntry {
42
215
  id: string;
43
216
  parentId: string | null;
44
217
  providerType: string;
45
- providerName: string;
218
+ providerName?: string;
46
219
  providerSessionId?: string;
47
220
  kind: SessionKind;
48
221
  transport: SessionTransport;
49
222
  status: SessionStatus;
50
223
  title: string;
51
- workspace: string | null;
224
+ workspace?: string | null;
52
225
  runtimeKey?: string;
53
226
  runtimeDisplayName?: string;
54
227
  runtimeWorkspaceLabel?: string;
@@ -58,7 +231,7 @@ export interface SessionEntry {
58
231
  runtimeAttachedClients?: RuntimeAttachedClient[];
59
232
  resume?: ProviderResumeCapability;
60
233
  activeChat: _ActiveChatData | null;
61
- capabilities: SessionCapability[];
234
+ capabilities?: SessionCapability[];
62
235
  cdpConnected?: boolean;
63
236
  currentModel?: string;
64
237
  currentPlan?: string;
@@ -163,15 +336,15 @@ export interface ProviderControlSchema {
163
336
  export interface MachineInfo {
164
337
  hostname: string;
165
338
  platform: string;
166
- arch: string;
167
- cpus: number;
168
- totalMem: number;
169
- freeMem: number;
339
+ arch?: string;
340
+ cpus?: number;
341
+ totalMem?: number;
342
+ freeMem?: number;
170
343
  /** macOS: reclaimable-inclusive; prefer for UI used% */
171
344
  availableMem?: number;
172
- loadavg: number[];
173
- uptime: number;
174
- release: string;
345
+ loadavg?: number[];
346
+ uptime?: number;
347
+ release?: string;
175
348
  }
176
349
  /** Detected IDE on a machine */
177
350
  export interface DetectedIdeInfo {
@@ -214,21 +387,80 @@ export interface CompactDaemonEntry {
214
387
  availableProviders?: AvailableProviderInfo[];
215
388
  sessions?: CompactSessionEntry[];
216
389
  }
390
+ /** Minimal daemon list payload returned by the cloud server REST API. */
391
+ export interface CloudDaemonSummaryEntry {
392
+ id: string;
393
+ type?: string;
394
+ machineId?: string;
395
+ platform?: string;
396
+ hostname?: string;
397
+ nickname?: string;
398
+ p2p?: StatusReportPayload['p2p'];
399
+ cdpConnected?: boolean;
400
+ timestamp?: number;
401
+ version?: string;
402
+ serverVersion?: string;
403
+ versionMismatch?: boolean;
404
+ terminalBackend?: TerminalBackendStatus;
405
+ }
406
+ /** Minimal daemon bootstrap payload used by dashboard WS to initiate P2P. */
407
+ export interface DashboardBootstrapDaemonEntry {
408
+ id: string;
409
+ p2p?: StatusReportPayload['p2p'];
410
+ timestamp?: number;
411
+ }
412
+ export type DaemonStatusEventName = 'agent:generating_started' | 'agent:waiting_approval' | 'agent:generating_completed' | 'agent:stopped' | 'monitor:long_generating';
413
+ /** Minimal daemon-originated event payload relayed through the server. */
414
+ export interface DaemonStatusEventPayload {
415
+ event: DaemonStatusEventName;
416
+ timestamp: number;
417
+ targetSessionId?: string;
418
+ providerType?: string;
419
+ duration?: number;
420
+ elapsedSec?: number;
421
+ modalMessage?: string;
422
+ modalButtons?: string[];
423
+ }
424
+ export type DashboardStatusEventName = DaemonStatusEventName | 'daemon:disconnect' | 'team:session_viewed' | 'team:view_request' | 'team:view_request_approved' | 'team:view_request_rejected';
425
+ /** Sanitized event payload delivered to dashboard clients. */
426
+ export interface DashboardStatusEventPayload {
427
+ event: DashboardStatusEventName;
428
+ timestamp: number;
429
+ daemonId?: string;
430
+ providerType?: string;
431
+ targetSessionId?: string;
432
+ duration?: number;
433
+ elapsedSec?: number;
434
+ modalMessage?: string;
435
+ modalButtons?: string[];
436
+ requestId?: string;
437
+ requesterName?: string;
438
+ targetName?: string;
439
+ orgId?: string;
440
+ permission?: string;
441
+ shareUrl?: string;
442
+ shareToken?: string;
443
+ viewerName?: string;
444
+ }
445
+ /** Minimal daemon->cloud status payload used for routing, fallback, and server APIs. */
446
+ export interface CloudStatusReportPayload {
447
+ sessions: CompactSessionEntry[];
448
+ p2p?: StatusReportPayload['p2p'];
449
+ timestamp: number;
450
+ }
217
451
  export interface StatusReportPayload {
218
452
  /** Unique daemon instance identifier */
219
453
  instanceId: string;
220
- /** Daemon version */
221
- version: string;
222
- /** Daemon mode flag */
223
- daemonMode: boolean;
454
+ /** Daemon version (metadata/full snapshots only) */
455
+ version?: string;
224
456
  /** Machine info */
225
457
  machine: MachineInfo;
226
458
  /** Machine nickname (user-set) */
227
459
  machineNickname?: string | null;
228
460
  /** Timestamp */
229
461
  timestamp: number;
230
- /** Detected IDEs on this machine */
231
- detectedIdes: DetectedIdeInfo[];
462
+ /** Detected IDEs on this machine (metadata snapshot only) */
463
+ detectedIdes?: DetectedIdeInfo[];
232
464
  /** P2P state */
233
465
  p2p?: {
234
466
  available: boolean;
@@ -10,6 +10,10 @@
10
10
  import type { DaemonCdpManager } from '../cdp/manager.js';
11
11
  import type { SessionEntry } from '../shared-types.js';
12
12
  import type { ProviderState } from '../providers/provider-instance.js';
13
+ export type SessionEntryProfile = 'full' | 'live' | 'metadata';
14
+ export interface SessionEntryBuildOptions {
15
+ profile?: SessionEntryProfile;
16
+ }
13
17
  /**
14
18
  * Find a CDP manager by key, with prefix matching for multi-window support.
15
19
  *
@@ -30,4 +34,4 @@ export declare function hasCdpManager(cdpManagers: Map<string, DaemonCdpManager>
30
34
  * Check if any CDP manager matching the key is connected.
31
35
  */
32
36
  export declare function isCdpConnected(cdpManagers: Map<string, DaemonCdpManager>, key: string): boolean;
33
- export declare function buildSessionEntries(allStates: ProviderState[], cdpManagers: Map<string, DaemonCdpManager>): SessionEntry[];
37
+ export declare function buildSessionEntries(allStates: ProviderState[], cdpManagers: Map<string, DaemonCdpManager>, options?: SessionEntryBuildOptions): SessionEntry[];
@@ -1,5 +1,15 @@
1
1
  import type { ActiveChatData } from '../providers/provider-instance.js';
2
2
  export type ManagedStatus = 'idle' | 'generating' | 'waiting_approval' | 'error' | 'stopped' | 'starting' | 'panel_hidden' | 'not_monitored' | 'disconnected';
3
+ export interface NormalizeActiveChatOptions {
4
+ includeMessages?: boolean;
5
+ includeInputContent?: boolean;
6
+ includeActiveModal?: boolean;
7
+ messageLimit?: number;
8
+ totalBytesLimit?: number;
9
+ stringLimit?: number;
10
+ fallbackStringLimit?: number;
11
+ }
12
+ export declare const LIVE_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions>;
3
13
  export declare function normalizeManagedStatus(status?: string | null, opts?: {
4
14
  activeModal?: {
5
15
  buttons?: unknown[] | null;
@@ -11,4 +21,4 @@ export declare function isManagedStatusWaiting(status?: string | null, opts?: {
11
21
  buttons?: unknown[] | null;
12
22
  } | null;
13
23
  }): boolean;
14
- export declare function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(activeChat: T): T;
24
+ export declare function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(activeChat: T, options?: NormalizeActiveChatOptions): T;
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/status/normalize.ts
21
21
  var normalize_exports = {};
22
22
  __export(normalize_exports, {
23
+ LIVE_STATUS_ACTIVE_CHAT_OPTIONS: () => LIVE_STATUS_ACTIVE_CHAT_OPTIONS,
23
24
  isManagedStatusWaiting: () => isManagedStatusWaiting,
24
25
  isManagedStatusWorking: () => isManagedStatusWorking,
25
26
  normalizeActiveChatData: () => normalizeActiveChatData,
@@ -34,11 +35,24 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
34
35
  "thinking",
35
36
  "active"
36
37
  ]);
37
- var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
38
- var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
39
- var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
40
- var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
41
- var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
38
+ var FULL_STATUS_ACTIVE_CHAT_OPTIONS = {
39
+ includeMessages: true,
40
+ includeInputContent: true,
41
+ includeActiveModal: true,
42
+ messageLimit: 60,
43
+ totalBytesLimit: 96 * 1024,
44
+ stringLimit: 4 * 1024,
45
+ fallbackStringLimit: 1024
46
+ };
47
+ var LIVE_STATUS_ACTIVE_CHAT_OPTIONS = {
48
+ includeMessages: false,
49
+ includeInputContent: false,
50
+ includeActiveModal: false,
51
+ messageLimit: 0,
52
+ totalBytesLimit: 0,
53
+ stringLimit: 512,
54
+ fallbackStringLimit: 256
55
+ };
42
56
  var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
43
57
  var STATUS_MODAL_BUTTON_LIMIT = 120;
44
58
  function truncateString(value, maxChars) {
@@ -77,19 +91,20 @@ function normalizeMessageTime(message) {
77
91
  }
78
92
  return msg;
79
93
  }
80
- function trimMessagesForStatus(messages) {
94
+ function trimMessagesForStatus(messages, options) {
95
+ if (!options.includeMessages || options.messageLimit <= 0 || options.totalBytesLimit <= 0) return [];
81
96
  if (!Array.isArray(messages) || messages.length === 0) return [];
82
- const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
97
+ const recent = messages.slice(-options.messageLimit);
83
98
  const kept = [];
84
99
  let totalBytes = 0;
85
100
  for (let i = recent.length - 1; i >= 0; i -= 1) {
86
- let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT));
101
+ let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.stringLimit));
87
102
  let size = estimateBytes(normalized);
88
- if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
89
- normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT));
103
+ if (size > options.totalBytesLimit) {
104
+ normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.fallbackStringLimit));
90
105
  size = estimateBytes(normalized);
91
106
  }
92
- if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
107
+ if (kept.length > 0 && totalBytes + size > options.totalBytesLimit) {
93
108
  continue;
94
109
  }
95
110
  kept.push(normalized);
@@ -119,23 +134,28 @@ function isManagedStatusWorking(status) {
119
134
  function isManagedStatusWaiting(status, opts) {
120
135
  return normalizeManagedStatus(status, opts) === "waiting_approval";
121
136
  }
122
- function normalizeActiveChatData(activeChat) {
137
+ function normalizeActiveChatData(activeChat, options = FULL_STATUS_ACTIVE_CHAT_OPTIONS) {
123
138
  if (!activeChat) return activeChat;
139
+ const resolvedOptions = {
140
+ ...FULL_STATUS_ACTIVE_CHAT_OPTIONS,
141
+ ...options
142
+ };
124
143
  return {
125
144
  ...activeChat,
126
145
  status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
127
- messages: trimMessagesForStatus(activeChat.messages),
128
- activeModal: activeChat.activeModal ? {
146
+ messages: trimMessagesForStatus(activeChat.messages, resolvedOptions),
147
+ activeModal: resolvedOptions.includeActiveModal && activeChat.activeModal ? {
129
148
  message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
130
149
  buttons: (activeChat.activeModal.buttons || []).map(
131
150
  (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
132
151
  )
133
- } : activeChat.activeModal,
134
- inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
152
+ } : null,
153
+ inputContent: resolvedOptions.includeInputContent && activeChat.inputContent ? truncateString(activeChat.inputContent, 2 * 1024) : void 0
135
154
  };
136
155
  }
137
156
  // Annotate the CommonJS export names for ESM import in node:
138
157
  0 && (module.exports = {
158
+ LIVE_STATUS_ACTIVE_CHAT_OPTIONS,
139
159
  isManagedStatusWaiting,
140
160
  isManagedStatusWorking,
141
161
  normalizeActiveChatData,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\n// Status snapshots are sent over P2P every 5s, so keep only a recent live window here.\n// Older history is fetched on demand via `chat_history`, and CLI terminals stream via runtime events.\nconst STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;\nconst STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;\nconst STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;\nconst STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;\nconst STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;\nconst STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;\nconst STATUS_MODAL_BUTTON_LIMIT = 120;\n\nfunction truncateString(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));\n return `${value.slice(0, maxChars - 12)}...[truncated]`;\n}\n\nfunction truncateStringTail(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));\n return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;\n}\n\nfunction trimStructuredStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === 'string') return truncateString(value, maxChars);\n if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)]),\n );\n}\n\nfunction estimateBytes(value: unknown): number {\n try {\n return JSON.stringify(value).length;\n } catch {\n return String(value ?? '').length;\n }\n}\n\nfunction trimMessageForStatus(message: unknown, stringLimit: number): unknown {\n if (!message || typeof message !== 'object') return message;\n return trimStructuredStrings(message, stringLimit);\n}\n\n/**\n * Collapse timestamp / createdAt into receivedAt so downstream consumers\n * only ever need to read a single canonical time field.\n */\nfunction normalizeMessageTime(message: unknown): unknown {\n if (!message || typeof message !== 'object') return message;\n const msg = message as Record<string, unknown>;\n if (msg.receivedAt == null) {\n const fallback = msg.timestamp ?? msg.createdAt;\n if (fallback != null) {\n const ts = typeof fallback === 'string' ? Date.parse(fallback as string) : Number(fallback);\n if (Number.isFinite(ts) && ts > 0) msg.receivedAt = ts;\n }\n }\n return msg;\n}\n\nfunction trimMessagesForStatus(messages: unknown[] | null | undefined): unknown[] {\n if (!Array.isArray(messages) || messages.length === 0) return [];\n\n const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);\n const kept: unknown[] = [];\n let totalBytes = 0;\n\n for (let i = recent.length - 1; i >= 0; i -= 1) {\n let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT));\n let size = estimateBytes(normalized);\n\n if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {\n normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT));\n size = estimateBytes(normalized);\n }\n\n if (kept.length > 0 && (totalBytes + size) > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {\n continue;\n }\n\n kept.push(normalized);\n totalBytes += size;\n }\n\n return kept.reverse();\n}\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n): T {\n if (!activeChat) return activeChat;\n return {\n ...activeChat,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n messages: trimMessagesForStatus(activeChat.messages) as T extends { messages: infer M } ? M : never,\n activeModal: activeChat.activeModal ? {\n message: truncateString(activeChat.activeModal.message || '', STATUS_MODAL_MESSAGE_LIMIT),\n buttons: (activeChat.activeModal.buttons || []).map((button) =>\n truncateString(String(button || ''), STATUS_MODAL_BUTTON_LIMIT)\n ),\n } : activeChat.activeModal,\n inputContent: activeChat.inputContent\n ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT)\n : activeChat.inputContent,\n } as T;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\nexport interface NormalizeActiveChatOptions {\n includeMessages?: boolean;\n includeInputContent?: boolean;\n includeActiveModal?: boolean;\n messageLimit?: number;\n totalBytesLimit?: number;\n stringLimit?: number;\n fallbackStringLimit?: number;\n}\n\n// Full snapshots are still capped, but can carry recent chat context for API/inspection use.\nconst FULL_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: true,\n includeInputContent: true,\n includeActiveModal: true,\n messageLimit: 60,\n totalBytesLimit: 96 * 1024,\n stringLimit: 4 * 1024,\n fallbackStringLimit: 1024,\n};\n\n// Live/metadata snapshots only need routing + UI summary. Current chat text is loaded\n// on demand via `read_chat`, and older history via `chat_history`.\nexport const LIVE_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: false,\n includeInputContent: false,\n includeActiveModal: false,\n messageLimit: 0,\n totalBytesLimit: 0,\n stringLimit: 512,\n fallbackStringLimit: 256,\n};\n\nconst STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;\nconst STATUS_MODAL_BUTTON_LIMIT = 120;\n\nfunction truncateString(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));\n return `${value.slice(0, maxChars - 12)}...[truncated]`;\n}\n\nfunction truncateStringTail(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));\n return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;\n}\n\nfunction trimStructuredStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === 'string') return truncateString(value, maxChars);\n if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)]),\n );\n}\n\nfunction estimateBytes(value: unknown): number {\n try {\n return JSON.stringify(value).length;\n } catch {\n return String(value ?? '').length;\n }\n}\n\nfunction trimMessageForStatus(message: unknown, stringLimit: number): unknown {\n if (!message || typeof message !== 'object') return message;\n return trimStructuredStrings(message, stringLimit);\n}\n\n/**\n * Collapse timestamp / createdAt into receivedAt so downstream consumers\n * only ever need to read a single canonical time field.\n */\nfunction normalizeMessageTime(message: unknown): unknown {\n if (!message || typeof message !== 'object') return message;\n const msg = message as Record<string, unknown>;\n if (msg.receivedAt == null) {\n const fallback = msg.timestamp ?? msg.createdAt;\n if (fallback != null) {\n const ts = typeof fallback === 'string' ? Date.parse(fallback as string) : Number(fallback);\n if (Number.isFinite(ts) && ts > 0) msg.receivedAt = ts;\n }\n }\n return msg;\n}\n\nfunction trimMessagesForStatus(\n messages: unknown[] | null | undefined,\n options: Required<NormalizeActiveChatOptions>,\n): unknown[] {\n if (!options.includeMessages || options.messageLimit <= 0 || options.totalBytesLimit <= 0) return [];\n if (!Array.isArray(messages) || messages.length === 0) return [];\n\n const recent = messages.slice(-options.messageLimit);\n const kept: unknown[] = [];\n let totalBytes = 0;\n\n for (let i = recent.length - 1; i >= 0; i -= 1) {\n let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.stringLimit));\n let size = estimateBytes(normalized);\n\n if (size > options.totalBytesLimit) {\n normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.fallbackStringLimit));\n size = estimateBytes(normalized);\n }\n\n if (kept.length > 0 && (totalBytes + size) > options.totalBytesLimit) {\n continue;\n }\n\n kept.push(normalized);\n totalBytes += size;\n }\n\n return kept.reverse();\n}\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n options: NormalizeActiveChatOptions = FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n): T {\n if (!activeChat) return activeChat;\n const resolvedOptions: Required<NormalizeActiveChatOptions> = {\n ...FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n ...options,\n };\n return {\n ...activeChat,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n messages: trimMessagesForStatus(activeChat.messages, resolvedOptions) as T extends { messages: infer M } ? M : never,\n activeModal: resolvedOptions.includeActiveModal && activeChat.activeModal ? {\n message: truncateString(activeChat.activeModal.message || '', STATUS_MODAL_MESSAGE_LIMIT),\n buttons: (activeChat.activeModal.buttons || []).map((button) =>\n truncateString(String(button || ''), STATUS_MODAL_BUTTON_LIMIT)\n ),\n } : null,\n inputContent: resolvedOptions.includeInputContent && activeChat.inputContent\n ? truncateString(activeChat.inputContent, 2 * 1024)\n : undefined,\n } as T;\n}\n"],"mappings":"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","names":[]}
@@ -7,11 +7,24 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
7
7
  "thinking",
8
8
  "active"
9
9
  ]);
10
- var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
11
- var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
12
- var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
13
- var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
14
- var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
10
+ var FULL_STATUS_ACTIVE_CHAT_OPTIONS = {
11
+ includeMessages: true,
12
+ includeInputContent: true,
13
+ includeActiveModal: true,
14
+ messageLimit: 60,
15
+ totalBytesLimit: 96 * 1024,
16
+ stringLimit: 4 * 1024,
17
+ fallbackStringLimit: 1024
18
+ };
19
+ var LIVE_STATUS_ACTIVE_CHAT_OPTIONS = {
20
+ includeMessages: false,
21
+ includeInputContent: false,
22
+ includeActiveModal: false,
23
+ messageLimit: 0,
24
+ totalBytesLimit: 0,
25
+ stringLimit: 512,
26
+ fallbackStringLimit: 256
27
+ };
15
28
  var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
16
29
  var STATUS_MODAL_BUTTON_LIMIT = 120;
17
30
  function truncateString(value, maxChars) {
@@ -50,19 +63,20 @@ function normalizeMessageTime(message) {
50
63
  }
51
64
  return msg;
52
65
  }
53
- function trimMessagesForStatus(messages) {
66
+ function trimMessagesForStatus(messages, options) {
67
+ if (!options.includeMessages || options.messageLimit <= 0 || options.totalBytesLimit <= 0) return [];
54
68
  if (!Array.isArray(messages) || messages.length === 0) return [];
55
- const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
69
+ const recent = messages.slice(-options.messageLimit);
56
70
  const kept = [];
57
71
  let totalBytes = 0;
58
72
  for (let i = recent.length - 1; i >= 0; i -= 1) {
59
- let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT));
73
+ let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.stringLimit));
60
74
  let size = estimateBytes(normalized);
61
- if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
62
- normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT));
75
+ if (size > options.totalBytesLimit) {
76
+ normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.fallbackStringLimit));
63
77
  size = estimateBytes(normalized);
64
78
  }
65
- if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
79
+ if (kept.length > 0 && totalBytes + size > options.totalBytesLimit) {
66
80
  continue;
67
81
  }
68
82
  kept.push(normalized);
@@ -92,22 +106,27 @@ function isManagedStatusWorking(status) {
92
106
  function isManagedStatusWaiting(status, opts) {
93
107
  return normalizeManagedStatus(status, opts) === "waiting_approval";
94
108
  }
95
- function normalizeActiveChatData(activeChat) {
109
+ function normalizeActiveChatData(activeChat, options = FULL_STATUS_ACTIVE_CHAT_OPTIONS) {
96
110
  if (!activeChat) return activeChat;
111
+ const resolvedOptions = {
112
+ ...FULL_STATUS_ACTIVE_CHAT_OPTIONS,
113
+ ...options
114
+ };
97
115
  return {
98
116
  ...activeChat,
99
117
  status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
100
- messages: trimMessagesForStatus(activeChat.messages),
101
- activeModal: activeChat.activeModal ? {
118
+ messages: trimMessagesForStatus(activeChat.messages, resolvedOptions),
119
+ activeModal: resolvedOptions.includeActiveModal && activeChat.activeModal ? {
102
120
  message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
103
121
  buttons: (activeChat.activeModal.buttons || []).map(
104
122
  (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
105
123
  )
106
- } : activeChat.activeModal,
107
- inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
124
+ } : null,
125
+ inputContent: resolvedOptions.includeInputContent && activeChat.inputContent ? truncateString(activeChat.inputContent, 2 * 1024) : void 0
108
126
  };
109
127
  }
110
128
  export {
129
+ LIVE_STATUS_ACTIVE_CHAT_OPTIONS,
111
130
  isManagedStatusWaiting,
112
131
  isManagedStatusWorking,
113
132
  normalizeActiveChatData,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\n// Status snapshots are sent over P2P every 5s, so keep only a recent live window here.\n// Older history is fetched on demand via `chat_history`, and CLI terminals stream via runtime events.\nconst STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;\nconst STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;\nconst STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;\nconst STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;\nconst STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;\nconst STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;\nconst STATUS_MODAL_BUTTON_LIMIT = 120;\n\nfunction truncateString(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));\n return `${value.slice(0, maxChars - 12)}...[truncated]`;\n}\n\nfunction truncateStringTail(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));\n return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;\n}\n\nfunction trimStructuredStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === 'string') return truncateString(value, maxChars);\n if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)]),\n );\n}\n\nfunction estimateBytes(value: unknown): number {\n try {\n return JSON.stringify(value).length;\n } catch {\n return String(value ?? '').length;\n }\n}\n\nfunction trimMessageForStatus(message: unknown, stringLimit: number): unknown {\n if (!message || typeof message !== 'object') return message;\n return trimStructuredStrings(message, stringLimit);\n}\n\n/**\n * Collapse timestamp / createdAt into receivedAt so downstream consumers\n * only ever need to read a single canonical time field.\n */\nfunction normalizeMessageTime(message: unknown): unknown {\n if (!message || typeof message !== 'object') return message;\n const msg = message as Record<string, unknown>;\n if (msg.receivedAt == null) {\n const fallback = msg.timestamp ?? msg.createdAt;\n if (fallback != null) {\n const ts = typeof fallback === 'string' ? Date.parse(fallback as string) : Number(fallback);\n if (Number.isFinite(ts) && ts > 0) msg.receivedAt = ts;\n }\n }\n return msg;\n}\n\nfunction trimMessagesForStatus(messages: unknown[] | null | undefined): unknown[] {\n if (!Array.isArray(messages) || messages.length === 0) return [];\n\n const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);\n const kept: unknown[] = [];\n let totalBytes = 0;\n\n for (let i = recent.length - 1; i >= 0; i -= 1) {\n let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT));\n let size = estimateBytes(normalized);\n\n if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {\n normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT));\n size = estimateBytes(normalized);\n }\n\n if (kept.length > 0 && (totalBytes + size) > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {\n continue;\n }\n\n kept.push(normalized);\n totalBytes += size;\n }\n\n return kept.reverse();\n}\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n): T {\n if (!activeChat) return activeChat;\n return {\n ...activeChat,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n messages: trimMessagesForStatus(activeChat.messages) as T extends { messages: infer M } ? M : never,\n activeModal: activeChat.activeModal ? {\n message: truncateString(activeChat.activeModal.message || '', STATUS_MODAL_MESSAGE_LIMIT),\n buttons: (activeChat.activeModal.buttons || []).map((button) =>\n truncateString(String(button || ''), STATUS_MODAL_BUTTON_LIMIT)\n ),\n } : activeChat.activeModal,\n inputContent: activeChat.inputContent\n ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT)\n : activeChat.inputContent,\n } as T;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\nexport interface NormalizeActiveChatOptions {\n includeMessages?: boolean;\n includeInputContent?: boolean;\n includeActiveModal?: boolean;\n messageLimit?: number;\n totalBytesLimit?: number;\n stringLimit?: number;\n fallbackStringLimit?: number;\n}\n\n// Full snapshots are still capped, but can carry recent chat context for API/inspection use.\nconst FULL_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: true,\n includeInputContent: true,\n includeActiveModal: true,\n messageLimit: 60,\n totalBytesLimit: 96 * 1024,\n stringLimit: 4 * 1024,\n fallbackStringLimit: 1024,\n};\n\n// Live/metadata snapshots only need routing + UI summary. Current chat text is loaded\n// on demand via `read_chat`, and older history via `chat_history`.\nexport const LIVE_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: false,\n includeInputContent: false,\n includeActiveModal: false,\n messageLimit: 0,\n totalBytesLimit: 0,\n stringLimit: 512,\n fallbackStringLimit: 256,\n};\n\nconst STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;\nconst STATUS_MODAL_BUTTON_LIMIT = 120;\n\nfunction truncateString(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));\n return `${value.slice(0, maxChars - 12)}...[truncated]`;\n}\n\nfunction truncateStringTail(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));\n return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;\n}\n\nfunction trimStructuredStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === 'string') return truncateString(value, maxChars);\n if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)]),\n );\n}\n\nfunction estimateBytes(value: unknown): number {\n try {\n return JSON.stringify(value).length;\n } catch {\n return String(value ?? '').length;\n }\n}\n\nfunction trimMessageForStatus(message: unknown, stringLimit: number): unknown {\n if (!message || typeof message !== 'object') return message;\n return trimStructuredStrings(message, stringLimit);\n}\n\n/**\n * Collapse timestamp / createdAt into receivedAt so downstream consumers\n * only ever need to read a single canonical time field.\n */\nfunction normalizeMessageTime(message: unknown): unknown {\n if (!message || typeof message !== 'object') return message;\n const msg = message as Record<string, unknown>;\n if (msg.receivedAt == null) {\n const fallback = msg.timestamp ?? msg.createdAt;\n if (fallback != null) {\n const ts = typeof fallback === 'string' ? Date.parse(fallback as string) : Number(fallback);\n if (Number.isFinite(ts) && ts > 0) msg.receivedAt = ts;\n }\n }\n return msg;\n}\n\nfunction trimMessagesForStatus(\n messages: unknown[] | null | undefined,\n options: Required<NormalizeActiveChatOptions>,\n): unknown[] {\n if (!options.includeMessages || options.messageLimit <= 0 || options.totalBytesLimit <= 0) return [];\n if (!Array.isArray(messages) || messages.length === 0) return [];\n\n const recent = messages.slice(-options.messageLimit);\n const kept: unknown[] = [];\n let totalBytes = 0;\n\n for (let i = recent.length - 1; i >= 0; i -= 1) {\n let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.stringLimit));\n let size = estimateBytes(normalized);\n\n if (size > options.totalBytesLimit) {\n normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.fallbackStringLimit));\n size = estimateBytes(normalized);\n }\n\n if (kept.length > 0 && (totalBytes + size) > options.totalBytesLimit) {\n continue;\n }\n\n kept.push(normalized);\n totalBytes += size;\n }\n\n return kept.reverse();\n}\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n options: NormalizeActiveChatOptions = FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n): T {\n if (!activeChat) return activeChat;\n const resolvedOptions: Required<NormalizeActiveChatOptions> = {\n ...FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n ...options,\n };\n return {\n ...activeChat,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n messages: trimMessagesForStatus(activeChat.messages, resolvedOptions) as T extends { messages: infer M } ? M : never,\n activeModal: resolvedOptions.includeActiveModal && activeChat.activeModal ? {\n message: truncateString(activeChat.activeModal.message || '', STATUS_MODAL_MESSAGE_LIMIT),\n buttons: (activeChat.activeModal.buttons || []).map((button) =>\n truncateString(String(button || ''), STATUS_MODAL_BUTTON_LIMIT)\n ),\n } : null,\n inputContent: resolvedOptions.includeInputContent && activeChat.inputContent\n ? truncateString(activeChat.inputContent, 2 * 1024)\n : undefined,\n } as T;\n}\n"],"mappings":"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","names":[]}
@@ -5,6 +5,7 @@
5
5
  * Each Instance manages its own status/transition. This module only assembles + transmits.
6
6
  */
7
7
  import type { DaemonCdpManager } from '../cdp/manager.js';
8
+ import type { DaemonStatusEventPayload } from '../shared-types.js';
8
9
  import type { ProviderState } from '../providers/provider-instance.js';
9
10
  export interface StatusReporterDeps {
10
11
  serverConn: {
@@ -20,6 +21,7 @@ export interface StatusReporterDeps {
20
21
  connectedPeerCount: number;
21
22
  screenshotActive: boolean;
22
23
  sendStatus(data: any): void;
24
+ sendStatusEvent(event: DaemonStatusEventPayload): void;
23
25
  } | null;
24
26
  providerLoader: {
25
27
  resolve(type: string): any;
@@ -55,6 +57,8 @@ export declare class DaemonStatusReporter {
55
57
  stopReporting(): void;
56
58
  onStatusChange(): void;
57
59
  throttledReport(): void;
60
+ private toDaemonStatusEventName;
61
+ private buildServerStatusEvent;
58
62
  emitStatusEvent(event: Record<string, unknown>): void;
59
63
  removeAgentTracking(_key: string): void;
60
64
  updateAgentStreams(_ideType: string, _streams: any[]): void;