@adhdev/daemon-core 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.
@@ -172,7 +172,9 @@ export declare class ProviderCliAdapter implements CliAdapter {
172
172
  private hasActionableApproval;
173
173
  private projectEffectiveStatus;
174
174
  private suppressStaleParsedApproval;
175
- getStatus(): CliSessionStatus;
175
+ getStatus(options?: {
176
+ allowParse?: boolean;
177
+ }): CliSessionStatus;
176
178
  seedCommittedMessages(messages: SeedCliChatMessage[]): void;
177
179
  private getSharedCommittedPrefixLength;
178
180
  private hydrateCommittedPrefixForParsedStatus;
package/dist/index.js CHANGED
@@ -1690,27 +1690,86 @@ function sliceFromOffset(text, start) {
1690
1690
  function hydrateCliParsedMessages(parsedMessages, options) {
1691
1691
  const { committedMessages, scope, lastOutputAt } = options;
1692
1692
  const referenceMessages = [...committedMessages];
1693
- const referenceComparables = referenceMessages.map((message) => normalizeComparableMessageContent(message?.content || ""));
1693
+ const referenceComparables = new Array(referenceMessages.length);
1694
1694
  const usedReferenceIndexes = /* @__PURE__ */ new Set();
1695
1695
  const now = options.now ?? Date.now();
1696
- const findReferenceTimestamp = (role, content, parsedIndex) => {
1696
+ let exactReferenceIndexesByKey = null;
1697
+ const exactReferenceCursorByKey = /* @__PURE__ */ new Map();
1698
+ const hasFiniteTimestamp = (message) => typeof message?.timestamp === "number" && Number.isFinite(message.timestamp);
1699
+ const getReferenceComparable = (index) => {
1700
+ if (typeof referenceComparables[index] === "string") return referenceComparables[index] || "";
1701
+ const comparable = normalizeComparableMessageContent(referenceMessages[index]?.content || "");
1702
+ referenceComparables[index] = comparable;
1703
+ return comparable;
1704
+ };
1705
+ const messagesShareStableIdentity = (parsed, reference) => {
1706
+ if (!parsed || !reference) return false;
1707
+ const parsedId = typeof parsed.id === "string" ? parsed.id.trim() : "";
1708
+ const referenceId = typeof reference.id === "string" ? reference.id.trim() : "";
1709
+ if (parsedId && referenceId && parsedId === referenceId) return true;
1710
+ return typeof parsed.index === "number" && Number.isFinite(parsed.index) && typeof reference.index === "number" && Number.isFinite(reference.index) && parsed.index === reference.index;
1711
+ };
1712
+ const exactReferenceKey = (role, comparable) => `${role}\0${comparable}`;
1713
+ const ensureExactReferenceIndex = () => {
1714
+ if (exactReferenceIndexesByKey) return exactReferenceIndexesByKey;
1715
+ const byKey = /* @__PURE__ */ new Map();
1716
+ for (let i = 0; i < referenceMessages.length; i++) {
1717
+ const candidate = referenceMessages[i];
1718
+ if (!candidate || candidate.role !== "user" && candidate.role !== "assistant" || !hasFiniteTimestamp(candidate)) continue;
1719
+ const comparable = getReferenceComparable(i);
1720
+ if (!comparable) continue;
1721
+ const key = exactReferenceKey(candidate.role, comparable);
1722
+ const indexes = byKey.get(key);
1723
+ if (indexes) {
1724
+ indexes.push(i);
1725
+ } else {
1726
+ byKey.set(key, [i]);
1727
+ }
1728
+ }
1729
+ exactReferenceIndexesByKey = byKey;
1730
+ return byKey;
1731
+ };
1732
+ const takeExactReferenceTimestamp = (role, normalizedContent) => {
1733
+ const key = exactReferenceKey(role, normalizedContent);
1734
+ const indexes = ensureExactReferenceIndex().get(key);
1735
+ if (!indexes) return void 0;
1736
+ let cursor = exactReferenceCursorByKey.get(key) || 0;
1737
+ while (cursor < indexes.length) {
1738
+ const candidateIndex = indexes[cursor];
1739
+ cursor += 1;
1740
+ if (usedReferenceIndexes.has(candidateIndex)) continue;
1741
+ const candidate = referenceMessages[candidateIndex];
1742
+ if (!candidate || candidate.role !== role || !hasFiniteTimestamp(candidate)) continue;
1743
+ usedReferenceIndexes.add(candidateIndex);
1744
+ exactReferenceCursorByKey.set(key, cursor);
1745
+ return candidate.timestamp;
1746
+ }
1747
+ exactReferenceCursorByKey.set(key, cursor);
1748
+ return void 0;
1749
+ };
1750
+ const findReferenceTimestamp = (message, role, content, parsedIndex) => {
1751
+ const sameIndex = referenceMessages[parsedIndex];
1752
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && hasFiniteTimestamp(sameIndex) && messagesShareStableIdentity(message, sameIndex)) {
1753
+ usedReferenceIndexes.add(parsedIndex);
1754
+ return sameIndex.timestamp;
1755
+ }
1697
1756
  const normalizedContent = normalizeComparableMessageContent(content);
1698
1757
  if (!normalizedContent) return void 0;
1699
- const sameIndex = referenceMessages[parsedIndex];
1700
- if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && referenceComparables[parsedIndex] === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1758
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && getReferenceComparable(parsedIndex) === normalizedContent && hasFiniteTimestamp(sameIndex)) {
1701
1759
  usedReferenceIndexes.add(parsedIndex);
1702
1760
  return sameIndex.timestamp;
1703
1761
  }
1762
+ const exactTimestamp = takeExactReferenceTimestamp(role, normalizedContent);
1763
+ if (typeof exactTimestamp === "number") return exactTimestamp;
1704
1764
  for (let i = 0; i < referenceMessages.length; i++) {
1705
1765
  if (usedReferenceIndexes.has(i)) continue;
1706
1766
  const candidate = referenceMessages[i];
1707
1767
  if (!candidate || candidate.role !== role) continue;
1708
- const candidateContent = referenceComparables[i];
1768
+ const candidateContent = getReferenceComparable(i);
1709
1769
  if (!candidateContent) continue;
1710
- const exactMatch = candidateContent === normalizedContent;
1711
1770
  const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
1712
- if (!exactMatch && !fuzzyMatch) continue;
1713
- if (typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp)) {
1771
+ if (!fuzzyMatch) continue;
1772
+ if (hasFiniteTimestamp(candidate)) {
1714
1773
  usedReferenceIndexes.add(i);
1715
1774
  return candidate.timestamp;
1716
1775
  }
@@ -1721,7 +1780,7 @@ function hydrateCliParsedMessages(parsedMessages, options) {
1721
1780
  const role = message.role;
1722
1781
  const content = typeof message.content === "string" ? message.content : String(message.content || "");
1723
1782
  const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
1724
- const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
1783
+ const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(message, role, content, index);
1725
1784
  const fallbackTimestamp = role === "user" ? scope?.startedAt || now : lastOutputAt || scope?.startedAt || now;
1726
1785
  const timestamp = referenceTimestamp ?? fallbackTimestamp;
1727
1786
  return {
@@ -3341,11 +3400,12 @@ var init_provider_cli_adapter = __esm({
3341
3400
  };
3342
3401
  }
3343
3402
  // ─── Public API (CliAdapter) ───────────────────
3344
- getStatus() {
3345
- const startupModal = this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
3403
+ getStatus(options = {}) {
3404
+ const allowParse = options.allowParse !== false;
3405
+ const startupModal = allowParse && this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
3346
3406
  let effectiveStatus = this.projectEffectiveStatus(startupModal);
3347
3407
  let effectiveModal = startupModal || this.activeModal;
3348
- if (!startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === "function") {
3408
+ if (allowParse && !startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === "function") {
3349
3409
  let parsed = this.getFreshParsedStatusCache();
3350
3410
  if (!parsed && effectiveStatus !== "idle") {
3351
3411
  const now = Date.now();
@@ -13230,17 +13290,24 @@ function buildPersistableCliHistorySignature(message) {
13230
13290
  normalizePersistableCliHistoryContent(message.content)
13231
13291
  ].join("|");
13232
13292
  }
13293
+ function hasSamePersistableCliHistoryIdentity(a, b) {
13294
+ 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 || "");
13295
+ }
13233
13296
  function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages) {
13234
13297
  if (!Array.isArray(currentMessages) || currentMessages.length === 0) return [];
13235
13298
  if (!Array.isArray(previousMessages) || previousMessages.length === 0) return currentMessages;
13236
- const previousSignatures = previousMessages.map(buildPersistableCliHistorySignature);
13237
- const currentSignatures = currentMessages.map(buildPersistableCliHistorySignature);
13299
+ const comparableLength = Math.min(previousMessages.length, currentMessages.length);
13238
13300
  let sharedPrefixLength = 0;
13239
- while (sharedPrefixLength < previousSignatures.length && sharedPrefixLength < currentSignatures.length && previousSignatures[sharedPrefixLength] === currentSignatures[sharedPrefixLength]) {
13301
+ while (sharedPrefixLength < comparableLength && hasSamePersistableCliHistoryIdentity(previousMessages[sharedPrefixLength], currentMessages[sharedPrefixLength])) {
13302
+ sharedPrefixLength += 1;
13303
+ }
13304
+ if (sharedPrefixLength === currentMessages.length) return [];
13305
+ if (sharedPrefixLength === previousMessages.length) return currentMessages.slice(sharedPrefixLength);
13306
+ while (sharedPrefixLength < comparableLength && buildPersistableCliHistorySignature(previousMessages[sharedPrefixLength]) === buildPersistableCliHistorySignature(currentMessages[sharedPrefixLength])) {
13240
13307
  sharedPrefixLength += 1;
13241
13308
  }
13242
- if (sharedPrefixLength === currentSignatures.length) return [];
13243
- if (sharedPrefixLength === previousSignatures.length) return currentMessages.slice(sharedPrefixLength);
13309
+ if (sharedPrefixLength === currentMessages.length) return [];
13310
+ if (sharedPrefixLength === previousMessages.length) return currentMessages.slice(sharedPrefixLength);
13244
13311
  return currentMessages;
13245
13312
  }
13246
13313
  var CachedDatabaseSync = null;
@@ -13486,13 +13553,15 @@ var CliProviderInstance = class {
13486
13553
  }));
13487
13554
  if (!canonicalBackedHistory && !shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
13488
13555
  const incrementalMessages = buildIncrementalHistoryAppendMessages(this.lastPersistedHistoryMessages, normalizedMessagesToSave);
13489
- this.historyWriter.appendNewMessages(
13490
- this.type,
13491
- incrementalMessages,
13492
- parsedStatus?.title || dirName,
13493
- this.instanceId,
13494
- this.providerSessionId
13495
- );
13556
+ if (incrementalMessages.length > 0) {
13557
+ this.historyWriter.appendNewMessages(
13558
+ this.type,
13559
+ incrementalMessages,
13560
+ parsedStatus?.title || dirName,
13561
+ this.instanceId,
13562
+ this.providerSessionId
13563
+ );
13564
+ }
13496
13565
  }
13497
13566
  if (!canonicalBackedHistory) {
13498
13567
  this.lastPersistedHistoryMessages = normalizedMessagesToSave;
@@ -13551,7 +13620,7 @@ var CliProviderInstance = class {
13551
13620
  return this.presentationMode;
13552
13621
  }
13553
13622
  getHotChatSessionState() {
13554
- const adapterStatus = this.adapter.getStatus();
13623
+ const adapterStatus = this.adapter.getStatus({ allowParse: false });
13555
13624
  const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
13556
13625
  const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
13557
13626
  const runtime = this.adapter.getRuntimeMetadata();