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/cli/index.js CHANGED
@@ -1738,6 +1738,7 @@ function classifyHotChatSessionsForSubscriptionFlush(sessions, previousHotSessio
1738
1738
  Number.isFinite(options.recentMessageGraceMs) ? Number(options.recentMessageGraceMs) : DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS
1739
1739
  );
1740
1740
  const activeStatuses = options.activeStatuses ?? DEFAULT_ACTIVE_CHAT_POLL_STATUSES;
1741
+ const activeSessionIds = options.activeSessionIds ?? /* @__PURE__ */ new Set();
1741
1742
  const active = /* @__PURE__ */ new Set();
1742
1743
  const excluded = /* @__PURE__ */ new Set();
1743
1744
  for (const session of sessions) {
@@ -1747,6 +1748,10 @@ function classifyHotChatSessionsForSubscriptionFlush(sessions, previousHotSessio
1747
1748
  excluded.add(sessionId);
1748
1749
  continue;
1749
1750
  }
1751
+ if (activeSessionIds.has(sessionId)) {
1752
+ active.add(sessionId);
1753
+ continue;
1754
+ }
1750
1755
  const status = String(session?.status || "").toLowerCase();
1751
1756
  const unread = session?.unread === true;
1752
1757
  const inboxBucket = String(session?.inboxBucket || "").toLowerCase();
@@ -1862,14 +1867,13 @@ function daemonLog(category, msg, level = "info") {
1862
1867
  const shouldOutput = LEVEL_NUM[level] >= LEVEL_NUM[currentLevel];
1863
1868
  const label = LEVEL_LABEL[level];
1864
1869
  const line = `[${ts()}] [${label}] [${category}] ${msg}`;
1870
+ if (!shouldOutput) return;
1865
1871
  writeToFile(line);
1866
1872
  ringBuffer.push({ ts: Date.now(), level, category, message: msg });
1867
1873
  if (ringBuffer.length > RING_BUFFER_SIZE) {
1868
1874
  ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
1869
1875
  }
1870
- if (shouldOutput) {
1871
- origConsoleLog(line);
1872
- }
1876
+ origConsoleLog(line);
1873
1877
  }
1874
1878
  function installGlobalInterceptor() {
1875
1879
  if (interceptorInstalled) return;
@@ -7977,6 +7981,26 @@ function toHistoryPersistedMessages(messages) {
7977
7981
  historyDedupKey: deriveHistoryDedupKey(message)
7978
7982
  }));
7979
7983
  }
7984
+ function findLastMessageIndexBySignature(messages, signature) {
7985
+ if (!signature) return -1;
7986
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
7987
+ if (getChatMessageSignature(messages[index]) === signature) {
7988
+ return index;
7989
+ }
7990
+ }
7991
+ return -1;
7992
+ }
7993
+ function buildBoundedTailSync(messages, cursor) {
7994
+ const totalMessages = messages.length;
7995
+ const tailMessages = cursor.tailLimit > 0 && totalMessages > cursor.tailLimit ? messages.slice(-cursor.tailLimit) : messages;
7996
+ return {
7997
+ syncMode: "full",
7998
+ replaceFrom: 0,
7999
+ messages: tailMessages,
8000
+ totalMessages,
8001
+ lastMessageSignature: getChatMessageSignature(messages[totalMessages - 1])
8002
+ };
8003
+ }
7980
8004
  function computeReadChatSync(messages, cursor) {
7981
8005
  const totalMessages = messages.length;
7982
8006
  const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
@@ -8008,6 +8032,15 @@ function computeReadChatSync(messages, cursor) {
8008
8032
  lastMessageSignature
8009
8033
  };
8010
8034
  }
8035
+ if (cursor.tailLimit > 0 && knownSignature === lastMessageSignature) {
8036
+ return {
8037
+ syncMode: "noop",
8038
+ replaceFrom: totalMessages,
8039
+ messages: [],
8040
+ totalMessages,
8041
+ lastMessageSignature
8042
+ };
8043
+ }
8011
8044
  if (knownMessageCount < totalMessages) {
8012
8045
  const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
8013
8046
  if (anchorSignature === knownSignature) {
@@ -8019,6 +8052,19 @@ function computeReadChatSync(messages, cursor) {
8019
8052
  lastMessageSignature
8020
8053
  };
8021
8054
  }
8055
+ if (cursor.tailLimit > 0) {
8056
+ const signatureIndex = findLastMessageIndexBySignature(messages, knownSignature);
8057
+ if (signatureIndex >= 0) {
8058
+ return {
8059
+ syncMode: "append",
8060
+ replaceFrom: knownMessageCount,
8061
+ messages: messages.slice(signatureIndex + 1),
8062
+ totalMessages,
8063
+ lastMessageSignature
8064
+ };
8065
+ }
8066
+ return buildBoundedTailSync(messages, cursor);
8067
+ }
8022
8068
  }
8023
8069
  const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
8024
8070
  return {
@@ -12796,6 +12842,7 @@ var init_provider_cli_adapter = __esm({
12796
12842
  static STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS = 1e3;
12797
12843
  static SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
12798
12844
  static MAX_TRACE_ENTRIES = 250;
12845
+ static PARSE_MESSAGE_TAIL_LIMIT = 100;
12799
12846
  providerResolutionMeta;
12800
12847
  static FINISH_RETRY_DELAY_MS = 300;
12801
12848
  static MAX_FINISH_RETRIES = 2;
@@ -12827,6 +12874,32 @@ var init_provider_cli_adapter = __esm({
12827
12874
  }
12828
12875
  return null;
12829
12876
  }
12877
+ selectParseBaseMessages(baseMessages) {
12878
+ if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
12879
+ return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
12880
+ }
12881
+ messagesComparable(left2, right2) {
12882
+ if (!left2 || !right2) return false;
12883
+ if ((left2.role || "") !== (right2.role || "")) return false;
12884
+ const leftText = normalizeComparableTranscriptText(left2.content);
12885
+ const rightText = normalizeComparableTranscriptText(right2.content);
12886
+ return !!leftText && leftText === rightText;
12887
+ }
12888
+ stitchParsedMessagesWithCommittedBase(parsedMessages, fullBaseMessages, parseBaseMessages) {
12889
+ if (!Array.isArray(parsedMessages) || parsedMessages.length === 0) return parsedMessages;
12890
+ if (fullBaseMessages.length <= parseBaseMessages.length) return parsedMessages;
12891
+ const parsedFirst = parsedMessages[0];
12892
+ const fullFirst = fullBaseMessages[0];
12893
+ if (parsedMessages.length >= fullBaseMessages.length && this.messagesComparable(parsedFirst, fullFirst)) {
12894
+ return parsedMessages;
12895
+ }
12896
+ const tailFirst = parseBaseMessages[0];
12897
+ if (tailFirst && this.messagesComparable(parsedFirst, tailFirst)) {
12898
+ const prefixLength = fullBaseMessages.length - parseBaseMessages.length;
12899
+ return [...fullBaseMessages.slice(0, prefixLength), ...parsedMessages];
12900
+ }
12901
+ return [...fullBaseMessages, ...parsedMessages];
12902
+ }
12830
12903
  getIdleFinishConfirmMs() {
12831
12904
  return this.timeouts.idleFinishConfirm;
12832
12905
  }
@@ -13412,7 +13485,7 @@ var init_provider_cli_adapter = __esm({
13412
13485
  const ctx = { now, modal, status, parsedMessages, lastParsedAssistant, parsedStatus: parsedStatus || null, prevStatus };
13413
13486
  if (!this.applyPendingScriptStatusDebounce(ctx)) return;
13414
13487
  const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
13415
- LOG.info(
13488
+ LOG.debug(
13416
13489
  "CLI",
13417
13490
  `[${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)}`
13418
13491
  );
@@ -13779,18 +13852,26 @@ var init_provider_cli_adapter = __esm({
13779
13852
  try {
13780
13853
  const screenText = this.terminalScreen.getText();
13781
13854
  const tail = this.recentOutputBuffer.slice(-500);
13855
+ const parseBaseMessages = this.selectParseBaseMessages(this.committedMessages);
13782
13856
  const input = buildCliParseInput({
13783
13857
  accumulatedBuffer: this.accumulatedBuffer,
13784
13858
  accumulatedRawBuffer: this.accumulatedRawBuffer,
13785
13859
  recentOutputBuffer: this.recentOutputBuffer,
13786
13860
  terminalScreenText: screenText,
13787
- baseMessages: this.committedMessages,
13861
+ baseMessages: parseBaseMessages,
13788
13862
  partialResponse: this.responseBuffer,
13789
13863
  isWaitingForResponse: this.isWaitingForResponse,
13790
13864
  scope: this.currentTurnScope,
13791
13865
  runtimeSettings: this.runtimeSettings
13792
13866
  });
13793
13867
  const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
13868
+ if (session && typeof session === "object" && Array.isArray(session.messages)) {
13869
+ session.messages = this.stitchParsedMessagesWithCommittedBase(
13870
+ session.messages,
13871
+ this.committedMessages,
13872
+ parseBaseMessages
13873
+ );
13874
+ }
13794
13875
  this.parseErrorMessage = null;
13795
13876
  return session && typeof session === "object" ? session : null;
13796
13877
  } catch (e) {
@@ -14111,12 +14192,13 @@ var init_provider_cli_adapter = __esm({
14111
14192
  }
14112
14193
  try {
14113
14194
  const screenText = typeof screenTextOverride === "string" ? screenTextOverride : this.terminalScreen.getText();
14195
+ const parseBaseMessages = this.selectParseBaseMessages(baseMessages);
14114
14196
  const input = buildCliParseInput({
14115
14197
  accumulatedBuffer: this.accumulatedBuffer,
14116
14198
  accumulatedRawBuffer: this.accumulatedRawBuffer,
14117
14199
  recentOutputBuffer: this.recentOutputBuffer,
14118
14200
  terminalScreenText: screenText,
14119
- baseMessages,
14201
+ baseMessages: parseBaseMessages,
14120
14202
  partialResponse,
14121
14203
  isWaitingForResponse: this.isWaitingForResponse,
14122
14204
  scope,
@@ -14128,6 +14210,11 @@ var init_provider_cli_adapter = __esm({
14128
14210
  }
14129
14211
  const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
14130
14212
  if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
14213
+ normalizedParsed.messages = this.stitchParsedMessagesWithCommittedBase(
14214
+ normalizedParsed.messages,
14215
+ baseMessages,
14216
+ parseBaseMessages
14217
+ );
14131
14218
  this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
14132
14219
  }
14133
14220
  this.parseErrorMessage = null;
@@ -35988,6 +36075,9 @@ var init_provider_loader = __esm({
35988
36075
  log(msg) {
35989
36076
  this.logFn(`[ProviderLoader] ${msg}`);
35990
36077
  }
36078
+ debugLog(msg) {
36079
+ LOG.debug("Provider", `[ProviderLoader] ${msg}`);
36080
+ }
35991
36081
  // ─── Public API ────────────────────────────────
35992
36082
  /**
35993
36083
  * User override root (~/.adhdev/providers by default).
@@ -36377,10 +36467,22 @@ var init_provider_loader = __esm({
36377
36467
  setMachineProviderEnabled(type, enabled) {
36378
36468
  return this.setMachineProviderConfig(type, { enabled });
36379
36469
  }
36470
+ getEffectiveProviderAvailability(type) {
36471
+ const providerType = this.resolveAlias(type);
36472
+ const availability = this.providerAvailability.get(providerType);
36473
+ if (availability) return availability;
36474
+ const machineConfig = this.getMachineProviderConfig(providerType);
36475
+ const lastDetection = machineConfig.lastDetection;
36476
+ if (!lastDetection) return void 0;
36477
+ return {
36478
+ installed: lastDetection.ok === true,
36479
+ detectedPath: typeof lastDetection.path === "string" && lastDetection.path.trim() ? lastDetection.path.trim() : null
36480
+ };
36481
+ }
36380
36482
  getMachineProviderStatus(type) {
36381
36483
  const providerType = this.resolveAlias(type);
36382
36484
  if (!this.isMachineProviderEnabled(providerType)) return "disabled";
36383
- const availability = this.providerAvailability.get(providerType);
36485
+ const availability = this.getEffectiveProviderAvailability(providerType);
36384
36486
  if (!availability) return "enabled_unchecked";
36385
36487
  return availability.installed ? "detected" : "not_detected";
36386
36488
  }
@@ -36508,7 +36610,7 @@ var init_provider_loader = __esm({
36508
36610
  }
36509
36611
  getAvailableProviderInfos() {
36510
36612
  return this.getAll().map((provider) => {
36511
- const availability = this.providerAvailability.get(provider.type);
36613
+ const availability = this.getEffectiveProviderAvailability(provider.type);
36512
36614
  const enabled = this.isMachineProviderEnabled(provider.type);
36513
36615
  const machineConfig = this.getMachineProviderConfig(provider.type);
36514
36616
  return {
@@ -36594,7 +36696,7 @@ var init_provider_loader = __esm({
36594
36696
  const loaded = this.loadScriptsFromDir(type, entry.scriptDir);
36595
36697
  if (loaded) {
36596
36698
  resolved.scripts = loaded;
36597
- this.log(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
36699
+ this.debugLog(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
36598
36700
  resolved._resolvedScriptDir = entry.scriptDir;
36599
36701
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
36600
36702
  if (providerDir) {
@@ -36610,7 +36712,7 @@ var init_provider_loader = __esm({
36610
36712
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
36611
36713
  if (loaded) {
36612
36714
  resolved.scripts = loaded;
36613
- this.log(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
36715
+ this.debugLog(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
36614
36716
  resolved._resolvedScriptDir = base.defaultScriptDir;
36615
36717
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
36616
36718
  if (providerDir) {
@@ -36645,7 +36747,7 @@ var init_provider_loader = __esm({
36645
36747
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
36646
36748
  if (loaded) {
36647
36749
  resolved.scripts = loaded;
36648
- this.log(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
36750
+ this.debugLog(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
36649
36751
  resolved._resolvedScriptDir = base.defaultScriptDir;
36650
36752
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
36651
36753
  if (providerDir) {
@@ -87791,7 +87893,7 @@ var init_adhdev_daemon = __esm({
87791
87893
  init_version();
87792
87894
  init_src();
87793
87895
  init_runtime_defaults();
87794
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.31" });
87896
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.33" });
87795
87897
  AdhdevDaemon = class _AdhdevDaemon {
87796
87898
  localHttpServer = null;
87797
87899
  localWss = null;
@@ -87805,8 +87907,12 @@ var init_adhdev_daemon = __esm({
87805
87907
  pendingP2PChatFlush = false;
87806
87908
  pendingP2PChatFlushOnlyActive = true;
87807
87909
  hotP2PChatSessionIds = /* @__PURE__ */ new Set();
87910
+ p2pChatOutputActiveAt = /* @__PURE__ */ new Map();
87911
+ p2pChatOutputFlushTimer = null;
87808
87912
  hotChatSnapshotCache = null;
87809
87913
  static HOT_CHAT_SNAPSHOT_CACHE_TTL_MS = 1500;
87914
+ static CHAT_OUTPUT_ACTIVITY_HOT_MS = DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS;
87915
+ static CHAT_OUTPUT_FLUSH_DEBOUNCE_MS = 700;
87810
87916
  components = null;
87811
87917
  sessionHostEndpoint = null;
87812
87918
  sessionHostController = null;
@@ -87991,6 +88097,26 @@ var init_adhdev_daemon = __esm({
87991
88097
  invalidateHotChatSnapshotCache() {
87992
88098
  this.hotChatSnapshotCache = null;
87993
88099
  }
88100
+ getRecentlyOutputActiveChatSessionIds(now) {
88101
+ const active = /* @__PURE__ */ new Set();
88102
+ for (const [sessionId, lastOutputAt] of this.p2pChatOutputActiveAt) {
88103
+ if (now - lastOutputAt <= _AdhdevDaemon.CHAT_OUTPUT_ACTIVITY_HOT_MS) {
88104
+ active.add(sessionId);
88105
+ } else {
88106
+ this.p2pChatOutputActiveAt.delete(sessionId);
88107
+ }
88108
+ }
88109
+ return active;
88110
+ }
88111
+ markP2PChatOutputActivity(sessionId) {
88112
+ if (!sessionId || !this.isCliSession(sessionId)) return;
88113
+ this.p2pChatOutputActiveAt.set(sessionId, Date.now());
88114
+ if (this.p2pChatOutputFlushTimer || !this.p2p?.isConnected || !this.p2p.hasChatSubscriptions()) return;
88115
+ this.p2pChatOutputFlushTimer = setTimeout(() => {
88116
+ this.p2pChatOutputFlushTimer = null;
88117
+ void this.flushP2PChatSubscriptions({ onlyActive: true });
88118
+ }, _AdhdevDaemon.CHAT_OUTPUT_FLUSH_DEBOUNCE_MS);
88119
+ }
87994
88120
  getHotChatSessionIdsForP2PFlush() {
87995
88121
  const now = Date.now();
87996
88122
  const cached2 = this.hotChatSnapshotCache;
@@ -88001,7 +88127,8 @@ var init_adhdev_daemon = __esm({
88001
88127
  })();
88002
88128
  const hotSessions = classifyHotChatSessionsForSubscriptionFlush(
88003
88129
  sessions,
88004
- this.hotP2PChatSessionIds
88130
+ this.hotP2PChatSessionIds,
88131
+ { activeSessionIds: this.getRecentlyOutputActiveChatSessionIds(now) }
88005
88132
  );
88006
88133
  this.hotP2PChatSessionIds = hotSessions.active;
88007
88134
  return hotSessions;
@@ -88226,6 +88353,7 @@ ${err?.stack || ""}`);
88226
88353
  getP2p: () => ({
88227
88354
  broadcastSessionOutput: (key, data) => {
88228
88355
  if (!this.isCliSession(key)) return;
88356
+ this.markP2PChatOutputActivity(key);
88229
88357
  this.p2p?.broadcastSessionOutput(key, data);
88230
88358
  }
88231
88359
  }),