@adhdev/daemon-core 0.9.82-rc.431 → 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.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-06-
|
|
412
|
+
const commit = readInjected(true ? "818d857089de19d818903a7a416b3f84ccb594e3" : void 0) ?? "unknown";
|
|
413
|
+
const commitShort = readInjected(true ? "818d8570" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
414
|
+
const version = readInjected(true ? "0.9.82-rc.432" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
415
|
+
const builtAt = readInjected(true ? "2026-06-30T07:51:07.054Z" : void 0);
|
|
416
416
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
417
417
|
return cached;
|
|
418
418
|
}
|
|
@@ -16782,7 +16782,9 @@ function flushPendingForMeshIdleCoordinators(components, meshId) {
|
|
|
16782
16782
|
if (readNonEmptyString2(settings.meshCoordinatorFor) !== meshId) continue;
|
|
16783
16783
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
16784
16784
|
const modalParked = typeof inst.isModalParked === "function" ? inst.isModalParked() === true : status === "waiting_choice" || status === "waiting_approval";
|
|
16785
|
-
|
|
16785
|
+
const drainStatus = typeof inst.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
16786
|
+
const idle = drainStatus !== null ? drainStatus === "idle" : status === "idle";
|
|
16787
|
+
if (idle && !modalParked) {
|
|
16786
16788
|
idleCoordinators.push({ instance: inst, sessionId: readNonEmptyString2(state.instanceId) });
|
|
16787
16789
|
}
|
|
16788
16790
|
}
|
|
@@ -16955,6 +16957,9 @@ function resolveAutoPruneMinAgeMs() {
|
|
|
16955
16957
|
}
|
|
16956
16958
|
return DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
16957
16959
|
}
|
|
16960
|
+
function resolvePendingHeldDrainEscalateMs() {
|
|
16961
|
+
return resolveTunedReconcileMs("MESH_PENDING_HELD_DRAIN_ESCALATE_MS", DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, 4e3, 5 * 6e4);
|
|
16962
|
+
}
|
|
16958
16963
|
function resolveReconcileIntervalMs() {
|
|
16959
16964
|
const raw = readNonEmptyString2(process.env.MESH_RECONCILE_INTERVAL_MS);
|
|
16960
16965
|
if (raw) {
|
|
@@ -17017,6 +17022,8 @@ function findLiveCoordinators(components) {
|
|
|
17017
17022
|
if (!meshId) continue;
|
|
17018
17023
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
17019
17024
|
const modalParked = typeof inst.isModalParked === "function" ? inst.isModalParked() === true : status === "waiting_choice" || status === "waiting_approval";
|
|
17025
|
+
const drainStatus = typeof inst.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
17026
|
+
const idle = drainStatus !== null ? drainStatus === "idle" : status === "idle";
|
|
17020
17027
|
const sessionId = readNonEmptyString2(state.instanceId);
|
|
17021
17028
|
if (getLogLevel() === "debug") {
|
|
17022
17029
|
let adapterRaw = "?";
|
|
@@ -17031,7 +17038,7 @@ function findLiveCoordinators(components) {
|
|
|
17031
17038
|
const lastStatus = readNonEmptyString2(inst.lastStatus) || "?";
|
|
17032
17039
|
const autoApproveBusy = inst.autoApproveBusy;
|
|
17033
17040
|
const maskSince = inst.autoApproveMaskSince;
|
|
17034
|
-
LOG.debug("MeshReconcile", `coordDiag sess=${sessionId || "?"} mesh=${meshId} getState=${status || "?"} lastStatus=${lastStatus} adapterRaw=${adapterRaw} autoApproveBusy=${autoApproveBusy === true} maskSince=${maskSince || 0}`);
|
|
17041
|
+
LOG.debug("MeshReconcile", `coordDiag sess=${sessionId || "?"} mesh=${meshId} getState=${status || "?"} drainStatus=${drainStatus || "n/a"} lastStatus=${lastStatus} adapterRaw=${adapterRaw} autoApproveBusy=${autoApproveBusy === true} maskSince=${maskSince || 0}`);
|
|
17035
17042
|
}
|
|
17036
17043
|
const stateKey = `${meshId}::${sessionId || "?"}`;
|
|
17037
17044
|
const prevParked = coordinatorModalParkState.get(stateKey);
|
|
@@ -17043,7 +17050,7 @@ function findLiveCoordinators(components) {
|
|
|
17043
17050
|
LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) left modal-park (status=${status}) \u2014 held events will drain on this/next tick`);
|
|
17044
17051
|
}
|
|
17045
17052
|
}
|
|
17046
|
-
out.push({ meshId, instance: inst, sessionId, idle
|
|
17053
|
+
out.push({ meshId, instance: inst, sessionId, idle, modalParked });
|
|
17047
17054
|
}
|
|
17048
17055
|
return out;
|
|
17049
17056
|
}
|
|
@@ -17138,6 +17145,63 @@ function recordHeldTerminalEventsToLedger(meshId, drainDaemonIds, reason, heldFo
|
|
|
17138
17145
|
}
|
|
17139
17146
|
}
|
|
17140
17147
|
}
|
|
17148
|
+
function oldestHeldTerminalEventAgeMs(meshId, drainDaemonIds) {
|
|
17149
|
+
let pending;
|
|
17150
|
+
try {
|
|
17151
|
+
pending = getPendingMeshCoordinatorEvents(meshId, drainDaemonIds.length > 0 ? drainDaemonIds : void 0);
|
|
17152
|
+
} catch {
|
|
17153
|
+
return 0;
|
|
17154
|
+
}
|
|
17155
|
+
const now = Date.now();
|
|
17156
|
+
let maxAge = 0;
|
|
17157
|
+
for (const event of pending) {
|
|
17158
|
+
if (!shouldForceInjectMeshEvent(event.event)) continue;
|
|
17159
|
+
const queuedAt = typeof event.queuedAt === "number" ? event.queuedAt : now;
|
|
17160
|
+
const age = now - queuedAt;
|
|
17161
|
+
if (age > maxAge) maxAge = age;
|
|
17162
|
+
}
|
|
17163
|
+
return maxAge;
|
|
17164
|
+
}
|
|
17165
|
+
function reconfirmGenuinelyIdleCoordinators(generating) {
|
|
17166
|
+
const out = [];
|
|
17167
|
+
for (const c of generating) {
|
|
17168
|
+
const inst = c.instance;
|
|
17169
|
+
const drainStatus = typeof inst?.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
17170
|
+
const genuinelyIdle = drainStatus !== null ? drainStatus === "idle" : c.idle;
|
|
17171
|
+
if (genuinelyIdle) out.push({ ...c, idle: true });
|
|
17172
|
+
}
|
|
17173
|
+
return out;
|
|
17174
|
+
}
|
|
17175
|
+
function drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, targetCoordinators, logLabel) {
|
|
17176
|
+
let pendingEvents = [];
|
|
17177
|
+
try {
|
|
17178
|
+
pendingEvents = drainPendingMeshCoordinatorEvents(
|
|
17179
|
+
meshId,
|
|
17180
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
|
|
17181
|
+
);
|
|
17182
|
+
} catch (e) {
|
|
17183
|
+
LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
17184
|
+
return 0;
|
|
17185
|
+
}
|
|
17186
|
+
if (pendingEvents.length === 0) return 0;
|
|
17187
|
+
LOG.info("MeshReconcile", `Reconcile inject \u2192 ${logLabel}: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
|
|
17188
|
+
for (const pending of pendingEvents) {
|
|
17189
|
+
const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
|
|
17190
|
+
if (wantSession) {
|
|
17191
|
+
const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
|
|
17192
|
+
if (matched.length === 0) {
|
|
17193
|
+
holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
|
|
17194
|
+
continue;
|
|
17195
|
+
}
|
|
17196
|
+
for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
|
|
17197
|
+
continue;
|
|
17198
|
+
}
|
|
17199
|
+
for (const c of targetCoordinators) {
|
|
17200
|
+
injectPendingIntoCoordinator(c.instance, pending);
|
|
17201
|
+
}
|
|
17202
|
+
}
|
|
17203
|
+
return pendingEvents.length;
|
|
17204
|
+
}
|
|
17141
17205
|
function recoverStrandedAssignedDispatches(meshId, store) {
|
|
17142
17206
|
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
17143
17207
|
if (!assigned.length) return;
|
|
@@ -17349,6 +17413,19 @@ async function runMeshReconcileTick(components) {
|
|
|
17349
17413
|
}
|
|
17350
17414
|
}
|
|
17351
17415
|
if (hasPending) {
|
|
17416
|
+
const escalateMs = resolvePendingHeldDrainEscalateMs();
|
|
17417
|
+
const heldAgeMs = oldestHeldTerminalEventAgeMs(
|
|
17418
|
+
meshId,
|
|
17419
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId ? [localDaemonId] : []
|
|
17420
|
+
);
|
|
17421
|
+
if (heldAgeMs >= escalateMs) {
|
|
17422
|
+
const escapeTargets = reconfirmGenuinelyIdleCoordinators(generatingCoordinators);
|
|
17423
|
+
if (escapeTargets.length > 0) {
|
|
17424
|
+
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`);
|
|
17425
|
+
const drained = drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, escapeTargets, "age-escape");
|
|
17426
|
+
if (drained > 0) continue;
|
|
17427
|
+
}
|
|
17428
|
+
}
|
|
17352
17429
|
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)`);
|
|
17353
17430
|
if (getLogLevel() === "debug") {
|
|
17354
17431
|
LOG.debug("MeshReconcile", `coordHoldGenerating mesh=${meshId} heldFor=[${generatingCoordinators.map((c) => c.sessionId || "?").join(",")}] (these were classified busy; cross-ref same-tick coordDiag by sessionId)`);
|
|
@@ -17369,33 +17446,7 @@ async function runMeshReconcileTick(components) {
|
|
|
17369
17446
|
} catch {
|
|
17370
17447
|
}
|
|
17371
17448
|
}
|
|
17372
|
-
|
|
17373
|
-
try {
|
|
17374
|
-
pendingEvents = drainPendingMeshCoordinatorEvents(
|
|
17375
|
-
meshId,
|
|
17376
|
-
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
|
|
17377
|
-
);
|
|
17378
|
-
} catch (e) {
|
|
17379
|
-
LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
17380
|
-
continue;
|
|
17381
|
-
}
|
|
17382
|
-
if (pendingEvents.length === 0) continue;
|
|
17383
|
-
LOG.info("MeshReconcile", `Reconcile inject \u2192 idle: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
|
|
17384
|
-
for (const pending of pendingEvents) {
|
|
17385
|
-
const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
|
|
17386
|
-
if (wantSession) {
|
|
17387
|
-
const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
|
|
17388
|
-
if (matched.length === 0) {
|
|
17389
|
-
holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
|
|
17390
|
-
continue;
|
|
17391
|
-
}
|
|
17392
|
-
for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
|
|
17393
|
-
continue;
|
|
17394
|
-
}
|
|
17395
|
-
for (const c of targetCoordinators) {
|
|
17396
|
-
injectPendingIntoCoordinator(c.instance, pending);
|
|
17397
|
-
}
|
|
17398
|
-
}
|
|
17449
|
+
drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, targetCoordinators, "idle");
|
|
17399
17450
|
}
|
|
17400
17451
|
}
|
|
17401
17452
|
function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
@@ -17845,7 +17896,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
17845
17896
|
}
|
|
17846
17897
|
};
|
|
17847
17898
|
}
|
|
17848
|
-
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;
|
|
17899
|
+
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;
|
|
17849
17900
|
var init_mesh_reconcile_loop = __esm({
|
|
17850
17901
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
17851
17902
|
"use strict";
|
|
@@ -17867,6 +17918,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
17867
17918
|
init_chat_message_normalization();
|
|
17868
17919
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
17869
17920
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
17921
|
+
DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS = 12e3;
|
|
17870
17922
|
ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
|
|
17871
17923
|
inFlightAckedHoldState = /* @__PURE__ */ new Map();
|
|
17872
17924
|
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
@@ -41239,6 +41291,49 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
41239
41291
|
isModalParked() {
|
|
41240
41292
|
return this.resolveModalParkStatus() !== null;
|
|
41241
41293
|
}
|
|
41294
|
+
/**
|
|
41295
|
+
* PTY-OVERTRUST-DRAIN (Defect B). The deliverability/drain status the mesh
|
|
41296
|
+
* reconcile loop must consult — the RAW adapter turn-state, with the
|
|
41297
|
+
* auto-approve "hold-idle" visual mask STRIPPED.
|
|
41298
|
+
*
|
|
41299
|
+
* getState().status overlays `autoApproveHoldIdle`/`autoApproveActive` to paint a
|
|
41300
|
+
* genuinely-idle adapter as `generating` (a UI-flicker suppression while an
|
|
41301
|
+
* auto-approve key-press settles — see getState() ~:800). That mask is correct
|
|
41302
|
+
* for the dashboard, but the reconcile loop trusts it as "the coordinator is
|
|
41303
|
+
* busy" and therefore HOLDS a worker's completion under
|
|
41304
|
+
* `generating_no_idle_coordinator` even though the coordinator's PTY is at a real
|
|
41305
|
+
* turn end and would accept the inject as a turn — the completion is stranded.
|
|
41306
|
+
*
|
|
41307
|
+
* This accessor reports the drain truth instead:
|
|
41308
|
+
* - 'modal_parked' — a GENUINE human-await modal (AskUserQuestion / a non-
|
|
41309
|
+
* transient tool-consent). Still excluded from drain (a force-inject here
|
|
41310
|
+
* writes raw keystrokes the modal eats → data corruption). Mirrors
|
|
41311
|
+
* isModalParked(), evaluated first so a parked session never reads idle.
|
|
41312
|
+
* - 'idle' — the RAW adapter is at a turn end (adapter.getStatus(allowParse:false)
|
|
41313
|
+
* === 'idle') and the session is not modal-parked. Drain-eligible REGARDLESS
|
|
41314
|
+
* of the auto-approve mask. This is the case the mask used to hide.
|
|
41315
|
+
* - 'generating' — the raw adapter is genuinely mid-turn. Held (a raw PTY write
|
|
41316
|
+
* into a generating claude-cli is not consumed as a turn → data loss). The
|
|
41317
|
+
* intentional removal of force-inject-into-generating is preserved.
|
|
41318
|
+
* - 'other' — any other raw status (error / starting / waiting_choice handled by
|
|
41319
|
+
* modal-park above). Not a drain target.
|
|
41320
|
+
*
|
|
41321
|
+
* Uses allowParse:false (engine.activeModal only, side-effect-free) so it never
|
|
41322
|
+
* mutates the very auto-approve mask state the diagnostics read.
|
|
41323
|
+
*/
|
|
41324
|
+
getDrainStatus() {
|
|
41325
|
+
if (this.isModalParked()) return "modal_parked";
|
|
41326
|
+
let rawStatus;
|
|
41327
|
+
try {
|
|
41328
|
+
const raw = this.adapter.getStatus({ allowParse: false })?.status;
|
|
41329
|
+
rawStatus = typeof raw === "string" ? raw.trim() : "";
|
|
41330
|
+
} catch {
|
|
41331
|
+
return "other";
|
|
41332
|
+
}
|
|
41333
|
+
if (rawStatus === "idle") return "idle";
|
|
41334
|
+
if (isCliGeneratingLikeStatus(rawStatus)) return "generating";
|
|
41335
|
+
return "other";
|
|
41336
|
+
}
|
|
41242
41337
|
onEvent(event, data) {
|
|
41243
41338
|
if (event === "send_message") {
|
|
41244
41339
|
const input = normalizeInputEnvelope(data);
|