@adhdev/daemon-core 0.9.82-rc.373 → 0.9.82-rc.375
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 +372 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +372 -66
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +53 -0
- package/dist/mesh/mesh-events-stale.d.ts +12 -0
- package/dist/mesh/mesh-ledger.d.ts +1 -1
- package/dist/providers/chat-message-normalization.d.ts +1 -1
- package/dist/providers/cli-provider-instance.d.ts +3 -0
- package/package.json +2 -2
- package/src/commands/high-family/mesh-coordinator-launch.ts +67 -2
- package/src/commands/med-family/cli-agent.ts +25 -13
- package/src/commands/med-family/fast-forward.ts +80 -48
- package/src/commands/med-family/mesh-crud.ts +12 -2
- package/src/mesh/coordinator-prompt.ts +145 -0
- package/src/mesh/mesh-events-coordinator.ts +64 -1
- package/src/mesh/mesh-events-stale.ts +23 -0
- package/src/mesh/mesh-events-utils.ts +1 -1
- package/src/mesh/mesh-ledger.ts +5 -0
- package/src/mesh/mesh-reconcile-loop.ts +145 -10
- package/src/providers/chat-message-normalization.ts +1 -1
- package/src/providers/cli-provider-instance.ts +69 -2
|
@@ -102,6 +102,24 @@ type ExternalTranscriptProbe = {
|
|
|
102
102
|
|
|
103
103
|
const COMPLETED_FINALIZATION_RETRY_MS = 1000;
|
|
104
104
|
const COMPLETED_FINALIZATION_MAX_WAIT_MS = 30_000;
|
|
105
|
+
// (FALSEIDLE-BGCHILD-a) Minimum generating→idle settle window for native-history mesh worker
|
|
106
|
+
// sessions. Native-history providers (e.g. claude-cli) normally flush the completion with
|
|
107
|
+
// flushDelay=0 — the transcript is authoritative, so there is no reason to wait. But a worker
|
|
108
|
+
// turn that spawns a BACKGROUND child (e.g. `npm test &`, a backgrounded Bash tool) can paint
|
|
109
|
+
// a burst of child output, fall quiet, and have the screen parser read a PRIOR/intermediate
|
|
110
|
+
// standard assistant as if the turn were done — firing a false idle while the agent is in fact
|
|
111
|
+
// still generating (e.g. mid-commit). With flushDelay=0 there is no window for the resume guard
|
|
112
|
+
// in flushCompletedDebounceIfFinalized (latestVisibleStatus !== 'idle' → cancel) to observe the
|
|
113
|
+
// agent picking the turn back up. A short non-zero settle window restores that resume guard for
|
|
114
|
+
// mesh workers without delaying genuinely-finished turns beyond this bound. Scoped to mesh
|
|
115
|
+
// worker sessions so interactive native-history sessions keep the immediate flush.
|
|
116
|
+
const NATIVE_HISTORY_MESH_IDLE_SETTLE_MS = 1500;
|
|
117
|
+
// TASKBUBBLE-DUP: window during which an identical user-input ack (same trimmed
|
|
118
|
+
// content on the same instance) is treated as a redelivery of one dispatch and
|
|
119
|
+
// suppressed from the chat transcript. Matches the coordinator-side
|
|
120
|
+
// DUPLICATE_DISPATCH_WINDOW_MS (mesh-tools) so the daemon's bubble-level guard
|
|
121
|
+
// covers the same retry horizon as the MCP-level dispatch dedup.
|
|
122
|
+
const USER_INPUT_ACK_DEDUP_WINDOW_MS = 60_000;
|
|
105
123
|
|
|
106
124
|
/** Events that signal a dispatched mesh task has reached a terminal state.
|
|
107
125
|
* Detach the mesh assignment after emitting one of these so the worker's
|
|
@@ -431,6 +449,14 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
431
449
|
private runtimeMessages: Array<{ key: string; message: ChatMessage }> = [];
|
|
432
450
|
private lastPersistedHistoryMessages: PersistableCliHistoryMessage[] = [];
|
|
433
451
|
private lastAcknowledgedUserInputAt = 0;
|
|
452
|
+
// TASKBUBBLE-DUP: per-content last-ack timestamps so the same dispatched
|
|
453
|
+
// prompt acked twice in quick succession (the worker buffers the first
|
|
454
|
+
// send during bootstrap/busy, then a redelivery — dispatch-confirm-timeout
|
|
455
|
+
// requeue or a reconcile re-dispatch — fires a SECOND send_chat before the
|
|
456
|
+
// outbound queue drains) collapses to ONE user bubble. Keyed on the trimmed
|
|
457
|
+
// content; an entry older than USER_INPUT_ACK_DEDUP_WINDOW_MS is treated as
|
|
458
|
+
// a fresh, intentional resend and is NOT suppressed.
|
|
459
|
+
private recentUserInputAcks = new Map<string, number>();
|
|
434
460
|
private lastNativeSourceCanonicalCheckAt = 0;
|
|
435
461
|
private lastNativeSourceCanonicalCacheKey: string | undefined = undefined;
|
|
436
462
|
private cachedSqliteDb: {
|
|
@@ -1056,7 +1082,31 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1056
1082
|
if (!content) return;
|
|
1057
1083
|
|
|
1058
1084
|
const receivedAt = Date.now();
|
|
1085
|
+
|
|
1086
|
+
// TASKBUBBLE-DUP: collapse a redelivered dispatch to one bubble. A single
|
|
1087
|
+
// mesh_send_task can reach this instance as TWO send_chat calls when the
|
|
1088
|
+
// first injection is buffered during bootstrap/busy and a retry (dispatch-
|
|
1089
|
+
// confirm-timeout requeue, or a reconcile re-dispatch) fires before the
|
|
1090
|
+
// outbound queue drains. The previous dedupKey hashed receivedAt, so the
|
|
1091
|
+
// two acks produced different keys and BOTH bubbled. Suppress an identical
|
|
1092
|
+
// content ack seen within USER_INPUT_ACK_DEDUP_WINDOW_MS; a later resend of
|
|
1093
|
+
// the same text (beyond the window) is a genuine new turn and still shows.
|
|
1094
|
+
const ackContentKey = shortHash(`${this.instanceId}:${content}`, 24);
|
|
1095
|
+
const lastAckAt = this.recentUserInputAcks.get(ackContentKey);
|
|
1096
|
+
if (lastAckAt !== undefined && receivedAt - lastAckAt <= USER_INPUT_ACK_DEDUP_WINDOW_MS) {
|
|
1097
|
+
// Refresh the timestamp so a steady stream of redeliveries keeps
|
|
1098
|
+
// collapsing, and prune stale entries to bound the map size.
|
|
1099
|
+
this.recentUserInputAcks.set(ackContentKey, receivedAt);
|
|
1100
|
+
this.pruneRecentUserInputAcks(receivedAt);
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
this.recentUserInputAcks.set(ackContentKey, receivedAt);
|
|
1104
|
+
this.pruneRecentUserInputAcks(receivedAt);
|
|
1105
|
+
|
|
1059
1106
|
this.lastAcknowledgedUserInputAt = receivedAt;
|
|
1107
|
+
// The runtimeMessages dedupKey stays per-call unique (includes receivedAt)
|
|
1108
|
+
// so a genuine resend of the same text after the window appends a fresh
|
|
1109
|
+
// bubble; redelivery within the window is already suppressed above.
|
|
1060
1110
|
const dedupKey = `user_input_ack:${shortHash(`${this.instanceId}:${content}:${receivedAt}`, 24)}`;
|
|
1061
1111
|
this.appendRuntimeMessage(buildChatMessage({
|
|
1062
1112
|
role: 'user',
|
|
@@ -1074,6 +1124,14 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1074
1124
|
} as ChatMessage), dedupKey);
|
|
1075
1125
|
}
|
|
1076
1126
|
|
|
1127
|
+
/** Drop user-input ack entries older than the dedup window so the map can't grow unbounded. */
|
|
1128
|
+
private pruneRecentUserInputAcks(now: number): void {
|
|
1129
|
+
if (this.recentUserInputAcks.size <= 1) return;
|
|
1130
|
+
for (const [key, at] of this.recentUserInputAcks) {
|
|
1131
|
+
if (now - at > USER_INPUT_ACK_DEDUP_WINDOW_MS) this.recentUserInputAcks.delete(key);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1077
1135
|
dispose(): void {
|
|
1078
1136
|
this.adapter.shutdown();
|
|
1079
1137
|
this.monitor.reset();
|
|
@@ -2004,8 +2062,17 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
2004
2062
|
previousStatus: this.lastStatus,
|
|
2005
2063
|
};
|
|
2006
2064
|
const ownsExternalHistory = !!(this.adapter as any)?.chatMessagesOwnedExternally;
|
|
2007
|
-
|
|
2008
|
-
|
|
2065
|
+
// (FALSEIDLE-BGCHILD-a) Native-history providers flush immediately (the
|
|
2066
|
+
// transcript is authoritative). For mesh worker sessions, give the
|
|
2067
|
+
// generating→idle transition a short settle window so a background-child
|
|
2068
|
+
// false idle (quiet after a backgrounded test/command while the parent turn
|
|
2069
|
+
// continues) gets caught by the resume guard in flushCompletedDebounceIfFinalized
|
|
2070
|
+
// instead of firing an early completion the coordinator can never correct.
|
|
2071
|
+
const meshWorkerSession = this.isMeshWorkerSession();
|
|
2072
|
+
const flushDelay = ownsExternalHistory
|
|
2073
|
+
? (meshWorkerSession ? NATIVE_HISTORY_MESH_IDLE_SETTLE_MS : 0)
|
|
2074
|
+
: 3000;
|
|
2075
|
+
LOG.debug('CLI', `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} meshWorker=${meshWorkerSession} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
|
|
2009
2076
|
this.scheduleCompletedDebounceFlush(flushDelay);
|
|
2010
2077
|
}
|
|
2011
2078
|
} else if (newStatus === 'idle' && this.lastStatus === 'starting') {
|