@adhdev/daemon-core 0.9.34 → 0.9.35

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.
@@ -79,6 +79,7 @@ export declare class CliProviderInstance implements ProviderInstance {
79
79
  previousProviderSessionId?: string;
80
80
  }) => void;
81
81
  });
82
+ refreshProviderDefinition(provider: ProviderModule): void;
82
83
  init(context: InstanceContext): Promise<void>;
83
84
  onTick(): Promise<void>;
84
85
  /**
@@ -78,6 +78,7 @@ export declare class ProviderInstanceManager {
78
78
  * Called when user changes settings from dashboard.
79
79
  */
80
80
  updateInstanceSettings(providerType: string, settings: Record<string, any>): number;
81
+ refreshProviderDefinitions(resolveProvider: (providerType: string) => unknown): number;
81
82
  /**
82
83
  * All terminate
83
84
  */
@@ -7,7 +7,7 @@
7
7
  * Daemon only collects via ProviderInstance.getState(),
8
8
  * Each Instance manages its own status.
9
9
  */
10
- import type { ProviderResumeCapability } from './contracts.js';
10
+ import type { ProviderModule, ProviderResumeCapability } from './contracts.js';
11
11
  import type { AcpConfigOption, AcpMode, ProviderControlSchema, ProviderSummaryMetadata, SessionCapability } from '../shared-types.js';
12
12
  import type { ChatMessage } from '../types.js';
13
13
  export type ProviderStatus = 'idle' | 'generating' | 'waiting_approval' | 'error' | 'stopped' | 'starting';
@@ -163,6 +163,8 @@ export interface ProviderInstance {
163
163
  onEvent(event: string, data?: any): void;
164
164
  /** Update settings at runtime (called when user changes settings from dashboard) */
165
165
  updateSettings?(newSettings: Record<string, any>): void;
166
+ /** Refresh static provider definition/scripts without restarting the live runtime. */
167
+ refreshProviderDefinition?(provider: ProviderModule): void;
166
168
  /** cleanup */
167
169
  dispose(): void;
168
170
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/session-host-core",
3
- "version": "0.9.34",
3
+ "version": "0.9.35",
4
4
  "description": "ADHDev local session host core \u2014 session registry, protocol, buffers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.34",
3
+ "version": "0.9.35",
4
4
  "description": "ADHDev daemon core \u2014 CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -51,6 +51,7 @@ export interface CliAdapter {
51
51
  isReady(): boolean;
52
52
  setOnStatusChange(callback: () => void): void;
53
53
  updateRuntimeSettings?(settings: Record<string, unknown>): void;
54
+ setCliScripts?(scripts: Record<string, unknown>): void;
54
55
  setServerConn?(serverConn: unknown): void;
55
56
  clearHistory?(): void;
56
57
  resolveAction?(data: unknown): Promise<void>;
@@ -32,6 +32,7 @@ import {
32
32
  extractPromptRetrySnippet,
33
33
  getLastUserPromptText,
34
34
  listCliScriptNames,
35
+ normalizeComparableMessageContent,
35
36
  normalizePromptText,
36
37
  normalizeScreenSnapshot,
37
38
  promptLikelyVisible,
@@ -183,6 +184,8 @@ export class ProviderCliAdapter implements CliAdapter {
183
184
  private messages: CliChatMessage[] = [];
184
185
  private committedMessages: CliChatMessage[] = [];
185
186
  private structuredMessages: CliChatMessage[] = [];
187
+ private committedMessagesActivitySignature = '';
188
+ private committedMessagesChangedAt = 0;
186
189
  private currentStatus: CliSessionStatus['status'] = 'starting';
187
190
  private onStatusChange: (() => void) | null = null;
188
191
 
@@ -288,11 +291,38 @@ export class ProviderCliAdapter implements CliAdapter {
288
291
  private static readonly FINISH_RETRY_DELAY_MS = 300;
289
292
  private static readonly MAX_FINISH_RETRIES = 2;
290
293
 
294
+ private buildCommittedMessagesActivitySignature(): string {
295
+ const last = this.committedMessages[this.committedMessages.length - 1];
296
+ return [
297
+ String(this.committedMessages.length),
298
+ String(last?.role || ''),
299
+ String(last?.kind || ''),
300
+ String(last?.senderName || ''),
301
+ String(last?.timestamp || ''),
302
+ String(last?.receivedAt || ''),
303
+ normalizeComparableMessageContent(last?.content || '').slice(-240),
304
+ ].join('|');
305
+ }
306
+
291
307
  private syncMessageViews(): void {
308
+ const signature = this.buildCommittedMessagesActivitySignature();
309
+ if (signature !== this.committedMessagesActivitySignature) {
310
+ this.committedMessagesActivitySignature = signature;
311
+ this.committedMessagesChangedAt = Date.now();
312
+ }
292
313
  this.messages = [...this.committedMessages];
293
314
  this.structuredMessages = [...this.committedMessages];
294
315
  }
295
316
 
317
+ getLastCommittedMessageActivityAt(): number {
318
+ const last = this.committedMessages[this.committedMessages.length - 1];
319
+ const messageTime = Math.max(
320
+ typeof last?.receivedAt === 'number' && Number.isFinite(last.receivedAt) ? last.receivedAt : 0,
321
+ typeof last?.timestamp === 'number' && Number.isFinite(last.timestamp) ? last.timestamp : 0,
322
+ );
323
+ return Math.max(messageTime, this.committedMessagesChangedAt || 0);
324
+ }
325
+
296
326
  private readTerminalScreenText(now = Date.now()): string {
297
327
  const screenText = this.terminalScreen.getText() || '';
298
328
  this.lastScreenText = screenText;
@@ -519,10 +549,18 @@ export class ProviderCliAdapter implements CliAdapter {
519
549
  /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
520
550
  setCliScripts(scripts: CliScripts): void {
521
551
  this.cliScripts = scripts;
552
+ this.parsedStatusCache = null;
553
+ this.parseErrorMessage = null;
522
554
  const scriptNames = listCliScriptNames(scripts);
523
555
  LOG.info('CLI', `[${this.cliType}] CLI scripts injected: [${scriptNames.join(', ')}]`);
524
556
  }
525
557
 
558
+ /** Refresh provider scripts/config used by this adapter without restarting the PTY runtime. */
559
+ refreshProviderDefinition(provider: CliProviderModule): void {
560
+ this.provider = provider;
561
+ this.setCliScripts(provider.scripts || {});
562
+ }
563
+
526
564
  updateRuntimeSettings(settings: Record<string, any>): void {
527
565
  this.runtimeSettings = { ...settings };
528
566
  }
@@ -507,7 +507,16 @@ export class DaemonCommandHandler implements CommandHelpers {
507
507
  if (this._ctx.providerLoader) {
508
508
  await this._ctx.providerLoader.fetchLatest().catch(() => {});
509
509
  this._ctx.providerLoader.reload();
510
- return { success: true };
510
+ this._ctx.providerLoader.registerToDetector();
511
+ const refreshedInstances = this._ctx.instanceManager
512
+ ? this._ctx.instanceManager.refreshProviderDefinitions((providerType) => this._ctx.providerLoader!.resolve(providerType))
513
+ : 0;
514
+ const providers = this._ctx.providerLoader.getAll().map((provider) => ({
515
+ type: provider.type,
516
+ name: provider.name,
517
+ category: provider.category,
518
+ }));
519
+ return { success: true, refreshedInstances, providers };
511
520
  }
512
521
  return { success: false, error: 'ProviderLoader not initialized' };
513
522
  }
@@ -507,20 +507,9 @@ export class DevServer implements DevServerContext {
507
507
  private async handleReload(_req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
508
508
  try {
509
509
  this.providerLoader.reload();
510
- let refreshedInstances = 0;
511
- if (this.instanceManager) {
512
- for (const id of this.instanceManager.listInstanceIds()) {
513
- const instance = this.instanceManager.getInstance(id) as any;
514
- const providerType = typeof instance?.type === 'string' ? instance.type : '';
515
- if (!providerType) continue;
516
- const resolved = this.providerLoader.resolve(providerType);
517
- if (!resolved) continue;
518
- if (instance && typeof instance === 'object' && 'provider' in instance) {
519
- instance.provider = resolved;
520
- refreshedInstances += 1;
521
- }
522
- }
523
- }
510
+ const refreshedInstances = this.instanceManager
511
+ ? this.instanceManager.refreshProviderDefinitions((providerType) => this.providerLoader.resolve(providerType))
512
+ : 0;
524
513
  const providers = this.providerLoader.getAll().map(p => ({
525
514
  type: p.type, name: p.name, category: p.category,
526
515
  }));
@@ -219,6 +219,12 @@ export class CliProviderInstance implements ProviderInstance {
219
219
  this.historyWriter = new ChatHistoryWriter();
220
220
  }
221
221
 
222
+ refreshProviderDefinition(provider: ProviderModule): void {
223
+ if (provider.type !== this.type || provider.category !== 'cli') return;
224
+ this.provider = provider;
225
+ this.adapter.refreshProviderDefinition(provider as CliProviderModule);
226
+ }
227
+
222
228
  // ─── Lifecycle ─────────────────────────────────
223
229
 
224
230
  async init(context: InstanceContext): Promise<void> {
@@ -492,9 +498,13 @@ export class CliProviderInstance implements ProviderInstance {
492
498
  const autoApproveActive = adapterStatus.status === 'waiting_approval' && this.shouldAutoApprove();
493
499
  const visibleStatus = autoApproveActive ? 'generating' : adapterStatus.status;
494
500
  const runtime = this.adapter.getRuntimeMetadata();
501
+ const lastCommittedMessageActivityAt = typeof this.adapter.getLastCommittedMessageActivityAt === 'function'
502
+ ? this.adapter.getLastCommittedMessageActivityAt()
503
+ : 0;
495
504
  return {
496
505
  id: this.instanceId,
497
506
  status: visibleStatus,
507
+ lastMessageAt: lastCommittedMessageActivityAt || undefined,
498
508
  runtimeLifecycle: runtime?.lifecycle ?? null,
499
509
  runtimeSurfaceKind: runtime?.surfaceKind,
500
510
  runtimeRestoredFromStorage: runtime?.restoredFromStorage === true,
@@ -15,6 +15,9 @@ function projectHotChatSessionStatesFromProviderState(state: ProviderState): Hot
15
15
  const project = (item: ProviderState): HotChatSessionState => ({
16
16
  id: item.instanceId,
17
17
  status: item.activeChat?.status || item.status,
18
+ unread: (item as any).unread,
19
+ inboxBucket: (item as any).inboxBucket,
20
+ lastMessageAt: (item as any).lastMessageAt ?? (item.activeChat as any)?.lastMessageAt,
18
21
  runtimeLifecycle: item.runtime?.lifecycle ?? null,
19
22
  runtimeSurfaceKind: item.runtime?.surfaceKind,
20
23
  runtimeRestoredFromStorage: item.runtime?.restoredFromStorage === true,
@@ -258,6 +261,18 @@ export class ProviderInstanceManager {
258
261
  return updated;
259
262
  }
260
263
 
264
+ refreshProviderDefinitions(resolveProvider: (providerType: string) => unknown): number {
265
+ let refreshed = 0;
266
+ for (const instance of this.instances.values()) {
267
+ if (typeof instance.refreshProviderDefinition !== 'function') continue;
268
+ const provider = resolveProvider(instance.type);
269
+ if (!provider || typeof provider !== 'object') continue;
270
+ instance.refreshProviderDefinition(provider as any);
271
+ refreshed += 1;
272
+ }
273
+ return refreshed;
274
+ }
275
+
261
276
  // ─── cleanup ──────────────────────────────────────
262
277
 
263
278
  /**
@@ -197,6 +197,9 @@ export interface ProviderInstance {
197
197
  /** Update settings at runtime (called when user changes settings from dashboard) */
198
198
  updateSettings?(newSettings: Record<string, any>): void;
199
199
 
200
+ /** Refresh static provider definition/scripts without restarting the live runtime. */
201
+ refreshProviderDefinition?(provider: ProviderModule): void;
202
+
200
203
  /** cleanup */
201
204
  dispose(): void;
202
205
  }