@adhdev/daemon-core 1.0.18-rc.12 → 1.0.18-rc.14
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 +192 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +192 -30
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-remote-event-pull.d.ts +3 -0
- package/dist/providers/cli-provider-instance.d.ts +45 -0
- package/package.json +3 -3
- package/src/commands/cli-manager.ts +18 -0
- package/src/mesh/mesh-reconcile-loop.ts +43 -2
- package/src/mesh/mesh-remote-event-pull.ts +68 -47
- package/src/providers/cli-provider-instance.ts +167 -0
package/dist/index.js
CHANGED
|
@@ -442,10 +442,10 @@ function readInjected(value) {
|
|
|
442
442
|
}
|
|
443
443
|
function getDaemonBuildInfo() {
|
|
444
444
|
if (cached) return cached;
|
|
445
|
-
const commit = readInjected(true ? "
|
|
446
|
-
const commitShort = readInjected(true ? "
|
|
447
|
-
const version = readInjected(true ? "1.0.18-rc.
|
|
448
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
445
|
+
const commit = readInjected(true ? "a44f4a2814c4db171a9ebb0f6fcfb0798203aebb" : void 0) ?? "unknown";
|
|
446
|
+
const commitShort = readInjected(true ? "a44f4a28" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
447
|
+
const version = readInjected(true ? "1.0.18-rc.14" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
448
|
+
const builtAt = readInjected(true ? "2026-07-22T17:37:52.683Z" : void 0);
|
|
449
449
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
450
450
|
return cached;
|
|
451
451
|
}
|
|
@@ -22227,34 +22227,37 @@ async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDa
|
|
|
22227
22227
|
if (!dispatchMeshCommand) return;
|
|
22228
22228
|
const meshId = mesh.id;
|
|
22229
22229
|
const pulls = candidateDaemonIds.length > 0 ? candidateDaemonIds.map((id) => ({ meshId, coordinatorDaemonId: id })) : [{ meshId }];
|
|
22230
|
-
await Promise.allSettled(mesh.nodes.map(
|
|
22231
|
-
|
|
22232
|
-
|
|
22233
|
-
|
|
22234
|
-
|
|
22235
|
-
|
|
22236
|
-
|
|
22237
|
-
|
|
22238
|
-
|
|
22239
|
-
|
|
22240
|
-
|
|
22241
|
-
|
|
22230
|
+
await Promise.allSettled(mesh.nodes.map((node) => pullPendingEventsFromNode(components, meshId, node, localDaemonId, candidateDaemonIds, pulls)));
|
|
22231
|
+
}
|
|
22232
|
+
async function pullPendingEventsFromNode(components, meshId, node, localDaemonId, candidateDaemonIds, pulls) {
|
|
22233
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
22234
|
+
if (!dispatchMeshCommand) return;
|
|
22235
|
+
const nodeDaemonId = readNonEmptyString(node.daemonId);
|
|
22236
|
+
if (!nodeDaemonId) return;
|
|
22237
|
+
if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) return;
|
|
22238
|
+
if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) return;
|
|
22239
|
+
const getPeerStatus = components.getMeshPeerConnectionStatus;
|
|
22240
|
+
if (getPeerStatus) {
|
|
22241
|
+
const peerSnapshot = getPeerStatus(nodeDaemonId);
|
|
22242
|
+
if (!peerSnapshot || String(peerSnapshot.state) !== "connected") return;
|
|
22243
|
+
}
|
|
22244
|
+
for (const pendingEventArgs of pulls) {
|
|
22245
|
+
let events;
|
|
22246
|
+
try {
|
|
22247
|
+
events = await dispatchMeshCommand(nodeDaemonId, "get_pending_mesh_events", pendingEventArgs);
|
|
22248
|
+
} catch {
|
|
22249
|
+
break;
|
|
22250
|
+
}
|
|
22251
|
+
const list = extractPendingEvents(events).filter((e) => readNonEmptyString(e?.meshId) === meshId);
|
|
22252
|
+
for (const event of list) {
|
|
22253
|
+
const payload = buildForwardPayloadFromPending(event);
|
|
22254
|
+
if (!payload.event || !payload.meshId) continue;
|
|
22242
22255
|
try {
|
|
22243
|
-
|
|
22256
|
+
handleMeshForwardEvent(components, payload);
|
|
22244
22257
|
} catch {
|
|
22245
|
-
break;
|
|
22246
|
-
}
|
|
22247
|
-
const list = extractPendingEvents(events).filter((e) => readNonEmptyString(e?.meshId) === meshId);
|
|
22248
|
-
for (const event of list) {
|
|
22249
|
-
const payload = buildForwardPayloadFromPending(event);
|
|
22250
|
-
if (!payload.event || !payload.meshId) continue;
|
|
22251
|
-
try {
|
|
22252
|
-
handleMeshForwardEvent(components, payload);
|
|
22253
|
-
} catch {
|
|
22254
|
-
}
|
|
22255
22258
|
}
|
|
22256
22259
|
}
|
|
22257
|
-
}
|
|
22260
|
+
}
|
|
22258
22261
|
}
|
|
22259
22262
|
function unwrapReadChatPayload(raw) {
|
|
22260
22263
|
let cursor = raw;
|
|
@@ -23156,7 +23159,7 @@ function assignedRowLiveStatusIsAwaitingApproval(mesh, nodeId, sessionId) {
|
|
|
23156
23159
|
return false;
|
|
23157
23160
|
}
|
|
23158
23161
|
}
|
|
23159
|
-
async function recoverStrandedAssignedDispatches(components, mesh, store) {
|
|
23162
|
+
async function recoverStrandedAssignedDispatches(components, mesh, store, localDaemonId, selfIds = []) {
|
|
23160
23163
|
const meshId = mesh.id;
|
|
23161
23164
|
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
23162
23165
|
if (!assigned.length) return;
|
|
@@ -23180,6 +23183,24 @@ async function recoverStrandedAssignedDispatches(components, mesh, store) {
|
|
|
23180
23183
|
updateTaskStatus(meshId, row.id, status);
|
|
23181
23184
|
continue;
|
|
23182
23185
|
}
|
|
23186
|
+
const assignedNode = row.assignedNodeId ? mesh.nodes?.find((n) => meshNodeIdMatches(n, row.assignedNodeId)) : void 0;
|
|
23187
|
+
if (assignedNode?.daemonId) {
|
|
23188
|
+
try {
|
|
23189
|
+
await pullPendingEventsFromNode(
|
|
23190
|
+
components,
|
|
23191
|
+
meshId,
|
|
23192
|
+
assignedNode,
|
|
23193
|
+
localDaemonId,
|
|
23194
|
+
selfIds,
|
|
23195
|
+
selfIds.length > 0 ? selfIds.map((id) => ({ meshId, coordinatorDaemonId: id })) : [{ meshId }]
|
|
23196
|
+
);
|
|
23197
|
+
} catch {
|
|
23198
|
+
}
|
|
23199
|
+
if (store.taskDeliveryConsumed(meshId, row.id)) {
|
|
23200
|
+
deliveredUnconsumedUnknownStreak.delete(`${meshId}::${row.id}`);
|
|
23201
|
+
continue;
|
|
23202
|
+
}
|
|
23203
|
+
}
|
|
23183
23204
|
const shortStreakKey = `${meshId}::${row.id}`;
|
|
23184
23205
|
const verdict = row.assignedSessionId ? resolveSessionBusyVerdict(components, row.assignedSessionId) : "IDLE_CONFIRMED";
|
|
23185
23206
|
if (verdict === "GENERATING") {
|
|
@@ -23438,7 +23459,7 @@ async function runMeshReconcileTick(components) {
|
|
|
23438
23459
|
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
23439
23460
|
if (!daemonHostsMesh(mesh, selfIds)) continue;
|
|
23440
23461
|
try {
|
|
23441
|
-
await recoverStrandedAssignedDispatches(components, mesh, store);
|
|
23462
|
+
await recoverStrandedAssignedDispatches(components, mesh, store, localDaemonId, selfIds);
|
|
23442
23463
|
} catch (e) {
|
|
23443
23464
|
LOG.warn("MeshReconcile", `Assigned-stranded watchdog failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
23444
23465
|
}
|
|
@@ -49540,6 +49561,18 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
49540
49561
|
// MESH_WORKER_STALL_REFIRE_COOLDOWN_MS between successive emissions across
|
|
49541
49562
|
// anchor re-arms (the per-anchor guard only covers a single continuous stall).
|
|
49542
49563
|
meshStallLastFiredAt = -1;
|
|
49564
|
+
// KIMI-MESH-COMPLETION-EMIT (axis 1): the native-source transcript progress
|
|
49565
|
+
// fingerprint (record count + source mtime) observed the LAST time the stall
|
|
49566
|
+
// watchdog checked a native-source provider (transcriptAuthority=provider — e.g.
|
|
49567
|
+
// kimi wire.jsonl). A pure-PTY native-source worker running a long, screen-quiet
|
|
49568
|
+
// tool (no viewport bytes for minutes) looks stalled by the lastOutputAt clock
|
|
49569
|
+
// even though its transcript file is still growing. Before firing the stall, we
|
|
49570
|
+
// compare the current transcript fingerprint against this snapshot; if the
|
|
49571
|
+
// transcript advanced, the "stall" is a false positive of PTY-render stasis, so
|
|
49572
|
+
// we re-arm the anchor instead of paging the coordinator (whose no_progress
|
|
49573
|
+
// handling can lead to the worker being stopped mid-work → completion never
|
|
49574
|
+
// emitted). null = not yet sampled for this session/anchor.
|
|
49575
|
+
meshStallNativeTranscriptSample = null;
|
|
49543
49576
|
// FALSE-IDLE continuity epoch: monotonically bumped on EVERY entry into a busy
|
|
49544
49577
|
// phase (→generating or →waiting_approval). The completedDebouncePending snapshots
|
|
49545
49578
|
// this value at arm time (busyEpochAtArm); the flush guard requires it UNCHANGED
|
|
@@ -50349,6 +50382,14 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
50349
50382
|
* once at completion). Reset on the next turn's start.
|
|
50350
50383
|
*/
|
|
50351
50384
|
lastCompletionSummary = null;
|
|
50385
|
+
// KIMI-MESH-COMPLETION-EMIT (axis 2, double-emit guard): the (taskId, wall-clock)
|
|
50386
|
+
// of the most recent agent:generating_completed this instance emitted, stamped by
|
|
50387
|
+
// emitGeneratingCompleted. The pre-cleanup completion flush
|
|
50388
|
+
// (flushMeshCompletionBeforeCleanup, driven by cli-manager's exit monitor) reads
|
|
50389
|
+
// this to refuse a SECOND completion for a turn whose completion already fired —
|
|
50390
|
+
// so a worker that finished cleanly and is simply being auto-cleaned never emits a
|
|
50391
|
+
// duplicate. taskId '' covers an ad-hoc (no-task) turn. null = none emitted yet.
|
|
50392
|
+
lastEmittedCompletion = null;
|
|
50352
50393
|
async enforceFreshSessionLaunchIfNeeded() {
|
|
50353
50394
|
const scriptName = getForcedNewSessionScriptName(this.provider, this.launchMode);
|
|
50354
50395
|
if (!scriptName) return;
|
|
@@ -50974,6 +51015,24 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
50974
51015
|
const threshold = turnActive ? _CliProviderInstance.MESH_WORKER_STALL_TURN_THRESHOLD_MS : _CliProviderInstance.MESH_WORKER_STALL_IDLE_THRESHOLD_MS;
|
|
50975
51016
|
const stalledMs = now - this.meshStallAnchorAt;
|
|
50976
51017
|
if (stalledMs < threshold) return;
|
|
51018
|
+
const nativeSample = this.sampleNativeTranscriptProgress();
|
|
51019
|
+
if (nativeSample) {
|
|
51020
|
+
const prev = this.meshStallNativeTranscriptSample;
|
|
51021
|
+
const advanced = !prev || nativeSample.msgCount > prev.msgCount || nativeSample.sourceMtimeMs > prev.sourceMtimeMs;
|
|
51022
|
+
this.meshStallNativeTranscriptSample = nativeSample;
|
|
51023
|
+
if (advanced) {
|
|
51024
|
+
if (this.isMeshWorkerSession()) {
|
|
51025
|
+
traceMeshEventDrop(
|
|
51026
|
+
"mesh_worker_stall_transcript_advancing",
|
|
51027
|
+
this.meshTraceCtx("monitor:no_progress"),
|
|
51028
|
+
`msgCount=${nativeSample.msgCount} sourceMtime=${nativeSample.sourceMtimeMs} (PTY quiet ${Math.round(stalledMs / 1e3)}s but transcript advancing)`
|
|
51029
|
+
);
|
|
51030
|
+
}
|
|
51031
|
+
this.meshStallAnchorAt = now;
|
|
51032
|
+
this.meshStallEmittedForAnchor = false;
|
|
51033
|
+
return;
|
|
51034
|
+
}
|
|
51035
|
+
}
|
|
50977
51036
|
this.meshStallEmittedForAnchor = true;
|
|
50978
51037
|
if (this.meshStallLastFiredAt >= 0 && now - this.meshStallLastFiredAt < _CliProviderInstance.MESH_WORKER_STALL_REFIRE_COOLDOWN_MS) {
|
|
50979
51038
|
return;
|
|
@@ -51010,6 +51069,99 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
51010
51069
|
this.meshStallEmittedForAnchor = false;
|
|
51011
51070
|
this.meshStallTurnActiveLast = void 0;
|
|
51012
51071
|
this.meshStallLastFiredAt = -1;
|
|
51072
|
+
this.meshStallNativeTranscriptSample = null;
|
|
51073
|
+
}
|
|
51074
|
+
/**
|
|
51075
|
+
* KIMI-MESH-COMPLETION-EMIT (axis 1). For a native-source provider
|
|
51076
|
+
* (transcriptAuthority=provider — its authoritative history is an on-disk
|
|
51077
|
+
* transcript file, e.g. kimi's wire.jsonl), sample the transcript's current
|
|
51078
|
+
* progress fingerprint (record count + source-file mtime) WITHOUT parsing the
|
|
51079
|
+
* PTY. Used by the stall watchdog to distinguish "PTY render is quiet but the
|
|
51080
|
+
* worker is still doing long tool work (transcript growing)" from a genuine
|
|
51081
|
+
* wedge. Returns null for a pure-PTY provider (no native source) or when the
|
|
51082
|
+
* source cannot be resolved this tick — the caller then falls back to the
|
|
51083
|
+
* unchanged lastOutputAt-only judgment.
|
|
51084
|
+
*
|
|
51085
|
+
* Generalized on the provider's native-source flag, NOT a hardcoded provider
|
|
51086
|
+
* type, so every current and future pure-PTY long-tool native-source provider
|
|
51087
|
+
* benefits. Cheap enough for the stall path: it runs only at the stall threshold
|
|
51088
|
+
* (≥180s of PTY stasis), never on the routine 5s tick.
|
|
51089
|
+
*/
|
|
51090
|
+
sampleNativeTranscriptProgress() {
|
|
51091
|
+
if (!isNativeSourceCanonicalHistory(this.provider?.nativeHistory)) return null;
|
|
51092
|
+
let messages = null;
|
|
51093
|
+
try {
|
|
51094
|
+
messages = this.readExternalCompletionMessages();
|
|
51095
|
+
} catch {
|
|
51096
|
+
return null;
|
|
51097
|
+
}
|
|
51098
|
+
const probe = this.lastExternalCompletionProbe;
|
|
51099
|
+
if (!probe) return null;
|
|
51100
|
+
return {
|
|
51101
|
+
msgCount: typeof probe.msgCount === "number" ? probe.msgCount : Array.isArray(messages) ? messages.length : 0,
|
|
51102
|
+
sourceMtimeMs: typeof probe.sourceMtimeMs === "number" ? probe.sourceMtimeMs : 0
|
|
51103
|
+
};
|
|
51104
|
+
}
|
|
51105
|
+
/**
|
|
51106
|
+
* KIMI-MESH-COMPLETION-EMIT (axis 2). Last-chance completion emit for a mesh
|
|
51107
|
+
* DELEGATED worker whose PTY has already exited (e.g. killed by a false stall)
|
|
51108
|
+
* and is about to be auto-cleaned (cli-manager.startCliExitMonitor →
|
|
51109
|
+
* removeInstance closes the event-emit window forever). If the worker actually
|
|
51110
|
+
* FINISHED its assigned turn — its authoritative native transcript holds a final
|
|
51111
|
+
* assistant message for the injected task — but the completion event never fired
|
|
51112
|
+
* (the stall-kill happened before the FSM's idle transition), emit it now so the
|
|
51113
|
+
* coordinator learns the task completed instead of waiting ~180s for the reconcile
|
|
51114
|
+
* transcript-poll to reclaim it.
|
|
51115
|
+
*
|
|
51116
|
+
* Scope & guards (must all hold to emit):
|
|
51117
|
+
* • mesh worker session only — a normal standalone session's ordinary exit is
|
|
51118
|
+
* never synthesized (isMeshWorkerSession()).
|
|
51119
|
+
* • DOUBLE-EMIT guard — refuse if this turn's completion already fired
|
|
51120
|
+
* (lastEmittedCompletion matches the current taskId). A worker that completed
|
|
51121
|
+
* cleanly and is merely being cleaned up never double-emits.
|
|
51122
|
+
* • evidence gate — reuse the same final-assistant/turn-scoped summary machinery
|
|
51123
|
+
* as the normal completion path (completionFinalSummary over the native
|
|
51124
|
+
* transcript). No in-turn assistant summary ⇒ no proof of completion ⇒ leave
|
|
51125
|
+
* the reclaim path to handle a genuinely-unfinished worker.
|
|
51126
|
+
*
|
|
51127
|
+
* Returns true when a synthetic completion was emitted, false otherwise. Safe to
|
|
51128
|
+
* call unconditionally from the cleanup path.
|
|
51129
|
+
*/
|
|
51130
|
+
flushMeshCompletionBeforeCleanup() {
|
|
51131
|
+
if (!this.isMeshWorkerSession()) return false;
|
|
51132
|
+
const taskId = this.completingTurnTaskId();
|
|
51133
|
+
if (this.lastEmittedCompletion && this.lastEmittedCompletion.taskId === (taskId ?? "")) {
|
|
51134
|
+
return false;
|
|
51135
|
+
}
|
|
51136
|
+
if (!this.injectedTaskHasStartedGenerating()) return false;
|
|
51137
|
+
const turnStartedAt = typeof this.adapter?.currentTurnStartedAt === "number" ? this.adapter.currentTurnStartedAt : this.meshTaskInjectedAt || void 0;
|
|
51138
|
+
let parsedMessages;
|
|
51139
|
+
try {
|
|
51140
|
+
parsedMessages = this.adapter?.getScriptParsedStatus?.()?.messages;
|
|
51141
|
+
} catch {
|
|
51142
|
+
parsedMessages = void 0;
|
|
51143
|
+
}
|
|
51144
|
+
let finalSummary;
|
|
51145
|
+
try {
|
|
51146
|
+
finalSummary = this.completionFinalSummary(parsedMessages, turnStartedAt);
|
|
51147
|
+
} catch {
|
|
51148
|
+
finalSummary = void 0;
|
|
51149
|
+
}
|
|
51150
|
+
if (!finalSummary) return false;
|
|
51151
|
+
LOG.warn("CLI", `[${this.type}] emitting pre-cleanup mesh completion for session ${this.instanceId} task=${taskId ?? "(none)"} \u2014 PTY exited before the completion event fired but the native transcript shows a finished turn; synthesizing completion so the coordinator is not left waiting for reclaim.`);
|
|
51152
|
+
if (this.isMeshWorkerSession()) {
|
|
51153
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), "pre_cleanup_transcript_completion");
|
|
51154
|
+
}
|
|
51155
|
+
this.emitGeneratingCompleted({
|
|
51156
|
+
chatTitle: "",
|
|
51157
|
+
duration: void 0,
|
|
51158
|
+
timestamp: Date.now(),
|
|
51159
|
+
taskId,
|
|
51160
|
+
finalSummary,
|
|
51161
|
+
evidenceLevel: "transcript",
|
|
51162
|
+
completionDiagnostic: { source: "pre_cleanup_transcript_completion" }
|
|
51163
|
+
});
|
|
51164
|
+
return true;
|
|
51013
51165
|
}
|
|
51014
51166
|
/**
|
|
51015
51167
|
* AUTOAPPROVE-FLAP-RECUR (Fix A+B): how long a busy blip / modal scroll-out may
|
|
@@ -51411,6 +51563,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
51411
51563
|
if (summary) {
|
|
51412
51564
|
this.lastCompletionSummary = { content: summary, receivedAt: opts.timestamp };
|
|
51413
51565
|
}
|
|
51566
|
+
this.lastEmittedCompletion = { taskId: typeof opts.taskId === "string" ? opts.taskId : "", at: Date.now() };
|
|
51414
51567
|
this.pushEvent({
|
|
51415
51568
|
event: "agent:generating_completed",
|
|
51416
51569
|
chatTitle: opts.chatTitle,
|
|
@@ -54202,6 +54355,15 @@ var DaemonCliManager = class {
|
|
|
54202
54355
|
clearInterval(checkStopped);
|
|
54203
54356
|
setTimeout(() => {
|
|
54204
54357
|
if (this.adapters.has(key2)) {
|
|
54358
|
+
try {
|
|
54359
|
+
const inst = instanceManager?.getInstance(key2);
|
|
54360
|
+
if (typeof inst?.flushMeshCompletionBeforeCleanup === "function") {
|
|
54361
|
+
const emitted = inst.flushMeshCompletionBeforeCleanup();
|
|
54362
|
+
if (emitted) LOG.info("CLI", `Emitted pre-cleanup mesh completion for ${cliType} session ${key2} before auto-clean`);
|
|
54363
|
+
}
|
|
54364
|
+
} catch (e) {
|
|
54365
|
+
LOG.warn("CLI", `pre-cleanup mesh completion flush failed for ${key2}: ${e?.message || e}`);
|
|
54366
|
+
}
|
|
54205
54367
|
this.adapters.delete(key2);
|
|
54206
54368
|
this.deps.removeAgentTracking(key2);
|
|
54207
54369
|
sessionRegistry?.unregisterByInstanceKey(key2);
|