@adhdev/daemon-core 0.8.21 → 0.8.23

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 (36) hide show
  1. package/dist/agent-stream/types.d.ts +3 -0
  2. package/dist/cli-adapter-types.d.ts +3 -0
  3. package/dist/cli-adapters/provider-cli-adapter.d.ts +71 -11
  4. package/dist/commands/stream-commands.d.ts +1 -0
  5. package/dist/config/config.d.ts +6 -0
  6. package/dist/index.js +1163 -314
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +1163 -314
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/providers/cli-provider-instance.d.ts +6 -0
  11. package/dist/providers/contracts.d.ts +59 -1
  12. package/dist/providers/control-effects.d.ts +4 -0
  13. package/dist/providers/extension-provider-instance.d.ts +9 -0
  14. package/dist/providers/ide-provider-instance.d.ts +8 -0
  15. package/dist/shared-types.d.ts +2 -1
  16. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  17. package/package.json +3 -2
  18. package/src/agent-stream/forward.ts +2 -0
  19. package/src/agent-stream/provider-adapter.ts +5 -15
  20. package/src/agent-stream/types.ts +4 -0
  21. package/src/cli-adapter-types.ts +3 -0
  22. package/src/cli-adapters/provider-cli-adapter.ts +399 -49
  23. package/src/commands/chat-commands.ts +33 -12
  24. package/src/commands/handler.ts +1 -0
  25. package/src/commands/stream-commands.ts +99 -8
  26. package/src/config/config.d.ts +1 -0
  27. package/src/config/config.ts +9 -0
  28. package/src/launch.ts +57 -11
  29. package/src/providers/cli-provider-instance.ts +148 -2
  30. package/src/providers/contracts.ts +65 -2
  31. package/src/providers/control-effects.ts +114 -0
  32. package/src/providers/extension-provider-instance.ts +163 -3
  33. package/src/providers/ide-provider-instance.ts +181 -2
  34. package/src/shared-types.d.ts +1 -0
  35. package/src/shared-types.ts +2 -1
  36. package/src/status/snapshot.ts +1 -0
@@ -17,6 +17,8 @@ import { ExtensionProviderInstance } from './extension-provider-instance.js';
17
17
  import { StatusMonitor } from './status-monitor.js';
18
18
  import { ChatHistoryWriter } from '../config/chat-history.js';
19
19
  import { LOG } from '../logging/logger.js';
20
+ import { extractProviderControlValues, normalizeProviderEffects } from './control-effects.js';
21
+ import type { ChatMessage } from '../types.js';
20
22
 
21
23
  export class IdeProviderInstance implements ProviderInstance {
22
24
  readonly type: string;
@@ -37,6 +39,8 @@ export class IdeProviderInstance implements ProviderInstance {
37
39
  private monitor: StatusMonitor;
38
40
  private historyWriter: ChatHistoryWriter;
39
41
  private autoApproveBusy = false;
42
+ private appliedEffectKeys = new Set<string>();
43
+ private runtimeMessages: Array<{ key: string; message: ChatMessage }> = [];
40
44
 
41
45
  // IDE meta
42
46
  private ideVersion: string = '';
@@ -115,7 +119,7 @@ export class IdeProviderInstance implements ProviderInstance {
115
119
  id: this.cachedChat.id || 'active_session',
116
120
  title: this.cachedChat.title || this.type,
117
121
  status: this.cachedChat.status || this.currentStatus,
118
- messages: this.cachedChat.messages || [],
122
+ messages: this.mergeConversationMessages(this.cachedChat.messages || []),
119
123
  activeModal: this.cachedChat.activeModal || null,
120
124
  inputContent: this.cachedChat.inputContent || '',
121
125
  } : null,
@@ -136,7 +140,7 @@ export class IdeProviderInstance implements ProviderInstance {
136
140
 
137
141
  onEvent(event: string, data?: any): void {
138
142
  if (event === 'cdp_connected') {
139
- // CDP connection done
143
+ // CDP connection done
140
144
  } else if (event === 'cdp_disconnected') {
141
145
  this.cachedChat = null;
142
146
  this.currentStatus = 'idle';
@@ -158,6 +162,13 @@ export class IdeProviderInstance implements ProviderInstance {
158
162
  for (const ext of this.extensions.values()) {
159
163
  ext.onEvent('stream_reset');
160
164
  }
165
+ } else if (event === 'provider_state_patch' && data && typeof data === 'object') {
166
+ const extType = typeof data.extensionType === 'string' ? data.extensionType : '';
167
+ if (extType && this.extensions.has(extType)) {
168
+ this.extensions.get(extType)!.onEvent('provider_state_patch', data);
169
+ } else {
170
+ this.applyProviderResponse(data, { phase: 'immediate' });
171
+ }
161
172
  }
162
173
  }
163
174
 
@@ -166,6 +177,8 @@ export class IdeProviderInstance implements ProviderInstance {
166
177
  this.lastAgentStatuses.clear();
167
178
  this.generatingStartedAt.clear();
168
179
  this.monitor.reset();
180
+ this.appliedEffectKeys.clear();
181
+ this.runtimeMessages = [];
169
182
  // Child Extension cleanup
170
183
  for (const ext of this.extensions.values()) {
171
184
  ext.dispose();
@@ -173,6 +186,15 @@ export class IdeProviderInstance implements ProviderInstance {
173
186
  this.extensions.clear();
174
187
  }
175
188
 
189
+ updateSettings(newSettings: Record<string, any>): void {
190
+ this.settings = { ...newSettings };
191
+ this.monitor.updateConfig({
192
+ approvalAlert: this.settings.approvalAlert !== false,
193
+ longGeneratingAlert: this.settings.longGeneratingAlert !== false,
194
+ longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180,
195
+ });
196
+ }
197
+
176
198
  // ─── Extension manage ─────────────────────────────
177
199
 
178
200
  /** Extension Instance add */
@@ -298,6 +320,9 @@ export class IdeProviderInstance implements ProviderInstance {
298
320
  }
299
321
  }
300
322
 
323
+ const controlValues = extractProviderControlValues(this.provider.controls, raw);
324
+ if (controlValues) raw.controlValues = controlValues;
325
+
301
326
  this.cachedChat = { ...raw, activeModal };
302
327
  this.detectAgentTransitions(raw, now);
303
328
 
@@ -382,6 +407,12 @@ export class IdeProviderInstance implements ProviderInstance {
382
407
  this.lastAgentStatuses.set(agentKey, agentStatus);
383
408
  }
384
409
 
410
+ this.applyProviderResponse(chatData, {
411
+ phase: (agentStatus === 'idle' && (lastStatus === 'generating' || lastStatus === 'waiting_approval'))
412
+ ? 'turn_completed'
413
+ : 'immediate',
414
+ });
415
+
385
416
  // Auto-approve: when waiting_approval + settings.autoApprove → auto-click approve via CDP
386
417
  if (agentStatus === 'waiting_approval' && this.settings.autoApprove && !this.autoApproveBusy) {
387
418
  this.autoApproveViaScript(chatData);
@@ -399,6 +430,154 @@ export class IdeProviderInstance implements ProviderInstance {
399
430
  if (this.events.length > 50) this.events = this.events.slice(-50);
400
431
  }
401
432
 
433
+ private applyProviderResponse(data: any, options: { phase: 'immediate' | 'turn_completed' }): void {
434
+ if (!data || typeof data !== 'object') return;
435
+
436
+ const controlValues = extractProviderControlValues(this.provider.controls, data);
437
+ if (controlValues) {
438
+ this.cachedChat = {
439
+ ...(this.cachedChat || {}),
440
+ ...data,
441
+ controlValues: { ...(this.cachedChat?.controlValues || {}), ...controlValues },
442
+ };
443
+ }
444
+
445
+ const effects = normalizeProviderEffects(data);
446
+ for (const effect of effects) {
447
+ const effectWhen = effect.when || 'immediate';
448
+ if (effectWhen === 'turn_completed' && options.phase !== 'turn_completed') continue;
449
+ if (effectWhen === 'immediate' && options.phase === 'turn_completed') continue;
450
+
451
+ const effectKey = this.getEffectDedupKey(effect);
452
+ if (this.appliedEffectKeys.has(effectKey)) continue;
453
+ this.appliedEffectKeys.add(effectKey);
454
+
455
+ if (effect.persist !== false) {
456
+ const persisted = this.getPersistedEffectContent(effect);
457
+ if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
458
+ }
459
+
460
+ if (effect.type === 'message' && effect.message) {
461
+ this.pushEvent({
462
+ event: 'provider:message',
463
+ timestamp: Date.now(),
464
+ content: typeof effect.message.content === 'string' ? effect.message.content : JSON.stringify(effect.message.content),
465
+ role: effect.message.role || 'system',
466
+ kind: effect.message.kind,
467
+ senderName: effect.message.senderName,
468
+ });
469
+ } else if (effect.type === 'toast' && effect.toast) {
470
+ this.pushEvent({
471
+ event: 'provider:toast',
472
+ effectId: effect.id || effectKey,
473
+ timestamp: Date.now(),
474
+ message: effect.toast.message,
475
+ level: effect.toast.level || 'info',
476
+ });
477
+ } else if (effect.type === 'notification' && effect.notification) {
478
+ this.pushEvent({
479
+ event: 'provider:notification',
480
+ effectId: effect.id || effectKey,
481
+ timestamp: Date.now(),
482
+ title: effect.notification.title,
483
+ message: effect.notification.body,
484
+ content: typeof effect.notification.bubbleContent === 'string'
485
+ ? effect.notification.bubbleContent
486
+ : effect.notification.body,
487
+ level: effect.notification.level || 'info',
488
+ channels: effect.notification.channels || ['toast'],
489
+ preferenceKey: effect.notification.preferenceKey,
490
+ });
491
+ }
492
+ }
493
+ }
494
+
495
+ private appendRuntimeSystemMessage(content: string, dedupKey: string, receivedAt = Date.now()): void {
496
+ const normalizedContent = String(content || '').trim();
497
+ if (!normalizedContent) return;
498
+ if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
499
+ if (!this.cachedChat) {
500
+ this.cachedChat = {
501
+ id: 'active_session',
502
+ title: this.provider.name,
503
+ status: this.currentStatus,
504
+ messages: [],
505
+ activeModal: null,
506
+ inputContent: '',
507
+ };
508
+ }
509
+
510
+ this.runtimeMessages.push({
511
+ key: dedupKey,
512
+ message: {
513
+ role: 'system',
514
+ senderName: 'System',
515
+ content: normalizedContent,
516
+ receivedAt,
517
+ timestamp: receivedAt,
518
+ },
519
+ });
520
+ if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
521
+
522
+ this.historyWriter.appendNewMessages(
523
+ this.type,
524
+ [{
525
+ role: 'system',
526
+ senderName: 'System',
527
+ content: normalizedContent,
528
+ kind: 'system',
529
+ receivedAt,
530
+ historyDedupKey: dedupKey,
531
+ }],
532
+ this.cachedChat?.title || this.provider.name,
533
+ this.instanceId,
534
+ this.cachedChat?.id || this.instanceId,
535
+ );
536
+ }
537
+
538
+ private mergeConversationMessages(messages: any[]): ChatMessage[] {
539
+ if (this.runtimeMessages.length === 0) return messages;
540
+ return [...messages, ...this.runtimeMessages.map((entry) => entry.message)]
541
+ .map((message, index) => ({ message, index }))
542
+ .sort((a, b) => {
543
+ const aTime = a.message.receivedAt || a.message.timestamp || 0;
544
+ const bTime = b.message.receivedAt || b.message.timestamp || 0;
545
+ if (aTime !== bTime) return aTime - bTime;
546
+ return a.index - b.index;
547
+ })
548
+ .map((entry) => entry.message);
549
+ }
550
+
551
+ private getPersistedEffectContent(effect: { type: string; message?: { content?: unknown }; toast?: { message?: string }; notification?: { title?: string; body?: string; bubbleContent?: unknown } }): string | null {
552
+ if (effect.type === 'message') {
553
+ return typeof effect.message?.content === 'string'
554
+ ? effect.message.content
555
+ : JSON.stringify(effect.message?.content || '');
556
+ }
557
+ if (effect.type === 'toast') {
558
+ return effect.toast?.message || null;
559
+ }
560
+ if (effect.type === 'notification') {
561
+ if (typeof effect.notification?.bubbleContent === 'string') return effect.notification.bubbleContent;
562
+ if (typeof effect.notification?.title === 'string' && effect.notification.title.trim()) {
563
+ return `${effect.notification.title}\n${effect.notification.body || ''}`.trim();
564
+ }
565
+ return effect.notification?.body || null;
566
+ }
567
+ return null;
568
+ }
569
+
570
+ private getEffectDedupKey(effect: { id?: string; type: string; message?: { content?: unknown }; toast?: { message?: string }; notification?: { title?: string; body?: string } }): string {
571
+ if (effect.id) return `provider_effect:${effect.id}`;
572
+ if (effect.type === 'message') {
573
+ return `provider_effect:message:${typeof effect.message?.content === 'string' ? effect.message.content : JSON.stringify(effect.message?.content || '')}`;
574
+ }
575
+ if (effect.type === 'notification') {
576
+ return `provider_effect:notification:${effect.notification?.title || ''}:${effect.notification?.body || ''}`;
577
+ }
578
+ return `provider_effect:toast:${effect.toast?.message || ''}`;
579
+ }
580
+
402
581
  private flushEvents(): ProviderEvent[] {
403
582
  const events = [...this.events];
404
583
  this.events = [];
@@ -187,6 +187,7 @@ export interface StatusReportPayload {
187
187
  workspaces?: WorkspaceEntry[];
188
188
  defaultWorkspaceId?: string | null;
189
189
  defaultWorkspacePath?: string | null;
190
+ terminalSizingMode?: 'measured' | 'fit';
190
191
  workspaceActivity?: WorkspaceActivity[];
191
192
  recentLaunches?: RecentLaunchEntry[];
192
193
  }
@@ -159,7 +159,7 @@ export interface AcpMode {
159
159
  /** Provider control schema transmitted to frontend */
160
160
  export interface ProviderControlSchema {
161
161
  id: string;
162
- type: 'select' | 'toggle' | 'cycle' | 'slider' | 'action';
162
+ type: 'select' | 'toggle' | 'cycle' | 'slider' | 'action' | 'display';
163
163
  label: string;
164
164
  icon?: string;
165
165
  placement: 'bar' | 'header' | 'menu';
@@ -255,6 +255,7 @@ export interface StatusReportPayload {
255
255
  workspaces?: WorkspaceEntry[];
256
256
  defaultWorkspaceId?: string | null;
257
257
  defaultWorkspacePath?: string | null;
258
+ terminalSizingMode?: 'measured' | 'fit';
258
259
  recentLaunches?: RecentLaunchEntry[];
259
260
  terminalBackend?: TerminalBackendStatus;
260
261
  /** Available providers (present in StatusSnapshot, optional in raw payload) */
@@ -256,6 +256,7 @@ export function buildStatusSnapshot(options: StatusSnapshotOptions): StatusSnaps
256
256
  workspaces: wsState.workspaces,
257
257
  defaultWorkspaceId: wsState.defaultWorkspaceId,
258
258
  defaultWorkspacePath: wsState.defaultWorkspacePath,
259
+ terminalSizingMode: cfg.terminalSizingMode || 'measured',
259
260
  recentLaunches: buildRecentLaunches(recentActivity),
260
261
  terminalBackend,
261
262
  availableProviders: buildAvailableProviders(options.providerLoader),