adhdev 0.9.22 → 0.9.24

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
@@ -7876,13 +7876,40 @@ function shouldCollapseReadChatReplayDuplicate(message) {
7876
7876
  const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
7877
7877
  return role === "assistant" || role === "system";
7878
7878
  }
7879
+ function normalizeReadChatReplayText(message) {
7880
+ return flattenContent(message?.content || "").replace(/\s+/g, " ").trim();
7881
+ }
7882
+ function isStableReadChatAssistantAnswer(message) {
7883
+ if (!message) return false;
7884
+ const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
7885
+ const kind = typeof message.kind === "string" ? message.kind.trim().toLowerCase() : "standard";
7886
+ if (role !== "assistant") return false;
7887
+ if (kind && kind !== "standard") return false;
7888
+ const content = normalizeReadChatReplayText(message);
7889
+ if (content.length < 160) return false;
7890
+ if (/^(bash|shell|terminal) command\b/i.test(content)) return false;
7891
+ return true;
7892
+ }
7893
+ function isReplayedAssistantAnswerAfterStableAnswer(message, stableAnswer) {
7894
+ if (!message || !stableAnswer) return false;
7895
+ const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
7896
+ const kind = typeof message.kind === "string" ? message.kind.trim().toLowerCase() : "standard";
7897
+ if (role !== "assistant") return false;
7898
+ if (kind && kind !== "standard") return false;
7899
+ const content = normalizeReadChatReplayText(message);
7900
+ const stableContent = normalizeReadChatReplayText(stableAnswer);
7901
+ if (content.length < 80 || stableContent.length < 80) return false;
7902
+ return content === stableContent || content.startsWith(stableContent) || stableContent.startsWith(content);
7903
+ }
7879
7904
  function collapseReplayDuplicatesFromReadChat(messages) {
7880
7905
  const collapsed = [];
7881
7906
  const replaySignaturesInCurrentTurn = /* @__PURE__ */ new Set();
7907
+ let stableAssistantAnswerInCurrentTurn = null;
7882
7908
  for (const message of messages) {
7883
7909
  const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
7884
7910
  if (role === "user") {
7885
7911
  replaySignaturesInCurrentTurn.clear();
7912
+ stableAssistantAnswerInCurrentTurn = null;
7886
7913
  }
7887
7914
  const signature = buildReadChatReplayCollapseSignature(message);
7888
7915
  const previous = collapsed[collapsed.length - 1];
@@ -7890,11 +7917,15 @@ function collapseReplayDuplicatesFromReadChat(messages) {
7890
7917
  if (shouldCollapseReadChatReplayDuplicate(message) && signature) {
7891
7918
  if (previousSignature === signature) continue;
7892
7919
  if (replaySignaturesInCurrentTurn.has(signature)) continue;
7920
+ if (isReplayedAssistantAnswerAfterStableAnswer(message, stableAssistantAnswerInCurrentTurn)) continue;
7893
7921
  }
7894
7922
  collapsed.push(message);
7895
7923
  if (shouldCollapseReadChatReplayDuplicate(message) && signature) {
7896
7924
  replaySignaturesInCurrentTurn.add(signature);
7897
7925
  }
7926
+ if (isStableReadChatAssistantAnswer(message)) {
7927
+ stableAssistantAnswerInCurrentTurn = message;
7928
+ }
7898
7929
  }
7899
7930
  return collapsed;
7900
7931
  }
@@ -14547,8 +14578,10 @@ var init_provider_cli_adapter = __esm({
14547
14578
  if (buttonIndex in this.approvalKeys) {
14548
14579
  this.ptyProcess.write(this.approvalKeys[buttonIndex]);
14549
14580
  } else {
14581
+ const buttonCount = Array.isArray(modal?.buttons) ? modal.buttons.length : 0;
14582
+ const clampedIndex = buttonCount > 0 ? Math.min(Math.max(0, buttonIndex), buttonCount - 1) : Math.max(0, buttonIndex);
14550
14583
  const DOWN = "\x1B[B";
14551
- const keys = DOWN.repeat(Math.max(0, buttonIndex)) + "\r";
14584
+ const keys = DOWN.repeat(clampedIndex) + "\r";
14552
14585
  this.ptyProcess.write(keys);
14553
14586
  }
14554
14587
  }
@@ -14922,6 +14955,12 @@ var init_cli_provider_instance = __esm({
14922
14955
  if (historyMessageCount !== null) {
14923
14956
  parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
14924
14957
  }
14958
+ const committedMessages = Array.isArray(adapterStatus.messages) ? adapterStatus.messages : [];
14959
+ const isActiveNonIdle = adapterStatus.status !== "idle";
14960
+ const shouldApplyCommittedFloor = parsedMessages.length < committedMessages.length && (adapterStatus.status === "waiting_approval" || isActiveNonIdle && historyMessageCount === null);
14961
+ if (shouldApplyCommittedFloor) {
14962
+ parsedMessages = normalizeChatMessages(committedMessages);
14963
+ }
14925
14964
  const mergedMessages = this.mergeConversationMessages(parsedMessages);
14926
14965
  const canonicalBackedHistory = this.syncCanonicalSavedHistoryIfNeeded();
14927
14966
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
@@ -46333,8 +46372,8 @@ var init_session_host_transport = __esm({
46333
46372
  }
46334
46373
  try {
46335
46374
  await this.client.close();
46336
- } catch {
46337
- if (destroy) throw new Error(`Failed to close session host client: ${this.options.runtimeId}`);
46375
+ } catch (err) {
46376
+ if (destroy) throw err instanceof Error ? err : new Error(`Failed to close session host client: ${this.options.runtimeId}`);
46338
46377
  }
46339
46378
  }
46340
46379
  };
@@ -79148,7 +79187,7 @@ var init_screenshot_sender = __esm({
79148
79187
  });
79149
79188
  let sentAny = false;
79150
79189
  for (const peer of peers.values()) {
79151
- if (peer.state !== "connected" || !peer.dataChannel) continue;
79190
+ if (peer.state !== "connected" || !peer.dataChannel?.isOpen()) continue;
79152
79191
  try {
79153
79192
  peer.dataChannel.sendMessage(payload);
79154
79193
  sentAny = true;
@@ -79165,7 +79204,7 @@ var init_screenshot_sender = __esm({
79165
79204
  });
79166
79205
  let sentAny = false;
79167
79206
  for (const peer of peers.values()) {
79168
- if (peer.state !== "connected" || !peer.dataChannel) continue;
79207
+ if (peer.state !== "connected" || !peer.dataChannel?.isOpen()) continue;
79169
79208
  try {
79170
79209
  peer.dataChannel.sendMessage(payload);
79171
79210
  sentAny = true;
@@ -79175,7 +79214,7 @@ var init_screenshot_sender = __esm({
79175
79214
  return sentAny;
79176
79215
  }
79177
79216
  sendTopicUpdateToPeer(peer, update) {
79178
- if (!peer?.dataChannel || peer.state !== "connected") return false;
79217
+ if (!peer?.dataChannel || peer.state !== "connected" || !peer.dataChannel.isOpen()) return false;
79179
79218
  try {
79180
79219
  peer.dataChannel.sendMessage(JSON.stringify({
79181
79220
  type: "topic_update",
@@ -79191,7 +79230,7 @@ var init_screenshot_sender = __esm({
79191
79230
  const msg = JSON.stringify({ type: "session_output", sessionId, data });
79192
79231
  let sentAny = false;
79193
79232
  for (const peer of peers.values()) {
79194
- if (peer.state !== "connected" || !peer.dataChannel) continue;
79233
+ if (peer.state !== "connected" || !peer.dataChannel?.isOpen()) continue;
79195
79234
  try {
79196
79235
  peer.dataChannel.sendMessage(msg);
79197
79236
  sentAny = true;
@@ -79717,7 +79756,7 @@ ${e?.stack || ""}`);
79717
79756
  }
79718
79757
  get isConnected() {
79719
79758
  for (const peer of this.peers.values()) {
79720
- if (peer.state === "connected" && peer.dataChannel) return true;
79759
+ if (peer.state === "connected" && peer.dataChannel?.isOpen()) return true;
79721
79760
  }
79722
79761
  return false;
79723
79762
  }
@@ -79895,7 +79934,22 @@ ${e?.stack || ""}`);
79895
79934
  if (!update) return;
79896
79935
  this.screenshotSender.sendTopicUpdateToPeer(peer, update);
79897
79936
  } catch (error48) {
79898
- log(`chat_tail flush skipped: peer=${peer.peerId} session=${subscription.params.targetSessionId} error=${error48?.message || error48}`);
79937
+ log(`chat_tail flush error: peer=${peer.peerId} session=${subscription.params.targetSessionId} error=${error48?.message || error48}`);
79938
+ const errorUpdate = {
79939
+ topic: "session.chat_tail",
79940
+ key: subscription.key,
79941
+ sessionId: subscription.params.targetSessionId,
79942
+ seq: subscription.seq,
79943
+ timestamp: Date.now(),
79944
+ syncMode: "noop",
79945
+ messages: [],
79946
+ status: "",
79947
+ replaceFrom: 0,
79948
+ totalMessages: 0,
79949
+ lastMessageSignature: "",
79950
+ error: error48?.message || "chat_tail build failed"
79951
+ };
79952
+ this.screenshotSender.sendTopicUpdateToPeer(peer, errorUpdate);
79899
79953
  }
79900
79954
  }, { concurrency: 4 });
79901
79955
  }
@@ -87400,7 +87454,7 @@ var init_adhdev_daemon = __esm({
87400
87454
  init_version();
87401
87455
  init_src();
87402
87456
  init_runtime_defaults();
87403
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.22" });
87457
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.24" });
87404
87458
  AdhdevDaemon = class _AdhdevDaemon {
87405
87459
  localHttpServer = null;
87406
87460
  localWss = null;
@@ -87414,6 +87468,8 @@ var init_adhdev_daemon = __esm({
87414
87468
  pendingP2PChatFlush = false;
87415
87469
  pendingP2PChatFlushOnlyActive = true;
87416
87470
  hotP2PChatSessionIds = /* @__PURE__ */ new Set();
87471
+ hotChatSnapshotCache = null;
87472
+ static HOT_CHAT_SNAPSHOT_CACHE_TTL_MS = 1500;
87417
87473
  components = null;
87418
87474
  sessionHostEndpoint = null;
87419
87475
  sessionHostController = null;
@@ -87595,8 +87651,17 @@ var init_adhdev_daemon = __esm({
87595
87651
  profile: "live"
87596
87652
  });
87597
87653
  }
87654
+ invalidateHotChatSnapshotCache() {
87655
+ this.hotChatSnapshotCache = null;
87656
+ }
87598
87657
  getHotChatSessionIdsForP2PFlush() {
87599
- const sessions = this.buildLiveStatusSnapshot().sessions || [];
87658
+ const now = Date.now();
87659
+ const cached2 = this.hotChatSnapshotCache;
87660
+ const sessions = cached2 && now - cached2.builtAt < _AdhdevDaemon.HOT_CHAT_SNAPSHOT_CACHE_TTL_MS ? cached2.sessions : (() => {
87661
+ const built = this.buildLiveStatusSnapshot().sessions || [];
87662
+ this.hotChatSnapshotCache = { sessions: built, builtAt: now };
87663
+ return built;
87664
+ })();
87600
87665
  const hotSessions = classifyHotChatSessionsForSubscriptionFlush(
87601
87666
  sessions,
87602
87667
  this.hotP2PChatSessionIds
@@ -87828,6 +87893,7 @@ ${err?.stack || ""}`);
87828
87893
  }
87829
87894
  }),
87830
87895
  onStatusChange: () => {
87896
+ this.invalidateHotChatSnapshotCache();
87831
87897
  this.statusReporter?.onStatusChange();
87832
87898
  void this.flushP2PChatSubscriptions({ onlyActive: true });
87833
87899
  },
@@ -87857,6 +87923,7 @@ ${err?.stack || ""}`);
87857
87923
  statusInstanceId: instanceId,
87858
87924
  statusVersion: pkgVersion,
87859
87925
  onStatusChange: () => {
87926
+ this.invalidateHotChatSnapshotCache();
87860
87927
  this.statusReporter?.onStatusChange();
87861
87928
  void this.flushP2PChatSubscriptions({ onlyActive: true });
87862
87929
  },