@adhdev/daemon-core 0.9.82-rc.376 → 0.9.82-rc.377
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/commands/chat-commands-debug-bundle.d.ts +14 -0
- package/dist/commands/chat-commands-read.d.ts +7 -0
- package/dist/commands/chat-commands-scope.d.ts +39 -0
- package/dist/commands/chat-commands-shared.d.ts +33 -0
- package/dist/commands/chat-commands-write.d.ts +14 -0
- package/dist/commands/chat-commands.d.ts +9 -49
- package/dist/index.js +2976 -2943
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2971 -2938
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-event-classify.d.ts +5 -0
- package/dist/mesh/mesh-event-forwarding.d.ts +18 -0
- package/dist/mesh/mesh-events-coordinator.d.ts +4 -92
- package/dist/mesh/mesh-events-utils.d.ts +3 -0
- package/dist/mesh/mesh-ledger-reconciliation.d.ts +0 -1
- package/dist/mesh/mesh-queue-assignment.d.ts +86 -0
- package/dist/mesh/mesh-runtime-store.d.ts +0 -3
- package/dist/providers/native-history/constants.d.ts +12 -0
- package/dist/runtime-defaults.d.ts +2 -0
- package/package.json +2 -2
- package/src/commands/chat-commands-debug-bundle.ts +398 -0
- package/src/commands/chat-commands-read.ts +2327 -0
- package/src/commands/chat-commands-scope.ts +54 -0
- package/src/commands/chat-commands-shared.ts +114 -0
- package/src/commands/chat-commands-write.ts +880 -0
- package/src/commands/chat-commands.ts +20 -3697
- package/src/commands/router.ts +5 -12
- package/src/mesh/mesh-event-classify.ts +51 -0
- package/src/mesh/mesh-event-forwarding.ts +1502 -0
- package/src/mesh/mesh-events-coordinator.ts +30 -2993
- package/src/mesh/mesh-events-pending.ts +1 -10
- package/src/mesh/mesh-events-stale.ts +3 -14
- package/src/mesh/mesh-events-utils.ts +52 -14
- package/src/mesh/mesh-ledger-reconciliation.ts +0 -2
- package/src/mesh/mesh-queue-assignment.ts +1457 -0
- package/src/mesh/mesh-runtime-store.ts +0 -37
- package/src/providers/cli-provider-instance.ts +40 -1
- package/src/providers/native-history/constants.ts +19 -0
- package/src/providers/native-history/dispatcher.ts +2 -3
- package/src/providers/spec/native-history-executor.ts +1 -9
- package/src/runtime-defaults.ts +39 -0
|
@@ -152,21 +152,6 @@ export class MeshRuntimeStore {
|
|
|
152
152
|
expires_at INTEGER NOT NULL
|
|
153
153
|
);
|
|
154
154
|
|
|
155
|
-
-- R3: idempotent coordinator inbox. When a terminal/force-inject event is
|
|
156
|
-
-- direct-injected into a LIVE local CLI coordinator (coord.onEvent('send_message')),
|
|
157
|
-
-- we record (coordinator_daemon_id, fingerprint) here. That same coordinator also
|
|
158
|
-
-- polls get_pending_mesh_events, which would re-deliver the queued copy of the very
|
|
159
|
-
-- event it just received in its PTY → user sees the completion twice. The drain for
|
|
160
|
-
-- a coordinator daemon filters out events already direct-delivered to it, giving
|
|
161
|
-
-- exactly-once-per-coordinator while keeping the queue for other consumers (idle /
|
|
162
|
-
-- MCP-only / remote) that did NOT receive the direct inject.
|
|
163
|
-
CREATE TABLE IF NOT EXISTS mesh_direct_delivered_events (
|
|
164
|
-
coordinator_daemon_id TEXT NOT NULL,
|
|
165
|
-
fingerprint TEXT NOT NULL,
|
|
166
|
-
expires_at INTEGER NOT NULL,
|
|
167
|
-
PRIMARY KEY (coordinator_daemon_id, fingerprint)
|
|
168
|
-
);
|
|
169
|
-
|
|
170
155
|
CREATE TABLE IF NOT EXISTS mesh_direct_dispatches (
|
|
171
156
|
task_id TEXT PRIMARY KEY,
|
|
172
157
|
mesh_id TEXT NOT NULL,
|
|
@@ -342,28 +327,6 @@ export class MeshRuntimeStore {
|
|
|
342
327
|
this.db.prepare('DELETE FROM mesh_completion_fingerprints WHERE expires_at <= ?').run(Date.now());
|
|
343
328
|
}
|
|
344
329
|
|
|
345
|
-
// R3: record that an event (by pending-event fingerprint) was direct-injected into a live
|
|
346
|
-
// coordinator on the given daemon, so that coordinator's own drain skips the queued copy.
|
|
347
|
-
recordDirectDelivered(coordinatorDaemonId: string, fingerprint: string, ttlMs: number): void {
|
|
348
|
-
if (!coordinatorDaemonId || !fingerprint) return;
|
|
349
|
-
this.db.prepare(
|
|
350
|
-
'INSERT OR REPLACE INTO mesh_direct_delivered_events (coordinator_daemon_id, fingerprint, expires_at) VALUES (?, ?, ?)'
|
|
351
|
-
).run(coordinatorDaemonId, fingerprint, Date.now() + ttlMs);
|
|
352
|
-
this.maybeCheckpointWal();
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
wasDirectDelivered(coordinatorDaemonId: string, fingerprint: string): boolean {
|
|
356
|
-
if (!coordinatorDaemonId || !fingerprint) return false;
|
|
357
|
-
const row = this.db.prepare(
|
|
358
|
-
'SELECT 1 FROM mesh_direct_delivered_events WHERE coordinator_daemon_id = ? AND fingerprint = ? AND expires_at > ?'
|
|
359
|
-
).get(coordinatorDaemonId, fingerprint, Date.now());
|
|
360
|
-
return row !== undefined;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
sweepExpiredDirectDelivered(): void {
|
|
364
|
-
this.db.prepare('DELETE FROM mesh_direct_delivered_events WHERE expires_at <= ?').run(Date.now());
|
|
365
|
-
}
|
|
366
|
-
|
|
367
330
|
private maybeCheckpointWal(): void {
|
|
368
331
|
if (++this.walWriteCounter < MeshRuntimeStore.WAL_CHECK_INTERVAL) return;
|
|
369
332
|
this.walWriteCounter = 0;
|
|
@@ -81,6 +81,14 @@ type CompletedFinalizationBlock = {
|
|
|
81
81
|
reason: string;
|
|
82
82
|
terminal?: boolean;
|
|
83
83
|
allowTimeout?: boolean;
|
|
84
|
+
// (SETTLE-VALLEY) When set, suppress the CANON-C decoupled-immediate emit for this
|
|
85
|
+
// missing_final_assistant block and HOLD (retry up to COMPLETED_FINALIZATION_MAX_WAIT_MS)
|
|
86
|
+
// until the native transcript's final assistant turn arrives (block clears → genuine emit)
|
|
87
|
+
// or the worker resumes (resume guard cancels). Set only for the inter-approval idle valley
|
|
88
|
+
// of a native-history mesh worker, where an immediate weak emit would freeze a truncated
|
|
89
|
+
// preamble summary (evidenceLevel=insufficient) into the append-only ledger before the
|
|
90
|
+
// worker's next approval turn resumes. Independent of valley length.
|
|
91
|
+
holdForTranscript?: boolean;
|
|
84
92
|
};
|
|
85
93
|
|
|
86
94
|
type CompletionFinalAssistantEvidence = {
|
|
@@ -113,7 +121,13 @@ const COMPLETED_FINALIZATION_MAX_WAIT_MS = 30_000;
|
|
|
113
121
|
// agent picking the turn back up. A short non-zero settle window restores that resume guard for
|
|
114
122
|
// mesh workers without delaying genuinely-finished turns beyond this bound. Scoped to mesh
|
|
115
123
|
// worker sessions so interactive native-history sessions keep the immediate flush.
|
|
116
|
-
|
|
124
|
+
// 4000ms (was 1500): live measurement showed the completion event can fire 1.6–3s
|
|
125
|
+
// BEFORE the worker's final-assistant turn lands in the transcript on a natural
|
|
126
|
+
// generating→idle completion (no approval modal), freezing a prior intermediate
|
|
127
|
+
// bubble as finalSummary (evidenceLevel=insufficient). The 68a3c324 waiting_approval
|
|
128
|
+
// hold only covers the approval-resolved valley; widening this settle window to 4000ms
|
|
129
|
+
// covers that race AND the ~3s waiting_approval valley within the settle bound.
|
|
130
|
+
const NATIVE_HISTORY_MESH_IDLE_SETTLE_MS = 4000;
|
|
117
131
|
// TASKBUBBLE-DUP: window during which an identical user-input ack (same trimmed
|
|
118
132
|
// content on the same instance) is treated as a redelivery of one dispatch and
|
|
119
133
|
// suppressed from the chat transcript. Matches the coordinator-side
|
|
@@ -1441,6 +1455,22 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1441
1455
|
if (this.type === 'antigravity-cli') {
|
|
1442
1456
|
return null;
|
|
1443
1457
|
}
|
|
1458
|
+
// (SETTLE-VALLEY) The inter-approval idle valley: a native-history mesh worker
|
|
1459
|
+
// that resolved an approval and fell briefly idle (waiting_approval→idle) BEFORE
|
|
1460
|
+
// the next approval turn resumes. The live valley (~3s) is mostly covered by the
|
|
1461
|
+
// 4000ms NATIVE_HISTORY_MESH_IDLE_SETTLE_MS settle window, but a longer valley can
|
|
1462
|
+
// still let the flush run while the transcript's final assistant turn is not yet
|
|
1463
|
+
// written (source still the screen parse → finalAssistantPresent=false,
|
|
1464
|
+
// workerResult.source='default'). CANON-C would emit immediately here, freezing a
|
|
1465
|
+
// truncated preamble summary as evidenceLevel=insufficient. Instead HOLD: this
|
|
1466
|
+
// waiting_approval hold complements the settle window. Retry until the transcript finalizes
|
|
1467
|
+
// (block clears → genuine emit) or the worker resumes (resume guard cancels),
|
|
1468
|
+
// bounded by COMPLETED_FINALIZATION_MAX_WAIT_MS. Scoped to the approval-resolved
|
|
1469
|
+
// idle so a genuinely-finished background-child turn keeps the CANON-C immediate
|
|
1470
|
+
// emit (its transcript trails by a write, not by a whole resume).
|
|
1471
|
+
if (allowMissingAssistantTimeout && pending.previousStatus === 'waiting_approval') {
|
|
1472
|
+
return { reason: 'missing_final_assistant', terminal: false, holdForTranscript: true };
|
|
1473
|
+
}
|
|
1444
1474
|
return { reason: 'missing_final_assistant', terminal: true, allowTimeout: allowMissingAssistantTimeout };
|
|
1445
1475
|
}
|
|
1446
1476
|
if ((this.provider as any).requiresFinalAssistantBeforeIdle === true) {
|
|
@@ -1585,6 +1615,15 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1585
1615
|
// one still surfaces, and isFalseIdleCompletion keeps the direct dispatch active until
|
|
1586
1616
|
// then). All OTHER blocks (genuinely-busy adapter/partial/parsed states, transient
|
|
1587
1617
|
// parse_error) keep the existing terminal-hold / 30s-retry behavior unchanged.
|
|
1618
|
+
//
|
|
1619
|
+
// (SETTLE-VALLEY) Exception: a `holdForTranscript` block is the inter-approval idle
|
|
1620
|
+
// valley of a native-history mesh worker (waiting_approval→idle that will resume into
|
|
1621
|
+
// the next approval). It deliberately does NOT carry allowTimeout, so it falls into the
|
|
1622
|
+
// hold-and-retry path below (terminal:false) rather than the CANON-C immediate emit —
|
|
1623
|
+
// the retry loop re-runs the resume guard each cycle, so when the worker resumes the
|
|
1624
|
+
// pending completion is cancelled, and when the transcript's final assistant arrives the
|
|
1625
|
+
// block clears for a GENUINE emit. This blocks the truncated weak (insufficient) summary
|
|
1626
|
+
// from ever being emitted during the valley, without depending on the valley's length.
|
|
1588
1627
|
const isTranscriptEvidenceGate = block.allowTimeout === true;
|
|
1589
1628
|
LOG.debug('CLI', `[${this.type}] finalization block: reason=${blockReason} terminal=${block.terminal} allowTimeout=${isTranscriptEvidenceGate} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
|
|
1590
1629
|
if (!isTranscriptEvidenceGate && (block.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS)) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared constants for the native-history subtree.
|
|
3
|
+
*
|
|
4
|
+
* OSS code (AGPL-3.0). Must not import from packages/ (proprietary).
|
|
5
|
+
*/
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Spawn-bind grace window: an on-disk rollout whose session_meta.timestamp
|
|
10
|
+
* lands within ±SPAWN_BIND_GRACE_MS of the daemon's spawnedAtMs is treated
|
|
11
|
+
* as belonging to that daemon session. 10s is long enough to absorb codex
|
|
12
|
+
* binary startup latency on cold caches and short enough that two
|
|
13
|
+
* back-to-back launches don't both fall inside the same window.
|
|
14
|
+
*
|
|
15
|
+
* Shared by the declarative executor (providers/spec/native-history-executor.ts)
|
|
16
|
+
* and the codex runtime disambiguator (providers/native-history/dispatcher.ts) —
|
|
17
|
+
* both apply the identical ±10s session-binding window.
|
|
18
|
+
*/
|
|
19
|
+
export const SPAWN_BIND_GRACE_MS = 10_000;
|
|
@@ -18,6 +18,7 @@ import { readSession as readClaudeCliSession } from './claude-cli-transcript.js'
|
|
|
18
18
|
import { readSession as readCodexCliSession } from './codex-cli-transcript.js';
|
|
19
19
|
import { readSession as readAntigravityCliSession } from './antigravity-cli-transcript.js';
|
|
20
20
|
import { readSession as readHermesCliSession } from './hermes-cli-transcript.js';
|
|
21
|
+
import { SPAWN_BIND_GRACE_MS } from './constants.js';
|
|
21
22
|
|
|
22
23
|
export type ReaderId = 'claude-cli' | 'codex-cli' | 'antigravity-cli' | 'hermes-cli';
|
|
23
24
|
|
|
@@ -153,8 +154,6 @@ function findCodexPathBySessionId(root: string, sessionId: string): string | nul
|
|
|
153
154
|
return matches[0]?.p ?? null;
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
const CODEX_SPAWN_BIND_GRACE_MS = 10_000;
|
|
157
|
-
|
|
158
157
|
function findCodexPathByRuntime(root: string, workspace: string, sessionStartedAtMs: number): string | null {
|
|
159
158
|
if (!fs.existsSync(root) || !workspace) return null;
|
|
160
159
|
const workspaceResolved = resolveRealPath(workspace);
|
|
@@ -180,7 +179,7 @@ function findCodexPathByRuntime(root: string, workspace: string, sessionStartedA
|
|
|
180
179
|
const diff = sessionStartedAtMs > 0 && meta.timestampMs != null
|
|
181
180
|
? Math.abs(meta.timestampMs - sessionStartedAtMs)
|
|
182
181
|
: 0;
|
|
183
|
-
if (sessionStartedAtMs > 0 && (meta.timestampMs == null || diff >
|
|
182
|
+
if (sessionStartedAtMs > 0 && (meta.timestampMs == null || diff > SPAWN_BIND_GRACE_MS)) continue;
|
|
184
183
|
matches.push({ p: entryPath, mtime, diff });
|
|
185
184
|
}
|
|
186
185
|
}
|
|
@@ -30,6 +30,7 @@ import type {
|
|
|
30
30
|
NativeHistorySqliteSource,
|
|
31
31
|
NativeHistoryToolMap,
|
|
32
32
|
} from './types.js';
|
|
33
|
+
import { SPAWN_BIND_GRACE_MS } from '../native-history/constants.js';
|
|
33
34
|
|
|
34
35
|
export interface NativeHistoryInput {
|
|
35
36
|
agentType?: string;
|
|
@@ -707,15 +708,6 @@ function readCandidateSessionMeta(filePath: string): CandidateMeta | null {
|
|
|
707
708
|
}
|
|
708
709
|
}
|
|
709
710
|
|
|
710
|
-
/**
|
|
711
|
-
* Spawn-bind grace window: an on-disk rollout whose session_meta.timestamp
|
|
712
|
-
* lands within ±SPAWN_BIND_GRACE_MS of the daemon's spawnedAtMs is treated
|
|
713
|
-
* as belonging to that daemon session. 10s is long enough to absorb codex
|
|
714
|
-
* binary startup latency on cold caches and short enough that two
|
|
715
|
-
* back-to-back launches don't both fall inside the same window.
|
|
716
|
-
*/
|
|
717
|
-
const SPAWN_BIND_GRACE_MS = 10_000;
|
|
718
|
-
|
|
719
711
|
function pickBoundFromEntries(
|
|
720
712
|
candidatePaths: string[],
|
|
721
713
|
sessionFloorMs: number,
|
package/src/runtime-defaults.ts
CHANGED
|
@@ -14,3 +14,42 @@ export const DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS = 10_000;
|
|
|
14
14
|
export const DEFAULT_SESSION_HOST_READY_TIMEOUT_MS = 15_000;
|
|
15
15
|
|
|
16
16
|
export const STANDALONE_CDP_SCAN_INTERVAL_MS = 15_000;
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Mesh P2P timeout windows (env-overridable)
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
// Reads a mesh timeout (ms) from the first non-empty env var in `names`, clamped
|
|
23
|
+
// to [1_000, 120_000]; falls back to `defaultMs` when none is set or the value is
|
|
24
|
+
// out of range. The clamp lets a slow real link be tuned up (TURN-relayed peers
|
|
25
|
+
// whose RTT is many seconds) and lets the test harness shrink the window to its
|
|
26
|
+
// 1s minimum, without ever degenerating to 0 or an absurd value. Multiple names
|
|
27
|
+
// are accepted so a renamed constant can keep honoring a legacy alias.
|
|
28
|
+
export function readMeshTimeoutEnvMs(names: string | string[], defaultMs: number): number {
|
|
29
|
+
const candidates = Array.isArray(names) ? names : [names];
|
|
30
|
+
for (const name of candidates) {
|
|
31
|
+
const raw = process.env[name]?.trim();
|
|
32
|
+
if (!raw) continue;
|
|
33
|
+
const parsed = Number.parseInt(raw, 10);
|
|
34
|
+
if (Number.isFinite(parsed) && parsed >= 1_000 && parsed <= 120_000) return parsed;
|
|
35
|
+
return defaultMs;
|
|
36
|
+
}
|
|
37
|
+
return defaultMs;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// SINGLE source of truth for the mesh cold-open *connect* budget — the time a
|
|
41
|
+
// caller grants a peer whose mesh DataChannel is not open yet to drive the
|
|
42
|
+
// cross-machine (often TURN-relayed) ICE/DTLS handshake before the response
|
|
43
|
+
// deadline takes over. Two call sites share this so an env override tunes BOTH:
|
|
44
|
+
// - commands/router.ts direct-peer git_status probe (requireDirectPeerTruth)
|
|
45
|
+
// - mesh/mesh-events-coordinator.ts remote task-dispatch (deliverTaskToSession)
|
|
46
|
+
// Before unification the coordinator hard-coded 45_000 while the router was
|
|
47
|
+
// env-overridable, so setting the env tuned the probe path but silently left the
|
|
48
|
+
// dispatch path at 45s — the same nominal 45s, but divergent the moment the env
|
|
49
|
+
// was set. Matches the daemon-cloud DaemonMeshManager CONNECT_TIMEOUT_MS (45s).
|
|
50
|
+
// `MESH_DIRECT_PROBE_CONNECT_TIMEOUT_MS` is honored as a backward-compat alias so
|
|
51
|
+
// environments already tuned under the old name keep working.
|
|
52
|
+
export const MESH_CONNECT_TIMEOUT_MS = readMeshTimeoutEnvMs(
|
|
53
|
+
['MESH_CONNECT_TIMEOUT_MS', 'MESH_DIRECT_PROBE_CONNECT_TIMEOUT_MS'],
|
|
54
|
+
45_000,
|
|
55
|
+
);
|