@adhdev/daemon-core 0.9.82-rc.466 → 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 +188 -147
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +195 -154
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-effect-format.d.ts +30 -0
- package/dist/providers/cli-provider-instance-types.d.ts +45 -0
- package/dist/providers/cli-provider-instance.d.ts +12 -6
- package/dist/providers/cli-provider-transcript-merge.d.ts +7 -0
- package/package.json +3 -3
- package/src/mesh/mesh-events-pending.ts +2 -0
- package/src/mesh/mesh-reconcile-loop.ts +32 -5
- package/src/mesh/mesh-runtime-store.ts +46 -1
- package/src/providers/cli-provider-effect-format.ts +53 -0
- package/src/providers/cli-provider-instance-types.ts +131 -0
- package/src/providers/cli-provider-instance.ts +87 -303
- package/src/providers/cli-provider-transcript-merge.ts +114 -0
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 ? "
|
|
413
|
-
const commitShort = readInjected(true ? "
|
|
414
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
415
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
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
|
-
|
|
19338
|
+
await Promise.allSettled(mesh.nodes.map(async (node) => {
|
|
19317
19339
|
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
19318
|
-
if (!nodeDaemonId)
|
|
19319
|
-
if (daemonIdsEquivalent(nodeDaemonId, localDaemonId))
|
|
19320
|
-
if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId))
|
|
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 ${
|
|
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.
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
|
44853
|
-
|
|
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
|
-
|
|
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.
|
|
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();
|