adhdev 0.9.36 → 0.9.38

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
@@ -11420,27 +11420,86 @@ function sliceFromOffset(text, start) {
11420
11420
  function hydrateCliParsedMessages(parsedMessages, options) {
11421
11421
  const { committedMessages, scope, lastOutputAt } = options;
11422
11422
  const referenceMessages = [...committedMessages];
11423
- const referenceComparables = referenceMessages.map((message) => normalizeComparableMessageContent(message?.content || ""));
11423
+ const referenceComparables = new Array(referenceMessages.length);
11424
11424
  const usedReferenceIndexes = /* @__PURE__ */ new Set();
11425
11425
  const now = options.now ?? Date.now();
11426
- const findReferenceTimestamp = (role, content, parsedIndex) => {
11426
+ let exactReferenceIndexesByKey = null;
11427
+ const exactReferenceCursorByKey = /* @__PURE__ */ new Map();
11428
+ const hasFiniteTimestamp = (message) => typeof message?.timestamp === "number" && Number.isFinite(message.timestamp);
11429
+ const getReferenceComparable = (index) => {
11430
+ if (typeof referenceComparables[index] === "string") return referenceComparables[index] || "";
11431
+ const comparable = normalizeComparableMessageContent(referenceMessages[index]?.content || "");
11432
+ referenceComparables[index] = comparable;
11433
+ return comparable;
11434
+ };
11435
+ const messagesShareStableIdentity = (parsed, reference) => {
11436
+ if (!parsed || !reference) return false;
11437
+ const parsedId = typeof parsed.id === "string" ? parsed.id.trim() : "";
11438
+ const referenceId = typeof reference.id === "string" ? reference.id.trim() : "";
11439
+ if (parsedId && referenceId && parsedId === referenceId) return true;
11440
+ return typeof parsed.index === "number" && Number.isFinite(parsed.index) && typeof reference.index === "number" && Number.isFinite(reference.index) && parsed.index === reference.index;
11441
+ };
11442
+ const exactReferenceKey = (role, comparable) => `${role}\0${comparable}`;
11443
+ const ensureExactReferenceIndex = () => {
11444
+ if (exactReferenceIndexesByKey) return exactReferenceIndexesByKey;
11445
+ const byKey = /* @__PURE__ */ new Map();
11446
+ for (let i = 0; i < referenceMessages.length; i++) {
11447
+ const candidate = referenceMessages[i];
11448
+ if (!candidate || candidate.role !== "user" && candidate.role !== "assistant" || !hasFiniteTimestamp(candidate)) continue;
11449
+ const comparable = getReferenceComparable(i);
11450
+ if (!comparable) continue;
11451
+ const key = exactReferenceKey(candidate.role, comparable);
11452
+ const indexes = byKey.get(key);
11453
+ if (indexes) {
11454
+ indexes.push(i);
11455
+ } else {
11456
+ byKey.set(key, [i]);
11457
+ }
11458
+ }
11459
+ exactReferenceIndexesByKey = byKey;
11460
+ return byKey;
11461
+ };
11462
+ const takeExactReferenceTimestamp = (role, normalizedContent) => {
11463
+ const key = exactReferenceKey(role, normalizedContent);
11464
+ const indexes = ensureExactReferenceIndex().get(key);
11465
+ if (!indexes) return void 0;
11466
+ let cursor = exactReferenceCursorByKey.get(key) || 0;
11467
+ while (cursor < indexes.length) {
11468
+ const candidateIndex = indexes[cursor];
11469
+ cursor += 1;
11470
+ if (usedReferenceIndexes.has(candidateIndex)) continue;
11471
+ const candidate = referenceMessages[candidateIndex];
11472
+ if (!candidate || candidate.role !== role || !hasFiniteTimestamp(candidate)) continue;
11473
+ usedReferenceIndexes.add(candidateIndex);
11474
+ exactReferenceCursorByKey.set(key, cursor);
11475
+ return candidate.timestamp;
11476
+ }
11477
+ exactReferenceCursorByKey.set(key, cursor);
11478
+ return void 0;
11479
+ };
11480
+ const findReferenceTimestamp = (message, role, content, parsedIndex) => {
11481
+ const sameIndex = referenceMessages[parsedIndex];
11482
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && hasFiniteTimestamp(sameIndex) && messagesShareStableIdentity(message, sameIndex)) {
11483
+ usedReferenceIndexes.add(parsedIndex);
11484
+ return sameIndex.timestamp;
11485
+ }
11427
11486
  const normalizedContent = normalizeComparableMessageContent(content);
11428
11487
  if (!normalizedContent) return void 0;
11429
- const sameIndex = referenceMessages[parsedIndex];
11430
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && referenceComparables[parsedIndex] === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
11488
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && getReferenceComparable(parsedIndex) === normalizedContent && hasFiniteTimestamp(sameIndex)) {
11431
11489
  usedReferenceIndexes.add(parsedIndex);
11432
11490
  return sameIndex.timestamp;
11433
11491
  }
11492
+ const exactTimestamp = takeExactReferenceTimestamp(role, normalizedContent);
11493
+ if (typeof exactTimestamp === "number") return exactTimestamp;
11434
11494
  for (let i = 0; i < referenceMessages.length; i++) {
11435
11495
  if (usedReferenceIndexes.has(i)) continue;
11436
11496
  const candidate = referenceMessages[i];
11437
11497
  if (!candidate || candidate.role !== role) continue;
11438
- const candidateContent = referenceComparables[i];
11498
+ const candidateContent = getReferenceComparable(i);
11439
11499
  if (!candidateContent) continue;
11440
- const exactMatch = candidateContent === normalizedContent;
11441
11500
  const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
11442
- if (!exactMatch && !fuzzyMatch) continue;
11443
- if (typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp)) {
11501
+ if (!fuzzyMatch) continue;
11502
+ if (hasFiniteTimestamp(candidate)) {
11444
11503
  usedReferenceIndexes.add(i);
11445
11504
  return candidate.timestamp;
11446
11505
  }
@@ -11451,7 +11510,7 @@ function hydrateCliParsedMessages(parsedMessages, options) {
11451
11510
  const role = message.role;
11452
11511
  const content = typeof message.content === "string" ? message.content : String(message.content || "");
11453
11512
  const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
11454
- const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
11513
+ const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(message, role, content, index);
11455
11514
  const fallbackTimestamp = role === "user" ? scope?.startedAt || now : lastOutputAt || scope?.startedAt || now;
11456
11515
  const timestamp = referenceTimestamp ?? fallbackTimestamp;
11457
11516
  return {
@@ -13071,11 +13130,12 @@ var init_provider_cli_adapter = __esm({
13071
13130
  };
13072
13131
  }
13073
13132
  // ─── Public API (CliAdapter) ───────────────────
13074
- getStatus() {
13075
- const startupModal = this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
13133
+ getStatus(options = {}) {
13134
+ const allowParse = options.allowParse !== false;
13135
+ const startupModal = allowParse && this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
13076
13136
  let effectiveStatus = this.projectEffectiveStatus(startupModal);
13077
13137
  let effectiveModal = startupModal || this.activeModal;
13078
- if (!startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === "function") {
13138
+ if (allowParse && !startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === "function") {
13079
13139
  let parsed = this.getFreshParsedStatusCache();
13080
13140
  if (!parsed && effectiveStatus !== "idle") {
13081
13141
  const now = Date.now();
@@ -14034,17 +14094,24 @@ function buildPersistableCliHistorySignature(message) {
14034
14094
  normalizePersistableCliHistoryContent(message.content)
14035
14095
  ].join("|");
14036
14096
  }
14097
+ function hasSamePersistableCliHistoryIdentity(a, b) {
14098
+ return String(a?.role || "") === String(b?.role || "") && String(a?.kind || "") === String(b?.kind || "") && String(a?.senderName || "") === String(b?.senderName || "") && String(a?.content || "") === String(b?.content || "");
14099
+ }
14037
14100
  function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages) {
14038
14101
  if (!Array.isArray(currentMessages) || currentMessages.length === 0) return [];
14039
14102
  if (!Array.isArray(previousMessages) || previousMessages.length === 0) return currentMessages;
14040
- const previousSignatures = previousMessages.map(buildPersistableCliHistorySignature);
14041
- const currentSignatures = currentMessages.map(buildPersistableCliHistorySignature);
14103
+ const comparableLength = Math.min(previousMessages.length, currentMessages.length);
14042
14104
  let sharedPrefixLength = 0;
14043
- while (sharedPrefixLength < previousSignatures.length && sharedPrefixLength < currentSignatures.length && previousSignatures[sharedPrefixLength] === currentSignatures[sharedPrefixLength]) {
14105
+ while (sharedPrefixLength < comparableLength && hasSamePersistableCliHistoryIdentity(previousMessages[sharedPrefixLength], currentMessages[sharedPrefixLength])) {
14106
+ sharedPrefixLength += 1;
14107
+ }
14108
+ if (sharedPrefixLength === currentMessages.length) return [];
14109
+ if (sharedPrefixLength === previousMessages.length) return currentMessages.slice(sharedPrefixLength);
14110
+ while (sharedPrefixLength < comparableLength && buildPersistableCliHistorySignature(previousMessages[sharedPrefixLength]) === buildPersistableCliHistorySignature(currentMessages[sharedPrefixLength])) {
14044
14111
  sharedPrefixLength += 1;
14045
14112
  }
14046
- if (sharedPrefixLength === currentSignatures.length) return [];
14047
- if (sharedPrefixLength === previousSignatures.length) return currentMessages.slice(sharedPrefixLength);
14113
+ if (sharedPrefixLength === currentMessages.length) return [];
14114
+ if (sharedPrefixLength === previousMessages.length) return currentMessages.slice(sharedPrefixLength);
14048
14115
  return currentMessages;
14049
14116
  }
14050
14117
  function getDatabaseSync() {
@@ -14311,13 +14378,15 @@ var init_cli_provider_instance = __esm({
14311
14378
  }));
14312
14379
  if (!canonicalBackedHistory && !shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
14313
14380
  const incrementalMessages = buildIncrementalHistoryAppendMessages(this.lastPersistedHistoryMessages, normalizedMessagesToSave);
14314
- this.historyWriter.appendNewMessages(
14315
- this.type,
14316
- incrementalMessages,
14317
- parsedStatus?.title || dirName,
14318
- this.instanceId,
14319
- this.providerSessionId
14320
- );
14381
+ if (incrementalMessages.length > 0) {
14382
+ this.historyWriter.appendNewMessages(
14383
+ this.type,
14384
+ incrementalMessages,
14385
+ parsedStatus?.title || dirName,
14386
+ this.instanceId,
14387
+ this.providerSessionId
14388
+ );
14389
+ }
14321
14390
  }
14322
14391
  if (!canonicalBackedHistory) {
14323
14392
  this.lastPersistedHistoryMessages = normalizedMessagesToSave;
@@ -14376,7 +14445,7 @@ var init_cli_provider_instance = __esm({
14376
14445
  return this.presentationMode;
14377
14446
  }
14378
14447
  getHotChatSessionState() {
14379
- const adapterStatus = this.adapter.getStatus();
14448
+ const adapterStatus = this.adapter.getStatus({ allowParse: false });
14380
14449
  const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
14381
14450
  const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
14382
14451
  const runtime = this.adapter.getRuntimeMetadata();
@@ -56515,7 +56584,7 @@ var init_adhdev_daemon = __esm({
56515
56584
  init_version();
56516
56585
  init_src();
56517
56586
  init_runtime_defaults();
56518
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.36" });
56587
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.38" });
56519
56588
  AdhdevDaemon = class _AdhdevDaemon {
56520
56589
  localHttpServer = null;
56521
56590
  localWss = null;
@@ -56532,7 +56601,7 @@ var init_adhdev_daemon = __esm({
56532
56601
  p2pChatOutputActiveAt = /* @__PURE__ */ new Map();
56533
56602
  p2pChatOutputFlushTimer = null;
56534
56603
  hotChatSnapshotCache = null;
56535
- static HOT_CHAT_SNAPSHOT_CACHE_TTL_MS = 1500;
56604
+ static HOT_CHAT_SNAPSHOT_CACHE_TTL_MS = 2400;
56536
56605
  static CHAT_OUTPUT_ACTIVITY_HOT_MS = DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS;
56537
56606
  static CHAT_OUTPUT_FLUSH_DEBOUNCE_MS = 700;
56538
56607
  components = null;