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/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;
@@ -8213,6 +8217,7 @@ async function handleReadChat(h, args) {
8213
8217
  return { success: false, error: `${transport} adapter not found` };
8214
8218
  }
8215
8219
  if (isExtensionTransport(transport)) {
8220
+ let extensionReadChatError = "";
8216
8221
  try {
8217
8222
  const evalResult = await h.evaluateProviderScript("readChat", void 0, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
8218
8223
  if (evalResult?.result) {
@@ -8220,7 +8225,8 @@ async function handleReadChat(h, args) {
8220
8225
  if (typeof parsed === "string") {
8221
8226
  try {
8222
8227
  parsed = JSON.parse(parsed);
8223
- } catch {
8228
+ } catch (e) {
8229
+ extensionReadChatError = `extension read_chat parse failed: ${e?.message || String(e)}`;
8224
8230
  }
8225
8231
  }
8226
8232
  if (parsed && typeof parsed === "object") {
@@ -8245,8 +8251,14 @@ async function handleReadChat(h, args) {
8245
8251
  );
8246
8252
  return buildReadChatCommandResult(validated, args);
8247
8253
  }
8254
+ if (!extensionReadChatError) {
8255
+ extensionReadChatError = "extension read_chat returned a non-object payload";
8256
+ }
8257
+ } else {
8258
+ extensionReadChatError = "extension read_chat returned no payload";
8248
8259
  }
8249
8260
  } catch (e) {
8261
+ extensionReadChatError = `extension read_chat failed: ${e?.message || String(e)}`;
8250
8262
  _log(`Extension error: ${e.message}`);
8251
8263
  traceProviderEvent(args, "provider", "extension.read_chat.error", {
8252
8264
  h,
@@ -8260,8 +8272,8 @@ async function handleReadChat(h, args) {
8260
8272
  const parentSessionId = h.currentSession?.parentSessionId;
8261
8273
  if (cdp2 && parentSessionId) {
8262
8274
  const stream = await h.agentStream.collectActiveSession(cdp2, parentSessionId);
8263
- if (stream?.agentType !== provider?.type) {
8264
- return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
8275
+ if (stream && stream.agentType !== provider?.type) {
8276
+ return { success: false, error: `extension read_chat stream agent mismatch for ${provider?.type || "unknown_extension"}` };
8265
8277
  }
8266
8278
  if (stream) {
8267
8279
  h.historyWriter.appendNewMessages(
@@ -8279,12 +8291,13 @@ async function handleReadChat(h, args) {
8279
8291
  }
8280
8292
  }
8281
8293
  }
8282
- return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
8294
+ return { success: false, error: extensionReadChatError || "extension read_chat unavailable" };
8283
8295
  }
8284
8296
  const cdp = h.getCdp();
8285
8297
  if (!cdp?.isConnected) return { success: false, error: "CDP not connected" };
8286
8298
  const webviewScript = h.getProviderScript("webviewReadChat") || h.getProviderScript("webview_read_chat");
8287
8299
  if (webviewScript) {
8300
+ let webviewReadChatError = "";
8288
8301
  try {
8289
8302
  const matchText = provider?.webviewMatchText;
8290
8303
  const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
@@ -8294,7 +8307,8 @@ async function handleReadChat(h, args) {
8294
8307
  if (typeof parsed === "string") {
8295
8308
  try {
8296
8309
  parsed = JSON.parse(parsed);
8297
- } catch {
8310
+ } catch (e) {
8311
+ webviewReadChatError = `webview read_chat parse failed: ${e?.message || String(e)}`;
8298
8312
  }
8299
8313
  }
8300
8314
  if (parsed && typeof parsed === "object") {
@@ -8309,14 +8323,21 @@ async function handleReadChat(h, args) {
8309
8323
  );
8310
8324
  return buildReadChatCommandResult(validated, args);
8311
8325
  }
8326
+ if (!webviewReadChatError) {
8327
+ webviewReadChatError = "webview read_chat returned a non-object payload";
8328
+ }
8329
+ } else {
8330
+ webviewReadChatError = "webview read_chat returned no payload";
8312
8331
  }
8313
8332
  } catch (e) {
8333
+ webviewReadChatError = `webview read_chat failed: ${e?.message || String(e)}`;
8314
8334
  _log(`Webview readChat error: ${e.message}`);
8315
8335
  }
8316
- return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
8336
+ return { success: false, error: webviewReadChatError || "webview read_chat unavailable" };
8317
8337
  }
8318
8338
  const script = h.getProviderScript("readChat") || h.getProviderScript("read_chat");
8319
8339
  if (script) {
8340
+ let ideReadChatError = "";
8320
8341
  try {
8321
8342
  const evalResult = await h.evaluateProviderScript("readChat", void 0, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
8322
8343
  if (evalResult?.result) {
@@ -8324,12 +8345,13 @@ async function handleReadChat(h, args) {
8324
8345
  if (typeof parsed === "string") {
8325
8346
  try {
8326
8347
  parsed = JSON.parse(parsed);
8327
- } catch {
8348
+ } catch (e) {
8349
+ ideReadChatError = `ide read_chat parse failed: ${e?.message || String(e)}`;
8328
8350
  }
8329
8351
  }
8330
- if (parsed && typeof parsed === "object" && parsed.messages?.length > 0) {
8352
+ if (parsed && typeof parsed === "object") {
8331
8353
  const validated = validateReadChatResultPayload(parsed, "ide read_chat");
8332
- _log(`OK: ${validated.messages?.length} msgs`);
8354
+ _log(`OK: ${validated.messages?.length || 0} msgs`);
8333
8355
  traceProviderEvent(args, "provider", "ide.read_chat.success", {
8334
8356
  h,
8335
8357
  provider,
@@ -8349,8 +8371,14 @@ async function handleReadChat(h, args) {
8349
8371
  );
8350
8372
  return buildReadChatCommandResult(validated, args);
8351
8373
  }
8374
+ if (!ideReadChatError) {
8375
+ ideReadChatError = "ide read_chat returned a non-object payload";
8376
+ }
8377
+ } else {
8378
+ ideReadChatError = "ide read_chat returned no payload";
8352
8379
  }
8353
8380
  } catch (e) {
8381
+ ideReadChatError = `ide read_chat failed: ${e?.message || String(e)}`;
8354
8382
  LOG.info("Command", `[read_chat] Script error: ${e.message}`);
8355
8383
  traceProviderEvent(args, "provider", "ide.read_chat.error", {
8356
8384
  h,
@@ -8359,8 +8387,9 @@ async function handleReadChat(h, args) {
8359
8387
  payload: { method: "evaluate", error: e.message }
8360
8388
  });
8361
8389
  }
8390
+ return { success: false, error: ideReadChatError || "ide read_chat unavailable" };
8362
8391
  }
8363
- return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
8392
+ return { success: false, error: "read_chat unavailable" };
8364
8393
  }
8365
8394
  async function handleSendChat(h, args) {
8366
8395
  const input = getSendChatInputEnvelope(args);
@@ -12771,6 +12800,7 @@ var init_provider_cli_adapter = __esm({
12771
12800
  static STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS = 1e3;
12772
12801
  static SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
12773
12802
  static MAX_TRACE_ENTRIES = 250;
12803
+ static PARSE_MESSAGE_TAIL_LIMIT = 100;
12774
12804
  providerResolutionMeta;
12775
12805
  static FINISH_RETRY_DELAY_MS = 300;
12776
12806
  static MAX_FINISH_RETRIES = 2;
@@ -12802,6 +12832,32 @@ var init_provider_cli_adapter = __esm({
12802
12832
  }
12803
12833
  return null;
12804
12834
  }
12835
+ selectParseBaseMessages(baseMessages) {
12836
+ if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
12837
+ return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
12838
+ }
12839
+ messagesComparable(left2, right2) {
12840
+ if (!left2 || !right2) return false;
12841
+ if ((left2.role || "") !== (right2.role || "")) return false;
12842
+ const leftText = normalizeComparableTranscriptText(left2.content);
12843
+ const rightText = normalizeComparableTranscriptText(right2.content);
12844
+ return !!leftText && leftText === rightText;
12845
+ }
12846
+ stitchParsedMessagesWithCommittedBase(parsedMessages, fullBaseMessages, parseBaseMessages) {
12847
+ if (!Array.isArray(parsedMessages) || parsedMessages.length === 0) return parsedMessages;
12848
+ if (fullBaseMessages.length <= parseBaseMessages.length) return parsedMessages;
12849
+ const parsedFirst = parsedMessages[0];
12850
+ const fullFirst = fullBaseMessages[0];
12851
+ if (parsedMessages.length >= fullBaseMessages.length && this.messagesComparable(parsedFirst, fullFirst)) {
12852
+ return parsedMessages;
12853
+ }
12854
+ const tailFirst = parseBaseMessages[0];
12855
+ if (tailFirst && this.messagesComparable(parsedFirst, tailFirst)) {
12856
+ const prefixLength = fullBaseMessages.length - parseBaseMessages.length;
12857
+ return [...fullBaseMessages.slice(0, prefixLength), ...parsedMessages];
12858
+ }
12859
+ return [...fullBaseMessages, ...parsedMessages];
12860
+ }
12805
12861
  getIdleFinishConfirmMs() {
12806
12862
  return this.timeouts.idleFinishConfirm;
12807
12863
  }
@@ -13387,7 +13443,7 @@ var init_provider_cli_adapter = __esm({
13387
13443
  const ctx = { now, modal, status, parsedMessages, lastParsedAssistant, parsedStatus: parsedStatus || null, prevStatus };
13388
13444
  if (!this.applyPendingScriptStatusDebounce(ctx)) return;
13389
13445
  const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
13390
- LOG.info(
13446
+ LOG.debug(
13391
13447
  "CLI",
13392
13448
  `[${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)}`
13393
13449
  );
@@ -13754,18 +13810,26 @@ var init_provider_cli_adapter = __esm({
13754
13810
  try {
13755
13811
  const screenText = this.terminalScreen.getText();
13756
13812
  const tail = this.recentOutputBuffer.slice(-500);
13813
+ const parseBaseMessages = this.selectParseBaseMessages(this.committedMessages);
13757
13814
  const input = buildCliParseInput({
13758
13815
  accumulatedBuffer: this.accumulatedBuffer,
13759
13816
  accumulatedRawBuffer: this.accumulatedRawBuffer,
13760
13817
  recentOutputBuffer: this.recentOutputBuffer,
13761
13818
  terminalScreenText: screenText,
13762
- baseMessages: this.committedMessages,
13819
+ baseMessages: parseBaseMessages,
13763
13820
  partialResponse: this.responseBuffer,
13764
13821
  isWaitingForResponse: this.isWaitingForResponse,
13765
13822
  scope: this.currentTurnScope,
13766
13823
  runtimeSettings: this.runtimeSettings
13767
13824
  });
13768
13825
  const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
13826
+ if (session && typeof session === "object" && Array.isArray(session.messages)) {
13827
+ session.messages = this.stitchParsedMessagesWithCommittedBase(
13828
+ session.messages,
13829
+ this.committedMessages,
13830
+ parseBaseMessages
13831
+ );
13832
+ }
13769
13833
  this.parseErrorMessage = null;
13770
13834
  return session && typeof session === "object" ? session : null;
13771
13835
  } catch (e) {
@@ -14086,12 +14150,13 @@ var init_provider_cli_adapter = __esm({
14086
14150
  }
14087
14151
  try {
14088
14152
  const screenText = typeof screenTextOverride === "string" ? screenTextOverride : this.terminalScreen.getText();
14153
+ const parseBaseMessages = this.selectParseBaseMessages(baseMessages);
14089
14154
  const input = buildCliParseInput({
14090
14155
  accumulatedBuffer: this.accumulatedBuffer,
14091
14156
  accumulatedRawBuffer: this.accumulatedRawBuffer,
14092
14157
  recentOutputBuffer: this.recentOutputBuffer,
14093
14158
  terminalScreenText: screenText,
14094
- baseMessages,
14159
+ baseMessages: parseBaseMessages,
14095
14160
  partialResponse,
14096
14161
  isWaitingForResponse: this.isWaitingForResponse,
14097
14162
  scope,
@@ -14103,6 +14168,11 @@ var init_provider_cli_adapter = __esm({
14103
14168
  }
14104
14169
  const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
14105
14170
  if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
14171
+ normalizedParsed.messages = this.stitchParsedMessagesWithCommittedBase(
14172
+ normalizedParsed.messages,
14173
+ baseMessages,
14174
+ parseBaseMessages
14175
+ );
14106
14176
  this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
14107
14177
  }
14108
14178
  this.parseErrorMessage = null;
@@ -35963,6 +36033,9 @@ var init_provider_loader = __esm({
35963
36033
  log(msg) {
35964
36034
  this.logFn(`[ProviderLoader] ${msg}`);
35965
36035
  }
36036
+ debugLog(msg) {
36037
+ LOG.debug("Provider", `[ProviderLoader] ${msg}`);
36038
+ }
35966
36039
  // ─── Public API ────────────────────────────────
35967
36040
  /**
35968
36041
  * User override root (~/.adhdev/providers by default).
@@ -36569,7 +36642,7 @@ var init_provider_loader = __esm({
36569
36642
  const loaded = this.loadScriptsFromDir(type, entry.scriptDir);
36570
36643
  if (loaded) {
36571
36644
  resolved.scripts = loaded;
36572
- this.log(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
36645
+ this.debugLog(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
36573
36646
  resolved._resolvedScriptDir = entry.scriptDir;
36574
36647
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
36575
36648
  if (providerDir) {
@@ -36585,7 +36658,7 @@ var init_provider_loader = __esm({
36585
36658
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
36586
36659
  if (loaded) {
36587
36660
  resolved.scripts = loaded;
36588
- this.log(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
36661
+ this.debugLog(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
36589
36662
  resolved._resolvedScriptDir = base.defaultScriptDir;
36590
36663
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
36591
36664
  if (providerDir) {
@@ -36620,7 +36693,7 @@ var init_provider_loader = __esm({
36620
36693
  const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
36621
36694
  if (loaded) {
36622
36695
  resolved.scripts = loaded;
36623
- this.log(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
36696
+ this.debugLog(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
36624
36697
  resolved._resolvedScriptDir = base.defaultScriptDir;
36625
36698
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
36626
36699
  if (providerDir) {
@@ -87766,7 +87839,7 @@ var init_adhdev_daemon = __esm({
87766
87839
  init_version();
87767
87840
  init_src();
87768
87841
  init_runtime_defaults();
87769
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.30" });
87842
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.32" });
87770
87843
  AdhdevDaemon = class _AdhdevDaemon {
87771
87844
  localHttpServer = null;
87772
87845
  localWss = null;
@@ -87780,8 +87853,12 @@ var init_adhdev_daemon = __esm({
87780
87853
  pendingP2PChatFlush = false;
87781
87854
  pendingP2PChatFlushOnlyActive = true;
87782
87855
  hotP2PChatSessionIds = /* @__PURE__ */ new Set();
87856
+ p2pChatOutputActiveAt = /* @__PURE__ */ new Map();
87857
+ p2pChatOutputFlushTimer = null;
87783
87858
  hotChatSnapshotCache = null;
87784
87859
  static HOT_CHAT_SNAPSHOT_CACHE_TTL_MS = 1500;
87860
+ static CHAT_OUTPUT_ACTIVITY_HOT_MS = DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS;
87861
+ static CHAT_OUTPUT_FLUSH_DEBOUNCE_MS = 700;
87785
87862
  components = null;
87786
87863
  sessionHostEndpoint = null;
87787
87864
  sessionHostController = null;
@@ -87966,6 +88043,26 @@ var init_adhdev_daemon = __esm({
87966
88043
  invalidateHotChatSnapshotCache() {
87967
88044
  this.hotChatSnapshotCache = null;
87968
88045
  }
88046
+ getRecentlyOutputActiveChatSessionIds(now) {
88047
+ const active = /* @__PURE__ */ new Set();
88048
+ for (const [sessionId, lastOutputAt] of this.p2pChatOutputActiveAt) {
88049
+ if (now - lastOutputAt <= _AdhdevDaemon.CHAT_OUTPUT_ACTIVITY_HOT_MS) {
88050
+ active.add(sessionId);
88051
+ } else {
88052
+ this.p2pChatOutputActiveAt.delete(sessionId);
88053
+ }
88054
+ }
88055
+ return active;
88056
+ }
88057
+ markP2PChatOutputActivity(sessionId) {
88058
+ if (!sessionId || !this.isCliSession(sessionId)) return;
88059
+ this.p2pChatOutputActiveAt.set(sessionId, Date.now());
88060
+ if (this.p2pChatOutputFlushTimer || !this.p2p?.isConnected || !this.p2p.hasChatSubscriptions()) return;
88061
+ this.p2pChatOutputFlushTimer = setTimeout(() => {
88062
+ this.p2pChatOutputFlushTimer = null;
88063
+ void this.flushP2PChatSubscriptions({ onlyActive: true });
88064
+ }, _AdhdevDaemon.CHAT_OUTPUT_FLUSH_DEBOUNCE_MS);
88065
+ }
87969
88066
  getHotChatSessionIdsForP2PFlush() {
87970
88067
  const now = Date.now();
87971
88068
  const cached2 = this.hotChatSnapshotCache;
@@ -87976,7 +88073,8 @@ var init_adhdev_daemon = __esm({
87976
88073
  })();
87977
88074
  const hotSessions = classifyHotChatSessionsForSubscriptionFlush(
87978
88075
  sessions,
87979
- this.hotP2PChatSessionIds
88076
+ this.hotP2PChatSessionIds,
88077
+ { activeSessionIds: this.getRecentlyOutputActiveChatSessionIds(now) }
87980
88078
  );
87981
88079
  this.hotP2PChatSessionIds = hotSessions.active;
87982
88080
  return hotSessions;
@@ -88201,6 +88299,7 @@ ${err?.stack || ""}`);
88201
88299
  getP2p: () => ({
88202
88300
  broadcastSessionOutput: (key, data) => {
88203
88301
  if (!this.isCliSession(key)) return;
88302
+ this.markP2PChatOutputActivity(key);
88204
88303
  this.p2p?.broadcastSessionOutput(key, data);
88205
88304
  }
88206
88305
  }),