@adhdev/daemon-core 0.9.82-rc.467 → 0.9.82-rc.468

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
@@ -409,10 +409,10 @@ function readInjected(value) {
409
409
  }
410
410
  function getDaemonBuildInfo() {
411
411
  if (cached) return cached;
412
- const commit = readInjected(true ? "e0f04b7d54855e0f0d5ed4200078d95596ab9f6f" : void 0) ?? "unknown";
413
- const commitShort = readInjected(true ? "e0f04b7d" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
414
- const version = readInjected(true ? "0.9.82-rc.467" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
415
- const builtAt = readInjected(true ? "2026-07-05T10:01:33.435Z" : void 0);
412
+ const commit = readInjected(true ? "f05125bad26f9ee974d8bd31a8b9ab66bca9d4cd" : void 0) ?? "unknown";
413
+ const commitShort = readInjected(true ? "f05125ba" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
414
+ const version = readInjected(true ? "0.9.82-rc.468" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
415
+ const builtAt = readInjected(true ? "2026-07-05T10:08:41.050Z" : void 0);
416
416
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
417
417
  return cached;
418
418
  }
@@ -6177,9 +6177,28 @@ function safeMeshId(meshId) {
6177
6177
  function legacyQueuePath(meshId) {
6178
6178
  return (0, import_path5.join)(getLedgerDir(), `${safeMeshId(meshId)}.queue.json`);
6179
6179
  }
6180
+ function cleanupStrayRootRuntimeDb(canonicalPath) {
6181
+ try {
6182
+ const strayPath = (0, import_path5.join)(getConfigDir(), "mesh-runtime.db");
6183
+ if (strayPath === canonicalPath) return;
6184
+ if (!(0, import_fs5.existsSync)(strayPath)) return;
6185
+ if ((0, import_fs5.statSync)(strayPath).size !== 0) return;
6186
+ (0, import_fs5.unlinkSync)(strayPath);
6187
+ if (!loggedStrayCleanup) {
6188
+ loggedStrayCleanup = true;
6189
+ LOG.info("MeshRuntimeStore", `Removed stray 0-byte root mesh-runtime.db at ${strayPath}`);
6190
+ }
6191
+ } catch (err) {
6192
+ if (!loggedStrayCleanup) {
6193
+ loggedStrayCleanup = true;
6194
+ LOG.warn("MeshRuntimeStore", `Stray root mesh-runtime.db cleanup failed (ignored): ${err?.message || err}`);
6195
+ }
6196
+ }
6197
+ }
6180
6198
  function meshRuntimeStorePath() {
6181
6199
  const dir = getLedgerDir();
6182
6200
  const nextPath = (0, import_path5.join)(dir, "mesh-runtime.db");
6201
+ cleanupStrayRootRuntimeDb(nextPath);
6183
6202
  if ((0, import_fs5.existsSync)(nextPath)) return nextPath;
6184
6203
  const legacyPath = (0, import_path5.join)(dir, "beads.db");
6185
6204
  if (!(0, import_fs5.existsSync)(legacyPath)) return nextPath;
@@ -6203,7 +6222,7 @@ function meshRuntimeStorePath() {
6203
6222
  }
6204
6223
  return nextPath;
6205
6224
  }
6206
- var import_fs5, import_path5, DatabaseCtor, loggedMigrationFailure, MeshRuntimeStore;
6225
+ var import_fs5, import_path5, DatabaseCtor, loggedMigrationFailure, loggedStrayCleanup, MeshRuntimeStore;
6207
6226
  var init_mesh_runtime_store = __esm({
6208
6227
  "src/mesh/mesh-runtime-store.ts"() {
6209
6228
  "use strict";
@@ -6211,10 +6230,12 @@ var init_mesh_runtime_store = __esm({
6211
6230
  import_path5 = require("path");
6212
6231
  init_logger();
6213
6232
  init_load_better_sqlite3();
6233
+ init_config();
6214
6234
  init_mesh_ledger();
6215
6235
  init_mesh_work_queue();
6216
6236
  init_dist();
6217
6237
  loggedMigrationFailure = false;
6238
+ loggedStrayCleanup = false;
6218
6239
  MeshRuntimeStore = class _MeshRuntimeStore {
6219
6240
  static instance;
6220
6241
  db;
@@ -6557,6 +6578,7 @@ var init_mesh_runtime_store = __esm({
6557
6578
  ON mesh_pending_events(mesh_id, event_id)
6558
6579
  WHERE event_id IS NOT NULL
6559
6580
  `);
6581
+ this.db.exec(`DROP TABLE IF EXISTS mesh_direct_delivered_events`);
6560
6582
  } catch (err) {
6561
6583
  if (!loggedMigrationFailure) {
6562
6584
  loggedMigrationFailure = true;
@@ -19313,11 +19335,13 @@ async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDa
19313
19335
  if (!dispatchMeshCommand) return;
19314
19336
  const meshId = mesh.id;
19315
19337
  const pulls = candidateDaemonIds.length > 0 ? candidateDaemonIds.map((id) => ({ meshId, coordinatorDaemonId: id })) : [{ meshId }];
19316
- for (const node of mesh.nodes) {
19338
+ await Promise.allSettled(mesh.nodes.map(async (node) => {
19317
19339
  const nodeDaemonId = readNonEmptyString2(node.daemonId);
19318
- if (!nodeDaemonId) continue;
19319
- if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) continue;
19320
- if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) continue;
19340
+ if (!nodeDaemonId) return;
19341
+ if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) return;
19342
+ if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) return;
19343
+ const peerSnapshot = components.getMeshPeerConnectionStatus?.(nodeDaemonId);
19344
+ if (peerSnapshot && String(peerSnapshot.state) !== "connected") return;
19321
19345
  for (const pendingEventArgs of pulls) {
19322
19346
  let events;
19323
19347
  try {
@@ -19335,7 +19359,7 @@ async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDa
19335
19359
  }
19336
19360
  }
19337
19361
  }
19338
- }
19362
+ }));
19339
19363
  }
19340
19364
  function unwrapReadChatPayload(raw) {
19341
19365
  let cursor = raw;
@@ -19571,6 +19595,10 @@ async function collectLiveNodesWithSessions(components, mesh, selfIds, localDaem
19571
19595
  return Promise.all(mesh.nodes.map(async (node) => {
19572
19596
  const nodeDaemonId = readNonEmptyString2(node.daemonId);
19573
19597
  const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId);
19598
+ if (!isLocalNode) {
19599
+ const peerSnapshot = components.getMeshPeerConnectionStatus?.(nodeDaemonId);
19600
+ if (peerSnapshot && String(peerSnapshot.state) !== "connected") return node;
19601
+ }
19574
19602
  let statusResult;
19575
19603
  try {
19576
19604
  if (isLocalNode) {
@@ -42716,7 +42744,7 @@ async function waitForCliAdapterReady(adapter, options) {
42716
42744
  throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
42717
42745
  }
42718
42746
 
42719
- // src/providers/cli-provider-instance.ts
42747
+ // src/providers/cli-provider-instance-types.ts
42720
42748
  var STATUS_HYDRATION_TAIL_LIMIT = 200;
42721
42749
  var COMPLETED_FINALIZATION_RETRY_MS = 1e3;
42722
42750
  var COMPLETED_FINALIZATION_MAX_WAIT_MS = 3e4;
@@ -42728,6 +42756,123 @@ var TERMINAL_MESH_EVENTS = /* @__PURE__ */ new Set([
42728
42756
  "agent:stopped",
42729
42757
  "agent:ready"
42730
42758
  ]);
42759
+
42760
+ // src/providers/cli-provider-transcript-merge.ts
42761
+ init_contracts2();
42762
+ init_chat_message_normalization();
42763
+ function mergeConversationMessages(runtimeMessages, parsedMessages) {
42764
+ if (runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
42765
+ const parsedEntries = parsedMessages.map((message, index) => ({
42766
+ message,
42767
+ index,
42768
+ source: "parsed"
42769
+ }));
42770
+ const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
42771
+ const runtimeEntries = runtimeMessages.map((entry, index) => ({
42772
+ message: entry.message,
42773
+ index: parsedMessages.length + index,
42774
+ source: "runtime",
42775
+ runtimeKey: entry.key
42776
+ })).filter((entry) => {
42777
+ const meta = entry.message.meta && typeof entry.message.meta === "object" && !Array.isArray(entry.message.meta) ? entry.message.meta : {};
42778
+ if (meta.runtimeInputAck !== true) return true;
42779
+ const runtimeText = flattenContent(entry.message.content).replace(/\s+/g, " ").trim();
42780
+ if (!runtimeText) return false;
42781
+ return !parsedEntries.some((parsedEntry) => {
42782
+ const parsedRole = getRole(parsedEntry.message);
42783
+ if (parsedRole !== "user" && parsedRole !== "human") return false;
42784
+ const parsedText = flattenContent(parsedEntry.message.content).replace(/\s+/g, " ").trim();
42785
+ return parsedText === runtimeText;
42786
+ });
42787
+ });
42788
+ const getTime = (message) => {
42789
+ const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
42790
+ return Number.isFinite(value) && value > 0 ? value : 0;
42791
+ };
42792
+ const isRuntimeOverlay = (entry) => {
42793
+ if (entry.source !== "runtime") return false;
42794
+ const key2 = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
42795
+ if (key2.startsWith("auto_approval:")) return true;
42796
+ return !isUserFacingChatMessage(entry.message);
42797
+ };
42798
+ const shouldKeepParsedBeforeUntimedRuntime = (message) => {
42799
+ const role = getRole(message);
42800
+ return role === "user" || role === "human";
42801
+ };
42802
+ const shouldKeepParsedAfterUntimedRuntime = (message) => {
42803
+ const role = getRole(message);
42804
+ if (role !== "assistant") return false;
42805
+ const kind = resolveChatMessageKind(message);
42806
+ return kind === "standard" || kind === "terminal";
42807
+ };
42808
+ return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
42809
+ const aTime = getTime(a.message);
42810
+ const bTime = getTime(b.message);
42811
+ if (aTime && bTime && aTime !== bTime) return aTime - bTime;
42812
+ if (a.source !== b.source && aTime !== bTime) {
42813
+ const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
42814
+ const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
42815
+ if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
42816
+ if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
42817
+ return a.source === "parsed" ? -1 : 1;
42818
+ }
42819
+ if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
42820
+ return a.source === "parsed" ? 1 : -1;
42821
+ }
42822
+ }
42823
+ }
42824
+ return a.index - b.index;
42825
+ }).map((entry) => entry.message));
42826
+ }
42827
+ function buildExternalTranscriptProbe(messages, sourcePath, sourceMtimeMs) {
42828
+ const visibleMessages = messages.filter((message) => isUserFacingChatMessage(message));
42829
+ const lastVisible = visibleMessages[visibleMessages.length - 1];
42830
+ const readAt = Date.now();
42831
+ const mtimeMs = Number(sourceMtimeMs) || 0;
42832
+ return {
42833
+ readAt,
42834
+ msgCount: messages.length,
42835
+ lastRole: typeof lastVisible?.role === "string" ? lastVisible.role.trim().toLowerCase() : null,
42836
+ lastKind: typeof lastVisible?.kind === "string" ? lastVisible.kind : null,
42837
+ contentLen: lastVisible ? flattenContent(lastVisible.content).trim().length : 0,
42838
+ sourcePath: typeof sourcePath === "string" && sourcePath ? sourcePath : null,
42839
+ sourceMtimeMs: mtimeMs || null,
42840
+ mtimeAgeMs: mtimeMs ? Math.max(0, readAt - mtimeMs) : null
42841
+ };
42842
+ }
42843
+
42844
+ // src/providers/cli-provider-effect-format.ts
42845
+ function getEffectDedupKey(effect) {
42846
+ if (effect.id) return `provider_effect:${effect.id}`;
42847
+ if (effect.type === "message") {
42848
+ const content = typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
42849
+ return `provider_effect:message:${content}`;
42850
+ }
42851
+ if (effect.type === "notification") {
42852
+ return `provider_effect:notification:${effect.notification?.title || ""}:${effect.notification?.body || ""}`;
42853
+ }
42854
+ return `provider_effect:toast:${effect.toast?.message || ""}`;
42855
+ }
42856
+ function formatApprovalRequestMessage(modalMessage, buttons) {
42857
+ const lines = ["Approval requested"];
42858
+ const cleanMessage = String(modalMessage || "").trim();
42859
+ if (cleanMessage) lines.push(cleanMessage);
42860
+ const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
42861
+ if (labels.length > 0) {
42862
+ lines.push(labels.map((label) => `[${label}]`).join(" "));
42863
+ }
42864
+ return lines.join("\n");
42865
+ }
42866
+ function formatMarkerTimestamp(timestamp) {
42867
+ const date = new Date(timestamp);
42868
+ const pad = (value) => String(value).padStart(2, "0");
42869
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
42870
+ }
42871
+
42872
+ // src/providers/cli-provider-instance.ts
42873
+ function approvalModalSignature(message, affirmativeAnchor) {
42874
+ return [typeof message === "string" ? message.trim() : "", affirmativeAnchor].join("::");
42875
+ }
42731
42876
  var CliProviderInstance = class _CliProviderInstance {
42732
42877
  constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
42733
42878
  this.provider = provider;
@@ -42975,7 +43120,7 @@ var CliProviderInstance = class _CliProviderInstance {
42975
43120
  const resumedAt = Date.now();
42976
43121
  this.historyWriter.appendSystemMarker(
42977
43122
  this.type,
42978
- `Resumed saved session at ${this.formatMarkerTimestamp(resumedAt)}`,
43123
+ `Resumed saved session at ${formatMarkerTimestamp(resumedAt)}`,
42979
43124
  {
42980
43125
  instanceId: this.instanceId,
42981
43126
  historySessionId: this.providerSessionId,
@@ -43087,7 +43232,7 @@ var CliProviderInstance = class _CliProviderInstance {
43087
43232
  if (historyMessageCount !== null) {
43088
43233
  parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
43089
43234
  }
43090
- const mergedMessages = this.mergeConversationMessages(parsedMessages);
43235
+ const mergedMessages = mergeConversationMessages(this.runtimeMessages, parsedMessages);
43091
43236
  const canonicalBackedHistory = this.shouldHydrateExistingProviderHistory() ? this.syncCanonicalSavedHistoryIfNeeded() : false;
43092
43237
  const statusMessages = canonicalBackedHistory && this.lastPersistedHistoryMessages.length > 0 ? this.lastPersistedHistoryMessages.map((message) => ({
43093
43238
  role: message.role,
@@ -43552,22 +43697,6 @@ var CliProviderInstance = class _CliProviderInstance {
43552
43697
  }
43553
43698
  return true;
43554
43699
  }
43555
- buildExternalTranscriptProbe(messages, sourcePath, sourceMtimeMs) {
43556
- const visibleMessages = messages.filter((message) => isUserFacingChatMessage(message));
43557
- const lastVisible = visibleMessages[visibleMessages.length - 1];
43558
- const readAt = Date.now();
43559
- const mtimeMs = Number(sourceMtimeMs) || 0;
43560
- return {
43561
- readAt,
43562
- msgCount: messages.length,
43563
- lastRole: typeof lastVisible?.role === "string" ? lastVisible.role.trim().toLowerCase() : null,
43564
- lastKind: typeof lastVisible?.kind === "string" ? lastVisible.kind : null,
43565
- contentLen: lastVisible ? flattenContent(lastVisible.content).trim().length : 0,
43566
- sourcePath: typeof sourcePath === "string" && sourcePath ? sourcePath : null,
43567
- sourceMtimeMs: mtimeMs || null,
43568
- mtimeAgeMs: mtimeMs ? Math.max(0, readAt - mtimeMs) : null
43569
- };
43570
- }
43571
43700
  recordPendingTranscriptProbe(pending) {
43572
43701
  const probe = this.lastExternalCompletionProbe;
43573
43702
  if (!probe) return null;
@@ -43619,7 +43748,7 @@ var CliProviderInstance = class _CliProviderInstance {
43619
43748
  this.lastExternalCompletionProbe = null;
43620
43749
  return null;
43621
43750
  }
43622
- this.lastExternalCompletionProbe = this.buildExternalTranscriptProbe(
43751
+ this.lastExternalCompletionProbe = buildExternalTranscriptProbe(
43623
43752
  restoredHistory.messages,
43624
43753
  restoredHistory.sourcePath,
43625
43754
  restoredHistory.sourceMtimeMs
@@ -43867,6 +43996,27 @@ var CliProviderInstance = class _CliProviderInstance {
43867
43996
  autoApproveContinuityWindowMs() {
43868
43997
  return this.autoApproveMaskSince > 0 && this.isMeshWorkerSession() ? _CliProviderInstance.AUTO_APPROVE_FLAP_CONTINUITY_MS : _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS;
43869
43998
  }
43999
+ /**
44000
+ * The settle-gate identity signature for a raw activeModal, or null when the
44001
+ * modal is NOT a concrete auto-approvable consent prompt (no captured buttons,
44002
+ * a picker/confirm kind, or no reliable affirmative+decline anchor). Mirrors the
44003
+ * gates the auto-approve fire path applies before computing modalSignature, so
44004
+ * the mask-stall nudge can ask the SAME question the settle gate is tracking —
44005
+ * "is THIS frame's modal the identity the settle clock is accruing against?" —
44006
+ * without duplicating the button-pick logic. The signature is message +
44007
+ * normalized affirmative label only (no volatile counters/button set), matching
44008
+ * the fire path exactly (AUTOAPPROVE-SETTLE-FLAP).
44009
+ */
44010
+ approvableModalSignature(modal) {
44011
+ const buttons = Array.isArray(modal?.buttons) ? modal.buttons.map((b) => String(b || "").trim()).filter(Boolean) : [];
44012
+ if (!modal || buttons.length === 0) return null;
44013
+ const modalKind = typeof modal?.kind === "string" ? modal.kind : "approval";
44014
+ if (modalKind !== "approval") return null;
44015
+ const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(buttons, this.provider);
44016
+ const hasReliableConsentAnchor = hasNegativeApprovalOption(buttons) || hasReliableApprovalAffirmative(buttons);
44017
+ if (buttonIndex < 0 || !hasReliableConsentAnchor) return null;
44018
+ return approvalModalSignature(modal?.message, normalizeApprovalLabel(buttonLabel));
44019
+ }
43870
44020
  // FALSE-IDLE (self-coordinator settle): an autonomously-progressing mesh session
43871
44021
  // is either a delegated worker (isMeshWorkerSession) OR the coordinator's OWN
43872
44022
  // claude-cli session (meshCoordinatorFor). Both run auto-approved tool turns whose
@@ -44170,10 +44320,7 @@ var CliProviderInstance = class _CliProviderInstance {
44170
44320
  return autoApproveActive;
44171
44321
  }
44172
44322
  const affirmativeAnchor = normalizeApprovalLabel(buttonLabel);
44173
- const modalSignature = [
44174
- typeof modal?.message === "string" ? modal.message.trim() : "",
44175
- affirmativeAnchor
44176
- ].join("::");
44323
+ const modalSignature = approvalModalSignature(modal?.message, affirmativeAnchor);
44177
44324
  const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
44178
44325
  const busySignature = `${approvalEntrySeq}::${modalSignature}`;
44179
44326
  if (this.autoApproveBusy && busySignature === this.lastAutoApprovalSignature) {
@@ -44406,7 +44553,7 @@ var CliProviderInstance = class _CliProviderInstance {
44406
44553
  if (approvalFingerprint !== this.lastApprovalEventFingerprint) {
44407
44554
  this.lastApprovalEventFingerprint = approvalFingerprint;
44408
44555
  this.appendRuntimeSystemMessage(
44409
- this.formatApprovalRequestMessage(modal?.message, modal?.buttons),
44556
+ formatApprovalRequestMessage(modal?.message, modal?.buttons),
44410
44557
  `approval_request:${now}`,
44411
44558
  now
44412
44559
  );
@@ -44707,7 +44854,7 @@ var CliProviderInstance = class _CliProviderInstance {
44707
44854
  const effectWhen = effect.when || "immediate";
44708
44855
  if (effectWhen === "turn_completed" && options.phase !== "turn_completed") continue;
44709
44856
  if (effectWhen === "immediate" && options.phase === "turn_completed") continue;
44710
- const effectKey = this.getEffectDedupKey(effect);
44857
+ const effectKey = getEffectDedupKey(effect);
44711
44858
  if (this.appliedEffectKeys.has(effectKey)) continue;
44712
44859
  this.appliedEffectKeys.add(effectKey);
44713
44860
  if (effect.persist !== false) {
@@ -44750,34 +44897,6 @@ var CliProviderInstance = class _CliProviderInstance {
44750
44897
  this.appliedEffectKeys = new Set(Array.from(this.appliedEffectKeys).slice(-100));
44751
44898
  }
44752
44899
  }
44753
- getEffectDedupKey(effect) {
44754
- if (effect.id) return `provider_effect:${effect.id}`;
44755
- if (effect.type === "message") {
44756
- const content = typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
44757
- return `provider_effect:message:${content}`;
44758
- }
44759
- if (effect.type === "notification") {
44760
- return `provider_effect:notification:${effect.notification?.title || ""}:${effect.notification?.body || ""}`;
44761
- }
44762
- return `provider_effect:toast:${effect.toast?.message || ""}`;
44763
- }
44764
- getPersistedEffectContent(effect) {
44765
- if (effect.type === "message") {
44766
- return typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
44767
- }
44768
- if (effect.type === "toast") {
44769
- return effect.toast?.message || null;
44770
- }
44771
- if (effect.type === "notification") {
44772
- if (typeof effect.notification?.bubbleContent === "string") return effect.notification.bubbleContent;
44773
- if (typeof effect.notification?.title === "string" && effect.notification.title.trim()) {
44774
- return `${effect.notification.title}
44775
- ${effect.notification.body || ""}`.trim();
44776
- }
44777
- return effect.notification?.body || null;
44778
- }
44779
- return null;
44780
- }
44781
44900
  // ─── Adapter access (backward compat) ──────────────────
44782
44901
  getAdapter() {
44783
44902
  return this.adapter;
@@ -44849,15 +44968,16 @@ ${effect.notification.body || ""}`.trim();
44849
44968
  if (!this.isMeshWorkerSession()) return;
44850
44969
  if (adapterStatus?.status !== "waiting_approval") return;
44851
44970
  if (!this.autoApproveMaskStalled(now)) return;
44852
- const modalButtons = Array.isArray(adapterStatus.activeModal?.buttons) ? adapterStatus.activeModal.buttons.map((b) => String(b || "").trim()).filter(Boolean) : [];
44853
- if (this.pendingAutoApprovalSince && modalButtons.length > 0) return;
44971
+ const currentSignature = this.approvableModalSignature(adapterStatus.activeModal);
44972
+ const settleProgressing = !!currentSignature && this.pendingAutoApprovalSince > 0 && currentSignature === this.pendingAutoApprovalSignature;
44973
+ if (settleProgressing) return;
44854
44974
  if (this.stalledApprovalNudgeEpisode === this.autoApproveMaskSince) return;
44855
44975
  this.stalledApprovalNudgeEpisode = this.autoApproveMaskSince;
44856
44976
  const modal = adapterStatus.activeModal;
44857
44977
  const dirName = workingDirBasename(this.workingDir);
44858
44978
  const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
44859
44979
  this.appendRuntimeSystemMessage(
44860
- this.formatApprovalRequestMessage(modal?.message, modal?.buttons),
44980
+ formatApprovalRequestMessage(modal?.message, modal?.buttons),
44861
44981
  `approval_request:${now}`,
44862
44982
  now
44863
44983
  );
@@ -44887,11 +45007,6 @@ ${effect.notification.body || ""}`.trim();
44887
45007
  now
44888
45008
  );
44889
45009
  }
44890
- formatMarkerTimestamp(timestamp) {
44891
- const date = new Date(timestamp);
44892
- const pad = (value) => String(value).padStart(2, "0");
44893
- return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
44894
- }
44895
45010
  maybeAppendRuntimeRecoveryMessage(runtime) {
44896
45011
  if (!runtime?.restoredFromStorage || !runtime.runtimeId) return;
44897
45012
  const recoveryState = String(runtime.recoveryState || "").trim();
@@ -44952,81 +45067,7 @@ ${effect.notification.body || ""}`.trim();
44952
45067
  }
44953
45068
  }
44954
45069
  mergeRuntimeChatMessages(parsedMessages) {
44955
- return this.mergeConversationMessages(parsedMessages);
44956
- }
44957
- mergeConversationMessages(parsedMessages) {
44958
- if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
44959
- const parsedEntries = parsedMessages.map((message, index) => ({
44960
- message,
44961
- index,
44962
- source: "parsed"
44963
- }));
44964
- const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
44965
- const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
44966
- message: entry.message,
44967
- index: parsedMessages.length + index,
44968
- source: "runtime",
44969
- runtimeKey: entry.key
44970
- })).filter((entry) => {
44971
- const meta = entry.message.meta && typeof entry.message.meta === "object" && !Array.isArray(entry.message.meta) ? entry.message.meta : {};
44972
- if (meta.runtimeInputAck !== true) return true;
44973
- const runtimeText = flattenContent(entry.message.content).replace(/\s+/g, " ").trim();
44974
- if (!runtimeText) return false;
44975
- return !parsedEntries.some((parsedEntry) => {
44976
- const parsedRole = getRole(parsedEntry.message);
44977
- if (parsedRole !== "user" && parsedRole !== "human") return false;
44978
- const parsedText = flattenContent(parsedEntry.message.content).replace(/\s+/g, " ").trim();
44979
- return parsedText === runtimeText;
44980
- });
44981
- });
44982
- const getTime = (message) => {
44983
- const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
44984
- return Number.isFinite(value) && value > 0 ? value : 0;
44985
- };
44986
- const isRuntimeOverlay = (entry) => {
44987
- if (entry.source !== "runtime") return false;
44988
- const key2 = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
44989
- if (key2.startsWith("auto_approval:")) return true;
44990
- return !isUserFacingChatMessage(entry.message);
44991
- };
44992
- const shouldKeepParsedBeforeUntimedRuntime = (message) => {
44993
- const role = getRole(message);
44994
- return role === "user" || role === "human";
44995
- };
44996
- const shouldKeepParsedAfterUntimedRuntime = (message) => {
44997
- const role = getRole(message);
44998
- if (role !== "assistant") return false;
44999
- const kind = resolveChatMessageKind(message);
45000
- return kind === "standard" || kind === "terminal";
45001
- };
45002
- return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
45003
- const aTime = getTime(a.message);
45004
- const bTime = getTime(b.message);
45005
- if (aTime && bTime && aTime !== bTime) return aTime - bTime;
45006
- if (a.source !== b.source && aTime !== bTime) {
45007
- const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
45008
- const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
45009
- if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
45010
- if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
45011
- return a.source === "parsed" ? -1 : 1;
45012
- }
45013
- if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
45014
- return a.source === "parsed" ? 1 : -1;
45015
- }
45016
- }
45017
- }
45018
- return a.index - b.index;
45019
- }).map((entry) => entry.message));
45020
- }
45021
- formatApprovalRequestMessage(modalMessage, buttons) {
45022
- const lines = ["Approval requested"];
45023
- const cleanMessage = String(modalMessage || "").trim();
45024
- if (cleanMessage) lines.push(cleanMessage);
45025
- const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
45026
- if (labels.length > 0) {
45027
- lines.push(labels.map((label) => `[${label}]`).join(" "));
45028
- }
45029
- return lines.join("\n");
45070
+ return mergeConversationMessages(this.runtimeMessages, parsedMessages);
45030
45071
  }
45031
45072
  promoteProviderSessionId(sessionId, opts = {}) {
45032
45073
  const nextSessionId = String(sessionId || "").trim();