@adhdev/daemon-core 1.0.18-rc.13 → 1.0.18-rc.15
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/cli-adapters/provider-cli-shared.d.ts +33 -0
- package/dist/index.js +176 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +176 -36
- 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 +27 -0
- package/package.json +3 -3
- package/src/cli-adapters/cli-state-engine.ts +17 -1
- package/src/cli-adapters/provider-cli-adapter.ts +2 -6
- package/src/cli-adapters/provider-cli-shared.ts +41 -0
- package/src/mesh/mesh-reconcile-loop.ts +131 -2
- package/src/mesh/mesh-remote-event-pull.ts +68 -47
- package/src/providers/cli-provider-instance.ts +92 -0
|
@@ -270,6 +270,39 @@ export interface CliProviderModule {
|
|
|
270
270
|
_resolvedScriptsSource?: string | null;
|
|
271
271
|
_versionWarning?: string | null;
|
|
272
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* PURE-PTY TRANSCRIPT CLASS predicate (kimi and kin).
|
|
275
|
+
*
|
|
276
|
+
* A provider is "pure-PTY full-buffer" when it reconstructs its ENTIRE transcript
|
|
277
|
+
* from the rendered PTY buffer on every read and has NO alternate transcript
|
|
278
|
+
* source:
|
|
279
|
+
* - transcriptAuthority !== 'provider' (the daemon PTY parser owns the transcript,
|
|
280
|
+
* not a provider-side canonical source)
|
|
281
|
+
* - NO nativeHistory (no on-disk / native-source history to fall back to)
|
|
282
|
+
* - tui.transcriptPty.scope === 'buffer' (the parser walks the full rendered buffer)
|
|
283
|
+
*
|
|
284
|
+
* This class is invisible to two provider-authority-keyed code paths that other
|
|
285
|
+
* providers rely on for mesh completion semantics:
|
|
286
|
+
* 1. CliStateEngine.onTurnStarted only promotes to 'generating' for
|
|
287
|
+
* transcriptAuthority==='provider' providers — so a pure-PTY session that
|
|
288
|
+
* submits a prompt while already idle collapses idle→idle, the
|
|
289
|
+
* generating→idle edge never occurs, and agent:generating_completed is never
|
|
290
|
+
* emitted (the coordinator ledger leaves the task 'assigned' forever).
|
|
291
|
+
* 2. checkMeshWorkerStall's native-transcript completion reconcile is gated on
|
|
292
|
+
* the native-source shape, so a finished pure-PTY worker's static idle is
|
|
293
|
+
* misread as monitor:no_progress (a false task_stalled).
|
|
294
|
+
*
|
|
295
|
+
* The runtime capability, NOT any single spec field value, is authoritative: a
|
|
296
|
+
* given kimi manifest checkout may declare nativeHistory/transcriptAuthority, but
|
|
297
|
+
* the live-loaded pure-PTY session has none. Callers that only hold a
|
|
298
|
+
* CliProviderModule (the engine) share this exact predicate with the adapter
|
|
299
|
+
* (parsesFullPtyTranscriptFromBuffer) so the two never drift.
|
|
300
|
+
*/
|
|
301
|
+
export declare function isPurePtyTranscriptProvider(provider: {
|
|
302
|
+
transcriptAuthority?: 'provider' | 'daemon';
|
|
303
|
+
nativeHistory?: unknown;
|
|
304
|
+
tui?: Record<string, unknown>;
|
|
305
|
+
}): boolean;
|
|
273
306
|
/**
|
|
274
307
|
* Stateful, transcript-oriented terminal cell accumulator.
|
|
275
308
|
*
|
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 ? "64f056340da99d3b28464efcf5c05fe643e5db63" : void 0) ?? "unknown";
|
|
446
|
+
const commitShort = readInjected(true ? "64f05634" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
447
|
+
const version = readInjected(true ? "1.0.18-rc.15" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
448
|
+
const builtAt = readInjected(true ? "2026-07-23T00:51:36.808Z" : void 0);
|
|
449
449
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
450
450
|
return cached;
|
|
451
451
|
}
|
|
@@ -12931,6 +12931,12 @@ var init_spawn_env = __esm({
|
|
|
12931
12931
|
});
|
|
12932
12932
|
|
|
12933
12933
|
// src/cli-adapters/provider-cli-shared.ts
|
|
12934
|
+
function isPurePtyTranscriptProvider(provider) {
|
|
12935
|
+
if (provider.transcriptAuthority === "provider") return false;
|
|
12936
|
+
if (provider.nativeHistory) return false;
|
|
12937
|
+
const transcriptPty = provider.tui?.transcriptPty;
|
|
12938
|
+
return transcriptPty?.scope === "buffer";
|
|
12939
|
+
}
|
|
12934
12940
|
function stripAnsi(str) {
|
|
12935
12941
|
return str.replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
12936
12942
|
}
|
|
@@ -22227,34 +22233,37 @@ async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDa
|
|
|
22227
22233
|
if (!dispatchMeshCommand) return;
|
|
22228
22234
|
const meshId = mesh.id;
|
|
22229
22235
|
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
|
-
|
|
22236
|
+
await Promise.allSettled(mesh.nodes.map((node) => pullPendingEventsFromNode(components, meshId, node, localDaemonId, candidateDaemonIds, pulls)));
|
|
22237
|
+
}
|
|
22238
|
+
async function pullPendingEventsFromNode(components, meshId, node, localDaemonId, candidateDaemonIds, pulls) {
|
|
22239
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
22240
|
+
if (!dispatchMeshCommand) return;
|
|
22241
|
+
const nodeDaemonId = readNonEmptyString(node.daemonId);
|
|
22242
|
+
if (!nodeDaemonId) return;
|
|
22243
|
+
if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) return;
|
|
22244
|
+
if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) return;
|
|
22245
|
+
const getPeerStatus = components.getMeshPeerConnectionStatus;
|
|
22246
|
+
if (getPeerStatus) {
|
|
22247
|
+
const peerSnapshot = getPeerStatus(nodeDaemonId);
|
|
22248
|
+
if (!peerSnapshot || String(peerSnapshot.state) !== "connected") return;
|
|
22249
|
+
}
|
|
22250
|
+
for (const pendingEventArgs of pulls) {
|
|
22251
|
+
let events;
|
|
22252
|
+
try {
|
|
22253
|
+
events = await dispatchMeshCommand(nodeDaemonId, "get_pending_mesh_events", pendingEventArgs);
|
|
22254
|
+
} catch {
|
|
22255
|
+
break;
|
|
22256
|
+
}
|
|
22257
|
+
const list = extractPendingEvents(events).filter((e) => readNonEmptyString(e?.meshId) === meshId);
|
|
22258
|
+
for (const event of list) {
|
|
22259
|
+
const payload = buildForwardPayloadFromPending(event);
|
|
22260
|
+
if (!payload.event || !payload.meshId) continue;
|
|
22242
22261
|
try {
|
|
22243
|
-
|
|
22262
|
+
handleMeshForwardEvent(components, payload);
|
|
22244
22263
|
} 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
22264
|
}
|
|
22256
22265
|
}
|
|
22257
|
-
}
|
|
22266
|
+
}
|
|
22258
22267
|
}
|
|
22259
22268
|
function unwrapReadChatPayload(raw) {
|
|
22260
22269
|
let cursor = raw;
|
|
@@ -23156,7 +23165,7 @@ function assignedRowLiveStatusIsAwaitingApproval(mesh, nodeId, sessionId) {
|
|
|
23156
23165
|
return false;
|
|
23157
23166
|
}
|
|
23158
23167
|
}
|
|
23159
|
-
async function recoverStrandedAssignedDispatches(components, mesh, store) {
|
|
23168
|
+
async function recoverStrandedAssignedDispatches(components, mesh, store, localDaemonId, selfIds = []) {
|
|
23160
23169
|
const meshId = mesh.id;
|
|
23161
23170
|
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
23162
23171
|
if (!assigned.length) return;
|
|
@@ -23169,10 +23178,54 @@ async function recoverStrandedAssignedDispatches(components, mesh, store) {
|
|
|
23169
23178
|
for (const key2 of [...deliveredUnconsumedUnknownStreak.keys()]) {
|
|
23170
23179
|
if (key2.startsWith(meshKeyPrefix) && !assignedKeys.has(key2)) deliveredUnconsumedUnknownStreak.delete(key2);
|
|
23171
23180
|
}
|
|
23181
|
+
for (const key2 of [...assignedIdleFinalAssistantSince.keys()]) {
|
|
23182
|
+
if (key2.startsWith(meshKeyPrefix) && !assignedKeys.has(key2)) assignedIdleFinalAssistantSince.delete(key2);
|
|
23183
|
+
}
|
|
23172
23184
|
for (const row of assigned) {
|
|
23173
23185
|
const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
|
|
23174
23186
|
if (!Number.isFinite(dispatchedAtMs)) continue;
|
|
23175
23187
|
const ageMs = nowMs - dispatchedAtMs;
|
|
23188
|
+
const idleTranscriptStreakKey = `${meshId}::${row.id}`;
|
|
23189
|
+
if (store.taskHasConfirmedDelivery(meshId, row.id) && !findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id }) && readNonEmptyString(row.assignedSessionId) && resolveSessionBusyVerdict(components, row.assignedSessionId) !== "GENERATING") {
|
|
23190
|
+
const since = assignedIdleFinalAssistantSince.get(idleTranscriptStreakKey);
|
|
23191
|
+
if (since === void 0) {
|
|
23192
|
+
assignedIdleFinalAssistantSince.set(idleTranscriptStreakKey, nowMs);
|
|
23193
|
+
} else if (nowMs - since >= ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS) {
|
|
23194
|
+
const terminalEvidence = await pollAssignedTaskTerminalEvidence(components, mesh, row);
|
|
23195
|
+
if (terminalEvidence) {
|
|
23196
|
+
assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
|
|
23197
|
+
updateTaskStatus(meshId, row.id, terminalEvidence);
|
|
23198
|
+
if (!findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id })) {
|
|
23199
|
+
try {
|
|
23200
|
+
appendLedgerEntry(meshId, {
|
|
23201
|
+
kind: terminalEvidence === "completed" ? "task_completed" : "task_failed",
|
|
23202
|
+
nodeId: row.assignedNodeId,
|
|
23203
|
+
sessionId: row.assignedSessionId,
|
|
23204
|
+
providerType: row.assignedProviderType,
|
|
23205
|
+
payload: {
|
|
23206
|
+
taskId: row.id,
|
|
23207
|
+
event: "agent:generating_completed",
|
|
23208
|
+
source: "early_idle_transcript_evidence"
|
|
23209
|
+
}
|
|
23210
|
+
});
|
|
23211
|
+
} catch {
|
|
23212
|
+
}
|
|
23213
|
+
}
|
|
23214
|
+
LOG.warn("MeshReconcile", `Early-completed assigned task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}): worker idle with a final assistant message after dispatch for \u2265${Math.round(ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS / 1e3)}s \u2014 the completion event was lost/late (pure-PTY provider), task is ${terminalEvidence} without waiting the 15-min deadline`);
|
|
23215
|
+
traceMeshEventDrop("assigned_early_transcript_completed", {
|
|
23216
|
+
taskId: row.id,
|
|
23217
|
+
sessionId: row.assignedSessionId,
|
|
23218
|
+
nodeId: row.assignedNodeId,
|
|
23219
|
+
meshId,
|
|
23220
|
+
event: "agent:generating_completed"
|
|
23221
|
+
}, terminalEvidence);
|
|
23222
|
+
continue;
|
|
23223
|
+
}
|
|
23224
|
+
assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
|
|
23225
|
+
}
|
|
23226
|
+
} else {
|
|
23227
|
+
assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
|
|
23228
|
+
}
|
|
23176
23229
|
if (ageMs >= ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS && ageMs < ASSIGNED_STRANDED_DEADLINE_MS && store.taskHasConfirmedDelivery(meshId, row.id) && !store.taskDeliveryConsumed(meshId, row.id)) {
|
|
23177
23230
|
const terminal2 = findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id });
|
|
23178
23231
|
if (terminal2) {
|
|
@@ -23180,6 +23233,24 @@ async function recoverStrandedAssignedDispatches(components, mesh, store) {
|
|
|
23180
23233
|
updateTaskStatus(meshId, row.id, status);
|
|
23181
23234
|
continue;
|
|
23182
23235
|
}
|
|
23236
|
+
const assignedNode = row.assignedNodeId ? mesh.nodes?.find((n) => meshNodeIdMatches(n, row.assignedNodeId)) : void 0;
|
|
23237
|
+
if (assignedNode?.daemonId) {
|
|
23238
|
+
try {
|
|
23239
|
+
await pullPendingEventsFromNode(
|
|
23240
|
+
components,
|
|
23241
|
+
meshId,
|
|
23242
|
+
assignedNode,
|
|
23243
|
+
localDaemonId,
|
|
23244
|
+
selfIds,
|
|
23245
|
+
selfIds.length > 0 ? selfIds.map((id) => ({ meshId, coordinatorDaemonId: id })) : [{ meshId }]
|
|
23246
|
+
);
|
|
23247
|
+
} catch {
|
|
23248
|
+
}
|
|
23249
|
+
if (store.taskDeliveryConsumed(meshId, row.id)) {
|
|
23250
|
+
deliveredUnconsumedUnknownStreak.delete(`${meshId}::${row.id}`);
|
|
23251
|
+
continue;
|
|
23252
|
+
}
|
|
23253
|
+
}
|
|
23183
23254
|
const shortStreakKey = `${meshId}::${row.id}`;
|
|
23184
23255
|
const verdict = row.assignedSessionId ? resolveSessionBusyVerdict(components, row.assignedSessionId) : "IDLE_CONFIRMED";
|
|
23185
23256
|
if (verdict === "GENERATING") {
|
|
@@ -23438,7 +23509,7 @@ async function runMeshReconcileTick(components) {
|
|
|
23438
23509
|
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
23439
23510
|
if (!daemonHostsMesh(mesh, selfIds)) continue;
|
|
23440
23511
|
try {
|
|
23441
|
-
await recoverStrandedAssignedDispatches(components, mesh, store);
|
|
23512
|
+
await recoverStrandedAssignedDispatches(components, mesh, store, localDaemonId, selfIds);
|
|
23442
23513
|
} catch (e) {
|
|
23443
23514
|
LOG.warn("MeshReconcile", `Assigned-stranded watchdog failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
23444
23515
|
}
|
|
@@ -23830,7 +23901,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
23830
23901
|
}
|
|
23831
23902
|
};
|
|
23832
23903
|
}
|
|
23833
|
-
var coordinatorModalParkState, DISK_RETENTION_INTERVAL_MS, lastDiskRetentionRunAt, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, deliveredUnconsumedUnknownStreak, ZOMBIE_ASSIGNED_MIN_AGE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS, UNRESOLVED_FORWARD_NUDGE_DELAY_MS, unresolvedForwardNudgeTimer, unresolvedForwardNudgeRunning;
|
|
23904
|
+
var coordinatorModalParkState, DISK_RETENTION_INTERVAL_MS, lastDiskRetentionRunAt, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, deliveredUnconsumedUnknownStreak, ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS, assignedIdleFinalAssistantSince, ZOMBIE_ASSIGNED_MIN_AGE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS, UNRESOLVED_FORWARD_NUDGE_DELAY_MS, unresolvedForwardNudgeTimer, unresolvedForwardNudgeRunning;
|
|
23834
23905
|
var init_mesh_reconcile_loop = __esm({
|
|
23835
23906
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
23836
23907
|
"use strict";
|
|
@@ -23868,6 +23939,8 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
23868
23939
|
RECLAIM_UNKNOWN_GRACE_TICKS = 3;
|
|
23869
23940
|
deliveredNoTurnUnknownStreak = /* @__PURE__ */ new Map();
|
|
23870
23941
|
deliveredUnconsumedUnknownStreak = /* @__PURE__ */ new Map();
|
|
23942
|
+
ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS = 8e3;
|
|
23943
|
+
assignedIdleFinalAssistantSince = /* @__PURE__ */ new Map();
|
|
23871
23944
|
ZOMBIE_ASSIGNED_MIN_AGE_MS = 30 * 60 * 1e3;
|
|
23872
23945
|
STRICT_SESSION_MATCH_TTL_MS = 6e4;
|
|
23873
23946
|
unresolvedForwardRejectionCounts = /* @__PURE__ */ new Map();
|
|
@@ -26637,7 +26710,8 @@ var init_cli_state_engine = __esm({
|
|
|
26637
26710
|
this.currentTurnStartedAt = Date.now();
|
|
26638
26711
|
this.responseEpoch += 1;
|
|
26639
26712
|
this.clearApprovalResolutionMemory();
|
|
26640
|
-
|
|
26713
|
+
const promoteOnTurnStart = this.provider.transcriptAuthority === "provider" || isPurePtyTranscriptProvider(this.provider);
|
|
26714
|
+
if (promoteOnTurnStart && this.currentStatus !== "waiting_approval") {
|
|
26641
26715
|
this.setStatus("generating", "turn_started");
|
|
26642
26716
|
this.callbacks.onStatusChange();
|
|
26643
26717
|
}
|
|
@@ -28168,10 +28242,7 @@ ${lastSnapshot}`;
|
|
|
28168
28242
|
* provider-owned) so no other provider's turn-scoped parse changes.
|
|
28169
28243
|
*/
|
|
28170
28244
|
parsesFullPtyTranscriptFromBuffer() {
|
|
28171
|
-
|
|
28172
|
-
if (this.provider.nativeHistory) return false;
|
|
28173
|
-
const transcriptPty = this.provider.tui?.transcriptPty;
|
|
28174
|
-
return transcriptPty?.scope === "buffer";
|
|
28245
|
+
return isPurePtyTranscriptProvider(this.provider);
|
|
28175
28246
|
}
|
|
28176
28247
|
/**
|
|
28177
28248
|
* The turn scope to feed the transcript parser. Normally the live turn scope
|
|
@@ -45336,6 +45407,7 @@ var fs24 = __toESM(require("fs"));
|
|
|
45336
45407
|
init_contracts2();
|
|
45337
45408
|
init_provider_input_support();
|
|
45338
45409
|
init_hash();
|
|
45410
|
+
init_provider_cli_shared();
|
|
45339
45411
|
|
|
45340
45412
|
// src/providers/spec/route.ts
|
|
45341
45413
|
var fs22 = __toESM(require("fs"));
|
|
@@ -51012,6 +51084,10 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
51012
51084
|
return;
|
|
51013
51085
|
}
|
|
51014
51086
|
}
|
|
51087
|
+
if (this.tryReconcilePurePtyCompletionForStall(observedStatus)) {
|
|
51088
|
+
this.meshStallEmittedForAnchor = true;
|
|
51089
|
+
return;
|
|
51090
|
+
}
|
|
51015
51091
|
this.meshStallEmittedForAnchor = true;
|
|
51016
51092
|
if (this.meshStallLastFiredAt >= 0 && now - this.meshStallLastFiredAt < _CliProviderInstance.MESH_WORKER_STALL_REFIRE_COOLDOWN_MS) {
|
|
51017
51093
|
return;
|
|
@@ -51142,6 +51218,70 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
51142
51218
|
});
|
|
51143
51219
|
return true;
|
|
51144
51220
|
}
|
|
51221
|
+
/**
|
|
51222
|
+
* KIMI-PURE-PTY-COMPLETION-EMIT (Fix 3): stall-path completion reconcile for the
|
|
51223
|
+
* PURE-PTY transcript class (kimi and kin — no native transcript, no provider
|
|
51224
|
+
* authority; see isPurePtyTranscriptProvider). Such a worker whose
|
|
51225
|
+
* generating_completed never emitted (the onTurnStarted idle→idle collapse Fix 1
|
|
51226
|
+
* fixes at the source) sits at a STATIC idle prompt: its PTY output stops the
|
|
51227
|
+
* instant the answer is rendered, so the status-agnostic no-progress watchdog
|
|
51228
|
+
* (checkMeshWorkerStall) reads the finished-but-quiet session as a stall and would
|
|
51229
|
+
* false-fire monitor:no_progress. The native-transcript reconcile
|
|
51230
|
+
* (sampleNativeTranscriptProgress) does NOT cover this class (no native source →
|
|
51231
|
+
* null sample), so the stall path needs its own guard.
|
|
51232
|
+
*
|
|
51233
|
+
* Called from checkMeshWorkerStall just before the fire. Returns true when the
|
|
51234
|
+
* session is a finished pure-PTY turn — idle, no pending response, and a PTY-parsed
|
|
51235
|
+
* in-turn final assistant summary — in which case it emits the missing
|
|
51236
|
+
* generating_completed (idempotent: a real/late emit writes the terminal ledger and
|
|
51237
|
+
* the coordinator's reconcile makes any duplicate a no-op) and the caller SUPPRESSES
|
|
51238
|
+
* the stall. Returns false for every other class/state (native-source provider, a
|
|
51239
|
+
* genuinely mid-turn or wedged worker with no final assistant), so a real stall still
|
|
51240
|
+
* fires unchanged.
|
|
51241
|
+
*
|
|
51242
|
+
* Evidence bar is identical to flushMeshCompletionBeforeCleanup: injected task's turn
|
|
51243
|
+
* genuinely started + an in-turn final assistant summary. Conservative by
|
|
51244
|
+
* construction — no summary ⇒ no proof of completion ⇒ return false and let the real
|
|
51245
|
+
* stall fire.
|
|
51246
|
+
*/
|
|
51247
|
+
tryReconcilePurePtyCompletionForStall(observedStatus) {
|
|
51248
|
+
if (!isPurePtyTranscriptProvider(this.provider)) return false;
|
|
51249
|
+
if (observedStatus !== "idle") return false;
|
|
51250
|
+
if (this.hasAdapterPendingResponse()) return false;
|
|
51251
|
+
const taskId = this.completingTurnTaskId();
|
|
51252
|
+
if (this.lastEmittedCompletion && this.lastEmittedCompletion.taskId === (taskId ?? "")) {
|
|
51253
|
+
return false;
|
|
51254
|
+
}
|
|
51255
|
+
if (!this.injectedTaskHasStartedGenerating()) return false;
|
|
51256
|
+
const turnStartedAt = typeof this.adapter?.currentTurnStartedAt === "number" ? this.adapter.currentTurnStartedAt : this.meshTaskInjectedAt || void 0;
|
|
51257
|
+
let parsedMessages;
|
|
51258
|
+
try {
|
|
51259
|
+
parsedMessages = this.adapter?.getScriptParsedStatus?.()?.messages;
|
|
51260
|
+
} catch {
|
|
51261
|
+
parsedMessages = void 0;
|
|
51262
|
+
}
|
|
51263
|
+
let finalSummary;
|
|
51264
|
+
try {
|
|
51265
|
+
finalSummary = this.completionFinalSummary(parsedMessages, turnStartedAt);
|
|
51266
|
+
} catch {
|
|
51267
|
+
finalSummary = void 0;
|
|
51268
|
+
}
|
|
51269
|
+
if (!finalSummary) return false;
|
|
51270
|
+
LOG.warn("CLI", `[${this.type}] reconciling pure-PTY mesh completion from the stall path for session ${this.instanceId} task=${taskId ?? "(none)"} \u2014 PTY is idle-quiet with an in-turn final assistant message but the completion event never fired (pure-PTY provider); emitting it instead of a false monitor:no_progress.`);
|
|
51271
|
+
if (this.isMeshWorkerSession()) {
|
|
51272
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), "stall_pure_pty_transcript_completion");
|
|
51273
|
+
}
|
|
51274
|
+
this.emitGeneratingCompleted({
|
|
51275
|
+
chatTitle: "",
|
|
51276
|
+
duration: void 0,
|
|
51277
|
+
timestamp: Date.now(),
|
|
51278
|
+
taskId,
|
|
51279
|
+
finalSummary,
|
|
51280
|
+
evidenceLevel: "transcript",
|
|
51281
|
+
completionDiagnostic: { source: "stall_pure_pty_transcript_completion" }
|
|
51282
|
+
});
|
|
51283
|
+
return true;
|
|
51284
|
+
}
|
|
51145
51285
|
/**
|
|
51146
51286
|
* AUTOAPPROVE-FLAP-RECUR (Fix A+B): how long a busy blip / modal scroll-out may
|
|
51147
51287
|
* persist before the in-progress settle gate is torn down. For a delegated
|