adhdev 0.9.30 → 0.9.32

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;
@@ -7693,6 +7697,7 @@ async function handleReadChat(h, args) {
7693
7697
  return { success: false, error: `${transport} adapter not found` };
7694
7698
  }
7695
7699
  if (isExtensionTransport(transport)) {
7700
+ let extensionReadChatError = "";
7696
7701
  try {
7697
7702
  const evalResult = await h.evaluateProviderScript("readChat", void 0, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
7698
7703
  if (evalResult?.result) {
@@ -7700,7 +7705,8 @@ async function handleReadChat(h, args) {
7700
7705
  if (typeof parsed === "string") {
7701
7706
  try {
7702
7707
  parsed = JSON.parse(parsed);
7703
- } catch {
7708
+ } catch (e) {
7709
+ extensionReadChatError = `extension read_chat parse failed: ${e?.message || String(e)}`;
7704
7710
  }
7705
7711
  }
7706
7712
  if (parsed && typeof parsed === "object") {
@@ -7725,8 +7731,14 @@ async function handleReadChat(h, args) {
7725
7731
  );
7726
7732
  return buildReadChatCommandResult(validated, args);
7727
7733
  }
7734
+ if (!extensionReadChatError) {
7735
+ extensionReadChatError = "extension read_chat returned a non-object payload";
7736
+ }
7737
+ } else {
7738
+ extensionReadChatError = "extension read_chat returned no payload";
7728
7739
  }
7729
7740
  } catch (e) {
7741
+ extensionReadChatError = `extension read_chat failed: ${e?.message || String(e)}`;
7730
7742
  _log(`Extension error: ${e.message}`);
7731
7743
  traceProviderEvent(args, "provider", "extension.read_chat.error", {
7732
7744
  h,
@@ -7740,8 +7752,8 @@ async function handleReadChat(h, args) {
7740
7752
  const parentSessionId = h.currentSession?.parentSessionId;
7741
7753
  if (cdp2 && parentSessionId) {
7742
7754
  const stream = await h.agentStream.collectActiveSession(cdp2, parentSessionId);
7743
- if (stream?.agentType !== provider?.type) {
7744
- return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
7755
+ if (stream && stream.agentType !== provider?.type) {
7756
+ return { success: false, error: `extension read_chat stream agent mismatch for ${provider?.type || "unknown_extension"}` };
7745
7757
  }
7746
7758
  if (stream) {
7747
7759
  h.historyWriter.appendNewMessages(
@@ -7759,12 +7771,13 @@ async function handleReadChat(h, args) {
7759
7771
  }
7760
7772
  }
7761
7773
  }
7762
- return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
7774
+ return { success: false, error: extensionReadChatError || "extension read_chat unavailable" };
7763
7775
  }
7764
7776
  const cdp = h.getCdp();
7765
7777
  if (!cdp?.isConnected) return { success: false, error: "CDP not connected" };
7766
7778
  const webviewScript = h.getProviderScript("webviewReadChat") || h.getProviderScript("webview_read_chat");
7767
7779
  if (webviewScript) {
7780
+ let webviewReadChatError = "";
7768
7781
  try {
7769
7782
  const matchText = provider?.webviewMatchText;
7770
7783
  const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
@@ -7774,7 +7787,8 @@ async function handleReadChat(h, args) {
7774
7787
  if (typeof parsed === "string") {
7775
7788
  try {
7776
7789
  parsed = JSON.parse(parsed);
7777
- } catch {
7790
+ } catch (e) {
7791
+ webviewReadChatError = `webview read_chat parse failed: ${e?.message || String(e)}`;
7778
7792
  }
7779
7793
  }
7780
7794
  if (parsed && typeof parsed === "object") {
@@ -7789,14 +7803,21 @@ async function handleReadChat(h, args) {
7789
7803
  );
7790
7804
  return buildReadChatCommandResult(validated, args);
7791
7805
  }
7806
+ if (!webviewReadChatError) {
7807
+ webviewReadChatError = "webview read_chat returned a non-object payload";
7808
+ }
7809
+ } else {
7810
+ webviewReadChatError = "webview read_chat returned no payload";
7792
7811
  }
7793
7812
  } catch (e) {
7813
+ webviewReadChatError = `webview read_chat failed: ${e?.message || String(e)}`;
7794
7814
  _log(`Webview readChat error: ${e.message}`);
7795
7815
  }
7796
- return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
7816
+ return { success: false, error: webviewReadChatError || "webview read_chat unavailable" };
7797
7817
  }
7798
7818
  const script = h.getProviderScript("readChat") || h.getProviderScript("read_chat");
7799
7819
  if (script) {
7820
+ let ideReadChatError = "";
7800
7821
  try {
7801
7822
  const evalResult = await h.evaluateProviderScript("readChat", void 0, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
7802
7823
  if (evalResult?.result) {
@@ -7804,12 +7825,13 @@ async function handleReadChat(h, args) {
7804
7825
  if (typeof parsed === "string") {
7805
7826
  try {
7806
7827
  parsed = JSON.parse(parsed);
7807
- } catch {
7828
+ } catch (e) {
7829
+ ideReadChatError = `ide read_chat parse failed: ${e?.message || String(e)}`;
7808
7830
  }
7809
7831
  }
7810
- if (parsed && typeof parsed === "object" && parsed.messages?.length > 0) {
7832
+ if (parsed && typeof parsed === "object") {
7811
7833
  const validated = validateReadChatResultPayload(parsed, "ide read_chat");
7812
- _log(`OK: ${validated.messages?.length} msgs`);
7834
+ _log(`OK: ${validated.messages?.length || 0} msgs`);
7813
7835
  traceProviderEvent(args, "provider", "ide.read_chat.success", {
7814
7836
  h,
7815
7837
  provider,
@@ -7829,8 +7851,14 @@ async function handleReadChat(h, args) {
7829
7851
  );
7830
7852
  return buildReadChatCommandResult(validated, args);
7831
7853
  }
7854
+ if (!ideReadChatError) {
7855
+ ideReadChatError = "ide read_chat returned a non-object payload";
7856
+ }
7857
+ } else {
7858
+ ideReadChatError = "ide read_chat returned no payload";
7832
7859
  }
7833
7860
  } catch (e) {
7861
+ ideReadChatError = `ide read_chat failed: ${e?.message || String(e)}`;
7834
7862
  LOG.info("Command", `[read_chat] Script error: ${e.message}`);
7835
7863
  traceProviderEvent(args, "provider", "ide.read_chat.error", {
7836
7864
  h,
@@ -7839,8 +7867,9 @@ async function handleReadChat(h, args) {
7839
7867
  payload: { method: "evaluate", error: e.message }
7840
7868
  });
7841
7869
  }
7870
+ return { success: false, error: ideReadChatError || "ide read_chat unavailable" };
7842
7871
  }
7843
- return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
7872
+ return { success: false, error: "read_chat unavailable" };
7844
7873
  }
7845
7874
  async function handleSendChat(h, args) {
7846
7875
  const input = getSendChatInputEnvelope(args);
@@ -11815,6 +11844,7 @@ var init_provider_cli_adapter = __esm({
11815
11844
  static STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS = 1e3;
11816
11845
  static SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
11817
11846
  static MAX_TRACE_ENTRIES = 250;
11847
+ static PARSE_MESSAGE_TAIL_LIMIT = 100;
11818
11848
  providerResolutionMeta;
11819
11849
  static FINISH_RETRY_DELAY_MS = 300;
11820
11850
  static MAX_FINISH_RETRIES = 2;
@@ -11846,6 +11876,32 @@ var init_provider_cli_adapter = __esm({
11846
11876
  }
11847
11877
  return null;
11848
11878
  }
11879
+ selectParseBaseMessages(baseMessages) {
11880
+ if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
11881
+ return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
11882
+ }
11883
+ messagesComparable(left2, right2) {
11884
+ if (!left2 || !right2) return false;
11885
+ if ((left2.role || "") !== (right2.role || "")) return false;
11886
+ const leftText = normalizeComparableTranscriptText(left2.content);
11887
+ const rightText = normalizeComparableTranscriptText(right2.content);
11888
+ return !!leftText && leftText === rightText;
11889
+ }
11890
+ stitchParsedMessagesWithCommittedBase(parsedMessages, fullBaseMessages, parseBaseMessages) {
11891
+ if (!Array.isArray(parsedMessages) || parsedMessages.length === 0) return parsedMessages;
11892
+ if (fullBaseMessages.length <= parseBaseMessages.length) return parsedMessages;
11893
+ const parsedFirst = parsedMessages[0];
11894
+ const fullFirst = fullBaseMessages[0];
11895
+ if (parsedMessages.length >= fullBaseMessages.length && this.messagesComparable(parsedFirst, fullFirst)) {
11896
+ return parsedMessages;
11897
+ }
11898
+ const tailFirst = parseBaseMessages[0];
11899
+ if (tailFirst && this.messagesComparable(parsedFirst, tailFirst)) {
11900
+ const prefixLength = fullBaseMessages.length - parseBaseMessages.length;
11901
+ return [...fullBaseMessages.slice(0, prefixLength), ...parsedMessages];
11902
+ }
11903
+ return [...fullBaseMessages, ...parsedMessages];
11904
+ }
11849
11905
  getIdleFinishConfirmMs() {
11850
11906
  return this.timeouts.idleFinishConfirm;
11851
11907
  }
@@ -12431,7 +12487,7 @@ var init_provider_cli_adapter = __esm({
12431
12487
  const ctx = { now, modal, status, parsedMessages, lastParsedAssistant, parsedStatus: parsedStatus || null, prevStatus };
12432
12488
  if (!this.applyPendingScriptStatusDebounce(ctx)) return;
12433
12489
  const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
12434
- LOG.info(
12490
+ LOG.debug(
12435
12491
  "CLI",
12436
12492
  `[${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)}`
12437
12493
  );
@@ -12798,18 +12854,26 @@ var init_provider_cli_adapter = __esm({
12798
12854
  try {
12799
12855
  const screenText = this.terminalScreen.getText();
12800
12856
  const tail = this.recentOutputBuffer.slice(-500);
12857
+ const parseBaseMessages = this.selectParseBaseMessages(this.committedMessages);
12801
12858
  const input = buildCliParseInput({
12802
12859
  accumulatedBuffer: this.accumulatedBuffer,
12803
12860
  accumulatedRawBuffer: this.accumulatedRawBuffer,
12804
12861
  recentOutputBuffer: this.recentOutputBuffer,
12805
12862
  terminalScreenText: screenText,
12806
- baseMessages: this.committedMessages,
12863
+ baseMessages: parseBaseMessages,
12807
12864
  partialResponse: this.responseBuffer,
12808
12865
  isWaitingForResponse: this.isWaitingForResponse,
12809
12866
  scope: this.currentTurnScope,
12810
12867
  runtimeSettings: this.runtimeSettings
12811
12868
  });
12812
12869
  const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
12870
+ if (session && typeof session === "object" && Array.isArray(session.messages)) {
12871
+ session.messages = this.stitchParsedMessagesWithCommittedBase(
12872
+ session.messages,
12873
+ this.committedMessages,
12874
+ parseBaseMessages
12875
+ );
12876
+ }
12813
12877
  this.parseErrorMessage = null;
12814
12878
  return session && typeof session === "object" ? session : null;
12815
12879
  } catch (e) {
@@ -13130,12 +13194,13 @@ var init_provider_cli_adapter = __esm({
13130
13194
  }
13131
13195
  try {
13132
13196
  const screenText = typeof screenTextOverride === "string" ? screenTextOverride : this.terminalScreen.getText();
13197
+ const parseBaseMessages = this.selectParseBaseMessages(baseMessages);
13133
13198
  const input = buildCliParseInput({
13134
13199
  accumulatedBuffer: this.accumulatedBuffer,
13135
13200
  accumulatedRawBuffer: this.accumulatedRawBuffer,
13136
13201
  recentOutputBuffer: this.recentOutputBuffer,
13137
13202
  terminalScreenText: screenText,
13138
- baseMessages,
13203
+ baseMessages: parseBaseMessages,
13139
13204
  partialResponse,
13140
13205
  isWaitingForResponse: this.isWaitingForResponse,
13141
13206
  scope,
@@ -13147,6 +13212,11 @@ var init_provider_cli_adapter = __esm({
13147
13212
  }
13148
13213
  const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
13149
13214
  if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
13215
+ normalizedParsed.messages = this.stitchParsedMessagesWithCommittedBase(
13216
+ normalizedParsed.messages,
13217
+ baseMessages,
13218
+ parseBaseMessages
13219
+ );
13150
13220
  this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
13151
13221
  }
13152
13222
  this.parseErrorMessage = null;
@@ -35007,6 +35077,9 @@ var init_provider_loader = __esm({
35007
35077
  log(msg) {
35008
35078
  this.logFn(`[ProviderLoader] ${msg}`);
35009
35079
  }
35080
+ debugLog(msg) {
35081
+ LOG.debug("Provider", `[ProviderLoader] ${msg}`);
35082
+ }
35010
35083
  // ─── Public API ────────────────────────────────
35011
35084
  /**
35012
35085
  * User override root (~/.adhdev/providers by default).
@@ -35613,7 +35686,7 @@ var init_provider_loader = __esm({
35613
35686
  const loaded = this.loadScriptsFromDir(type, entry.scriptDir);
35614
35687
  if (loaded) {
35615
35688
  resolved.scripts = loaded;
35616
- this.log(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
35689
+ this.debugLog(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
35617
35690
  resolved._resolvedScriptDir = entry.scriptDir;
35618
35691
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
35619
35692
  if (providerDir) {
@@ -35629,7 +35702,7 @@ var init_provider_loader = __esm({
35629
35702
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
35630
35703
  if (loaded) {
35631
35704
  resolved.scripts = loaded;
35632
- this.log(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
35705
+ this.debugLog(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
35633
35706
  resolved._resolvedScriptDir = base.defaultScriptDir;
35634
35707
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
35635
35708
  if (providerDir) {
@@ -35664,7 +35737,7 @@ var init_provider_loader = __esm({
35664
35737
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
35665
35738
  if (loaded) {
35666
35739
  resolved.scripts = loaded;
35667
- this.log(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
35740
+ this.debugLog(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
35668
35741
  resolved._resolvedScriptDir = base.defaultScriptDir;
35669
35742
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
35670
35743
  if (providerDir) {
@@ -56046,7 +56119,7 @@ var init_adhdev_daemon = __esm({
56046
56119
  init_version();
56047
56120
  init_src();
56048
56121
  init_runtime_defaults();
56049
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.30" });
56122
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.32" });
56050
56123
  AdhdevDaemon = class _AdhdevDaemon {
56051
56124
  localHttpServer = null;
56052
56125
  localWss = null;
@@ -56060,8 +56133,12 @@ var init_adhdev_daemon = __esm({
56060
56133
  pendingP2PChatFlush = false;
56061
56134
  pendingP2PChatFlushOnlyActive = true;
56062
56135
  hotP2PChatSessionIds = /* @__PURE__ */ new Set();
56136
+ p2pChatOutputActiveAt = /* @__PURE__ */ new Map();
56137
+ p2pChatOutputFlushTimer = null;
56063
56138
  hotChatSnapshotCache = null;
56064
56139
  static HOT_CHAT_SNAPSHOT_CACHE_TTL_MS = 1500;
56140
+ static CHAT_OUTPUT_ACTIVITY_HOT_MS = DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS;
56141
+ static CHAT_OUTPUT_FLUSH_DEBOUNCE_MS = 700;
56065
56142
  components = null;
56066
56143
  sessionHostEndpoint = null;
56067
56144
  sessionHostController = null;
@@ -56246,6 +56323,26 @@ var init_adhdev_daemon = __esm({
56246
56323
  invalidateHotChatSnapshotCache() {
56247
56324
  this.hotChatSnapshotCache = null;
56248
56325
  }
56326
+ getRecentlyOutputActiveChatSessionIds(now) {
56327
+ const active = /* @__PURE__ */ new Set();
56328
+ for (const [sessionId, lastOutputAt] of this.p2pChatOutputActiveAt) {
56329
+ if (now - lastOutputAt <= _AdhdevDaemon.CHAT_OUTPUT_ACTIVITY_HOT_MS) {
56330
+ active.add(sessionId);
56331
+ } else {
56332
+ this.p2pChatOutputActiveAt.delete(sessionId);
56333
+ }
56334
+ }
56335
+ return active;
56336
+ }
56337
+ markP2PChatOutputActivity(sessionId) {
56338
+ if (!sessionId || !this.isCliSession(sessionId)) return;
56339
+ this.p2pChatOutputActiveAt.set(sessionId, Date.now());
56340
+ if (this.p2pChatOutputFlushTimer || !this.p2p?.isConnected || !this.p2p.hasChatSubscriptions()) return;
56341
+ this.p2pChatOutputFlushTimer = setTimeout(() => {
56342
+ this.p2pChatOutputFlushTimer = null;
56343
+ void this.flushP2PChatSubscriptions({ onlyActive: true });
56344
+ }, _AdhdevDaemon.CHAT_OUTPUT_FLUSH_DEBOUNCE_MS);
56345
+ }
56249
56346
  getHotChatSessionIdsForP2PFlush() {
56250
56347
  const now = Date.now();
56251
56348
  const cached2 = this.hotChatSnapshotCache;
@@ -56256,7 +56353,8 @@ var init_adhdev_daemon = __esm({
56256
56353
  })();
56257
56354
  const hotSessions = classifyHotChatSessionsForSubscriptionFlush(
56258
56355
  sessions,
56259
- this.hotP2PChatSessionIds
56356
+ this.hotP2PChatSessionIds,
56357
+ { activeSessionIds: this.getRecentlyOutputActiveChatSessionIds(now) }
56260
56358
  );
56261
56359
  this.hotP2PChatSessionIds = hotSessions.active;
56262
56360
  return hotSessions;
@@ -56481,6 +56579,7 @@ ${err?.stack || ""}`);
56481
56579
  getP2p: () => ({
56482
56580
  broadcastSessionOutput: (key, data) => {
56483
56581
  if (!this.isCliSession(key)) return;
56582
+ this.markP2PChatOutputActivity(key);
56484
56583
  this.p2p?.broadcastSessionOutput(key, data);
56485
56584
  }
56486
56585
  }),