adhdev 0.9.31 → 0.9.33

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.
package/dist/index.js CHANGED
@@ -1218,6 +1218,7 @@ function classifyHotChatSessionsForSubscriptionFlush(sessions, previousHotSessio
1218
1218
  Number.isFinite(options.recentMessageGraceMs) ? Number(options.recentMessageGraceMs) : DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS
1219
1219
  );
1220
1220
  const activeStatuses = options.activeStatuses ?? DEFAULT_ACTIVE_CHAT_POLL_STATUSES;
1221
+ const activeSessionIds = options.activeSessionIds ?? /* @__PURE__ */ new Set();
1221
1222
  const active = /* @__PURE__ */ new Set();
1222
1223
  const excluded = /* @__PURE__ */ new Set();
1223
1224
  for (const session of sessions) {
@@ -1227,6 +1228,10 @@ function classifyHotChatSessionsForSubscriptionFlush(sessions, previousHotSessio
1227
1228
  excluded.add(sessionId);
1228
1229
  continue;
1229
1230
  }
1231
+ if (activeSessionIds.has(sessionId)) {
1232
+ active.add(sessionId);
1233
+ continue;
1234
+ }
1230
1235
  const status = String(session?.status || "").toLowerCase();
1231
1236
  const unread = session?.unread === true;
1232
1237
  const inboxBucket = String(session?.inboxBucket || "").toLowerCase();
@@ -1342,14 +1347,13 @@ function daemonLog(category, msg, level = "info") {
1342
1347
  const shouldOutput = LEVEL_NUM[level] >= LEVEL_NUM[currentLevel];
1343
1348
  const label = LEVEL_LABEL[level];
1344
1349
  const line = `[${ts()}] [${label}] [${category}] ${msg}`;
1350
+ if (!shouldOutput) return;
1345
1351
  writeToFile(line);
1346
1352
  ringBuffer.push({ ts: Date.now(), level, category, message: msg });
1347
1353
  if (ringBuffer.length > RING_BUFFER_SIZE) {
1348
1354
  ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
1349
1355
  }
1350
- if (shouldOutput) {
1351
- origConsoleLog(line);
1352
- }
1356
+ origConsoleLog(line);
1353
1357
  }
1354
1358
  function installGlobalInterceptor() {
1355
1359
  if (interceptorInstalled) return;
@@ -7457,6 +7461,26 @@ function toHistoryPersistedMessages(messages) {
7457
7461
  historyDedupKey: deriveHistoryDedupKey(message)
7458
7462
  }));
7459
7463
  }
7464
+ function findLastMessageIndexBySignature(messages, signature) {
7465
+ if (!signature) return -1;
7466
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
7467
+ if (getChatMessageSignature(messages[index]) === signature) {
7468
+ return index;
7469
+ }
7470
+ }
7471
+ return -1;
7472
+ }
7473
+ function buildBoundedTailSync(messages, cursor) {
7474
+ const totalMessages = messages.length;
7475
+ const tailMessages = cursor.tailLimit > 0 && totalMessages > cursor.tailLimit ? messages.slice(-cursor.tailLimit) : messages;
7476
+ return {
7477
+ syncMode: "full",
7478
+ replaceFrom: 0,
7479
+ messages: tailMessages,
7480
+ totalMessages,
7481
+ lastMessageSignature: getChatMessageSignature(messages[totalMessages - 1])
7482
+ };
7483
+ }
7460
7484
  function computeReadChatSync(messages, cursor) {
7461
7485
  const totalMessages = messages.length;
7462
7486
  const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
@@ -7488,6 +7512,15 @@ function computeReadChatSync(messages, cursor) {
7488
7512
  lastMessageSignature
7489
7513
  };
7490
7514
  }
7515
+ if (cursor.tailLimit > 0 && knownSignature === lastMessageSignature) {
7516
+ return {
7517
+ syncMode: "noop",
7518
+ replaceFrom: totalMessages,
7519
+ messages: [],
7520
+ totalMessages,
7521
+ lastMessageSignature
7522
+ };
7523
+ }
7491
7524
  if (knownMessageCount < totalMessages) {
7492
7525
  const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
7493
7526
  if (anchorSignature === knownSignature) {
@@ -7499,6 +7532,19 @@ function computeReadChatSync(messages, cursor) {
7499
7532
  lastMessageSignature
7500
7533
  };
7501
7534
  }
7535
+ if (cursor.tailLimit > 0) {
7536
+ const signatureIndex = findLastMessageIndexBySignature(messages, knownSignature);
7537
+ if (signatureIndex >= 0) {
7538
+ return {
7539
+ syncMode: "append",
7540
+ replaceFrom: knownMessageCount,
7541
+ messages: messages.slice(signatureIndex + 1),
7542
+ totalMessages,
7543
+ lastMessageSignature
7544
+ };
7545
+ }
7546
+ return buildBoundedTailSync(messages, cursor);
7547
+ }
7502
7548
  }
7503
7549
  const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
7504
7550
  return {
@@ -11840,6 +11886,7 @@ var init_provider_cli_adapter = __esm({
11840
11886
  static STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS = 1e3;
11841
11887
  static SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
11842
11888
  static MAX_TRACE_ENTRIES = 250;
11889
+ static PARSE_MESSAGE_TAIL_LIMIT = 100;
11843
11890
  providerResolutionMeta;
11844
11891
  static FINISH_RETRY_DELAY_MS = 300;
11845
11892
  static MAX_FINISH_RETRIES = 2;
@@ -11871,6 +11918,32 @@ var init_provider_cli_adapter = __esm({
11871
11918
  }
11872
11919
  return null;
11873
11920
  }
11921
+ selectParseBaseMessages(baseMessages) {
11922
+ if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
11923
+ return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
11924
+ }
11925
+ messagesComparable(left2, right2) {
11926
+ if (!left2 || !right2) return false;
11927
+ if ((left2.role || "") !== (right2.role || "")) return false;
11928
+ const leftText = normalizeComparableTranscriptText(left2.content);
11929
+ const rightText = normalizeComparableTranscriptText(right2.content);
11930
+ return !!leftText && leftText === rightText;
11931
+ }
11932
+ stitchParsedMessagesWithCommittedBase(parsedMessages, fullBaseMessages, parseBaseMessages) {
11933
+ if (!Array.isArray(parsedMessages) || parsedMessages.length === 0) return parsedMessages;
11934
+ if (fullBaseMessages.length <= parseBaseMessages.length) return parsedMessages;
11935
+ const parsedFirst = parsedMessages[0];
11936
+ const fullFirst = fullBaseMessages[0];
11937
+ if (parsedMessages.length >= fullBaseMessages.length && this.messagesComparable(parsedFirst, fullFirst)) {
11938
+ return parsedMessages;
11939
+ }
11940
+ const tailFirst = parseBaseMessages[0];
11941
+ if (tailFirst && this.messagesComparable(parsedFirst, tailFirst)) {
11942
+ const prefixLength = fullBaseMessages.length - parseBaseMessages.length;
11943
+ return [...fullBaseMessages.slice(0, prefixLength), ...parsedMessages];
11944
+ }
11945
+ return [...fullBaseMessages, ...parsedMessages];
11946
+ }
11874
11947
  getIdleFinishConfirmMs() {
11875
11948
  return this.timeouts.idleFinishConfirm;
11876
11949
  }
@@ -12456,7 +12529,7 @@ var init_provider_cli_adapter = __esm({
12456
12529
  const ctx = { now, modal, status, parsedMessages, lastParsedAssistant, parsedStatus: parsedStatus || null, prevStatus };
12457
12530
  if (!this.applyPendingScriptStatusDebounce(ctx)) return;
12458
12531
  const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
12459
- LOG.info(
12532
+ LOG.debug(
12460
12533
  "CLI",
12461
12534
  `[${this.cliType}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope?.prompt || "").slice(0, 140)} status=${String(status || "")} parsedStatus=${String(parsedStatus || "")} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify(summarizeCliTraceText(lastParsedAssistant?.content || "", 120)).slice(0, 160)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 160)).slice(0, 220)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 160)).slice(0, 220)}`
12462
12535
  );
@@ -12823,18 +12896,26 @@ var init_provider_cli_adapter = __esm({
12823
12896
  try {
12824
12897
  const screenText = this.terminalScreen.getText();
12825
12898
  const tail = this.recentOutputBuffer.slice(-500);
12899
+ const parseBaseMessages = this.selectParseBaseMessages(this.committedMessages);
12826
12900
  const input = buildCliParseInput({
12827
12901
  accumulatedBuffer: this.accumulatedBuffer,
12828
12902
  accumulatedRawBuffer: this.accumulatedRawBuffer,
12829
12903
  recentOutputBuffer: this.recentOutputBuffer,
12830
12904
  terminalScreenText: screenText,
12831
- baseMessages: this.committedMessages,
12905
+ baseMessages: parseBaseMessages,
12832
12906
  partialResponse: this.responseBuffer,
12833
12907
  isWaitingForResponse: this.isWaitingForResponse,
12834
12908
  scope: this.currentTurnScope,
12835
12909
  runtimeSettings: this.runtimeSettings
12836
12910
  });
12837
12911
  const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
12912
+ if (session && typeof session === "object" && Array.isArray(session.messages)) {
12913
+ session.messages = this.stitchParsedMessagesWithCommittedBase(
12914
+ session.messages,
12915
+ this.committedMessages,
12916
+ parseBaseMessages
12917
+ );
12918
+ }
12838
12919
  this.parseErrorMessage = null;
12839
12920
  return session && typeof session === "object" ? session : null;
12840
12921
  } catch (e) {
@@ -13155,12 +13236,13 @@ var init_provider_cli_adapter = __esm({
13155
13236
  }
13156
13237
  try {
13157
13238
  const screenText = typeof screenTextOverride === "string" ? screenTextOverride : this.terminalScreen.getText();
13239
+ const parseBaseMessages = this.selectParseBaseMessages(baseMessages);
13158
13240
  const input = buildCliParseInput({
13159
13241
  accumulatedBuffer: this.accumulatedBuffer,
13160
13242
  accumulatedRawBuffer: this.accumulatedRawBuffer,
13161
13243
  recentOutputBuffer: this.recentOutputBuffer,
13162
13244
  terminalScreenText: screenText,
13163
- baseMessages,
13245
+ baseMessages: parseBaseMessages,
13164
13246
  partialResponse,
13165
13247
  isWaitingForResponse: this.isWaitingForResponse,
13166
13248
  scope,
@@ -13172,6 +13254,11 @@ var init_provider_cli_adapter = __esm({
13172
13254
  }
13173
13255
  const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
13174
13256
  if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
13257
+ normalizedParsed.messages = this.stitchParsedMessagesWithCommittedBase(
13258
+ normalizedParsed.messages,
13259
+ baseMessages,
13260
+ parseBaseMessages
13261
+ );
13175
13262
  this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
13176
13263
  }
13177
13264
  this.parseErrorMessage = null;
@@ -35032,6 +35119,9 @@ var init_provider_loader = __esm({
35032
35119
  log(msg) {
35033
35120
  this.logFn(`[ProviderLoader] ${msg}`);
35034
35121
  }
35122
+ debugLog(msg) {
35123
+ LOG.debug("Provider", `[ProviderLoader] ${msg}`);
35124
+ }
35035
35125
  // ─── Public API ────────────────────────────────
35036
35126
  /**
35037
35127
  * User override root (~/.adhdev/providers by default).
@@ -35421,10 +35511,22 @@ var init_provider_loader = __esm({
35421
35511
  setMachineProviderEnabled(type, enabled) {
35422
35512
  return this.setMachineProviderConfig(type, { enabled });
35423
35513
  }
35514
+ getEffectiveProviderAvailability(type) {
35515
+ const providerType = this.resolveAlias(type);
35516
+ const availability = this.providerAvailability.get(providerType);
35517
+ if (availability) return availability;
35518
+ const machineConfig = this.getMachineProviderConfig(providerType);
35519
+ const lastDetection = machineConfig.lastDetection;
35520
+ if (!lastDetection) return void 0;
35521
+ return {
35522
+ installed: lastDetection.ok === true,
35523
+ detectedPath: typeof lastDetection.path === "string" && lastDetection.path.trim() ? lastDetection.path.trim() : null
35524
+ };
35525
+ }
35424
35526
  getMachineProviderStatus(type) {
35425
35527
  const providerType = this.resolveAlias(type);
35426
35528
  if (!this.isMachineProviderEnabled(providerType)) return "disabled";
35427
- const availability = this.providerAvailability.get(providerType);
35529
+ const availability = this.getEffectiveProviderAvailability(providerType);
35428
35530
  if (!availability) return "enabled_unchecked";
35429
35531
  return availability.installed ? "detected" : "not_detected";
35430
35532
  }
@@ -35552,7 +35654,7 @@ var init_provider_loader = __esm({
35552
35654
  }
35553
35655
  getAvailableProviderInfos() {
35554
35656
  return this.getAll().map((provider) => {
35555
- const availability = this.providerAvailability.get(provider.type);
35657
+ const availability = this.getEffectiveProviderAvailability(provider.type);
35556
35658
  const enabled = this.isMachineProviderEnabled(provider.type);
35557
35659
  const machineConfig = this.getMachineProviderConfig(provider.type);
35558
35660
  return {
@@ -35638,7 +35740,7 @@ var init_provider_loader = __esm({
35638
35740
  const loaded = this.loadScriptsFromDir(type, entry.scriptDir);
35639
35741
  if (loaded) {
35640
35742
  resolved.scripts = loaded;
35641
- this.log(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
35743
+ this.debugLog(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
35642
35744
  resolved._resolvedScriptDir = entry.scriptDir;
35643
35745
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
35644
35746
  if (providerDir) {
@@ -35654,7 +35756,7 @@ var init_provider_loader = __esm({
35654
35756
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
35655
35757
  if (loaded) {
35656
35758
  resolved.scripts = loaded;
35657
- this.log(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
35759
+ this.debugLog(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
35658
35760
  resolved._resolvedScriptDir = base.defaultScriptDir;
35659
35761
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
35660
35762
  if (providerDir) {
@@ -35689,7 +35791,7 @@ var init_provider_loader = __esm({
35689
35791
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
35690
35792
  if (loaded) {
35691
35793
  resolved.scripts = loaded;
35692
- this.log(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
35794
+ this.debugLog(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
35693
35795
  resolved._resolvedScriptDir = base.defaultScriptDir;
35694
35796
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
35695
35797
  if (providerDir) {
@@ -56071,7 +56173,7 @@ var init_adhdev_daemon = __esm({
56071
56173
  init_version();
56072
56174
  init_src();
56073
56175
  init_runtime_defaults();
56074
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.31" });
56176
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.33" });
56075
56177
  AdhdevDaemon = class _AdhdevDaemon {
56076
56178
  localHttpServer = null;
56077
56179
  localWss = null;
@@ -56085,8 +56187,12 @@ var init_adhdev_daemon = __esm({
56085
56187
  pendingP2PChatFlush = false;
56086
56188
  pendingP2PChatFlushOnlyActive = true;
56087
56189
  hotP2PChatSessionIds = /* @__PURE__ */ new Set();
56190
+ p2pChatOutputActiveAt = /* @__PURE__ */ new Map();
56191
+ p2pChatOutputFlushTimer = null;
56088
56192
  hotChatSnapshotCache = null;
56089
56193
  static HOT_CHAT_SNAPSHOT_CACHE_TTL_MS = 1500;
56194
+ static CHAT_OUTPUT_ACTIVITY_HOT_MS = DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS;
56195
+ static CHAT_OUTPUT_FLUSH_DEBOUNCE_MS = 700;
56090
56196
  components = null;
56091
56197
  sessionHostEndpoint = null;
56092
56198
  sessionHostController = null;
@@ -56271,6 +56377,26 @@ var init_adhdev_daemon = __esm({
56271
56377
  invalidateHotChatSnapshotCache() {
56272
56378
  this.hotChatSnapshotCache = null;
56273
56379
  }
56380
+ getRecentlyOutputActiveChatSessionIds(now) {
56381
+ const active = /* @__PURE__ */ new Set();
56382
+ for (const [sessionId, lastOutputAt] of this.p2pChatOutputActiveAt) {
56383
+ if (now - lastOutputAt <= _AdhdevDaemon.CHAT_OUTPUT_ACTIVITY_HOT_MS) {
56384
+ active.add(sessionId);
56385
+ } else {
56386
+ this.p2pChatOutputActiveAt.delete(sessionId);
56387
+ }
56388
+ }
56389
+ return active;
56390
+ }
56391
+ markP2PChatOutputActivity(sessionId) {
56392
+ if (!sessionId || !this.isCliSession(sessionId)) return;
56393
+ this.p2pChatOutputActiveAt.set(sessionId, Date.now());
56394
+ if (this.p2pChatOutputFlushTimer || !this.p2p?.isConnected || !this.p2p.hasChatSubscriptions()) return;
56395
+ this.p2pChatOutputFlushTimer = setTimeout(() => {
56396
+ this.p2pChatOutputFlushTimer = null;
56397
+ void this.flushP2PChatSubscriptions({ onlyActive: true });
56398
+ }, _AdhdevDaemon.CHAT_OUTPUT_FLUSH_DEBOUNCE_MS);
56399
+ }
56274
56400
  getHotChatSessionIdsForP2PFlush() {
56275
56401
  const now = Date.now();
56276
56402
  const cached2 = this.hotChatSnapshotCache;
@@ -56281,7 +56407,8 @@ var init_adhdev_daemon = __esm({
56281
56407
  })();
56282
56408
  const hotSessions = classifyHotChatSessionsForSubscriptionFlush(
56283
56409
  sessions,
56284
- this.hotP2PChatSessionIds
56410
+ this.hotP2PChatSessionIds,
56411
+ { activeSessionIds: this.getRecentlyOutputActiveChatSessionIds(now) }
56285
56412
  );
56286
56413
  this.hotP2PChatSessionIds = hotSessions.active;
56287
56414
  return hotSessions;
@@ -56506,6 +56633,7 @@ ${err?.stack || ""}`);
56506
56633
  getP2p: () => ({
56507
56634
  broadcastSessionOutput: (key, data) => {
56508
56635
  if (!this.isCliSession(key)) return;
56636
+ this.markP2PChatOutputActivity(key);
56509
56637
  this.p2p?.broadcastSessionOutput(key, data);
56510
56638
  }
56511
56639
  }),