@adhdev/daemon-core 1.0.18-rc.14 → 1.0.18-rc.16
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 +198 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +198 -10
- package/dist/index.mjs.map +1 -1
- package/dist/providers/chat-message-normalization.d.ts +22 -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-completion-synthesis.ts +12 -1
- package/src/mesh/mesh-reconcile-loop.ts +209 -1
- package/src/providers/chat-message-normalization.ts +53 -0
- 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 ? "74f34080bcd7c145e55fd7e5fd492a40a4942bc4" : void 0) ?? "unknown";
|
|
446
|
+
const commitShort = readInjected(true ? "74f34080" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
447
|
+
const version = readInjected(true ? "1.0.18-rc.16" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
448
|
+
const builtAt = readInjected(true ? "2026-07-23T02:29:46.281Z" : 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
|
}
|
|
@@ -19176,6 +19182,26 @@ function selectFinalAssistantTurnEndMessage(messages) {
|
|
|
19176
19182
|
}
|
|
19177
19183
|
return null;
|
|
19178
19184
|
}
|
|
19185
|
+
function hasTrailingToolActivityAfterFinalAssistant(messages) {
|
|
19186
|
+
if (!Array.isArray(messages) || messages.length === 0) return false;
|
|
19187
|
+
let sawTrailingToolActivity = false;
|
|
19188
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
19189
|
+
const msg = messages[i];
|
|
19190
|
+
if (!msg) continue;
|
|
19191
|
+
const classification = classifyChatMessageVisibility(msg);
|
|
19192
|
+
if (classification.isUserFacing && (msg.role === "assistant" || msg.role === "model")) {
|
|
19193
|
+
if (flattenContent(msg.content).trim()) return sawTrailingToolActivity;
|
|
19194
|
+
return false;
|
|
19195
|
+
}
|
|
19196
|
+
if (classification.isUserFacing) {
|
|
19197
|
+
return false;
|
|
19198
|
+
}
|
|
19199
|
+
if (classification.kind === "tool" || classification.kind === "terminal") {
|
|
19200
|
+
sawTrailingToolActivity = true;
|
|
19201
|
+
}
|
|
19202
|
+
}
|
|
19203
|
+
return false;
|
|
19204
|
+
}
|
|
19179
19205
|
function canonicalizeKindHint(value) {
|
|
19180
19206
|
return value.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
19181
19207
|
}
|
|
@@ -22867,6 +22893,7 @@ async function pollAssignedTaskTerminalEvidence(components, mesh, row) {
|
|
|
22867
22893
|
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
22868
22894
|
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
22869
22895
|
if (!evidence.finalSummary) return null;
|
|
22896
|
+
if (hasTrailingToolActivityAfterFinalAssistant(messages)) return null;
|
|
22870
22897
|
const dispatchedAtMs = Date.parse(readNonEmptyString(row.dispatchTimestamp));
|
|
22871
22898
|
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
|
|
22872
22899
|
if (!(Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs >= dispatchedAtMs)) {
|
|
@@ -23159,6 +23186,52 @@ function assignedRowLiveStatusIsAwaitingApproval(mesh, nodeId, sessionId) {
|
|
|
23159
23186
|
return false;
|
|
23160
23187
|
}
|
|
23161
23188
|
}
|
|
23189
|
+
function resolveLocalSessionPurePty(components, sessionId) {
|
|
23190
|
+
try {
|
|
23191
|
+
const instances = components.instanceManager?.getByCategory?.("cli") || [];
|
|
23192
|
+
const inst = instances.find((i) => {
|
|
23193
|
+
const sid = readNonEmptyString(i?.getState?.().instanceId);
|
|
23194
|
+
return sid && sessionIdsEquivalent(sid, sessionId);
|
|
23195
|
+
});
|
|
23196
|
+
if (!inst) return void 0;
|
|
23197
|
+
const provider = inst.provider;
|
|
23198
|
+
if (!provider || typeof provider !== "object") return void 0;
|
|
23199
|
+
return isPurePtyTranscriptProvider(provider);
|
|
23200
|
+
} catch {
|
|
23201
|
+
return void 0;
|
|
23202
|
+
}
|
|
23203
|
+
}
|
|
23204
|
+
async function evaluateEarlyIdleTranscriptArm(components, mesh, store, row, localDaemonId, selfIds = []) {
|
|
23205
|
+
const sessionId = readNonEmptyString(row.assignedSessionId);
|
|
23206
|
+
if (!sessionId) return false;
|
|
23207
|
+
const verdict = resolveSessionBusyVerdict(components, sessionId);
|
|
23208
|
+
if (verdict === "GENERATING") return false;
|
|
23209
|
+
if (verdict === "UNKNOWN") {
|
|
23210
|
+
const nodeId = readNonEmptyString(row.assignedNodeId);
|
|
23211
|
+
const node = (mesh.nodes ?? []).find((n) => n.id === nodeId);
|
|
23212
|
+
const liveStatus = nodeId ? readNonEmptyString(sessionStatusFromNodes(mesh.nodes, nodeId, sessionId).status).toLowerCase() : "";
|
|
23213
|
+
if (liveStatus && liveStatus !== "idle") return false;
|
|
23214
|
+
if (!liveStatus) {
|
|
23215
|
+
const nodeDaemonId = readNonEmptyString(node?.daemonId);
|
|
23216
|
+
const isLocalNode = !nodeDaemonId || daemonIdsEquivalent(nodeDaemonId, localDaemonId) || daemonIdListIncludes(selfIds, nodeDaemonId) || !!components.instanceManager?.getInstance?.(sessionId);
|
|
23217
|
+
const providerType = readNonEmptyString(row.assignedProviderType);
|
|
23218
|
+
const readArgs = {
|
|
23219
|
+
sessionId,
|
|
23220
|
+
targetSessionId: sessionId,
|
|
23221
|
+
tailLimit: 1,
|
|
23222
|
+
...node?.workspace ? { workspace: node.workspace } : {},
|
|
23223
|
+
...providerType ? { agentType: providerType, providerType } : {}
|
|
23224
|
+
};
|
|
23225
|
+
const probedStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
|
|
23226
|
+
if (probedStatus !== "idle") return false;
|
|
23227
|
+
}
|
|
23228
|
+
}
|
|
23229
|
+
if (store.taskDeliveryConsumed(mesh.id, row.id)) return true;
|
|
23230
|
+
const localPurePty = resolveLocalSessionPurePty(components, sessionId);
|
|
23231
|
+
if (localPurePty === true) return true;
|
|
23232
|
+
if (localPurePty === false) return false;
|
|
23233
|
+
return verdict === "UNKNOWN";
|
|
23234
|
+
}
|
|
23162
23235
|
async function recoverStrandedAssignedDispatches(components, mesh, store, localDaemonId, selfIds = []) {
|
|
23163
23236
|
const meshId = mesh.id;
|
|
23164
23237
|
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
@@ -23172,10 +23245,55 @@ async function recoverStrandedAssignedDispatches(components, mesh, store, localD
|
|
|
23172
23245
|
for (const key2 of [...deliveredUnconsumedUnknownStreak.keys()]) {
|
|
23173
23246
|
if (key2.startsWith(meshKeyPrefix) && !assignedKeys.has(key2)) deliveredUnconsumedUnknownStreak.delete(key2);
|
|
23174
23247
|
}
|
|
23248
|
+
for (const key2 of [...assignedIdleFinalAssistantSince.keys()]) {
|
|
23249
|
+
if (key2.startsWith(meshKeyPrefix) && !assignedKeys.has(key2)) assignedIdleFinalAssistantSince.delete(key2);
|
|
23250
|
+
}
|
|
23175
23251
|
for (const row of assigned) {
|
|
23176
23252
|
const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
|
|
23177
23253
|
if (!Number.isFinite(dispatchedAtMs)) continue;
|
|
23178
23254
|
const ageMs = nowMs - dispatchedAtMs;
|
|
23255
|
+
const idleTranscriptStreakKey = `${meshId}::${row.id}`;
|
|
23256
|
+
const earlyArm = store.taskHasConfirmedDelivery(meshId, row.id) && !findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id }) && readNonEmptyString(row.assignedSessionId) ? await evaluateEarlyIdleTranscriptArm(components, mesh, store, row, localDaemonId, selfIds) : false;
|
|
23257
|
+
if (earlyArm) {
|
|
23258
|
+
const since = assignedIdleFinalAssistantSince.get(idleTranscriptStreakKey);
|
|
23259
|
+
if (since === void 0) {
|
|
23260
|
+
assignedIdleFinalAssistantSince.set(idleTranscriptStreakKey, nowMs);
|
|
23261
|
+
} else if (nowMs - since >= ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS) {
|
|
23262
|
+
const terminalEvidence = await pollAssignedTaskTerminalEvidence(components, mesh, row);
|
|
23263
|
+
if (terminalEvidence) {
|
|
23264
|
+
assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
|
|
23265
|
+
updateTaskStatus(meshId, row.id, terminalEvidence);
|
|
23266
|
+
if (!findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id })) {
|
|
23267
|
+
try {
|
|
23268
|
+
appendLedgerEntry(meshId, {
|
|
23269
|
+
kind: terminalEvidence === "completed" ? "task_completed" : "task_failed",
|
|
23270
|
+
nodeId: row.assignedNodeId,
|
|
23271
|
+
sessionId: row.assignedSessionId,
|
|
23272
|
+
providerType: row.assignedProviderType,
|
|
23273
|
+
payload: {
|
|
23274
|
+
taskId: row.id,
|
|
23275
|
+
event: "agent:generating_completed",
|
|
23276
|
+
source: "early_idle_transcript_evidence"
|
|
23277
|
+
}
|
|
23278
|
+
});
|
|
23279
|
+
} catch {
|
|
23280
|
+
}
|
|
23281
|
+
}
|
|
23282
|
+
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`);
|
|
23283
|
+
traceMeshEventDrop("assigned_early_transcript_completed", {
|
|
23284
|
+
taskId: row.id,
|
|
23285
|
+
sessionId: row.assignedSessionId,
|
|
23286
|
+
nodeId: row.assignedNodeId,
|
|
23287
|
+
meshId,
|
|
23288
|
+
event: "agent:generating_completed"
|
|
23289
|
+
}, terminalEvidence);
|
|
23290
|
+
continue;
|
|
23291
|
+
}
|
|
23292
|
+
assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
|
|
23293
|
+
}
|
|
23294
|
+
} else {
|
|
23295
|
+
assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
|
|
23296
|
+
}
|
|
23179
23297
|
if (ageMs >= ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS && ageMs < ASSIGNED_STRANDED_DEADLINE_MS && store.taskHasConfirmedDelivery(meshId, row.id) && !store.taskDeliveryConsumed(meshId, row.id)) {
|
|
23180
23298
|
const terminal2 = findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id });
|
|
23181
23299
|
if (terminal2) {
|
|
@@ -23851,7 +23969,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
23851
23969
|
}
|
|
23852
23970
|
};
|
|
23853
23971
|
}
|
|
23854
|
-
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;
|
|
23972
|
+
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;
|
|
23855
23973
|
var init_mesh_reconcile_loop = __esm({
|
|
23856
23974
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
23857
23975
|
"use strict";
|
|
@@ -23875,6 +23993,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
23875
23993
|
init_mesh_reconcile_identity();
|
|
23876
23994
|
init_mesh_reconcile_config();
|
|
23877
23995
|
init_mesh_remote_event_pull();
|
|
23996
|
+
init_provider_cli_shared();
|
|
23878
23997
|
init_mesh_disk_retention();
|
|
23879
23998
|
init_mesh_completion_synthesis();
|
|
23880
23999
|
init_mesh_active_work();
|
|
@@ -23889,6 +24008,8 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
23889
24008
|
RECLAIM_UNKNOWN_GRACE_TICKS = 3;
|
|
23890
24009
|
deliveredNoTurnUnknownStreak = /* @__PURE__ */ new Map();
|
|
23891
24010
|
deliveredUnconsumedUnknownStreak = /* @__PURE__ */ new Map();
|
|
24011
|
+
ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS = 8e3;
|
|
24012
|
+
assignedIdleFinalAssistantSince = /* @__PURE__ */ new Map();
|
|
23892
24013
|
ZOMBIE_ASSIGNED_MIN_AGE_MS = 30 * 60 * 1e3;
|
|
23893
24014
|
STRICT_SESSION_MATCH_TTL_MS = 6e4;
|
|
23894
24015
|
unresolvedForwardRejectionCounts = /* @__PURE__ */ new Map();
|
|
@@ -26658,7 +26779,8 @@ var init_cli_state_engine = __esm({
|
|
|
26658
26779
|
this.currentTurnStartedAt = Date.now();
|
|
26659
26780
|
this.responseEpoch += 1;
|
|
26660
26781
|
this.clearApprovalResolutionMemory();
|
|
26661
|
-
|
|
26782
|
+
const promoteOnTurnStart = this.provider.transcriptAuthority === "provider" || isPurePtyTranscriptProvider(this.provider);
|
|
26783
|
+
if (promoteOnTurnStart && this.currentStatus !== "waiting_approval") {
|
|
26662
26784
|
this.setStatus("generating", "turn_started");
|
|
26663
26785
|
this.callbacks.onStatusChange();
|
|
26664
26786
|
}
|
|
@@ -28189,10 +28311,7 @@ ${lastSnapshot}`;
|
|
|
28189
28311
|
* provider-owned) so no other provider's turn-scoped parse changes.
|
|
28190
28312
|
*/
|
|
28191
28313
|
parsesFullPtyTranscriptFromBuffer() {
|
|
28192
|
-
|
|
28193
|
-
if (this.provider.nativeHistory) return false;
|
|
28194
|
-
const transcriptPty = this.provider.tui?.transcriptPty;
|
|
28195
|
-
return transcriptPty?.scope === "buffer";
|
|
28314
|
+
return isPurePtyTranscriptProvider(this.provider);
|
|
28196
28315
|
}
|
|
28197
28316
|
/**
|
|
28198
28317
|
* The turn scope to feed the transcript parser. Normally the live turn scope
|
|
@@ -45357,6 +45476,7 @@ var fs24 = __toESM(require("fs"));
|
|
|
45357
45476
|
init_contracts2();
|
|
45358
45477
|
init_provider_input_support();
|
|
45359
45478
|
init_hash();
|
|
45479
|
+
init_provider_cli_shared();
|
|
45360
45480
|
|
|
45361
45481
|
// src/providers/spec/route.ts
|
|
45362
45482
|
var fs22 = __toESM(require("fs"));
|
|
@@ -51033,6 +51153,10 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
51033
51153
|
return;
|
|
51034
51154
|
}
|
|
51035
51155
|
}
|
|
51156
|
+
if (this.tryReconcilePurePtyCompletionForStall(observedStatus)) {
|
|
51157
|
+
this.meshStallEmittedForAnchor = true;
|
|
51158
|
+
return;
|
|
51159
|
+
}
|
|
51036
51160
|
this.meshStallEmittedForAnchor = true;
|
|
51037
51161
|
if (this.meshStallLastFiredAt >= 0 && now - this.meshStallLastFiredAt < _CliProviderInstance.MESH_WORKER_STALL_REFIRE_COOLDOWN_MS) {
|
|
51038
51162
|
return;
|
|
@@ -51163,6 +51287,70 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
51163
51287
|
});
|
|
51164
51288
|
return true;
|
|
51165
51289
|
}
|
|
51290
|
+
/**
|
|
51291
|
+
* KIMI-PURE-PTY-COMPLETION-EMIT (Fix 3): stall-path completion reconcile for the
|
|
51292
|
+
* PURE-PTY transcript class (kimi and kin — no native transcript, no provider
|
|
51293
|
+
* authority; see isPurePtyTranscriptProvider). Such a worker whose
|
|
51294
|
+
* generating_completed never emitted (the onTurnStarted idle→idle collapse Fix 1
|
|
51295
|
+
* fixes at the source) sits at a STATIC idle prompt: its PTY output stops the
|
|
51296
|
+
* instant the answer is rendered, so the status-agnostic no-progress watchdog
|
|
51297
|
+
* (checkMeshWorkerStall) reads the finished-but-quiet session as a stall and would
|
|
51298
|
+
* false-fire monitor:no_progress. The native-transcript reconcile
|
|
51299
|
+
* (sampleNativeTranscriptProgress) does NOT cover this class (no native source →
|
|
51300
|
+
* null sample), so the stall path needs its own guard.
|
|
51301
|
+
*
|
|
51302
|
+
* Called from checkMeshWorkerStall just before the fire. Returns true when the
|
|
51303
|
+
* session is a finished pure-PTY turn — idle, no pending response, and a PTY-parsed
|
|
51304
|
+
* in-turn final assistant summary — in which case it emits the missing
|
|
51305
|
+
* generating_completed (idempotent: a real/late emit writes the terminal ledger and
|
|
51306
|
+
* the coordinator's reconcile makes any duplicate a no-op) and the caller SUPPRESSES
|
|
51307
|
+
* the stall. Returns false for every other class/state (native-source provider, a
|
|
51308
|
+
* genuinely mid-turn or wedged worker with no final assistant), so a real stall still
|
|
51309
|
+
* fires unchanged.
|
|
51310
|
+
*
|
|
51311
|
+
* Evidence bar is identical to flushMeshCompletionBeforeCleanup: injected task's turn
|
|
51312
|
+
* genuinely started + an in-turn final assistant summary. Conservative by
|
|
51313
|
+
* construction — no summary ⇒ no proof of completion ⇒ return false and let the real
|
|
51314
|
+
* stall fire.
|
|
51315
|
+
*/
|
|
51316
|
+
tryReconcilePurePtyCompletionForStall(observedStatus) {
|
|
51317
|
+
if (!isPurePtyTranscriptProvider(this.provider)) return false;
|
|
51318
|
+
if (observedStatus !== "idle") return false;
|
|
51319
|
+
if (this.hasAdapterPendingResponse()) return false;
|
|
51320
|
+
const taskId = this.completingTurnTaskId();
|
|
51321
|
+
if (this.lastEmittedCompletion && this.lastEmittedCompletion.taskId === (taskId ?? "")) {
|
|
51322
|
+
return false;
|
|
51323
|
+
}
|
|
51324
|
+
if (!this.injectedTaskHasStartedGenerating()) return false;
|
|
51325
|
+
const turnStartedAt = typeof this.adapter?.currentTurnStartedAt === "number" ? this.adapter.currentTurnStartedAt : this.meshTaskInjectedAt || void 0;
|
|
51326
|
+
let parsedMessages;
|
|
51327
|
+
try {
|
|
51328
|
+
parsedMessages = this.adapter?.getScriptParsedStatus?.()?.messages;
|
|
51329
|
+
} catch {
|
|
51330
|
+
parsedMessages = void 0;
|
|
51331
|
+
}
|
|
51332
|
+
let finalSummary;
|
|
51333
|
+
try {
|
|
51334
|
+
finalSummary = this.completionFinalSummary(parsedMessages, turnStartedAt);
|
|
51335
|
+
} catch {
|
|
51336
|
+
finalSummary = void 0;
|
|
51337
|
+
}
|
|
51338
|
+
if (!finalSummary) return false;
|
|
51339
|
+
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.`);
|
|
51340
|
+
if (this.isMeshWorkerSession()) {
|
|
51341
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), "stall_pure_pty_transcript_completion");
|
|
51342
|
+
}
|
|
51343
|
+
this.emitGeneratingCompleted({
|
|
51344
|
+
chatTitle: "",
|
|
51345
|
+
duration: void 0,
|
|
51346
|
+
timestamp: Date.now(),
|
|
51347
|
+
taskId,
|
|
51348
|
+
finalSummary,
|
|
51349
|
+
evidenceLevel: "transcript",
|
|
51350
|
+
completionDiagnostic: { source: "stall_pure_pty_transcript_completion" }
|
|
51351
|
+
});
|
|
51352
|
+
return true;
|
|
51353
|
+
}
|
|
51166
51354
|
/**
|
|
51167
51355
|
* AUTOAPPROVE-FLAP-RECUR (Fix A+B): how long a busy blip / modal scroll-out may
|
|
51168
51356
|
* persist before the in-progress settle gate is torn down. For a delegated
|