@adhdev/daemon-core 0.9.82-rc.430 → 0.9.82-rc.432
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 +130 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +130 -35
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-instance.d.ts +31 -0
- package/package.json +2 -2
- package/src/mesh/mesh-event-forwarding.ts +10 -1
- package/src/mesh/mesh-reconcile-loop.ts +171 -44
- package/src/providers/cli-provider-instance.ts +44 -0
package/dist/index.mjs
CHANGED
|
@@ -404,10 +404,10 @@ function readInjected(value) {
|
|
|
404
404
|
}
|
|
405
405
|
function getDaemonBuildInfo() {
|
|
406
406
|
if (cached) return cached;
|
|
407
|
-
const commit = readInjected(true ? "
|
|
408
|
-
const commitShort = readInjected(true ? "
|
|
409
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
410
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
407
|
+
const commit = readInjected(true ? "818d857089de19d818903a7a416b3f84ccb594e3" : void 0) ?? "unknown";
|
|
408
|
+
const commitShort = readInjected(true ? "818d8570" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
409
|
+
const version = readInjected(true ? "0.9.82-rc.432" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
410
|
+
const builtAt = readInjected(true ? "2026-06-30T07:51:07.054Z" : void 0);
|
|
411
411
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
412
412
|
return cached;
|
|
413
413
|
}
|
|
@@ -16777,7 +16777,9 @@ function flushPendingForMeshIdleCoordinators(components, meshId) {
|
|
|
16777
16777
|
if (readNonEmptyString2(settings.meshCoordinatorFor) !== meshId) continue;
|
|
16778
16778
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
16779
16779
|
const modalParked = typeof inst.isModalParked === "function" ? inst.isModalParked() === true : status === "waiting_choice" || status === "waiting_approval";
|
|
16780
|
-
|
|
16780
|
+
const drainStatus = typeof inst.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
16781
|
+
const idle = drainStatus !== null ? drainStatus === "idle" : status === "idle";
|
|
16782
|
+
if (idle && !modalParked) {
|
|
16781
16783
|
idleCoordinators.push({ instance: inst, sessionId: readNonEmptyString2(state.instanceId) });
|
|
16782
16784
|
}
|
|
16783
16785
|
}
|
|
@@ -16950,6 +16952,9 @@ function resolveAutoPruneMinAgeMs() {
|
|
|
16950
16952
|
}
|
|
16951
16953
|
return DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
16952
16954
|
}
|
|
16955
|
+
function resolvePendingHeldDrainEscalateMs() {
|
|
16956
|
+
return resolveTunedReconcileMs("MESH_PENDING_HELD_DRAIN_ESCALATE_MS", DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, 4e3, 5 * 6e4);
|
|
16957
|
+
}
|
|
16953
16958
|
function resolveReconcileIntervalMs() {
|
|
16954
16959
|
const raw = readNonEmptyString2(process.env.MESH_RECONCILE_INTERVAL_MS);
|
|
16955
16960
|
if (raw) {
|
|
@@ -17012,6 +17017,8 @@ function findLiveCoordinators(components) {
|
|
|
17012
17017
|
if (!meshId) continue;
|
|
17013
17018
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
17014
17019
|
const modalParked = typeof inst.isModalParked === "function" ? inst.isModalParked() === true : status === "waiting_choice" || status === "waiting_approval";
|
|
17020
|
+
const drainStatus = typeof inst.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
17021
|
+
const idle = drainStatus !== null ? drainStatus === "idle" : status === "idle";
|
|
17015
17022
|
const sessionId = readNonEmptyString2(state.instanceId);
|
|
17016
17023
|
if (getLogLevel() === "debug") {
|
|
17017
17024
|
let adapterRaw = "?";
|
|
@@ -17026,7 +17033,7 @@ function findLiveCoordinators(components) {
|
|
|
17026
17033
|
const lastStatus = readNonEmptyString2(inst.lastStatus) || "?";
|
|
17027
17034
|
const autoApproveBusy = inst.autoApproveBusy;
|
|
17028
17035
|
const maskSince = inst.autoApproveMaskSince;
|
|
17029
|
-
LOG.debug("MeshReconcile", `coordDiag sess=${sessionId || "?"} mesh=${meshId} getState=${status || "?"} lastStatus=${lastStatus} adapterRaw=${adapterRaw} autoApproveBusy=${autoApproveBusy === true} maskSince=${maskSince || 0}`);
|
|
17036
|
+
LOG.debug("MeshReconcile", `coordDiag sess=${sessionId || "?"} mesh=${meshId} getState=${status || "?"} drainStatus=${drainStatus || "n/a"} lastStatus=${lastStatus} adapterRaw=${adapterRaw} autoApproveBusy=${autoApproveBusy === true} maskSince=${maskSince || 0}`);
|
|
17030
17037
|
}
|
|
17031
17038
|
const stateKey = `${meshId}::${sessionId || "?"}`;
|
|
17032
17039
|
const prevParked = coordinatorModalParkState.get(stateKey);
|
|
@@ -17038,7 +17045,7 @@ function findLiveCoordinators(components) {
|
|
|
17038
17045
|
LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) left modal-park (status=${status}) \u2014 held events will drain on this/next tick`);
|
|
17039
17046
|
}
|
|
17040
17047
|
}
|
|
17041
|
-
out.push({ meshId, instance: inst, sessionId, idle
|
|
17048
|
+
out.push({ meshId, instance: inst, sessionId, idle, modalParked });
|
|
17042
17049
|
}
|
|
17043
17050
|
return out;
|
|
17044
17051
|
}
|
|
@@ -17133,6 +17140,63 @@ function recordHeldTerminalEventsToLedger(meshId, drainDaemonIds, reason, heldFo
|
|
|
17133
17140
|
}
|
|
17134
17141
|
}
|
|
17135
17142
|
}
|
|
17143
|
+
function oldestHeldTerminalEventAgeMs(meshId, drainDaemonIds) {
|
|
17144
|
+
let pending;
|
|
17145
|
+
try {
|
|
17146
|
+
pending = getPendingMeshCoordinatorEvents(meshId, drainDaemonIds.length > 0 ? drainDaemonIds : void 0);
|
|
17147
|
+
} catch {
|
|
17148
|
+
return 0;
|
|
17149
|
+
}
|
|
17150
|
+
const now = Date.now();
|
|
17151
|
+
let maxAge = 0;
|
|
17152
|
+
for (const event of pending) {
|
|
17153
|
+
if (!shouldForceInjectMeshEvent(event.event)) continue;
|
|
17154
|
+
const queuedAt = typeof event.queuedAt === "number" ? event.queuedAt : now;
|
|
17155
|
+
const age = now - queuedAt;
|
|
17156
|
+
if (age > maxAge) maxAge = age;
|
|
17157
|
+
}
|
|
17158
|
+
return maxAge;
|
|
17159
|
+
}
|
|
17160
|
+
function reconfirmGenuinelyIdleCoordinators(generating) {
|
|
17161
|
+
const out = [];
|
|
17162
|
+
for (const c of generating) {
|
|
17163
|
+
const inst = c.instance;
|
|
17164
|
+
const drainStatus = typeof inst?.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
17165
|
+
const genuinelyIdle = drainStatus !== null ? drainStatus === "idle" : c.idle;
|
|
17166
|
+
if (genuinelyIdle) out.push({ ...c, idle: true });
|
|
17167
|
+
}
|
|
17168
|
+
return out;
|
|
17169
|
+
}
|
|
17170
|
+
function drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, targetCoordinators, logLabel) {
|
|
17171
|
+
let pendingEvents = [];
|
|
17172
|
+
try {
|
|
17173
|
+
pendingEvents = drainPendingMeshCoordinatorEvents(
|
|
17174
|
+
meshId,
|
|
17175
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
|
|
17176
|
+
);
|
|
17177
|
+
} catch (e) {
|
|
17178
|
+
LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
17179
|
+
return 0;
|
|
17180
|
+
}
|
|
17181
|
+
if (pendingEvents.length === 0) return 0;
|
|
17182
|
+
LOG.info("MeshReconcile", `Reconcile inject \u2192 ${logLabel}: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
|
|
17183
|
+
for (const pending of pendingEvents) {
|
|
17184
|
+
const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
|
|
17185
|
+
if (wantSession) {
|
|
17186
|
+
const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
|
|
17187
|
+
if (matched.length === 0) {
|
|
17188
|
+
holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
|
|
17189
|
+
continue;
|
|
17190
|
+
}
|
|
17191
|
+
for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
|
|
17192
|
+
continue;
|
|
17193
|
+
}
|
|
17194
|
+
for (const c of targetCoordinators) {
|
|
17195
|
+
injectPendingIntoCoordinator(c.instance, pending);
|
|
17196
|
+
}
|
|
17197
|
+
}
|
|
17198
|
+
return pendingEvents.length;
|
|
17199
|
+
}
|
|
17136
17200
|
function recoverStrandedAssignedDispatches(meshId, store) {
|
|
17137
17201
|
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
17138
17202
|
if (!assigned.length) return;
|
|
@@ -17344,6 +17408,19 @@ async function runMeshReconcileTick(components) {
|
|
|
17344
17408
|
}
|
|
17345
17409
|
}
|
|
17346
17410
|
if (hasPending) {
|
|
17411
|
+
const escalateMs = resolvePendingHeldDrainEscalateMs();
|
|
17412
|
+
const heldAgeMs = oldestHeldTerminalEventAgeMs(
|
|
17413
|
+
meshId,
|
|
17414
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId ? [localDaemonId] : []
|
|
17415
|
+
);
|
|
17416
|
+
if (heldAgeMs >= escalateMs) {
|
|
17417
|
+
const escapeTargets = reconfirmGenuinelyIdleCoordinators(generatingCoordinators);
|
|
17418
|
+
if (escapeTargets.length > 0) {
|
|
17419
|
+
LOG.info("MeshReconcile", `Reconcile age-escape \u2192 generating-hold: held terminal event(s) for mesh ${meshId} aged ${Math.round(heldAgeMs / 1e3)}s (\u2265 ${Math.round(escalateMs / 1e3)}s) and ${escapeTargets.length} coordinator(s) re-confirmed genuinely idle on the raw adapter \u2014 draining once`);
|
|
17420
|
+
const drained = drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, escapeTargets, "age-escape");
|
|
17421
|
+
if (drained > 0) continue;
|
|
17422
|
+
}
|
|
17423
|
+
}
|
|
17347
17424
|
LOG.info("MeshReconcile", `Reconcile skip \u2192 generating: holding pending event(s) for mesh ${meshId} (${generatingCoordinators.length} coordinator(s) busy; events left queued for the next idle tick)`);
|
|
17348
17425
|
if (getLogLevel() === "debug") {
|
|
17349
17426
|
LOG.debug("MeshReconcile", `coordHoldGenerating mesh=${meshId} heldFor=[${generatingCoordinators.map((c) => c.sessionId || "?").join(",")}] (these were classified busy; cross-ref same-tick coordDiag by sessionId)`);
|
|
@@ -17364,33 +17441,7 @@ async function runMeshReconcileTick(components) {
|
|
|
17364
17441
|
} catch {
|
|
17365
17442
|
}
|
|
17366
17443
|
}
|
|
17367
|
-
|
|
17368
|
-
try {
|
|
17369
|
-
pendingEvents = drainPendingMeshCoordinatorEvents(
|
|
17370
|
-
meshId,
|
|
17371
|
-
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
|
|
17372
|
-
);
|
|
17373
|
-
} catch (e) {
|
|
17374
|
-
LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
17375
|
-
continue;
|
|
17376
|
-
}
|
|
17377
|
-
if (pendingEvents.length === 0) continue;
|
|
17378
|
-
LOG.info("MeshReconcile", `Reconcile inject \u2192 idle: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
|
|
17379
|
-
for (const pending of pendingEvents) {
|
|
17380
|
-
const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
|
|
17381
|
-
if (wantSession) {
|
|
17382
|
-
const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
|
|
17383
|
-
if (matched.length === 0) {
|
|
17384
|
-
holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
|
|
17385
|
-
continue;
|
|
17386
|
-
}
|
|
17387
|
-
for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
|
|
17388
|
-
continue;
|
|
17389
|
-
}
|
|
17390
|
-
for (const c of targetCoordinators) {
|
|
17391
|
-
injectPendingIntoCoordinator(c.instance, pending);
|
|
17392
|
-
}
|
|
17393
|
-
}
|
|
17444
|
+
drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, targetCoordinators, "idle");
|
|
17394
17445
|
}
|
|
17395
17446
|
}
|
|
17396
17447
|
function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
@@ -17840,7 +17891,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
17840
17891
|
}
|
|
17841
17892
|
};
|
|
17842
17893
|
}
|
|
17843
|
-
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
|
|
17894
|
+
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
|
|
17844
17895
|
var init_mesh_reconcile_loop = __esm({
|
|
17845
17896
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
17846
17897
|
"use strict";
|
|
@@ -17862,6 +17913,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
17862
17913
|
init_chat_message_normalization();
|
|
17863
17914
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
17864
17915
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
17916
|
+
DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS = 12e3;
|
|
17865
17917
|
ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
|
|
17866
17918
|
inFlightAckedHoldState = /* @__PURE__ */ new Map();
|
|
17867
17919
|
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
@@ -40840,6 +40892,49 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
40840
40892
|
isModalParked() {
|
|
40841
40893
|
return this.resolveModalParkStatus() !== null;
|
|
40842
40894
|
}
|
|
40895
|
+
/**
|
|
40896
|
+
* PTY-OVERTRUST-DRAIN (Defect B). The deliverability/drain status the mesh
|
|
40897
|
+
* reconcile loop must consult — the RAW adapter turn-state, with the
|
|
40898
|
+
* auto-approve "hold-idle" visual mask STRIPPED.
|
|
40899
|
+
*
|
|
40900
|
+
* getState().status overlays `autoApproveHoldIdle`/`autoApproveActive` to paint a
|
|
40901
|
+
* genuinely-idle adapter as `generating` (a UI-flicker suppression while an
|
|
40902
|
+
* auto-approve key-press settles — see getState() ~:800). That mask is correct
|
|
40903
|
+
* for the dashboard, but the reconcile loop trusts it as "the coordinator is
|
|
40904
|
+
* busy" and therefore HOLDS a worker's completion under
|
|
40905
|
+
* `generating_no_idle_coordinator` even though the coordinator's PTY is at a real
|
|
40906
|
+
* turn end and would accept the inject as a turn — the completion is stranded.
|
|
40907
|
+
*
|
|
40908
|
+
* This accessor reports the drain truth instead:
|
|
40909
|
+
* - 'modal_parked' — a GENUINE human-await modal (AskUserQuestion / a non-
|
|
40910
|
+
* transient tool-consent). Still excluded from drain (a force-inject here
|
|
40911
|
+
* writes raw keystrokes the modal eats → data corruption). Mirrors
|
|
40912
|
+
* isModalParked(), evaluated first so a parked session never reads idle.
|
|
40913
|
+
* - 'idle' — the RAW adapter is at a turn end (adapter.getStatus(allowParse:false)
|
|
40914
|
+
* === 'idle') and the session is not modal-parked. Drain-eligible REGARDLESS
|
|
40915
|
+
* of the auto-approve mask. This is the case the mask used to hide.
|
|
40916
|
+
* - 'generating' — the raw adapter is genuinely mid-turn. Held (a raw PTY write
|
|
40917
|
+
* into a generating claude-cli is not consumed as a turn → data loss). The
|
|
40918
|
+
* intentional removal of force-inject-into-generating is preserved.
|
|
40919
|
+
* - 'other' — any other raw status (error / starting / waiting_choice handled by
|
|
40920
|
+
* modal-park above). Not a drain target.
|
|
40921
|
+
*
|
|
40922
|
+
* Uses allowParse:false (engine.activeModal only, side-effect-free) so it never
|
|
40923
|
+
* mutates the very auto-approve mask state the diagnostics read.
|
|
40924
|
+
*/
|
|
40925
|
+
getDrainStatus() {
|
|
40926
|
+
if (this.isModalParked()) return "modal_parked";
|
|
40927
|
+
let rawStatus;
|
|
40928
|
+
try {
|
|
40929
|
+
const raw = this.adapter.getStatus({ allowParse: false })?.status;
|
|
40930
|
+
rawStatus = typeof raw === "string" ? raw.trim() : "";
|
|
40931
|
+
} catch {
|
|
40932
|
+
return "other";
|
|
40933
|
+
}
|
|
40934
|
+
if (rawStatus === "idle") return "idle";
|
|
40935
|
+
if (isCliGeneratingLikeStatus(rawStatus)) return "generating";
|
|
40936
|
+
return "other";
|
|
40937
|
+
}
|
|
40843
40938
|
onEvent(event, data) {
|
|
40844
40939
|
if (event === "send_message") {
|
|
40845
40940
|
const input = normalizeInputEnvelope(data);
|