@adhdev/daemon-core 0.9.34 → 0.9.36

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.
@@ -47,6 +47,7 @@ export interface CliAdapter {
47
47
  isReady(): boolean;
48
48
  setOnStatusChange(callback: () => void): void;
49
49
  updateRuntimeSettings?(settings: Record<string, unknown>): void;
50
+ setCliScripts?(scripts: Record<string, unknown>): void;
50
51
  setServerConn?(serverConn: unknown): void;
51
52
  clearHistory?(): void;
52
53
  resolveAction?(data: unknown): Promise<void>;
@@ -34,6 +34,8 @@ export declare class ProviderCliAdapter implements CliAdapter {
34
34
  private messages;
35
35
  private committedMessages;
36
36
  private structuredMessages;
37
+ private committedMessagesActivitySignature;
38
+ private committedMessagesChangedAt;
37
39
  private currentStatus;
38
40
  private onStatusChange;
39
41
  private responseBuffer;
@@ -107,12 +109,15 @@ export declare class ProviderCliAdapter implements CliAdapter {
107
109
  private readonly providerResolutionMeta;
108
110
  private static readonly FINISH_RETRY_DELAY_MS;
109
111
  private static readonly MAX_FINISH_RETRIES;
112
+ private buildCommittedMessagesActivitySignature;
110
113
  private syncMessageViews;
114
+ getLastCommittedMessageActivityAt(): number;
111
115
  private readTerminalScreenText;
112
116
  private shouldReadTerminalScreenSnapshot;
113
117
  private resetTerminalScreen;
114
118
  private getFreshParsedStatusCache;
115
119
  private selectParseBaseMessages;
120
+ private messagesShareStableIdentity;
116
121
  private messagesComparable;
117
122
  private stitchParsedMessagesWithCommittedBase;
118
123
  private getIdleFinishConfirmMs;
@@ -131,6 +136,8 @@ export declare class ProviderCliAdapter implements CliAdapter {
131
136
  constructor(provider: CliProviderModule, workingDir: string, extraArgs?: string[], transportFactory?: PtyTransportFactory);
132
137
  /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
133
138
  setCliScripts(scripts: CliScripts): void;
139
+ /** Refresh provider scripts/config used by this adapter without restarting the PTY runtime. */
140
+ refreshProviderDefinition(provider: CliProviderModule): void;
134
141
  updateRuntimeSettings(settings: Record<string, any>): void;
135
142
  setServerConn(serverConn: any): void;
136
143
  setOnStatusChange(callback: () => void): void;
@@ -167,6 +174,10 @@ export declare class ProviderCliAdapter implements CliAdapter {
167
174
  private suppressStaleParsedApproval;
168
175
  getStatus(): CliSessionStatus;
169
176
  seedCommittedMessages(messages: SeedCliChatMessage[]): void;
177
+ private getSharedCommittedPrefixLength;
178
+ private hydrateCommittedPrefixForParsedStatus;
179
+ private hydrateParsedMessagesForStatus;
180
+ private buildCommittedChatMessages;
170
181
  /**
171
182
  * Script-based full parse — returns ReadChatResult.
172
183
  * Called by command handler / dashboard for rich content rendering.
package/dist/index.js CHANGED
@@ -2087,6 +2087,8 @@ var init_provider_cli_adapter = __esm({
2087
2087
  messages = [];
2088
2088
  committedMessages = [];
2089
2089
  structuredMessages = [];
2090
+ committedMessagesActivitySignature = "";
2091
+ committedMessagesChangedAt = 0;
2090
2092
  currentStatus = "starting";
2091
2093
  onStatusChange = null;
2092
2094
  responseBuffer = "";
@@ -2168,10 +2170,35 @@ var init_provider_cli_adapter = __esm({
2168
2170
  providerResolutionMeta;
2169
2171
  static FINISH_RETRY_DELAY_MS = 300;
2170
2172
  static MAX_FINISH_RETRIES = 2;
2173
+ buildCommittedMessagesActivitySignature() {
2174
+ const last = this.committedMessages[this.committedMessages.length - 1];
2175
+ return [
2176
+ String(this.committedMessages.length),
2177
+ String(last?.role || ""),
2178
+ String(last?.kind || ""),
2179
+ String(last?.senderName || ""),
2180
+ String(last?.timestamp || ""),
2181
+ String(last?.receivedAt || ""),
2182
+ normalizeComparableMessageContent(last?.content || "").slice(-240)
2183
+ ].join("|");
2184
+ }
2171
2185
  syncMessageViews() {
2186
+ const signature = this.buildCommittedMessagesActivitySignature();
2187
+ if (signature !== this.committedMessagesActivitySignature) {
2188
+ this.committedMessagesActivitySignature = signature;
2189
+ this.committedMessagesChangedAt = Date.now();
2190
+ }
2172
2191
  this.messages = [...this.committedMessages];
2173
2192
  this.structuredMessages = [...this.committedMessages];
2174
2193
  }
2194
+ getLastCommittedMessageActivityAt() {
2195
+ const last = this.committedMessages[this.committedMessages.length - 1];
2196
+ const messageTime = Math.max(
2197
+ typeof last?.receivedAt === "number" && Number.isFinite(last.receivedAt) ? last.receivedAt : 0,
2198
+ typeof last?.timestamp === "number" && Number.isFinite(last.timestamp) ? last.timestamp : 0
2199
+ );
2200
+ return Math.max(messageTime, this.committedMessagesChangedAt || 0);
2201
+ }
2175
2202
  readTerminalScreenText(now = Date.now()) {
2176
2203
  const screenText = this.terminalScreen.getText() || "";
2177
2204
  this.lastScreenText = screenText;
@@ -2200,7 +2227,16 @@ var init_provider_cli_adapter = __esm({
2200
2227
  if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
2201
2228
  return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
2202
2229
  }
2230
+ messagesShareStableIdentity(left, right) {
2231
+ if (left === right) return true;
2232
+ if (!left || !right) return false;
2233
+ if ((left.role || "") !== (right.role || "")) return false;
2234
+ if (left.id && right.id && String(left.id) === String(right.id)) return true;
2235
+ if (typeof left.index === "number" && typeof right.index === "number" && left.index === right.index) return true;
2236
+ return false;
2237
+ }
2203
2238
  messagesComparable(left, right) {
2239
+ if (this.messagesShareStableIdentity(left, right)) return true;
2204
2240
  if (!left || !right) return false;
2205
2241
  if ((left.role || "") !== (right.role || "")) return false;
2206
2242
  const leftText = normalizeComparableTranscriptText(left.content);
@@ -2311,9 +2347,16 @@ var init_provider_cli_adapter = __esm({
2311
2347
  /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
2312
2348
  setCliScripts(scripts) {
2313
2349
  this.cliScripts = scripts;
2350
+ this.parsedStatusCache = null;
2351
+ this.parseErrorMessage = null;
2314
2352
  const scriptNames = listCliScriptNames(scripts);
2315
2353
  LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
2316
2354
  }
2355
+ /** Refresh provider scripts/config used by this adapter without restarting the PTY runtime. */
2356
+ refreshProviderDefinition(provider) {
2357
+ this.provider = provider;
2358
+ this.setCliScripts(provider.scripts || {});
2359
+ }
2317
2360
  updateRuntimeSettings(settings) {
2318
2361
  this.runtimeSettings = { ...settings };
2319
2362
  }
@@ -3344,6 +3387,69 @@ var init_provider_cli_adapter = __esm({
3344
3387
  this.committedMessages = normalized;
3345
3388
  this.syncMessageViews();
3346
3389
  }
3390
+ getSharedCommittedPrefixLength(parsedMessages) {
3391
+ const committedMessages = this.committedMessages;
3392
+ const max = Math.min(parsedMessages.length, committedMessages.length);
3393
+ let index = 0;
3394
+ while (index < max && this.messagesShareStableIdentity(parsedMessages[index], committedMessages[index])) {
3395
+ index += 1;
3396
+ }
3397
+ return index;
3398
+ }
3399
+ hydrateCommittedPrefixForParsedStatus(parsedMessages) {
3400
+ const sharedPrefixLength = this.getSharedCommittedPrefixLength(parsedMessages);
3401
+ if (sharedPrefixLength !== this.committedMessages.length) return null;
3402
+ const committedHydratedMessages = this.committedMessages.map((message, index) => {
3403
+ const timestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : this.lastOutputAt || this.currentTurnScope?.startedAt || Date.now();
3404
+ const contentValue = message.content;
3405
+ return {
3406
+ role: message.role,
3407
+ content: typeof contentValue === "string" ? contentValue : String(contentValue || ""),
3408
+ timestamp,
3409
+ receivedAt: typeof message.receivedAt === "number" && Number.isFinite(message.receivedAt) ? message.receivedAt : timestamp,
3410
+ kind: message.kind,
3411
+ id: message.id || `msg_${index}`,
3412
+ index: typeof message.index === "number" ? message.index : index,
3413
+ meta: message.meta,
3414
+ senderName: message.senderName
3415
+ };
3416
+ });
3417
+ const extraMessages = parsedMessages.slice(sharedPrefixLength);
3418
+ if (extraMessages.length === 0) return committedHydratedMessages;
3419
+ const extraHydratedMessages = hydrateCliParsedMessages(extraMessages, {
3420
+ committedMessages: [],
3421
+ scope: this.currentTurnScope,
3422
+ lastOutputAt: this.lastOutputAt
3423
+ }).map((message, offset) => ({
3424
+ ...message,
3425
+ id: message.id || `msg_${sharedPrefixLength + offset}`,
3426
+ index: typeof message.index === "number" ? message.index : sharedPrefixLength + offset
3427
+ }));
3428
+ return [...committedHydratedMessages, ...extraHydratedMessages];
3429
+ }
3430
+ hydrateParsedMessagesForStatus(parsedMessages) {
3431
+ return this.hydrateCommittedPrefixForParsedStatus(parsedMessages) || hydrateCliParsedMessages(parsedMessages, {
3432
+ committedMessages: this.committedMessages,
3433
+ scope: this.currentTurnScope,
3434
+ lastOutputAt: this.lastOutputAt
3435
+ });
3436
+ }
3437
+ buildCommittedChatMessages() {
3438
+ return this.committedMessages.map((message, index) => {
3439
+ const contentValue = message.content;
3440
+ return buildChatMessage({
3441
+ role: message.role,
3442
+ content: typeof contentValue === "string" ? contentValue : String(contentValue || ""),
3443
+ timestamp: message.timestamp,
3444
+ kind: message.kind,
3445
+ meta: message.meta,
3446
+ senderName: message.senderName,
3447
+ id: message.id || `msg_${index}`,
3448
+ index: typeof message.index === "number" ? message.index : index,
3449
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
3450
+ });
3451
+ });
3452
+ }
3347
3453
  /**
3348
3454
  * Script-based full parse — returns ReadChatResult.
3349
3455
  * Called by command handler / dashboard for rich content rendering.
@@ -3369,7 +3475,7 @@ var init_provider_cli_adapter = __esm({
3369
3475
  this.onStatusChange?.();
3370
3476
  }
3371
3477
  }
3372
- if (parsed && Array.isArray(parsed.messages)) {
3478
+ if (parsed && Array.isArray(parsed.messages) && this.provider.allowInputDuringGeneration === true) {
3373
3479
  const hydratedForCommit = normalizeCliParsedMessages(parsed.messages, {
3374
3480
  committedMessages: this.committedMessages,
3375
3481
  scope: this.currentTurnScope,
@@ -3388,21 +3494,21 @@ var init_provider_cli_adapter = __esm({
3388
3494
  const shouldPreferCommittedMessages = !this.currentTurnScope && !this.activeModal && this.currentStatus === "idle";
3389
3495
  let result;
3390
3496
  if (parsed && Array.isArray(parsed.messages)) {
3391
- const parsedHydratedMessages = hydrateCliParsedMessages(parsed.messages, {
3392
- committedMessages: this.committedMessages,
3393
- scope: this.currentTurnScope,
3394
- lastOutputAt: this.lastOutputAt
3395
- });
3396
- const committedHydratedMessages = this.committedMessages.map((message, index) => buildChatMessage({
3397
- ...message,
3398
- id: message.id || `msg_${index}`,
3399
- index: typeof message.index === "number" ? message.index : index,
3400
- receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
3401
- }));
3497
+ const parsedHydratedMessages = this.hydrateParsedMessagesForStatus(parsed.messages);
3402
3498
  const parsedLastAssistant = [...parsedHydratedMessages].reverse().find((message) => message.role === "assistant" && typeof message.content === "string" && message.content.trim());
3403
- const shouldAdoptParsedIdleReplay = !this.currentTurnScope && !this.activeModal && !!parsedLastAssistant && parsedTranscriptIsRicherThanCommitted(parsedHydratedMessages, committedHydratedMessages) && (this.currentStatus === "idle" || this.currentStatus === "generating" && this.isWaitingForResponse && parsed.status === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle");
3499
+ const shouldAdoptParsedIdleReplay = !this.currentTurnScope && !this.activeModal && !!parsedLastAssistant && parsedTranscriptIsRicherThanCommitted(parsedHydratedMessages, this.committedMessages) && (this.currentStatus === "idle" || this.currentStatus === "generating" && this.isWaitingForResponse && parsed.status === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle");
3404
3500
  if (shouldAdoptParsedIdleReplay) {
3405
- this.committedMessages = normalizeCliParsedMessages(parsed.messages, {
3501
+ this.committedMessages = this.getSharedCommittedPrefixLength(parsed.messages) === this.committedMessages.length ? parsedHydratedMessages.map((message) => ({
3502
+ role: message.role,
3503
+ content: typeof message.content === "string" ? message.content : String(message.content || ""),
3504
+ timestamp: message.timestamp,
3505
+ receivedAt: message.receivedAt,
3506
+ kind: message.kind,
3507
+ id: message.id,
3508
+ index: message.index,
3509
+ meta: message.meta,
3510
+ senderName: message.senderName
3511
+ })) : normalizeCliParsedMessages(parsed.messages, {
3406
3512
  committedMessages: this.committedMessages,
3407
3513
  scope: this.currentTurnScope,
3408
3514
  lastOutputAt: this.lastOutputAt
@@ -3421,15 +3527,9 @@ var init_provider_cli_adapter = __esm({
3421
3527
  this.onStatusChange?.();
3422
3528
  }
3423
3529
  }
3424
- const effectiveCommittedHydratedMessages = shouldAdoptParsedIdleReplay ? this.committedMessages.map((message, index) => buildChatMessage({
3425
- ...message,
3426
- id: message.id || `msg_${index}`,
3427
- index: typeof message.index === "number" ? message.index : index,
3428
- receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
3429
- })) : committedHydratedMessages;
3430
- const shouldPreferCommittedHistoryReplay = !this.currentTurnScope && !this.activeModal && effectiveCommittedHydratedMessages.length > parsedHydratedMessages.length;
3530
+ const shouldPreferCommittedHistoryReplay = !this.currentTurnScope && !this.activeModal && this.committedMessages.length > parsedHydratedMessages.length;
3431
3531
  const shouldPreferCommittedIdleReplay = shouldPreferCommittedMessages && !shouldAdoptParsedIdleReplay;
3432
- const hydratedMessages = shouldPreferCommittedIdleReplay || shouldPreferCommittedHistoryReplay ? effectiveCommittedHydratedMessages : parsedHydratedMessages;
3532
+ const hydratedMessages = shouldPreferCommittedIdleReplay || shouldPreferCommittedHistoryReplay ? this.buildCommittedChatMessages() : parsedHydratedMessages;
3433
3533
  result = {
3434
3534
  id: parsed.id || "cli_session",
3435
3535
  status: parsed.status || this.currentStatus,
@@ -12978,7 +13078,14 @@ var DaemonCommandHandler = class {
12978
13078
  await this._ctx.providerLoader.fetchLatest().catch(() => {
12979
13079
  });
12980
13080
  this._ctx.providerLoader.reload();
12981
- return { success: true };
13081
+ this._ctx.providerLoader.registerToDetector();
13082
+ const refreshedInstances = this._ctx.instanceManager ? this._ctx.instanceManager.refreshProviderDefinitions((providerType) => this._ctx.providerLoader.resolve(providerType)) : 0;
13083
+ const providers = this._ctx.providerLoader.getAll().map((provider) => ({
13084
+ type: provider.type,
13085
+ name: provider.name,
13086
+ category: provider.category
13087
+ }));
13088
+ return { success: true, refreshedInstances, providers };
12982
13089
  }
12983
13090
  return { success: false, error: "ProviderLoader not initialized" };
12984
13091
  }
@@ -13233,6 +13340,11 @@ var CliProviderInstance = class {
13233
13340
  launchMode;
13234
13341
  startedAt = Date.now();
13235
13342
  onProviderSessionResolved;
13343
+ refreshProviderDefinition(provider) {
13344
+ if (provider.type !== this.type || provider.category !== "cli") return;
13345
+ this.provider = provider;
13346
+ this.adapter.refreshProviderDefinition(provider);
13347
+ }
13236
13348
  // ─── Lifecycle ─────────────────────────────────
13237
13349
  async init(context) {
13238
13350
  this.context = context;
@@ -13443,9 +13555,11 @@ var CliProviderInstance = class {
13443
13555
  const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
13444
13556
  const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
13445
13557
  const runtime = this.adapter.getRuntimeMetadata();
13558
+ const lastCommittedMessageActivityAt = typeof this.adapter.getLastCommittedMessageActivityAt === "function" ? this.adapter.getLastCommittedMessageActivityAt() : 0;
13446
13559
  return {
13447
13560
  id: this.instanceId,
13448
13561
  status: visibleStatus,
13562
+ lastMessageAt: lastCommittedMessageActivityAt || void 0,
13449
13563
  runtimeLifecycle: runtime?.lifecycle ?? null,
13450
13564
  runtimeSurfaceKind: runtime?.surfaceKind,
13451
13565
  runtimeRestoredFromStorage: runtime?.restoredFromStorage === true,
@@ -20932,6 +21046,9 @@ function projectHotChatSessionStatesFromProviderState(state) {
20932
21046
  const project = (item) => ({
20933
21047
  id: item.instanceId,
20934
21048
  status: item.activeChat?.status || item.status,
21049
+ unread: item.unread,
21050
+ inboxBucket: item.inboxBucket,
21051
+ lastMessageAt: item.lastMessageAt ?? item.activeChat?.lastMessageAt,
20935
21052
  runtimeLifecycle: item.runtime?.lifecycle ?? null,
20936
21053
  runtimeSurfaceKind: item.runtime?.surfaceKind,
20937
21054
  runtimeRestoredFromStorage: item.runtime?.restoredFromStorage === true,
@@ -21139,6 +21256,17 @@ var ProviderInstanceManager = class {
21139
21256
  }
21140
21257
  return updated;
21141
21258
  }
21259
+ refreshProviderDefinitions(resolveProvider) {
21260
+ let refreshed = 0;
21261
+ for (const instance of this.instances.values()) {
21262
+ if (typeof instance.refreshProviderDefinition !== "function") continue;
21263
+ const provider = resolveProvider(instance.type);
21264
+ if (!provider || typeof provider !== "object") continue;
21265
+ instance.refreshProviderDefinition(provider);
21266
+ refreshed += 1;
21267
+ }
21268
+ return refreshed;
21269
+ }
21142
21270
  // ─── cleanup ──────────────────────────────────────
21143
21271
  /**
21144
21272
  * All terminate
@@ -25383,20 +25511,7 @@ var DevServer = class _DevServer {
25383
25511
  async handleReload(_req, res) {
25384
25512
  try {
25385
25513
  this.providerLoader.reload();
25386
- let refreshedInstances = 0;
25387
- if (this.instanceManager) {
25388
- for (const id of this.instanceManager.listInstanceIds()) {
25389
- const instance = this.instanceManager.getInstance(id);
25390
- const providerType = typeof instance?.type === "string" ? instance.type : "";
25391
- if (!providerType) continue;
25392
- const resolved = this.providerLoader.resolve(providerType);
25393
- if (!resolved) continue;
25394
- if (instance && typeof instance === "object" && "provider" in instance) {
25395
- instance.provider = resolved;
25396
- refreshedInstances += 1;
25397
- }
25398
- }
25399
- }
25514
+ const refreshedInstances = this.instanceManager ? this.instanceManager.refreshProviderDefinitions((providerType) => this.providerLoader.resolve(providerType)) : 0;
25400
25515
  const providers = this.providerLoader.getAll().map((p) => ({
25401
25516
  type: p.type,
25402
25517
  name: p.name,