@adhdev/daemon-core 0.7.41 → 0.7.42

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 (37) hide show
  1. package/dist/cli-adapters/provider-cli-adapter.d.ts +1 -0
  2. package/dist/commands/cli-manager.d.ts +4 -2
  3. package/dist/config/config.d.ts +2 -22
  4. package/dist/index.js +314 -88
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +314 -88
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/providers/cli-provider-instance.d.ts +4 -10
  9. package/dist/providers/contracts.d.ts +0 -79
  10. package/dist/providers/extension-provider-instance.d.ts +1 -0
  11. package/dist/providers/provider-instance.d.ts +0 -2
  12. package/dist/shared-types.d.ts +1 -3
  13. package/dist/status/normalize.js +67 -1
  14. package/dist/status/normalize.js.map +1 -1
  15. package/dist/status/normalize.mjs +67 -1
  16. package/dist/status/normalize.mjs.map +1 -1
  17. package/dist/status/reporter.d.ts +1 -0
  18. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  19. package/package.json +1 -1
  20. package/src/agent-stream/forward.ts +21 -1
  21. package/src/agent-stream/poller.ts +6 -1
  22. package/src/cli-adapters/provider-cli-adapter.ts +37 -2
  23. package/src/commands/cli-manager.ts +44 -39
  24. package/src/commands/router.ts +1 -0
  25. package/src/commands/stream-commands.ts +14 -0
  26. package/src/config/config.d.ts +5 -50
  27. package/src/config/config.ts +71 -49
  28. package/src/config/workspaces.d.ts +1 -4
  29. package/src/providers/cli-provider-instance.ts +18 -32
  30. package/src/providers/contracts.ts +0 -81
  31. package/src/providers/extension-provider-instance.ts +27 -0
  32. package/src/providers/ide-provider-instance.ts +12 -0
  33. package/src/providers/provider-instance.ts +0 -2
  34. package/src/shared-types.ts +1 -3
  35. package/src/status/builders.ts +7 -2
  36. package/src/status/normalize.ts +85 -0
  37. package/src/status/reporter.ts +31 -2
@@ -26,19 +26,13 @@ export declare class CliProviderInstance implements ProviderInstance {
26
26
  private lastApprovalEventAt;
27
27
  private historyWriter;
28
28
  readonly instanceId: string;
29
- private launchMode;
30
- private resolvedOutputFormat;
31
- constructor(provider: ProviderModule, workingDir: string, cliArgs?: string[], instanceId?: string, transportFactory?: PtyTransportFactory, launchModeId?: string);
32
- /**
33
- * Determine output rendering format from:
34
- * 1. launchMode.outputFormat (explicit override)
35
- * 2. launchOptions[].outputFormatMap — check actual args for matching values
36
- * 3. Default: 'terminal'
37
- */
38
- private resolveOutputFormat;
29
+ private presentationMode;
30
+ constructor(provider: ProviderModule, workingDir: string, cliArgs?: string[], instanceId?: string, transportFactory?: PtyTransportFactory);
39
31
  init(context: InstanceContext): Promise<void>;
40
32
  onTick(): Promise<void>;
41
33
  getState(): ProviderState;
34
+ setPresentationMode(mode: 'terminal' | 'chat'): void;
35
+ getPresentationMode(): 'terminal' | 'chat';
42
36
  onEvent(event: string, data?: any): void;
43
37
  dispose(): void;
44
38
  private completedDebounceTimer;
@@ -245,20 +245,6 @@ export interface ProviderModule {
245
245
  shell?: boolean;
246
246
  env?: Record<string, string>;
247
247
  };
248
- /**
249
- * Configurable options shown at session launch time (schema declaration).
250
- * The frontend renders these as a launch config UI.
251
- * Values are passed to launchArgBuilder to produce the final args.
252
- */
253
- launchOptions?: ProviderLaunchOption[];
254
- /**
255
- * Builds extra spawn args from user-selected launch option values.
256
- * Called with the merged defaults + mode preset + user overrides.
257
- * When defined, takes precedence over launchMode.extraArgs.
258
- */
259
- launchArgBuilder?: (options: Record<string, string | boolean | number>) => string[];
260
- /** Named presets — shortcuts that set launchOption values in bulk */
261
- launchModes?: ProviderLaunchMode[];
262
248
  patterns?: {
263
249
  prompt?: RegExp[];
264
250
  generating?: RegExp[];
@@ -320,71 +306,6 @@ export interface ProviderModule {
320
306
  /** ACP agent auth methods (multiple supported — in priority order) */
321
307
  auth?: AcpAuthMethod[];
322
308
  }
323
- export type ProviderLaunchOptionType = 'select' | 'boolean' | 'string' | 'number';
324
- /**
325
- * A single configurable option exposed at session launch time.
326
- * Providers declare these so the frontend can render a launch config UI.
327
- * The final args are built by launchArgBuilder(selectedValues).
328
- *
329
- * Example — Claude Code:
330
- * { id: 'outputFormat', type: 'select', options: [
331
- * { value: 'terminal', label: 'Terminal' },
332
- * { value: 'stream-json', label: 'Chat' },
333
- * ], default: 'terminal' }
334
- */
335
- export interface ProviderLaunchOption {
336
- /** Unique identifier — key used in launchArgBuilder options map */
337
- id: string;
338
- /** Display label */
339
- name: string;
340
- description?: string;
341
- type: ProviderLaunchOptionType;
342
- /** Options for 'select' type */
343
- options?: {
344
- value: string;
345
- label: string;
346
- description?: string;
347
- }[];
348
- /** Default value — applied when not explicitly set */
349
- default?: string | boolean | number;
350
- /**
351
- * Maps specific values of this option to a frontend rendering hint.
352
- * e.g. { 'stream-json': 'stream-json' } tells the UI to switch to Chat mode.
353
- */
354
- outputFormatMap?: Record<string, 'terminal' | 'stream-json'>;
355
- }
356
- /**
357
- * A named launch preset — shorthand for a specific set of launchOption values.
358
- * When selected, its `options` are merged with user-configured values before
359
- * calling launchArgBuilder. Falls back to `extraArgs` if no launchArgBuilder defined.
360
- */
361
- export interface ProviderLaunchMode {
362
- /** Unique mode identifier (e.g. 'terminal', 'chat') */
363
- id: string;
364
- /** Display name */
365
- name: string;
366
- description?: string;
367
- /**
368
- * Preset option values — merged over defaults before calling launchArgBuilder.
369
- * Keys correspond to ProviderLaunchOption.id.
370
- */
371
- options?: Record<string, string | boolean | number>;
372
- /**
373
- * Fallback: raw args appended when no launchArgBuilder is defined.
374
- * Use launchArgBuilder + options for anything more than trivial cases.
375
- */
376
- extraArgs?: string[];
377
- /** Env var overrides applied on top of spawn.env */
378
- env?: Record<string, string>;
379
- /**
380
- * Output rendering hint (shorthand when not using launchOptions/outputFormatMap).
381
- * - 'terminal' — raw PTY stream (default)
382
- * - 'stream-json' — structured JSON events → chat messages
383
- */
384
- outputFormat?: 'terminal' | 'stream-json';
385
- /** Whether this is the default mode when none is specified */
386
- default?: boolean;
387
- }
388
309
  export interface ProviderResumeCapability {
389
310
  supported: boolean;
390
311
  stopStrategy?: 'command' | 'ctrl_c';
@@ -41,4 +41,5 @@ export declare class ExtensionProviderInstance implements ProviderInstance {
41
41
  private pushEvent;
42
42
  private flushEvents;
43
43
  private resolveChatTitle;
44
+ private resetStreamState;
44
45
  }
@@ -86,8 +86,6 @@ export interface CliProviderState extends ProviderStateBase {
86
86
  category: 'cli';
87
87
  /** terminal = PTY stream, chat = parsed conversation */
88
88
  mode: 'terminal' | 'chat';
89
- /** Active launch mode id (e.g. 'chat') — undefined means default terminal */
90
- launchMode?: string;
91
89
  }
92
90
  /** ACP provider state */
93
91
  export interface AcpProviderState extends ProviderStateBase {
@@ -51,9 +51,7 @@ export interface SessionEntry {
51
51
  runtimeKey?: string;
52
52
  runtimeDisplayName?: string;
53
53
  runtimeWorkspaceLabel?: string;
54
- /** CLI only: active launch mode id (e.g. 'terminal', 'chat') */
55
- launchMode?: string;
56
- /** CLI only: output rendering mode derived from launchMode.outputFormat */
54
+ /** CLI only: active presentation mode */
57
55
  mode?: 'terminal' | 'chat';
58
56
  runtimeWriteOwner?: RuntimeWriteOwner | null;
59
57
  runtimeAttachedClients?: RuntimeAttachedClient[];
@@ -34,6 +34,63 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
34
34
  "thinking",
35
35
  "active"
36
36
  ]);
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_TERMINAL_HISTORY_LIMIT = 8 * 1024;
42
+ var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
43
+ var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
44
+ var STATUS_MODAL_BUTTON_LIMIT = 120;
45
+ function truncateString(value, maxChars) {
46
+ if (value.length <= maxChars) return value;
47
+ if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
48
+ return `${value.slice(0, maxChars - 12)}...[truncated]`;
49
+ }
50
+ function truncateStringTail(value, maxChars) {
51
+ if (value.length <= maxChars) return value;
52
+ if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));
53
+ return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;
54
+ }
55
+ function trimStructuredStrings(value, maxChars) {
56
+ if (typeof value === "string") return truncateString(value, maxChars);
57
+ if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
58
+ if (!value || typeof value !== "object") return value;
59
+ return Object.fromEntries(
60
+ Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
61
+ );
62
+ }
63
+ function estimateBytes(value) {
64
+ try {
65
+ return JSON.stringify(value).length;
66
+ } catch {
67
+ return String(value ?? "").length;
68
+ }
69
+ }
70
+ function trimMessageForStatus(message, stringLimit) {
71
+ if (!message || typeof message !== "object") return message;
72
+ return trimStructuredStrings(message, stringLimit);
73
+ }
74
+ function trimMessagesForStatus(messages) {
75
+ if (!Array.isArray(messages) || messages.length === 0) return [];
76
+ const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
77
+ const kept = [];
78
+ let totalBytes = 0;
79
+ for (let i = recent.length - 1; i >= 0; i -= 1) {
80
+ let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
81
+ let size = estimateBytes(normalized);
82
+ if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
83
+ normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
84
+ size = estimateBytes(normalized);
85
+ }
86
+ if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
87
+ continue;
88
+ }
89
+ kept.push(normalized);
90
+ totalBytes += size;
91
+ }
92
+ return kept.reverse();
93
+ }
37
94
  function hasApprovalButtons(activeModal) {
38
95
  return (activeModal?.buttons?.length ?? 0) > 0;
39
96
  }
@@ -60,7 +117,16 @@ function normalizeActiveChatData(activeChat) {
60
117
  if (!activeChat) return activeChat;
61
118
  return {
62
119
  ...activeChat,
63
- status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
120
+ status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
121
+ messages: trimMessagesForStatus(activeChat.messages),
122
+ activeModal: activeChat.activeModal ? {
123
+ message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
124
+ buttons: (activeChat.activeModal.buttons || []).map(
125
+ (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
126
+ )
127
+ } : activeChat.activeModal,
128
+ terminalHistory: activeChat.terminalHistory ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT) : activeChat.terminalHistory,
129
+ inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
64
130
  };
65
131
  }
66
132
  // Annotate the CommonJS export names for ESM import in node:
@@ -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\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 } as T;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,CAAC;AAED,SAAS,mBAAmB,aAA8D;AACtF,UAAQ,aAAa,SAAS,UAAU,KAAK;AACjD;AAEO,SAAS,uBACZ,QACA,MACa;AACb,MAAI,mBAAmB,MAAM,WAAW,EAAG,QAAO;AAElD,QAAM,aAAa,OAAO,UAAU,MAAM,EAAE,KAAK,EAAE,YAAY;AAC/D,MAAI,eAAe,mBAAoB,QAAO;AAC9C,MAAI,iBAAiB,IAAI,UAAU,EAAG,QAAO;AAC7C,MAAI,eAAe,QAAS,QAAO;AACnC,MAAI,eAAe,UAAW,QAAO;AACrC,MAAI,eAAe,WAAY,QAAO;AACtC,MAAI,eAAe,eAAgB,QAAO;AAC1C,MAAI,eAAe,gBAAiB,QAAO;AAC3C,MAAI,eAAe,eAAgB,QAAO;AAC1C,SAAO;AACX;AAEO,SAAS,uBAAuB,QAAiC;AACpE,SAAO,uBAAuB,MAAM,MAAM;AAC9C;AAEO,SAAS,uBACZ,QACA,MACO;AACP,SAAO,uBAAuB,QAAQ,IAAI,MAAM;AACpD;AAEO,SAAS,wBACZ,YACC;AACD,MAAI,CAAC,WAAY,QAAO;AACxB,SAAO;AAAA,IACH,GAAG;AAAA,IACH,QAAQ,uBAAuB,WAAW,QAAQ,EAAE,aAAa,WAAW,YAAY,CAAC;AAAA,EAC7F;AACJ;","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\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_TERMINAL_HISTORY_LIMIT = 8 * 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\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 = 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 = 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 terminalHistory: activeChat.terminalHistory\n ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT)\n : activeChat.terminalHistory,\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":[]}
@@ -7,6 +7,63 @@ 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_TERMINAL_HISTORY_LIMIT = 8 * 1024;
15
+ var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
16
+ var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
17
+ var STATUS_MODAL_BUTTON_LIMIT = 120;
18
+ function truncateString(value, maxChars) {
19
+ if (value.length <= maxChars) return value;
20
+ if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
21
+ return `${value.slice(0, maxChars - 12)}...[truncated]`;
22
+ }
23
+ function truncateStringTail(value, maxChars) {
24
+ if (value.length <= maxChars) return value;
25
+ if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));
26
+ return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;
27
+ }
28
+ function trimStructuredStrings(value, maxChars) {
29
+ if (typeof value === "string") return truncateString(value, maxChars);
30
+ if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
31
+ if (!value || typeof value !== "object") return value;
32
+ return Object.fromEntries(
33
+ Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
34
+ );
35
+ }
36
+ function estimateBytes(value) {
37
+ try {
38
+ return JSON.stringify(value).length;
39
+ } catch {
40
+ return String(value ?? "").length;
41
+ }
42
+ }
43
+ function trimMessageForStatus(message, stringLimit) {
44
+ if (!message || typeof message !== "object") return message;
45
+ return trimStructuredStrings(message, stringLimit);
46
+ }
47
+ function trimMessagesForStatus(messages) {
48
+ if (!Array.isArray(messages) || messages.length === 0) return [];
49
+ const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
50
+ const kept = [];
51
+ let totalBytes = 0;
52
+ for (let i = recent.length - 1; i >= 0; i -= 1) {
53
+ let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
54
+ let size = estimateBytes(normalized);
55
+ if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
56
+ normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
57
+ size = estimateBytes(normalized);
58
+ }
59
+ if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
60
+ continue;
61
+ }
62
+ kept.push(normalized);
63
+ totalBytes += size;
64
+ }
65
+ return kept.reverse();
66
+ }
10
67
  function hasApprovalButtons(activeModal) {
11
68
  return (activeModal?.buttons?.length ?? 0) > 0;
12
69
  }
@@ -33,7 +90,16 @@ function normalizeActiveChatData(activeChat) {
33
90
  if (!activeChat) return activeChat;
34
91
  return {
35
92
  ...activeChat,
36
- status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
93
+ status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
94
+ messages: trimMessagesForStatus(activeChat.messages),
95
+ activeModal: activeChat.activeModal ? {
96
+ message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
97
+ buttons: (activeChat.activeModal.buttons || []).map(
98
+ (button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
99
+ )
100
+ } : activeChat.activeModal,
101
+ terminalHistory: activeChat.terminalHistory ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT) : activeChat.terminalHistory,
102
+ inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
37
103
  };
38
104
  }
39
105
  export {
@@ -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\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 } as T;\n}\n"],"mappings":";AAaA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,CAAC;AAED,SAAS,mBAAmB,aAA8D;AACtF,UAAQ,aAAa,SAAS,UAAU,KAAK;AACjD;AAEO,SAAS,uBACZ,QACA,MACa;AACb,MAAI,mBAAmB,MAAM,WAAW,EAAG,QAAO;AAElD,QAAM,aAAa,OAAO,UAAU,MAAM,EAAE,KAAK,EAAE,YAAY;AAC/D,MAAI,eAAe,mBAAoB,QAAO;AAC9C,MAAI,iBAAiB,IAAI,UAAU,EAAG,QAAO;AAC7C,MAAI,eAAe,QAAS,QAAO;AACnC,MAAI,eAAe,UAAW,QAAO;AACrC,MAAI,eAAe,WAAY,QAAO;AACtC,MAAI,eAAe,eAAgB,QAAO;AAC1C,MAAI,eAAe,gBAAiB,QAAO;AAC3C,MAAI,eAAe,eAAgB,QAAO;AAC1C,SAAO;AACX;AAEO,SAAS,uBAAuB,QAAiC;AACpE,SAAO,uBAAuB,MAAM,MAAM;AAC9C;AAEO,SAAS,uBACZ,QACA,MACO;AACP,SAAO,uBAAuB,QAAQ,IAAI,MAAM;AACpD;AAEO,SAAS,wBACZ,YACC;AACD,MAAI,CAAC,WAAY,QAAO;AACxB,SAAO;AAAA,IACH,GAAG;AAAA,IACH,QAAQ,uBAAuB,WAAW,QAAQ,EAAE,aAAa,WAAW,YAAY,CAAC;AAAA,EAC7F;AACJ;","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\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_TERMINAL_HISTORY_LIMIT = 8 * 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\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 = 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 = 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 terminalHistory: activeChat.terminalHistory\n ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT)\n : activeChat.terminalHistory,\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":[]}
@@ -61,6 +61,7 @@ export declare class DaemonStatusReporter {
61
61
  /** Reset P2P dedup hash — forces next send to transmit even if content unchanged */
62
62
  resetP2PHash(): void;
63
63
  private ts;
64
+ private summarizeLargePayloadSessions;
64
65
  sendUnifiedStatusReport(opts?: {
65
66
  p2pOnly?: boolean;
66
67
  }): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/session-host-core",
3
- "version": "0.7.41",
3
+ "version": "0.7.42",
4
4
  "description": "ADHDev local session host core — 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.7.41",
3
+ "version": "0.7.42",
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",
@@ -10,12 +10,20 @@ export function forwardAgentStreamsToIdeInstance(
10
10
  streams: any[],
11
11
  ): void {
12
12
  const ideInstance = instanceManager.getInstance(`ide:${ideType}`) as
13
- | { onEvent?: (event: string, payload: Record<string, unknown>) => void }
13
+ | {
14
+ onEvent?: (event: string, payload?: Record<string, unknown>) => void;
15
+ getExtensionTypes?: () => string[];
16
+ }
14
17
  | undefined;
15
18
 
16
19
  if (!ideInstance?.onEvent) return;
17
20
 
21
+ const seenExtensionTypes = new Set<string>();
22
+
18
23
  for (const stream of streams) {
24
+ if (typeof stream.agentType === 'string' && stream.agentType) {
25
+ seenExtensionTypes.add(stream.agentType);
26
+ }
19
27
  ideInstance.onEvent('stream_update', {
20
28
  extensionType: stream.agentType,
21
29
  streams: [stream],
@@ -32,4 +40,16 @@ export function forwardAgentStreamsToIdeInstance(
32
40
  inputContent: stream.inputContent || '',
33
41
  });
34
42
  }
43
+
44
+ const extensionTypes = ideInstance.getExtensionTypes?.() || [];
45
+ if (streams.length === 0) {
46
+ ideInstance.onEvent('stream_reset_all');
47
+ return;
48
+ }
49
+
50
+ for (const extensionType of extensionTypes) {
51
+ if (!seenExtensionTypes.has(extensionType)) {
52
+ ideInstance.onEvent('stream_reset', { extensionType });
53
+ }
54
+ }
35
55
  }
@@ -167,7 +167,12 @@ export class AgentStreamPoller {
167
167
  } catch { }
168
168
  }
169
169
 
170
- if (!resolvedActiveSessionId || !parentSessionId) continue;
170
+ if (!resolvedActiveSessionId || !parentSessionId) {
171
+ if (parentSessionId) {
172
+ this.deps.onStreamsUpdated?.(ideType, []);
173
+ }
174
+ continue;
175
+ }
171
176
 
172
177
  try {
173
178
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
@@ -440,6 +440,18 @@ export class ProviderCliAdapter implements CliAdapter {
440
440
  this.structuredMessages = [...this.committedMessages];
441
441
  }
442
442
 
443
+ private normalizeParsedMessages(parsedMessages: any[]): CliChatMessage[] {
444
+ return parsedMessages
445
+ .filter((message) => message && (message.role === 'user' || message.role === 'assistant'))
446
+ .map((message) => ({
447
+ role: message.role,
448
+ content: typeof message.content === 'string' ? message.content : String(message.content || ''),
449
+ timestamp: typeof message.timestamp === 'number' && Number.isFinite(message.timestamp)
450
+ ? message.timestamp
451
+ : Date.now(),
452
+ }));
453
+ }
454
+
443
455
  private sliceFromOffset(text: string, start: number): string {
444
456
  if (!text) return '';
445
457
  if (!Number.isFinite(start) || start <= 0) return text;
@@ -951,8 +963,15 @@ export class ProviderCliAdapter implements CliAdapter {
951
963
  }
952
964
 
953
965
  private commitCurrentTranscript(): void {
954
- // No-op: terminal output is the canonical display for CLI providers.
955
- // Assistant text extraction from PTY output has been removed.
966
+ const parsed = this.parseCurrentTranscript(
967
+ this.committedMessages,
968
+ this.responseBuffer,
969
+ this.currentTurnScope,
970
+ );
971
+ if (parsed && Array.isArray(parsed.messages)) {
972
+ this.committedMessages = this.normalizeParsedMessages(parsed.messages);
973
+ this.syncMessageViews();
974
+ }
956
975
  }
957
976
 
958
977
  // ─── Script Execution ──────────────────────────
@@ -1003,6 +1022,22 @@ export class ProviderCliAdapter implements CliAdapter {
1003
1022
  * Called by command handler / dashboard for rich content rendering.
1004
1023
  */
1005
1024
  getScriptParsedStatus(): any {
1025
+ const parsed = this.parseCurrentTranscript(
1026
+ this.committedMessages,
1027
+ this.responseBuffer,
1028
+ this.currentTurnScope,
1029
+ );
1030
+ if (parsed && Array.isArray(parsed.messages)) {
1031
+ return {
1032
+ id: parsed.id || 'cli_session',
1033
+ status: parsed.status || this.currentStatus,
1034
+ title: parsed.title || this.cliName,
1035
+ terminalHistory: this.terminalHistory,
1036
+ messages: parsed.messages,
1037
+ activeModal: parsed.activeModal ?? this.activeModal,
1038
+ };
1039
+ }
1040
+
1006
1041
  const messages = [...this.committedMessages];
1007
1042
  return {
1008
1043
  id: 'cli_session',