@adhdev/daemon-core 0.9.82-rc.467 → 0.9.82-rc.469
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.d.ts +7 -5
- package/dist/index.js +955 -726
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +953 -731
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-completion-synthesis.d.ts +4 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +0 -27
- package/dist/mesh/mesh-events-pending.d.ts +40 -0
- package/dist/mesh/mesh-events.d.ts +2 -2
- package/dist/mesh/mesh-ledger.d.ts +1 -1
- package/dist/mesh/mesh-reconcile-config.d.ts +6 -0
- package/dist/mesh/mesh-remote-event-pull.d.ts +15 -0
- package/dist/mesh/mesh-runtime-store.d.ts +0 -22
- package/dist/mesh/mesh-work-queue.d.ts +45 -0
- package/dist/providers/cli-provider-effect-format.d.ts +30 -0
- package/dist/providers/cli-provider-instance-types.d.ts +45 -0
- package/dist/providers/cli-provider-instance.d.ts +12 -6
- package/dist/providers/cli-provider-transcript-merge.d.ts +7 -0
- package/package.json +3 -3
- package/src/index.ts +11 -5
- package/src/mesh/coordinator-prompt.ts +15 -0
- package/src/mesh/mesh-completion-synthesis.ts +398 -0
- package/src/mesh/mesh-delivery-policy.ts +7 -38
- package/src/mesh/mesh-event-forwarding.ts +9 -10
- package/src/mesh/mesh-events-pending.ts +178 -0
- package/src/mesh/mesh-events.ts +6 -1
- package/src/mesh/mesh-ledger.ts +5 -0
- package/src/mesh/mesh-queue-assignment.ts +16 -2
- package/src/mesh/mesh-reconcile-config.ts +66 -0
- package/src/mesh/mesh-reconcile-loop.ts +21 -647
- package/src/mesh/mesh-remote-event-pull.ts +279 -0
- package/src/mesh/mesh-runtime-store.ts +92 -83
- package/src/mesh/mesh-work-queue.ts +90 -0
- package/src/providers/cli-provider-effect-format.ts +53 -0
- package/src/providers/cli-provider-instance-types.ts +131 -0
- package/src/providers/cli-provider-instance.ts +87 -303
- package/src/providers/cli-provider-transcript-merge.ts +114 -0
package/dist/index.mjs
CHANGED
|
@@ -404,10 +404,10 @@ function readInjected(value) {
|
|
|
404
404
|
}
|
|
405
405
|
function getDaemonBuildInfo() {
|
|
406
406
|
if (cached) return cached;
|
|
407
|
-
const commit = readInjected(true ? "
|
|
408
|
-
const commitShort = readInjected(true ? "
|
|
409
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
410
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
407
|
+
const commit = readInjected(true ? "7e34ff6bc7c6528fca49478a57e0a83620f3a063" : void 0) ?? "unknown";
|
|
408
|
+
const commitShort = readInjected(true ? "7e34ff6b" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
409
|
+
const version = readInjected(true ? "0.9.82-rc.469" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
410
|
+
const builtAt = readInjected(true ? "2026-07-05T12:18:38.077Z" : void 0);
|
|
411
411
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
412
412
|
return cached;
|
|
413
413
|
}
|
|
@@ -2765,12 +2765,57 @@ function summarizeGitShape(status) {
|
|
|
2765
2765
|
submodules
|
|
2766
2766
|
};
|
|
2767
2767
|
}
|
|
2768
|
-
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP;
|
|
2768
|
+
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP, CANONICAL_MESH_TOOL_NAMES, CANONICAL_MESH_TOOL_COUNT;
|
|
2769
2769
|
var init_dist = __esm({
|
|
2770
2770
|
"../mesh-shared/dist/index.mjs"() {
|
|
2771
2771
|
"use strict";
|
|
2772
2772
|
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
2773
2773
|
MAGI_RAW_ANSWER_CAP = 4e3;
|
|
2774
|
+
CANONICAL_MESH_TOOL_NAMES = [
|
|
2775
|
+
"mesh_status",
|
|
2776
|
+
"mesh_list_nodes",
|
|
2777
|
+
"mesh_enqueue_task",
|
|
2778
|
+
"mesh_view_queue",
|
|
2779
|
+
"mesh_queue_cancel",
|
|
2780
|
+
"mesh_queue_requeue",
|
|
2781
|
+
"mesh_send_task",
|
|
2782
|
+
"mesh_read_chat",
|
|
2783
|
+
"mesh_read_debug",
|
|
2784
|
+
"mesh_launch_session",
|
|
2785
|
+
"mesh_git_status",
|
|
2786
|
+
"mesh_read_node_logs",
|
|
2787
|
+
"mesh_fast_forward_node",
|
|
2788
|
+
"mesh_restart_daemon",
|
|
2789
|
+
"mesh_checkpoint",
|
|
2790
|
+
"mesh_approve",
|
|
2791
|
+
"mesh_clone_node",
|
|
2792
|
+
"mesh_remove_node",
|
|
2793
|
+
"mesh_refine_node",
|
|
2794
|
+
"mesh_refine_batch",
|
|
2795
|
+
"mesh_refine_config",
|
|
2796
|
+
"mesh_change_impact_config",
|
|
2797
|
+
"mesh_init",
|
|
2798
|
+
"mesh_reinit",
|
|
2799
|
+
"mesh_write_mesh_json_config",
|
|
2800
|
+
"mesh_refine_plan",
|
|
2801
|
+
"mesh_cleanup_sessions",
|
|
2802
|
+
"mesh_prune_stale_direct",
|
|
2803
|
+
"mesh_task_history",
|
|
2804
|
+
"mesh_record_note",
|
|
2805
|
+
"mesh_forget_note",
|
|
2806
|
+
"mesh_reconcile_ledger",
|
|
2807
|
+
"mesh_requeue_held_events",
|
|
2808
|
+
"mesh_mission_upsert",
|
|
2809
|
+
"mesh_mission_list",
|
|
2810
|
+
"mesh_review_inbox",
|
|
2811
|
+
"mesh_magi_review",
|
|
2812
|
+
"mesh_magi_collect",
|
|
2813
|
+
"mesh_magi_panel_set",
|
|
2814
|
+
"mesh_magi_panel_list",
|
|
2815
|
+
"mesh_magi_kind_panel_set",
|
|
2816
|
+
"mesh_magi_kind_panel_list"
|
|
2817
|
+
];
|
|
2818
|
+
CANONICAL_MESH_TOOL_COUNT = CANONICAL_MESH_TOOL_NAMES.length;
|
|
2774
2819
|
}
|
|
2775
2820
|
});
|
|
2776
2821
|
|
|
@@ -3792,24 +3837,39 @@ var init_coordinator_prompt = __esm({
|
|
|
3792
3837
|
| \`mesh_queue_cancel\` | Cancel a queue task without deleting audit history |
|
|
3793
3838
|
| \`mesh_queue_requeue\` | Return a task to pending for retry; clears stale session targets |
|
|
3794
3839
|
| \`mesh_send_task\` | Legacy push: enqueue a task targeted at a specific node |
|
|
3840
|
+
| \`mesh_mission_upsert\` | Create/update a persistent mission so a multi-task plan survives coordinator restarts; set status completed/abandoned when the outcome is decided |
|
|
3841
|
+
| \`mesh_mission_list\` | List every mission with goal, status, and live task progress \u2014 the authority for "what work remains" (never hidden by status) |
|
|
3795
3842
|
| \`mesh_launch_session\` | Start a new agent session on a node |
|
|
3796
3843
|
| \`mesh_read_chat\` | Read recent chat messages from a delegated agent session |
|
|
3797
3844
|
| \`mesh_read_debug\` | Collect a daemon-side chat/parser debug bundle for a session |
|
|
3798
3845
|
| \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
|
|
3846
|
+
| \`mesh_reconcile_ledger\` | Reconcile daemon-local ledgers over P2P \u2014 import missing entries from remote nodes into the coordinator local ledger |
|
|
3847
|
+
| \`mesh_requeue_held_events\` | Restore recoverable held coordinator events (T6 quarantine / pending-trim) back to the pending queue; lossless, no double-requeue |
|
|
3848
|
+
| \`mesh_review_inbox\` | List local worktree nodes needing human review \u2014 merge candidates and Refinery-blocked results with evidence/diff summaries |
|
|
3799
3849
|
| \`mesh_record_note\` | Record a durable, provider-neutral operating note (provider quirk / pattern to avoid / recovery lesson). Future coordinators see it under "## Operating Notes" at launch |
|
|
3800
3850
|
| \`mesh_forget_note\` | Retract a stale/wrong operating note by note_id or exact text so it stops riding into future coordinators' prompts (append-only tombstone; history preserved) |
|
|
3801
3851
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
3802
3852
|
| \`mesh_read_node_logs\` | Fetch a remote node's daemon log tail directly over P2P (grep/since/byte-bounded, secrets redacted) \u2014 no session/PowerShell needed to debug a node's daemon |
|
|
3803
3853
|
| \`mesh_fast_forward_node\` | Safely dry-run or explicitly execute an obvious clean fast-forward without launching an agent session |
|
|
3854
|
+
| \`mesh_restart_daemon\` | Update a node's daemon to the latest published version on its channel and restart it (the dashboard "preview update" path, as a mesh command) |
|
|
3804
3855
|
| \`mesh_checkpoint\` | Create a git checkpoint on a node |
|
|
3805
3856
|
| \`mesh_approve\` | Approve/reject a pending agent action |
|
|
3806
3857
|
| \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
|
|
3807
3858
|
| \`mesh_refine_node\` | Validate and merge a completed worktree node back into its base branch |
|
|
3859
|
+
| \`mesh_refine_batch\` | Batch Refinery: converge multiple sibling worktree nodes onto the base branch in one conflict-aware sequential pipeline |
|
|
3860
|
+
| \`mesh_refine_plan\` | Dry-run Refinery plan for a worktree node \u2014 config source, validation commands, merge/cleanup intent \u2014 without executing validation or git merge |
|
|
3861
|
+
| \`mesh_refine_config\` | Refinery config helper (read-only) \u2014 unified entry for schema/validate/suggest via a required \`mode\` |
|
|
3862
|
+
| \`mesh_change_impact_config\` | Change Impact config helper \u2014 unified entry for schema/validate/suggest via a required \`mode\` |
|
|
3808
3863
|
| \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |
|
|
3809
3864
|
| \`mesh_cleanup_sessions\` | Manually clean up delegated session records for a node |
|
|
3865
|
+
| \`mesh_prune_stale_direct\` | Prune orphaned staleDirect dispatch records (dry-run by default); live/pending work and audit history preserved |
|
|
3810
3866
|
| \`mesh_init\` | Guided onboarding for a fresh repo: dry-run scan \u2192 suggest \`.adhdev/*\` configs (refine/bootstrap/change-impact) + providerPriority + current-config echo; gated write on approval |
|
|
3811
3867
|
| \`mesh_reinit\` | Re-onboard an already-configured repo: re-suggest with overwrite semantics + current-vs-suggested diff; dry-run preview first, per-section approval before write |
|
|
3812
3868
|
| \`mesh_write_mesh_json_config\` | Gated write of \`.adhdev/mesh.json\` (repo coordinator-prompt config) from the mesh entry \u2014 dry-run/overwrite like mesh_init |
|
|
3869
|
+
| \`mesh_magi_review\` | Cross-verify a read-only investigation across a standing panel of independent mesh agents (different machines/providers) instead of a single worker |
|
|
3870
|
+
| \`mesh_magi_collect\` | Collect + synthesize a previously dispatched MAGI fan-out by its consensus group id (async companion to mesh_magi_review wait:false) |
|
|
3871
|
+
| \`mesh_magi_panel_set\` | Upsert a named MAGI panel (standing set of independent node\xD7provider members) into machine-local config |
|
|
3872
|
+
| \`mesh_magi_panel_list\` | List configured MAGI panels and resolve each member's availability against the current mesh (read-only) |
|
|
3813
3873
|
| \`mesh_magi_kind_panel_set\` | Bind a task_kind \u2192 MAGI kind-panel slots (machine-local, wholesale replacement \u2014 approve current-vs-new first) |
|
|
3814
3874
|
| \`mesh_magi_kind_panel_list\` | List configured task_kind \u2192 MAGI kind-panel slot bindings (machine-local, read-only) |`;
|
|
3815
3875
|
TOOL_EXPOSURE_PREFLIGHT_SECTION = `## Tool Exposure Preflight
|
|
@@ -5267,29 +5327,6 @@ function getActiveSessionDeliveries(meshId, sessionId) {
|
|
|
5267
5327
|
return [];
|
|
5268
5328
|
}
|
|
5269
5329
|
}
|
|
5270
|
-
function recordCompletionConflict(opts) {
|
|
5271
|
-
try {
|
|
5272
|
-
MeshRuntimeStore.getInstance().recordCompletionConflict({
|
|
5273
|
-
id: randomUUID5(),
|
|
5274
|
-
meshId: opts.meshId,
|
|
5275
|
-
fingerprint: opts.fingerprint,
|
|
5276
|
-
conflictingTaskId: opts.conflictingTaskId,
|
|
5277
|
-
conflictingSessionId: opts.conflictingSessionId,
|
|
5278
|
-
originalTaskId: opts.originalTaskId,
|
|
5279
|
-
originalSessionId: opts.originalSessionId,
|
|
5280
|
-
event: opts.event,
|
|
5281
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5282
|
-
});
|
|
5283
|
-
} catch {
|
|
5284
|
-
}
|
|
5285
|
-
}
|
|
5286
|
-
function getRecentCompletionConflicts(meshId, limitMs) {
|
|
5287
|
-
try {
|
|
5288
|
-
return MeshRuntimeStore.getInstance().getRecentCompletionConflicts(meshId, limitMs);
|
|
5289
|
-
} catch {
|
|
5290
|
-
return [];
|
|
5291
|
-
}
|
|
5292
|
-
}
|
|
5293
5330
|
function markSessionDeliveriesTerminal(meshId, sessionId, terminalStatus) {
|
|
5294
5331
|
try {
|
|
5295
5332
|
const active = MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
|
|
@@ -5363,6 +5400,8 @@ __export(mesh_work_queue_exports, {
|
|
|
5363
5400
|
ACTIVE_MESH_QUEUE_STATUSES: () => ACTIVE_MESH_QUEUE_STATUSES,
|
|
5364
5401
|
HISTORICAL_MESH_QUEUE_STATUSES: () => HISTORICAL_MESH_QUEUE_STATUSES,
|
|
5365
5402
|
MESH_TASK_MODES: () => MESH_TASK_MODES,
|
|
5403
|
+
MESH_TASK_PRIORITIES: () => MESH_TASK_PRIORITIES,
|
|
5404
|
+
NOT_BEFORE_RELATIVE_THRESHOLD_MS: () => NOT_BEFORE_RELATIVE_THRESHOLD_MS,
|
|
5366
5405
|
__clearDirectDispatchesForTests: () => __clearDirectDispatchesForTests,
|
|
5367
5406
|
__clearMeshQueueForTests: () => __clearMeshQueueForTests,
|
|
5368
5407
|
__replaceMeshQueueForTests: () => __replaceMeshQueueForTests,
|
|
@@ -5383,15 +5422,19 @@ __export(mesh_work_queue_exports, {
|
|
|
5383
5422
|
insertDirectDispatch: () => insertDirectDispatch,
|
|
5384
5423
|
isTaskReadonly: () => isTaskReadonly,
|
|
5385
5424
|
markStaleDirectDispatches: () => markStaleDirectDispatches,
|
|
5425
|
+
meshTaskNotBeforeReady: () => meshTaskNotBeforeReady,
|
|
5426
|
+
meshTaskPriorityRank: () => meshTaskPriorityRank,
|
|
5386
5427
|
nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
|
|
5387
5428
|
normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
|
|
5388
5429
|
normalizeMeshTaskMode: () => normalizeMeshTaskMode,
|
|
5430
|
+
normalizeMeshTaskPriority: () => normalizeMeshTaskPriority,
|
|
5389
5431
|
reclaimStrandedAssignedTask: () => reclaimStrandedAssignedTask,
|
|
5390
5432
|
recordDirectDispatchTask: () => recordDirectDispatchTask,
|
|
5391
5433
|
recordMeshToolCall: () => recordMeshToolCall,
|
|
5392
5434
|
recordTaskAutoLaunch: () => recordTaskAutoLaunch,
|
|
5393
5435
|
requeueTask: () => requeueTask,
|
|
5394
5436
|
resolveConvergeRequiredTags: () => resolveConvergeRequiredTags,
|
|
5437
|
+
resolveNotBefore: () => resolveNotBefore,
|
|
5395
5438
|
taskDependenciesSatisfied: () => taskDependenciesSatisfied,
|
|
5396
5439
|
updateDirectDispatchStatus: () => updateDirectDispatchStatus,
|
|
5397
5440
|
updateSessionTaskStatus: () => updateSessionTaskStatus,
|
|
@@ -5399,6 +5442,41 @@ __export(mesh_work_queue_exports, {
|
|
|
5399
5442
|
validateMeshTaskModeRequest: () => validateMeshTaskModeRequest
|
|
5400
5443
|
});
|
|
5401
5444
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
5445
|
+
function meshTaskPriorityRank(priority) {
|
|
5446
|
+
switch (priority) {
|
|
5447
|
+
case "high":
|
|
5448
|
+
return 2;
|
|
5449
|
+
case "low":
|
|
5450
|
+
return 0;
|
|
5451
|
+
default:
|
|
5452
|
+
return 1;
|
|
5453
|
+
}
|
|
5454
|
+
}
|
|
5455
|
+
function normalizeMeshTaskPriority(value) {
|
|
5456
|
+
return value === "low" || value === "normal" || value === "high" ? value : void 0;
|
|
5457
|
+
}
|
|
5458
|
+
function resolveNotBefore(value, nowMs = Date.now()) {
|
|
5459
|
+
if (value === void 0 || value === null) return void 0;
|
|
5460
|
+
let absMs;
|
|
5461
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
5462
|
+
absMs = value < NOT_BEFORE_RELATIVE_THRESHOLD_MS ? nowMs + value : value;
|
|
5463
|
+
} else if (typeof value === "string" && value.trim()) {
|
|
5464
|
+
const parsed = Date.parse(value.trim());
|
|
5465
|
+
if (Number.isNaN(parsed)) return void 0;
|
|
5466
|
+
absMs = parsed;
|
|
5467
|
+
} else {
|
|
5468
|
+
return void 0;
|
|
5469
|
+
}
|
|
5470
|
+
if (absMs <= nowMs) return new Date(nowMs).toISOString();
|
|
5471
|
+
return new Date(absMs).toISOString();
|
|
5472
|
+
}
|
|
5473
|
+
function meshTaskNotBeforeReady(task, nowMs = Date.now()) {
|
|
5474
|
+
const nb = task?.notBefore;
|
|
5475
|
+
if (!nb) return true;
|
|
5476
|
+
const parsed = Date.parse(nb);
|
|
5477
|
+
if (Number.isNaN(parsed)) return true;
|
|
5478
|
+
return parsed <= nowMs;
|
|
5479
|
+
}
|
|
5402
5480
|
function isTaskReadonly(task) {
|
|
5403
5481
|
if (!task) return false;
|
|
5404
5482
|
return task.readonly === true || task.taskMode === "live_debug_readonly";
|
|
@@ -5726,6 +5804,9 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5726
5804
|
}
|
|
5727
5805
|
const id = typeof opts?.id === "string" && opts.id.trim() ? opts.id.trim() : randomUUID6();
|
|
5728
5806
|
const dependsOn = normalizeDependsOn(opts?.dependsOn);
|
|
5807
|
+
const priority = normalizeMeshTaskPriority(opts?.priority);
|
|
5808
|
+
const notBefore = resolveNotBefore(opts?.notBefore);
|
|
5809
|
+
const maxRetries = typeof opts?.maxRetries === "number" && Number.isFinite(opts.maxRetries) && opts.maxRetries >= 0 ? Math.floor(opts.maxRetries) : void 0;
|
|
5729
5810
|
return withQueueLock(meshId, () => {
|
|
5730
5811
|
if (MeshRuntimeStore.getInstance().findQueueEntryById(meshId, id)) {
|
|
5731
5812
|
throw new Error(`duplicate_task_id: task '${id}' already exists in mesh '${meshId}'`);
|
|
@@ -5749,6 +5830,12 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5749
5830
|
targetSessionId: opts?.targetSessionId,
|
|
5750
5831
|
requiredTags: resolvedRequiredTags,
|
|
5751
5832
|
...dependsOn.length > 0 ? { dependsOn } : {},
|
|
5833
|
+
// G6: only persist a non-default priority so legacy/normal rows stay minimal.
|
|
5834
|
+
...priority && priority !== "normal" ? { priority } : {},
|
|
5835
|
+
// G7: hold-until gate (stored ISO). Omitted when absent/immediate.
|
|
5836
|
+
...notBefore ? { notBefore } : {},
|
|
5837
|
+
// P3: explicit retry cap. Omitted → requeue path falls back to policy default.
|
|
5838
|
+
...maxRetries !== void 0 ? { maxRetries } : {},
|
|
5752
5839
|
...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
|
|
5753
5840
|
...typeof opts?.consensusGroupId === "string" && opts.consensusGroupId.trim() ? { consensusGroupId: opts.consensusGroupId.trim() } : {},
|
|
5754
5841
|
...typeof opts?.model === "string" && opts.model.trim() ? { model: opts.model.trim() } : {},
|
|
@@ -6089,7 +6176,7 @@ function recordMeshToolCall(opts) {
|
|
|
6089
6176
|
return { rateLimitExceeded: false, callsInWindow: 0, advisory: null };
|
|
6090
6177
|
}
|
|
6091
6178
|
}
|
|
6092
|
-
var ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES, MESH_TASK_MODES, LIVE_DEBUG_READONLY_FORBIDDEN, NEGATION_CUES, NEGATION_WINDOW_TOKENS, GIT_MUTATION_SUBCOMMANDS, GIT_STASH_READONLY_SUBCOMMANDS, DEPENDENCY_FAILURE_TERMINALS, MAX_STRANDED_RECLAIMS;
|
|
6179
|
+
var ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES, MESH_TASK_MODES, MESH_TASK_PRIORITIES, NOT_BEFORE_RELATIVE_THRESHOLD_MS, LIVE_DEBUG_READONLY_FORBIDDEN, NEGATION_CUES, NEGATION_WINDOW_TOKENS, GIT_MUTATION_SUBCOMMANDS, GIT_STASH_READONLY_SUBCOMMANDS, DEPENDENCY_FAILURE_TERMINALS, MAX_STRANDED_RECLAIMS;
|
|
6093
6180
|
var init_mesh_work_queue = __esm({
|
|
6094
6181
|
"src/mesh/mesh-work-queue.ts"() {
|
|
6095
6182
|
"use strict";
|
|
@@ -6105,6 +6192,8 @@ var init_mesh_work_queue = __esm({
|
|
|
6105
6192
|
ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
|
|
6106
6193
|
HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
|
|
6107
6194
|
MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
|
|
6195
|
+
MESH_TASK_PRIORITIES = ["low", "normal", "high"];
|
|
6196
|
+
NOT_BEFORE_RELATIVE_THRESHOLD_MS = 365 * 24 * 60 * 60 * 1e3;
|
|
6108
6197
|
LIVE_DEBUG_READONLY_FORBIDDEN = [
|
|
6109
6198
|
{ label: "source_edit", pattern: /\b(edit|modify|patch|apply\s+patch|write\s+(?:to\s+)?(?:file|source)|overwrite|delete\s+file|remove\s+file|create\s+file|touch\s+file)\b/i },
|
|
6110
6199
|
{ label: "checkpoint", pattern: /\b(checkpoint|mesh_checkpoint)\b/i },
|
|
@@ -6159,7 +6248,7 @@ var init_mesh_work_queue = __esm({
|
|
|
6159
6248
|
});
|
|
6160
6249
|
|
|
6161
6250
|
// src/mesh/mesh-runtime-store.ts
|
|
6162
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync6, renameSync as renameSync3, statSync as statSync5 } from "fs";
|
|
6251
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync6, renameSync as renameSync3, statSync as statSync5, unlinkSync as unlinkSync2 } from "fs";
|
|
6163
6252
|
import { dirname as dirname2, join as join9 } from "path";
|
|
6164
6253
|
function loadDatabaseCtor() {
|
|
6165
6254
|
if (DatabaseCtor) return DatabaseCtor;
|
|
@@ -6172,9 +6261,28 @@ function safeMeshId(meshId) {
|
|
|
6172
6261
|
function legacyQueuePath(meshId) {
|
|
6173
6262
|
return join9(getLedgerDir(), `${safeMeshId(meshId)}.queue.json`);
|
|
6174
6263
|
}
|
|
6264
|
+
function cleanupStrayRootRuntimeDb(canonicalPath) {
|
|
6265
|
+
try {
|
|
6266
|
+
const strayPath = join9(getConfigDir(), "mesh-runtime.db");
|
|
6267
|
+
if (strayPath === canonicalPath) return;
|
|
6268
|
+
if (!existsSync8(strayPath)) return;
|
|
6269
|
+
if (statSync5(strayPath).size !== 0) return;
|
|
6270
|
+
unlinkSync2(strayPath);
|
|
6271
|
+
if (!loggedStrayCleanup) {
|
|
6272
|
+
loggedStrayCleanup = true;
|
|
6273
|
+
LOG.info("MeshRuntimeStore", `Removed stray 0-byte root mesh-runtime.db at ${strayPath}`);
|
|
6274
|
+
}
|
|
6275
|
+
} catch (err) {
|
|
6276
|
+
if (!loggedStrayCleanup) {
|
|
6277
|
+
loggedStrayCleanup = true;
|
|
6278
|
+
LOG.warn("MeshRuntimeStore", `Stray root mesh-runtime.db cleanup failed (ignored): ${err?.message || err}`);
|
|
6279
|
+
}
|
|
6280
|
+
}
|
|
6281
|
+
}
|
|
6175
6282
|
function meshRuntimeStorePath() {
|
|
6176
6283
|
const dir = getLedgerDir();
|
|
6177
6284
|
const nextPath = join9(dir, "mesh-runtime.db");
|
|
6285
|
+
cleanupStrayRootRuntimeDb(nextPath);
|
|
6178
6286
|
if (existsSync8(nextPath)) return nextPath;
|
|
6179
6287
|
const legacyPath = join9(dir, "beads.db");
|
|
6180
6288
|
if (!existsSync8(legacyPath)) return nextPath;
|
|
@@ -6198,16 +6306,18 @@ function meshRuntimeStorePath() {
|
|
|
6198
6306
|
}
|
|
6199
6307
|
return nextPath;
|
|
6200
6308
|
}
|
|
6201
|
-
var DatabaseCtor, loggedMigrationFailure, MeshRuntimeStore;
|
|
6309
|
+
var DatabaseCtor, loggedMigrationFailure, loggedStrayCleanup, MeshRuntimeStore;
|
|
6202
6310
|
var init_mesh_runtime_store = __esm({
|
|
6203
6311
|
"src/mesh/mesh-runtime-store.ts"() {
|
|
6204
6312
|
"use strict";
|
|
6205
6313
|
init_logger();
|
|
6206
6314
|
init_load_better_sqlite3();
|
|
6315
|
+
init_config();
|
|
6207
6316
|
init_mesh_ledger();
|
|
6208
6317
|
init_mesh_work_queue();
|
|
6209
6318
|
init_dist();
|
|
6210
6319
|
loggedMigrationFailure = false;
|
|
6320
|
+
loggedStrayCleanup = false;
|
|
6211
6321
|
MeshRuntimeStore = class _MeshRuntimeStore {
|
|
6212
6322
|
static instance;
|
|
6213
6323
|
db;
|
|
@@ -6356,20 +6466,9 @@ var init_mesh_runtime_store = __esm({
|
|
|
6356
6466
|
CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_task
|
|
6357
6467
|
ON mesh_session_delivery(mesh_id, task_id);
|
|
6358
6468
|
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
fingerprint TEXT NOT NULL,
|
|
6363
|
-
conflicting_task_id TEXT,
|
|
6364
|
-
conflicting_session_id TEXT,
|
|
6365
|
-
original_task_id TEXT,
|
|
6366
|
-
original_session_id TEXT,
|
|
6367
|
-
event TEXT NOT NULL,
|
|
6368
|
-
created_at TEXT NOT NULL
|
|
6369
|
-
);
|
|
6370
|
-
|
|
6371
|
-
CREATE INDEX IF NOT EXISTS idx_mesh_completion_conflicts_mesh
|
|
6372
|
-
ON mesh_completion_conflicts(mesh_id, created_at);
|
|
6469
|
+
-- MESH-COMPLEXITY-AUDIT Part 8-2: mesh_completion_conflicts removed
|
|
6470
|
+
-- (write-only fingerprint-collision diagnostic, no production reader,
|
|
6471
|
+
-- no no-loss role). Dropped in migrateMeshIsolationColumns step 6.
|
|
6373
6472
|
|
|
6374
6473
|
CREATE TABLE IF NOT EXISTS mesh_tool_call_log (
|
|
6375
6474
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -6550,6 +6649,8 @@ var init_mesh_runtime_store = __esm({
|
|
|
6550
6649
|
ON mesh_pending_events(mesh_id, event_id)
|
|
6551
6650
|
WHERE event_id IS NOT NULL
|
|
6552
6651
|
`);
|
|
6652
|
+
this.db.exec(`DROP TABLE IF EXISTS mesh_direct_delivered_events`);
|
|
6653
|
+
this.db.exec(`DROP TABLE IF EXISTS mesh_completion_conflicts`);
|
|
6553
6654
|
} catch (err) {
|
|
6554
6655
|
if (!loggedMigrationFailure) {
|
|
6555
6656
|
loggedMigrationFailure = true;
|
|
@@ -6859,24 +6960,27 @@ var init_mesh_runtime_store = __esm({
|
|
|
6859
6960
|
}
|
|
6860
6961
|
const nodeIdForms = expandDaemonIdForms(nodeId);
|
|
6861
6962
|
const nodePinnedPlaceholders = nodeIdForms.map(() => "?").join(", ");
|
|
6862
|
-
const
|
|
6863
|
-
|
|
6963
|
+
const parseTier = (query, ...params) => {
|
|
6964
|
+
const tierRows = this.db.prepare(query).all(...params);
|
|
6965
|
+
return tierRows.map((row) => JSON.parse(row.payload)).sort((a, b) => meshTaskPriorityRank(b.priority) - meshTaskPriorityRank(a.priority));
|
|
6966
|
+
};
|
|
6967
|
+
const candidates = [
|
|
6968
|
+
...parseTier(`
|
|
6864
6969
|
SELECT payload FROM mesh_queue
|
|
6865
6970
|
WHERE mesh_id = ? AND status = 'pending' AND target_session_id = ?
|
|
6866
6971
|
ORDER BY created_at ASC
|
|
6867
|
-
|
|
6868
|
-
...
|
|
6972
|
+
`, meshId, sessionId),
|
|
6973
|
+
...parseTier(`
|
|
6869
6974
|
SELECT payload FROM mesh_queue
|
|
6870
6975
|
WHERE mesh_id = ? AND status = 'pending' AND target_node_id IN (${nodePinnedPlaceholders}) AND target_session_id IS NULL
|
|
6871
6976
|
ORDER BY created_at ASC
|
|
6872
|
-
|
|
6873
|
-
...
|
|
6977
|
+
`, meshId, ...nodeIdForms),
|
|
6978
|
+
...parseTier(`
|
|
6874
6979
|
SELECT payload FROM mesh_queue
|
|
6875
6980
|
WHERE mesh_id = ? AND status = 'pending' AND target_node_id IS NULL AND target_session_id IS NULL
|
|
6876
6981
|
ORDER BY created_at ASC
|
|
6877
|
-
|
|
6982
|
+
`, meshId)
|
|
6878
6983
|
];
|
|
6879
|
-
const candidates = rows.map((row) => JSON.parse(row.payload));
|
|
6880
6984
|
const depIds = [...new Set(candidates.flatMap((c) => Array.isArray(c.dependsOn) ? c.dependsOn : []))];
|
|
6881
6985
|
const depStatus = /* @__PURE__ */ new Map();
|
|
6882
6986
|
if (depIds.length > 0) {
|
|
@@ -6891,6 +6995,8 @@ var init_mesh_runtime_store = __esm({
|
|
|
6891
6995
|
if (isTaskReadonly(candidate)) return true;
|
|
6892
6996
|
return !nodeBusy;
|
|
6893
6997
|
};
|
|
6998
|
+
const claimNowMs = Date.now();
|
|
6999
|
+
const notBeforeReady = (candidate) => meshTaskNotBeforeReady(candidate, claimNowMs);
|
|
6894
7000
|
const nodeIsWorktree = opts?.nodeIsWorktree === true;
|
|
6895
7001
|
const convergenceAllows = (candidate) => candidate.taskMode !== "convergence" || !nodeIsWorktree;
|
|
6896
7002
|
const targetMatches = (candidate) => {
|
|
@@ -6900,7 +7006,7 @@ var init_mesh_runtime_store = __esm({
|
|
|
6900
7006
|
}
|
|
6901
7007
|
return true;
|
|
6902
7008
|
};
|
|
6903
|
-
const entry = candidates.find((candidate) => nodeSatisfiesRequiredTags(candidate.requiredTags, capabilityTags) && dependenciesSatisfied(candidate) && convergenceAllows(candidate) && targetMatches(candidate) && nodeConflictAllows(candidate));
|
|
7009
|
+
const entry = candidates.find((candidate) => nodeSatisfiesRequiredTags(candidate.requiredTags, capabilityTags) && dependenciesSatisfied(candidate) && notBeforeReady(candidate) && convergenceAllows(candidate) && targetMatches(candidate) && nodeConflictAllows(candidate));
|
|
6904
7010
|
if (!entry) return null;
|
|
6905
7011
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6906
7012
|
entry.status = "assigned";
|
|
@@ -7260,43 +7366,11 @@ var init_mesh_runtime_store = __esm({
|
|
|
7260
7366
|
this.db.prepare("DELETE FROM mesh_session_delivery WHERE mesh_id = ?").run(meshId);
|
|
7261
7367
|
}
|
|
7262
7368
|
// ── Completion Conflict Diagnostics ──────────────────────────────────────
|
|
7263
|
-
recordCompletionConflict
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
VALUES (@id, @meshId, @fingerprint, @conflictingTaskId, @conflictingSessionId,
|
|
7269
|
-
@originalTaskId, @originalSessionId, @event, @createdAt)
|
|
7270
|
-
`).run({
|
|
7271
|
-
id: entry.id,
|
|
7272
|
-
meshId: entry.meshId,
|
|
7273
|
-
fingerprint: entry.fingerprint,
|
|
7274
|
-
conflictingTaskId: entry.conflictingTaskId ?? null,
|
|
7275
|
-
conflictingSessionId: entry.conflictingSessionId ?? null,
|
|
7276
|
-
originalTaskId: entry.originalTaskId ?? null,
|
|
7277
|
-
originalSessionId: entry.originalSessionId ?? null,
|
|
7278
|
-
event: entry.event,
|
|
7279
|
-
createdAt: entry.createdAt
|
|
7280
|
-
});
|
|
7281
|
-
this.maybeCheckpointWal();
|
|
7282
|
-
}
|
|
7283
|
-
getRecentCompletionConflicts(meshId, limitMs = 60 * 60 * 1e3) {
|
|
7284
|
-
const cutoff = new Date(Date.now() - limitMs).toISOString();
|
|
7285
|
-
const rows = this.db.prepare(
|
|
7286
|
-
"SELECT * FROM mesh_completion_conflicts WHERE mesh_id = ? AND created_at >= ? ORDER BY created_at DESC LIMIT 50"
|
|
7287
|
-
).all(meshId, cutoff);
|
|
7288
|
-
return rows.map((r) => ({
|
|
7289
|
-
id: r.id,
|
|
7290
|
-
meshId: r.mesh_id,
|
|
7291
|
-
fingerprint: r.fingerprint,
|
|
7292
|
-
conflictingTaskId: r.conflicting_task_id,
|
|
7293
|
-
conflictingSessionId: r.conflicting_session_id,
|
|
7294
|
-
originalTaskId: r.original_task_id,
|
|
7295
|
-
originalSessionId: r.original_session_id,
|
|
7296
|
-
event: r.event,
|
|
7297
|
-
createdAt: r.created_at
|
|
7298
|
-
}));
|
|
7299
|
-
}
|
|
7369
|
+
// MESH-COMPLEXITY-AUDIT Part 8-2: recordCompletionConflict /
|
|
7370
|
+
// getRecentCompletionConflicts (and their mesh_completion_conflicts table)
|
|
7371
|
+
// were removed. They were a write-only diagnostic of fingerprint-dedup
|
|
7372
|
+
// collisions with no production reader and no part in the no-loss delivery
|
|
7373
|
+
// contract; the table is dropped in migrateMeshIsolationColumns (step 6).
|
|
7300
7374
|
/**
|
|
7301
7375
|
* Record a mesh tool call and check whether this mesh+tool combination is
|
|
7302
7376
|
* being called too rapidly (sliding window rate guard).
|
|
@@ -11510,7 +11584,7 @@ var init_mesh_events_utils = __esm({
|
|
|
11510
11584
|
});
|
|
11511
11585
|
|
|
11512
11586
|
// src/mesh/mesh-events-pending.ts
|
|
11513
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync15, readFileSync as readFileSync12, renameSync as renameSync4, statSync as statSync6, unlinkSync as
|
|
11587
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync15, readFileSync as readFileSync12, renameSync as renameSync4, statSync as statSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
11514
11588
|
import { join as join16 } from "path";
|
|
11515
11589
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
11516
11590
|
function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
|
|
@@ -11537,7 +11611,11 @@ function ledgerRecordQuarantinedEvent(event, reason) {
|
|
|
11537
11611
|
targetCoordinatorDaemonId: event.targetCoordinatorDaemonId ?? null,
|
|
11538
11612
|
...readNonEmptyString2(event.eventId) ? { eventId: event.eventId } : {},
|
|
11539
11613
|
queuedAt: event.queuedAt,
|
|
11540
|
-
...finalSummary ? { finalSummary } : {}
|
|
11614
|
+
...finalSummary ? { finalSummary } : {},
|
|
11615
|
+
// Full original event so mesh_requeue_held_events can restore it
|
|
11616
|
+
// losslessly (event_held→pending). The summary/label fields above stay
|
|
11617
|
+
// for human-readable audit; `heldEvent` is the machine recovery copy.
|
|
11618
|
+
heldEvent: event
|
|
11541
11619
|
}
|
|
11542
11620
|
});
|
|
11543
11621
|
} catch (e) {
|
|
@@ -11848,8 +11926,11 @@ function trimPendingEventsIfNeeded(path45) {
|
|
|
11848
11926
|
nodeLabel: event.nodeLabel,
|
|
11849
11927
|
...event.workspace ? { workspace: event.workspace } : {},
|
|
11850
11928
|
targetCoordinatorDaemonId: event.targetCoordinatorDaemonId ?? null,
|
|
11929
|
+
...readNonEmptyString2(event.eventId) ? { eventId: event.eventId } : {},
|
|
11851
11930
|
queuedAt: event.queuedAt,
|
|
11852
|
-
...finalSummary ? { finalSummary } : {}
|
|
11931
|
+
...finalSummary ? { finalSummary } : {},
|
|
11932
|
+
// Full original event for lossless mesh_requeue_held_events restore.
|
|
11933
|
+
heldEvent: event
|
|
11853
11934
|
}
|
|
11854
11935
|
});
|
|
11855
11936
|
LOG.warn("MeshEvents", `Pending-events trim dropping undelivered ${event.event} for mesh ${event.meshId} \u2014 recorded to ledger (recoverable)`);
|
|
@@ -11986,13 +12067,13 @@ function atomicDrainFile(path45) {
|
|
|
11986
12067
|
try {
|
|
11987
12068
|
const content = readFileSync12(tmpPath, "utf-8");
|
|
11988
12069
|
try {
|
|
11989
|
-
|
|
12070
|
+
unlinkSync3(tmpPath);
|
|
11990
12071
|
} catch {
|
|
11991
12072
|
}
|
|
11992
12073
|
return content;
|
|
11993
12074
|
} catch {
|
|
11994
12075
|
try {
|
|
11995
|
-
|
|
12076
|
+
unlinkSync3(tmpPath);
|
|
11996
12077
|
} catch {
|
|
11997
12078
|
}
|
|
11998
12079
|
return null;
|
|
@@ -12010,7 +12091,7 @@ function selectiveDrainFile(path45, predicate) {
|
|
|
12010
12091
|
content = readFileSync12(tmpPath, "utf-8");
|
|
12011
12092
|
} catch {
|
|
12012
12093
|
try {
|
|
12013
|
-
|
|
12094
|
+
unlinkSync3(tmpPath);
|
|
12014
12095
|
} catch {
|
|
12015
12096
|
}
|
|
12016
12097
|
return [];
|
|
@@ -12035,7 +12116,7 @@ function selectiveDrainFile(path45, predicate) {
|
|
|
12035
12116
|
if (keptLines.length > 0) {
|
|
12036
12117
|
writeFileSync6(path45, keptLines.join("\n") + "\n", "utf-8");
|
|
12037
12118
|
}
|
|
12038
|
-
|
|
12119
|
+
unlinkSync3(tmpPath);
|
|
12039
12120
|
} catch {
|
|
12040
12121
|
try {
|
|
12041
12122
|
if (existsSync15(tmpPath) && !existsSync15(path45)) renameSync4(tmpPath, path45);
|
|
@@ -12176,6 +12257,83 @@ function getPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId, opts) {
|
|
|
12176
12257
|
});
|
|
12177
12258
|
return reconcilePendingMeshCoordinatorEvents(meshId, routed);
|
|
12178
12259
|
}
|
|
12260
|
+
function readHeldTaskId(restored, payload) {
|
|
12261
|
+
const fromMeta = restored?.metadataEvent && typeof restored.metadataEvent === "object" ? readNonEmptyString2(restored.metadataEvent.taskId) : "";
|
|
12262
|
+
return fromMeta || readNonEmptyString2(payload.taskId) || "";
|
|
12263
|
+
}
|
|
12264
|
+
function requeueHeldMeshCoordinatorEvents(meshId, filter) {
|
|
12265
|
+
const result = {
|
|
12266
|
+
meshId,
|
|
12267
|
+
matched: 0,
|
|
12268
|
+
alreadyRequeued: 0,
|
|
12269
|
+
unrecoverable: 0,
|
|
12270
|
+
requeued: 0,
|
|
12271
|
+
dedupSuppressed: 0,
|
|
12272
|
+
entries: []
|
|
12273
|
+
};
|
|
12274
|
+
const all = readLedgerEntries(meshId);
|
|
12275
|
+
const requeuedIds = /* @__PURE__ */ new Set();
|
|
12276
|
+
for (const entry of all) {
|
|
12277
|
+
if (entry.kind !== "event_held_requeued") continue;
|
|
12278
|
+
const id = readNonEmptyString2(entry.payload?.heldEntryId);
|
|
12279
|
+
if (id) requeuedIds.add(id);
|
|
12280
|
+
}
|
|
12281
|
+
const sinceMs = filter?.since ? new Date(filter.since).getTime() : NaN;
|
|
12282
|
+
const wantEvent = readNonEmptyString2(filter?.event);
|
|
12283
|
+
const wantNode = readNonEmptyString2(filter?.nodeId);
|
|
12284
|
+
const wantTask = readNonEmptyString2(filter?.taskId);
|
|
12285
|
+
const wantReason = readNonEmptyString2(filter?.reason);
|
|
12286
|
+
for (const entry of all) {
|
|
12287
|
+
if (entry.kind !== "event_held") continue;
|
|
12288
|
+
const payload = entry.payload && typeof entry.payload === "object" ? entry.payload : {};
|
|
12289
|
+
if (payload.recoverable !== true) continue;
|
|
12290
|
+
const restored = payload.heldEvent && typeof payload.heldEvent === "object" ? { ...payload.heldEvent } : void 0;
|
|
12291
|
+
const eventName = restored?.event || readNonEmptyString2(payload.event);
|
|
12292
|
+
const nodeId = restored?.nodeId || entry.nodeId || readNonEmptyString2(payload.nodeId) || void 0;
|
|
12293
|
+
const taskId = readHeldTaskId(restored, payload);
|
|
12294
|
+
const reason = readNonEmptyString2(payload.reason) || void 0;
|
|
12295
|
+
if (wantEvent && eventName !== wantEvent) continue;
|
|
12296
|
+
if (wantNode && nodeId !== wantNode) continue;
|
|
12297
|
+
if (wantTask && taskId !== wantTask) continue;
|
|
12298
|
+
if (wantReason && reason !== wantReason) continue;
|
|
12299
|
+
if (filter?.since && !Number.isNaN(sinceMs) && new Date(entry.timestamp).getTime() < sinceMs) continue;
|
|
12300
|
+
result.matched++;
|
|
12301
|
+
if (requeuedIds.has(entry.id)) {
|
|
12302
|
+
result.alreadyRequeued++;
|
|
12303
|
+
result.entries.push({ heldEntryId: entry.id, event: eventName, ...nodeId ? { nodeId } : {}, ...taskId ? { taskId } : {}, ...reason ? { reason } : {}, outcome: "already_requeued" });
|
|
12304
|
+
continue;
|
|
12305
|
+
}
|
|
12306
|
+
if (!restored || !readNonEmptyString2(restored.event) || !readNonEmptyString2(restored.meshId)) {
|
|
12307
|
+
result.unrecoverable++;
|
|
12308
|
+
result.entries.push({ heldEntryId: entry.id, event: eventName, ...nodeId ? { nodeId } : {}, ...taskId ? { taskId } : {}, ...reason ? { reason } : {}, outcome: "unrecoverable" });
|
|
12309
|
+
continue;
|
|
12310
|
+
}
|
|
12311
|
+
const beforeDup = hasPendingCoordinatorEventDuplicate(restored);
|
|
12312
|
+
let ok = false;
|
|
12313
|
+
try {
|
|
12314
|
+
ok = queuePendingMeshCoordinatorEvent(restored);
|
|
12315
|
+
} catch (e) {
|
|
12316
|
+
LOG.warn("MeshEvents", `Requeue of held ${eventName} for mesh ${meshId} failed: ${e?.message || e}`);
|
|
12317
|
+
}
|
|
12318
|
+
appendLedgerEntry(meshId, {
|
|
12319
|
+
kind: "event_held_requeued",
|
|
12320
|
+
...nodeId ? { nodeId } : {},
|
|
12321
|
+
payload: {
|
|
12322
|
+
heldEntryId: entry.id,
|
|
12323
|
+
event: eventName,
|
|
12324
|
+
requeued: ok,
|
|
12325
|
+
...taskId ? { taskId } : {},
|
|
12326
|
+
...reason ? { reason } : {},
|
|
12327
|
+
...beforeDup ? { dedupSuppressed: true } : {}
|
|
12328
|
+
}
|
|
12329
|
+
});
|
|
12330
|
+
requeuedIds.add(entry.id);
|
|
12331
|
+
result.requeued++;
|
|
12332
|
+
if (beforeDup) result.dedupSuppressed++;
|
|
12333
|
+
result.entries.push({ heldEntryId: entry.id, event: eventName, ...nodeId ? { nodeId } : {}, ...taskId ? { taskId } : {}, ...reason ? { reason } : {}, outcome: "requeued" });
|
|
12334
|
+
}
|
|
12335
|
+
return result;
|
|
12336
|
+
}
|
|
12179
12337
|
function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
12180
12338
|
if (!meshId) return;
|
|
12181
12339
|
try {
|
|
@@ -12185,7 +12343,7 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
|
12185
12343
|
const paths = coordinatorDaemonId ? [getPendingEventsPath(meshId, coordinatorDaemonId), getPendingEventsPath(meshId)] : [getPendingEventsPath(meshId)];
|
|
12186
12344
|
for (const path45 of paths) {
|
|
12187
12345
|
if (existsSync15(path45)) try {
|
|
12188
|
-
|
|
12346
|
+
unlinkSync3(path45);
|
|
12189
12347
|
} catch {
|
|
12190
12348
|
}
|
|
12191
12349
|
}
|
|
@@ -14211,7 +14369,7 @@ function driveExpiredAwaitClaim(components, meshId, task, ctx) {
|
|
|
14211
14369
|
async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
14212
14370
|
const queue = getQueue(meshId);
|
|
14213
14371
|
const statusById = new Map(queue.map((task) => [task.id, task.status]));
|
|
14214
|
-
const pending = queue.filter((task) => task.status === "pending");
|
|
14372
|
+
const pending = queue.filter((task) => task.status === "pending").sort((a, b) => meshTaskPriorityRank(b.priority) - meshTaskPriorityRank(a.priority));
|
|
14215
14373
|
{
|
|
14216
14374
|
const pendingIds = new Set(pending.map((t) => t.id));
|
|
14217
14375
|
const prefix = `${meshId}::`;
|
|
@@ -14227,6 +14385,10 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
14227
14385
|
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "dependencies_unsatisfied" });
|
|
14228
14386
|
continue;
|
|
14229
14387
|
}
|
|
14388
|
+
if (!meshTaskNotBeforeReady(task)) {
|
|
14389
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "not_before_delayed" });
|
|
14390
|
+
continue;
|
|
14391
|
+
}
|
|
14230
14392
|
const isReadonly = isTaskReadonly(task);
|
|
14231
14393
|
if (isReadonly) {
|
|
14232
14394
|
if (activeReadonlyAssignedCount(meshId) >= maxReadonlyParallelTasks) {
|
|
@@ -17362,15 +17524,6 @@ function isDuplicateMeshCompletionEvent(args) {
|
|
|
17362
17524
|
const fingerprint = buildMeshCompletionFingerprint(args);
|
|
17363
17525
|
if (!fingerprint) return false;
|
|
17364
17526
|
if (hasFingerprintSeen(args.meshId, fingerprint)) {
|
|
17365
|
-
if (args.taskId) {
|
|
17366
|
-
recordCompletionConflict({
|
|
17367
|
-
meshId: args.meshId,
|
|
17368
|
-
fingerprint,
|
|
17369
|
-
conflictingTaskId: args.taskId,
|
|
17370
|
-
conflictingSessionId: args.sessionId,
|
|
17371
|
-
event: args.event
|
|
17372
|
-
});
|
|
17373
|
-
}
|
|
17374
17527
|
return true;
|
|
17375
17528
|
}
|
|
17376
17529
|
recordFingerprintSeen(args.meshId, fingerprint);
|
|
@@ -18448,6 +18601,347 @@ var init_mesh_reconcile_identity = __esm({
|
|
|
18448
18601
|
}
|
|
18449
18602
|
});
|
|
18450
18603
|
|
|
18604
|
+
// src/mesh/mesh-reconcile-acked-hold.ts
|
|
18605
|
+
function resolveTunedReconcileMs(envName, def, min, max) {
|
|
18606
|
+
const raw = readNonEmptyString2(process.env[envName]);
|
|
18607
|
+
if (raw) {
|
|
18608
|
+
const parsed = Number.parseInt(raw, 10);
|
|
18609
|
+
if (Number.isFinite(parsed) && parsed >= min && parsed <= max) return parsed;
|
|
18610
|
+
}
|
|
18611
|
+
return def;
|
|
18612
|
+
}
|
|
18613
|
+
function resolveAckedDeathDeadlineMs() {
|
|
18614
|
+
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
|
|
18615
|
+
}
|
|
18616
|
+
function resolveAckedTranscriptFastTrackGraceMs() {
|
|
18617
|
+
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
|
|
18618
|
+
}
|
|
18619
|
+
function inFlightSynthKey(meshId, taskId) {
|
|
18620
|
+
return `${meshId}::${taskId}`;
|
|
18621
|
+
}
|
|
18622
|
+
function taskIdFromSynthKey(meshId, synthKey) {
|
|
18623
|
+
const prefix = `${meshId}::`;
|
|
18624
|
+
return synthKey.startsWith(prefix) ? synthKey.slice(prefix.length) : synthKey;
|
|
18625
|
+
}
|
|
18626
|
+
function holdStore() {
|
|
18627
|
+
try {
|
|
18628
|
+
return MeshRuntimeStore.getInstance();
|
|
18629
|
+
} catch {
|
|
18630
|
+
return void 0;
|
|
18631
|
+
}
|
|
18632
|
+
}
|
|
18633
|
+
function getHoldState(synthKey, meshId) {
|
|
18634
|
+
const cached3 = inFlightAckedHoldState.get(synthKey);
|
|
18635
|
+
if (cached3) return cached3;
|
|
18636
|
+
const store = holdStore();
|
|
18637
|
+
if (!store) return void 0;
|
|
18638
|
+
let row;
|
|
18639
|
+
try {
|
|
18640
|
+
row = store.getInflightHold(taskIdFromSynthKey(meshId, synthKey));
|
|
18641
|
+
} catch {
|
|
18642
|
+
return void 0;
|
|
18643
|
+
}
|
|
18644
|
+
if (!row) return void 0;
|
|
18645
|
+
const state = {
|
|
18646
|
+
liveConfirmedSinceAck: row.holdReason === "live",
|
|
18647
|
+
consecutiveReadFailures: row.readFailureCount ?? 0,
|
|
18648
|
+
...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {}
|
|
18649
|
+
};
|
|
18650
|
+
inFlightAckedHoldState.set(synthKey, state);
|
|
18651
|
+
return state;
|
|
18652
|
+
}
|
|
18653
|
+
function setHoldState(synthKey, meshId, state) {
|
|
18654
|
+
inFlightAckedHoldState.set(synthKey, state);
|
|
18655
|
+
const store = holdStore();
|
|
18656
|
+
if (!store) return;
|
|
18657
|
+
try {
|
|
18658
|
+
store.upsertInflightHold({
|
|
18659
|
+
taskId: taskIdFromSynthKey(meshId, synthKey),
|
|
18660
|
+
meshId,
|
|
18661
|
+
holdReason: state.liveConfirmedSinceAck ? "live" : "unconfirmed",
|
|
18662
|
+
firstIdleSinceAck: state.transcriptIdleSinceMs ?? null,
|
|
18663
|
+
readFailureCount: state.consecutiveReadFailures
|
|
18664
|
+
});
|
|
18665
|
+
} catch {
|
|
18666
|
+
}
|
|
18667
|
+
}
|
|
18668
|
+
function deleteHoldState(synthKey, meshId) {
|
|
18669
|
+
inFlightAckedHoldState.delete(synthKey);
|
|
18670
|
+
const store = holdStore();
|
|
18671
|
+
if (!store) return;
|
|
18672
|
+
try {
|
|
18673
|
+
store.deleteInflightHold(taskIdFromSynthKey(meshId, synthKey));
|
|
18674
|
+
} catch {
|
|
18675
|
+
}
|
|
18676
|
+
}
|
|
18677
|
+
function rehydrateAckedHoldsForMesh(meshId) {
|
|
18678
|
+
if (rehydratedHoldMeshes.has(meshId)) return;
|
|
18679
|
+
rehydratedHoldMeshes.add(meshId);
|
|
18680
|
+
const store = holdStore();
|
|
18681
|
+
if (!store) return;
|
|
18682
|
+
let rows;
|
|
18683
|
+
try {
|
|
18684
|
+
rows = store.listInflightHoldsByMesh(meshId);
|
|
18685
|
+
} catch {
|
|
18686
|
+
return;
|
|
18687
|
+
}
|
|
18688
|
+
for (const row of rows) {
|
|
18689
|
+
const synthKey = inFlightSynthKey(meshId, row.taskId);
|
|
18690
|
+
if (inFlightAckedHoldState.has(synthKey)) continue;
|
|
18691
|
+
inFlightAckedHoldState.set(synthKey, {
|
|
18692
|
+
liveConfirmedSinceAck: row.holdReason === "live",
|
|
18693
|
+
consecutiveReadFailures: row.readFailureCount ?? 0,
|
|
18694
|
+
...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {}
|
|
18695
|
+
});
|
|
18696
|
+
}
|
|
18697
|
+
if (rows.length > 0) {
|
|
18698
|
+
LOG.info("MeshReconcile", `Rehydrated ${rows.length} persisted acked-hold row(s) for mesh ${meshId} after (re)start`);
|
|
18699
|
+
}
|
|
18700
|
+
}
|
|
18701
|
+
function collectHeldSynthKeysForMesh(meshId) {
|
|
18702
|
+
const heldKeys = /* @__PURE__ */ new Set();
|
|
18703
|
+
for (const key2 of inFlightAckedHoldState.keys()) {
|
|
18704
|
+
if (key2.startsWith(`${meshId}::`)) heldKeys.add(key2);
|
|
18705
|
+
}
|
|
18706
|
+
const store = holdStore();
|
|
18707
|
+
if (store) {
|
|
18708
|
+
try {
|
|
18709
|
+
for (const row of store.listInflightHoldsByMesh(meshId)) {
|
|
18710
|
+
heldKeys.add(inFlightSynthKey(meshId, row.taskId));
|
|
18711
|
+
}
|
|
18712
|
+
} catch {
|
|
18713
|
+
}
|
|
18714
|
+
}
|
|
18715
|
+
return heldKeys;
|
|
18716
|
+
}
|
|
18717
|
+
var ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, rehydratedHoldMeshes;
|
|
18718
|
+
var init_mesh_reconcile_acked_hold = __esm({
|
|
18719
|
+
"src/mesh/mesh-reconcile-acked-hold.ts"() {
|
|
18720
|
+
"use strict";
|
|
18721
|
+
init_logger();
|
|
18722
|
+
init_mesh_runtime_store();
|
|
18723
|
+
init_mesh_events_utils();
|
|
18724
|
+
ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
|
|
18725
|
+
inFlightAckedHoldState = /* @__PURE__ */ new Map();
|
|
18726
|
+
rehydratedHoldMeshes = /* @__PURE__ */ new Set();
|
|
18727
|
+
}
|
|
18728
|
+
});
|
|
18729
|
+
|
|
18730
|
+
// src/mesh/mesh-reconcile-config.ts
|
|
18731
|
+
function resolveAutoPruneMinAgeMs() {
|
|
18732
|
+
const raw = readNonEmptyString2(process.env.MESH_AUTO_PRUNE_MIN_AGE_MS);
|
|
18733
|
+
if (raw) {
|
|
18734
|
+
const parsed = Number.parseInt(raw, 10);
|
|
18735
|
+
if (Number.isFinite(parsed) && parsed >= 60 * 6e4 && parsed <= 30 * 24 * 60 * 6e4) return parsed;
|
|
18736
|
+
}
|
|
18737
|
+
return DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
18738
|
+
}
|
|
18739
|
+
function resolvePendingHeldDrainEscalateMs() {
|
|
18740
|
+
return resolveTunedReconcileMs("MESH_PENDING_HELD_DRAIN_ESCALATE_MS", DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, 4e3, 5 * 6e4);
|
|
18741
|
+
}
|
|
18742
|
+
function resolveReconcileIntervalMs() {
|
|
18743
|
+
const raw = readNonEmptyString2(process.env.MESH_RECONCILE_INTERVAL_MS);
|
|
18744
|
+
if (raw) {
|
|
18745
|
+
const parsed = Number.parseInt(raw, 10);
|
|
18746
|
+
if (Number.isFinite(parsed) && parsed >= 1e3 && parsed <= 6e4) return parsed;
|
|
18747
|
+
}
|
|
18748
|
+
return DEFAULT_RECONCILE_INTERVAL_MS;
|
|
18749
|
+
}
|
|
18750
|
+
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS;
|
|
18751
|
+
var init_mesh_reconcile_config = __esm({
|
|
18752
|
+
"src/mesh/mesh-reconcile-config.ts"() {
|
|
18753
|
+
"use strict";
|
|
18754
|
+
init_mesh_events_utils();
|
|
18755
|
+
init_mesh_reconcile_acked_hold();
|
|
18756
|
+
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
18757
|
+
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
18758
|
+
DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS = 12e3;
|
|
18759
|
+
}
|
|
18760
|
+
});
|
|
18761
|
+
|
|
18762
|
+
// src/mesh/mesh-remote-event-pull.ts
|
|
18763
|
+
async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDaemonIds) {
|
|
18764
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
18765
|
+
if (!dispatchMeshCommand) return;
|
|
18766
|
+
const meshId = mesh.id;
|
|
18767
|
+
const pulls = candidateDaemonIds.length > 0 ? candidateDaemonIds.map((id) => ({ meshId, coordinatorDaemonId: id })) : [{ meshId }];
|
|
18768
|
+
await Promise.allSettled(mesh.nodes.map(async (node) => {
|
|
18769
|
+
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
18770
|
+
if (!nodeDaemonId) return;
|
|
18771
|
+
if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) return;
|
|
18772
|
+
if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) return;
|
|
18773
|
+
const peerSnapshot = components.getMeshPeerConnectionStatus?.(nodeDaemonId);
|
|
18774
|
+
if (peerSnapshot && String(peerSnapshot.state) !== "connected") return;
|
|
18775
|
+
for (const pendingEventArgs of pulls) {
|
|
18776
|
+
let events;
|
|
18777
|
+
try {
|
|
18778
|
+
events = await dispatchMeshCommand(nodeDaemonId, "get_pending_mesh_events", pendingEventArgs);
|
|
18779
|
+
} catch {
|
|
18780
|
+
break;
|
|
18781
|
+
}
|
|
18782
|
+
const list = extractPendingEvents(events).filter((e) => readNonEmptyString2(e?.meshId) === meshId);
|
|
18783
|
+
for (const event of list) {
|
|
18784
|
+
const payload = buildForwardPayloadFromPending(event);
|
|
18785
|
+
if (!payload.event || !payload.meshId) continue;
|
|
18786
|
+
try {
|
|
18787
|
+
handleMeshForwardEvent(components, payload);
|
|
18788
|
+
} catch {
|
|
18789
|
+
}
|
|
18790
|
+
}
|
|
18791
|
+
}
|
|
18792
|
+
}));
|
|
18793
|
+
}
|
|
18794
|
+
function unwrapReadChatPayload(raw) {
|
|
18795
|
+
let cursor = raw;
|
|
18796
|
+
for (let depth = 0; depth < 4 && cursor && typeof cursor === "object"; depth++) {
|
|
18797
|
+
const record = cursor;
|
|
18798
|
+
if (Array.isArray(record.messages)) return record;
|
|
18799
|
+
if (record.payload && typeof record.payload === "object") {
|
|
18800
|
+
cursor = record.payload;
|
|
18801
|
+
continue;
|
|
18802
|
+
}
|
|
18803
|
+
if (record.result && typeof record.result === "object") {
|
|
18804
|
+
cursor = record.result;
|
|
18805
|
+
continue;
|
|
18806
|
+
}
|
|
18807
|
+
if (record.data && typeof record.data === "object") {
|
|
18808
|
+
cursor = record.data;
|
|
18809
|
+
continue;
|
|
18810
|
+
}
|
|
18811
|
+
break;
|
|
18812
|
+
}
|
|
18813
|
+
return cursor && typeof cursor === "object" ? cursor : null;
|
|
18814
|
+
}
|
|
18815
|
+
function readChatPayloadStatus(payload) {
|
|
18816
|
+
return readNonEmptyString2(payload?.status).toLowerCase();
|
|
18817
|
+
}
|
|
18818
|
+
function realTerminalEmitPendingForTask(meshId, taskId) {
|
|
18819
|
+
let pending;
|
|
18820
|
+
try {
|
|
18821
|
+
pending = getPendingMeshCoordinatorEvents(meshId);
|
|
18822
|
+
} catch {
|
|
18823
|
+
return false;
|
|
18824
|
+
}
|
|
18825
|
+
return pending.some((e) => readNonEmptyString2(e.metadataEvent?.taskId) === taskId && (e.event === "agent:generating_completed" || e.event === "agent:stopped"));
|
|
18826
|
+
}
|
|
18827
|
+
async function reprobeWorkerStatus(components, args) {
|
|
18828
|
+
try {
|
|
18829
|
+
if (args.isLocalNode) {
|
|
18830
|
+
const r = await components.commandHandler.handle("read_chat", args.readArgs);
|
|
18831
|
+
if (r && r.success === false) return null;
|
|
18832
|
+
return readChatPayloadStatus(unwrapReadChatPayload(r));
|
|
18833
|
+
}
|
|
18834
|
+
if (components.dispatchMeshCommand) {
|
|
18835
|
+
const r = await components.dispatchMeshCommand(args.nodeDaemonId, "read_chat", args.readArgs);
|
|
18836
|
+
const p = unwrapReadChatPayload(r);
|
|
18837
|
+
if (p && p.success === false) return null;
|
|
18838
|
+
return readChatPayloadStatus(p);
|
|
18839
|
+
}
|
|
18840
|
+
} catch {
|
|
18841
|
+
return null;
|
|
18842
|
+
}
|
|
18843
|
+
return null;
|
|
18844
|
+
}
|
|
18845
|
+
async function collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId) {
|
|
18846
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
18847
|
+
return Promise.all(mesh.nodes.map(async (node) => {
|
|
18848
|
+
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
18849
|
+
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId);
|
|
18850
|
+
if (!isLocalNode) {
|
|
18851
|
+
const peerSnapshot = components.getMeshPeerConnectionStatus?.(nodeDaemonId);
|
|
18852
|
+
if (peerSnapshot && String(peerSnapshot.state) !== "connected") return node;
|
|
18853
|
+
}
|
|
18854
|
+
let statusResult;
|
|
18855
|
+
try {
|
|
18856
|
+
if (isLocalNode) {
|
|
18857
|
+
statusResult = await components.commandHandler.handle("get_status_metadata", {});
|
|
18858
|
+
} else if (dispatchMeshCommand) {
|
|
18859
|
+
statusResult = await dispatchMeshCommand(nodeDaemonId, "get_status_metadata", {});
|
|
18860
|
+
} else {
|
|
18861
|
+
return node;
|
|
18862
|
+
}
|
|
18863
|
+
} catch {
|
|
18864
|
+
return node;
|
|
18865
|
+
}
|
|
18866
|
+
const sessions = extractStatusMetadataSessions(statusResult);
|
|
18867
|
+
return sessions.length > 0 ? { ...node, sessions } : node;
|
|
18868
|
+
}));
|
|
18869
|
+
}
|
|
18870
|
+
function extractStatusMetadataSessions(raw) {
|
|
18871
|
+
let cursor = raw;
|
|
18872
|
+
for (let depth = 0; depth < 4 && cursor && typeof cursor === "object"; depth++) {
|
|
18873
|
+
const record = cursor;
|
|
18874
|
+
const status = record.status && typeof record.status === "object" ? record.status : void 0;
|
|
18875
|
+
if (status && Array.isArray(status.sessions)) return status.sessions;
|
|
18876
|
+
if (Array.isArray(record.sessions)) return record.sessions;
|
|
18877
|
+
if (record.payload && typeof record.payload === "object") {
|
|
18878
|
+
cursor = record.payload;
|
|
18879
|
+
continue;
|
|
18880
|
+
}
|
|
18881
|
+
if (record.result && typeof record.result === "object") {
|
|
18882
|
+
cursor = record.result;
|
|
18883
|
+
continue;
|
|
18884
|
+
}
|
|
18885
|
+
if (record.data && typeof record.data === "object") {
|
|
18886
|
+
cursor = record.data;
|
|
18887
|
+
continue;
|
|
18888
|
+
}
|
|
18889
|
+
break;
|
|
18890
|
+
}
|
|
18891
|
+
return [];
|
|
18892
|
+
}
|
|
18893
|
+
function extractPendingEvents(raw) {
|
|
18894
|
+
if (Array.isArray(raw)) return raw;
|
|
18895
|
+
if (raw && typeof raw === "object") {
|
|
18896
|
+
const events = raw.events;
|
|
18897
|
+
if (Array.isArray(events)) return events;
|
|
18898
|
+
}
|
|
18899
|
+
return [];
|
|
18900
|
+
}
|
|
18901
|
+
function buildForwardPayloadFromPending(event) {
|
|
18902
|
+
const metadata = event?.metadataEvent && typeof event.metadataEvent === "object" ? event.metadataEvent : {};
|
|
18903
|
+
return {
|
|
18904
|
+
event: readNonEmptyString2(event?.event),
|
|
18905
|
+
meshId: readNonEmptyString2(event?.meshId),
|
|
18906
|
+
nodeId: readNonEmptyString2(event?.nodeId) || readNonEmptyString2(metadata.meshNodeId),
|
|
18907
|
+
workspace: readNonEmptyString2(event?.workspace) || readNonEmptyString2(metadata.workspace),
|
|
18908
|
+
// Preserve the originating coordinator session id across the relay. It is normally
|
|
18909
|
+
// carried inside metadataEvent.meshCoordinatorSessionId (spread below), but pass the
|
|
18910
|
+
// top-level field through explicitly too so the handleMeshForwardEvent whitelist
|
|
18911
|
+
// recovers it regardless of which carrier the producing daemon used.
|
|
18912
|
+
...readNonEmptyString2(event?.targetCoordinatorSessionId) ? { targetCoordinatorSessionId: readNonEmptyString2(event.targetCoordinatorSessionId) } : {},
|
|
18913
|
+
...metadata,
|
|
18914
|
+
// NOTIF-MISS (FIX 3): surface the dispatch task id at the TOP LEVEL so the relay's
|
|
18915
|
+
// received-stage trace (and buildRelayMetadataEvent) recovers it regardless of which
|
|
18916
|
+
// carrier the producing daemon used. The metadata spread above may carry the id only as
|
|
18917
|
+
// `meshActiveTaskId` (a worker provider event), leaving top-level `taskId` unset and the
|
|
18918
|
+
// received stage rendering `task=-`. Resolve both carriers into an explicit `taskId` so
|
|
18919
|
+
// dedup stays task-scoped end-to-end. Only set when a non-empty id exists (no clobber to
|
|
18920
|
+
// undefined when neither is present).
|
|
18921
|
+
...(() => {
|
|
18922
|
+
const tid = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(metadata.meshActiveTaskId);
|
|
18923
|
+
return tid ? { taskId: tid } : {};
|
|
18924
|
+
})(),
|
|
18925
|
+
// T4 (B3b): carry the v2 envelope (protocolVersion/eventId/scope/dispatchedBy/
|
|
18926
|
+
// intendedFor) across the P2P relay boundary at the TOP LEVEL. These live on the
|
|
18927
|
+
// pending event itself, not inside metadataEvent, so without this the remote pull
|
|
18928
|
+
// re-queue would re-stamp a fresh eventId — breaking cross-machine idempotency and
|
|
18929
|
+
// downgrading the relayed completion to v1 broadcast routing. Spread LAST so the
|
|
18930
|
+
// authoritative envelope always wins over any stale key the metadata spread carried.
|
|
18931
|
+
...serializeV2EnvelopeToWire(event)
|
|
18932
|
+
};
|
|
18933
|
+
}
|
|
18934
|
+
var init_mesh_remote_event_pull = __esm({
|
|
18935
|
+
"src/mesh/mesh-remote-event-pull.ts"() {
|
|
18936
|
+
"use strict";
|
|
18937
|
+
init_mesh_events_pending();
|
|
18938
|
+
init_mesh_events_coordinator();
|
|
18939
|
+
init_mesh_events_utils();
|
|
18940
|
+
init_dist();
|
|
18941
|
+
init_mesh_reconcile_identity();
|
|
18942
|
+
}
|
|
18943
|
+
});
|
|
18944
|
+
|
|
18451
18945
|
// src/mesh/mesh-reconcile-v2-backstop.ts
|
|
18452
18946
|
function getMeshV2BackstopCounters() {
|
|
18453
18947
|
return { ...meshV2BackstopCounters };
|
|
@@ -18480,152 +18974,205 @@ var init_mesh_reconcile_v2_backstop = __esm({
|
|
|
18480
18974
|
}
|
|
18481
18975
|
});
|
|
18482
18976
|
|
|
18483
|
-
// src/mesh/mesh-
|
|
18484
|
-
function
|
|
18485
|
-
const
|
|
18486
|
-
|
|
18487
|
-
|
|
18488
|
-
|
|
18489
|
-
|
|
18490
|
-
|
|
18491
|
-
|
|
18492
|
-
|
|
18493
|
-
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
|
|
18494
|
-
}
|
|
18495
|
-
function resolveAckedTranscriptFastTrackGraceMs() {
|
|
18496
|
-
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
|
|
18497
|
-
}
|
|
18498
|
-
function inFlightSynthKey(meshId, taskId) {
|
|
18499
|
-
return `${meshId}::${taskId}`;
|
|
18500
|
-
}
|
|
18501
|
-
function taskIdFromSynthKey(meshId, synthKey) {
|
|
18502
|
-
const prefix = `${meshId}::`;
|
|
18503
|
-
return synthKey.startsWith(prefix) ? synthKey.slice(prefix.length) : synthKey;
|
|
18504
|
-
}
|
|
18505
|
-
function holdStore() {
|
|
18506
|
-
try {
|
|
18507
|
-
return MeshRuntimeStore.getInstance();
|
|
18508
|
-
} catch {
|
|
18509
|
-
return void 0;
|
|
18510
|
-
}
|
|
18511
|
-
}
|
|
18512
|
-
function getHoldState(synthKey, meshId) {
|
|
18513
|
-
const cached3 = inFlightAckedHoldState.get(synthKey);
|
|
18514
|
-
if (cached3) return cached3;
|
|
18515
|
-
const store = holdStore();
|
|
18516
|
-
if (!store) return void 0;
|
|
18517
|
-
let row;
|
|
18518
|
-
try {
|
|
18519
|
-
row = store.getInflightHold(taskIdFromSynthKey(meshId, synthKey));
|
|
18520
|
-
} catch {
|
|
18521
|
-
return void 0;
|
|
18522
|
-
}
|
|
18523
|
-
if (!row) return void 0;
|
|
18524
|
-
const state = {
|
|
18525
|
-
liveConfirmedSinceAck: row.holdReason === "live",
|
|
18526
|
-
consecutiveReadFailures: row.readFailureCount ?? 0,
|
|
18527
|
-
...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {}
|
|
18528
|
-
};
|
|
18529
|
-
inFlightAckedHoldState.set(synthKey, state);
|
|
18530
|
-
return state;
|
|
18531
|
-
}
|
|
18532
|
-
function setHoldState(synthKey, meshId, state) {
|
|
18533
|
-
inFlightAckedHoldState.set(synthKey, state);
|
|
18534
|
-
const store = holdStore();
|
|
18535
|
-
if (!store) return;
|
|
18536
|
-
try {
|
|
18537
|
-
store.upsertInflightHold({
|
|
18538
|
-
taskId: taskIdFromSynthKey(meshId, synthKey),
|
|
18539
|
-
meshId,
|
|
18540
|
-
holdReason: state.liveConfirmedSinceAck ? "live" : "unconfirmed",
|
|
18541
|
-
firstIdleSinceAck: state.transcriptIdleSinceMs ?? null,
|
|
18542
|
-
readFailureCount: state.consecutiveReadFailures
|
|
18543
|
-
});
|
|
18544
|
-
} catch {
|
|
18545
|
-
}
|
|
18546
|
-
}
|
|
18547
|
-
function deleteHoldState(synthKey, meshId) {
|
|
18548
|
-
inFlightAckedHoldState.delete(synthKey);
|
|
18549
|
-
const store = holdStore();
|
|
18550
|
-
if (!store) return;
|
|
18551
|
-
try {
|
|
18552
|
-
store.deleteInflightHold(taskIdFromSynthKey(meshId, synthKey));
|
|
18553
|
-
} catch {
|
|
18554
|
-
}
|
|
18555
|
-
}
|
|
18556
|
-
function rehydrateAckedHoldsForMesh(meshId) {
|
|
18557
|
-
if (rehydratedHoldMeshes.has(meshId)) return;
|
|
18558
|
-
rehydratedHoldMeshes.add(meshId);
|
|
18559
|
-
const store = holdStore();
|
|
18560
|
-
if (!store) return;
|
|
18561
|
-
let rows;
|
|
18562
|
-
try {
|
|
18563
|
-
rows = store.listInflightHoldsByMesh(meshId);
|
|
18564
|
-
} catch {
|
|
18565
|
-
return;
|
|
18566
|
-
}
|
|
18567
|
-
for (const row of rows) {
|
|
18568
|
-
const synthKey = inFlightSynthKey(meshId, row.taskId);
|
|
18569
|
-
if (inFlightAckedHoldState.has(synthKey)) continue;
|
|
18570
|
-
inFlightAckedHoldState.set(synthKey, {
|
|
18571
|
-
liveConfirmedSinceAck: row.holdReason === "live",
|
|
18572
|
-
consecutiveReadFailures: row.readFailureCount ?? 0,
|
|
18573
|
-
...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {}
|
|
18574
|
-
});
|
|
18575
|
-
}
|
|
18576
|
-
if (rows.length > 0) {
|
|
18577
|
-
LOG.info("MeshReconcile", `Rehydrated ${rows.length} persisted acked-hold row(s) for mesh ${meshId} after (re)start`);
|
|
18578
|
-
}
|
|
18579
|
-
}
|
|
18580
|
-
function collectHeldSynthKeysForMesh(meshId) {
|
|
18581
|
-
const heldKeys = /* @__PURE__ */ new Set();
|
|
18582
|
-
for (const key2 of inFlightAckedHoldState.keys()) {
|
|
18583
|
-
if (key2.startsWith(`${meshId}::`)) heldKeys.add(key2);
|
|
18977
|
+
// src/mesh/mesh-completion-synthesis.ts
|
|
18978
|
+
async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds, localDaemonId) {
|
|
18979
|
+
const dispatches = getActiveDirectDispatches(mesh.id);
|
|
18980
|
+
rehydrateAckedHoldsForMesh(mesh.id);
|
|
18981
|
+
const activeTaskKeys = new Set(
|
|
18982
|
+
dispatches.map((d) => readNonEmptyString2(d.taskId)).filter(Boolean).map((taskId) => inFlightSynthKey(mesh.id, taskId))
|
|
18983
|
+
);
|
|
18984
|
+
const heldKeys = collectHeldSynthKeysForMesh(mesh.id);
|
|
18985
|
+
for (const key2 of heldKeys) {
|
|
18986
|
+
if (!activeTaskKeys.has(key2)) deleteHoldState(key2, mesh.id);
|
|
18584
18987
|
}
|
|
18585
|
-
|
|
18586
|
-
|
|
18988
|
+
if (dispatches.length === 0) return;
|
|
18989
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
18990
|
+
const nodeById = new Map(mesh.nodes.map((n) => [n.id, n]));
|
|
18991
|
+
for (const dispatch of dispatches) {
|
|
18992
|
+
const sessionId = readNonEmptyString2(dispatch.sessionId);
|
|
18993
|
+
const nodeId = readNonEmptyString2(dispatch.nodeId);
|
|
18994
|
+
const taskId = readNonEmptyString2(dispatch.taskId);
|
|
18995
|
+
if (!sessionId || !nodeId || !taskId) continue;
|
|
18996
|
+
const node = nodeById.get(nodeId);
|
|
18997
|
+
const nodeDaemonId = readNonEmptyString2(node?.daemonId);
|
|
18998
|
+
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId) || !!components.instanceManager.getInstance(sessionId);
|
|
18999
|
+
const providerType = readNonEmptyString2(dispatch.providerType);
|
|
19000
|
+
const readArgs = {
|
|
19001
|
+
sessionId,
|
|
19002
|
+
targetSessionId: sessionId,
|
|
19003
|
+
tailLimit: 10,
|
|
19004
|
+
...node?.workspace ? { workspace: node.workspace } : {},
|
|
19005
|
+
...providerType ? { agentType: providerType, providerType } : {}
|
|
19006
|
+
};
|
|
19007
|
+
const synthKey = inFlightSynthKey(mesh.id, taskId);
|
|
19008
|
+
const isAcked = dispatch.status === "acked";
|
|
19009
|
+
let backstopKind;
|
|
19010
|
+
let payload = null;
|
|
19011
|
+
let readFailed = false;
|
|
18587
19012
|
try {
|
|
18588
|
-
|
|
18589
|
-
|
|
19013
|
+
if (isLocalNode) {
|
|
19014
|
+
const result = await components.commandHandler.handle("read_chat", readArgs);
|
|
19015
|
+
if (result && result.success === false) {
|
|
19016
|
+
readFailed = true;
|
|
19017
|
+
} else {
|
|
19018
|
+
payload = unwrapReadChatPayload(result);
|
|
19019
|
+
}
|
|
19020
|
+
} else if (dispatchMeshCommand) {
|
|
19021
|
+
const result = await dispatchMeshCommand(nodeDaemonId, "read_chat", readArgs);
|
|
19022
|
+
payload = unwrapReadChatPayload(result);
|
|
19023
|
+
if (payload && payload.success === false) {
|
|
19024
|
+
payload = null;
|
|
19025
|
+
readFailed = true;
|
|
19026
|
+
}
|
|
19027
|
+
} else {
|
|
19028
|
+
continue;
|
|
18590
19029
|
}
|
|
18591
19030
|
} catch {
|
|
19031
|
+
readFailed = true;
|
|
19032
|
+
}
|
|
19033
|
+
if (!payload && !readFailed) continue;
|
|
19034
|
+
if (readFailed || !payload) {
|
|
19035
|
+
if (isAcked) {
|
|
19036
|
+
const prior = getHoldState(synthKey, mesh.id);
|
|
19037
|
+
const failures = (prior?.consecutiveReadFailures ?? 0) + 1;
|
|
19038
|
+
const liveConfirmedSinceAck = prior?.liveConfirmedSinceAck ?? false;
|
|
19039
|
+
setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck, consecutiveReadFailures: failures });
|
|
19040
|
+
if (liveConfirmedSinceAck && failures >= ACKED_DEATH_CONSECUTIVE_READ_FAILURES) {
|
|
19041
|
+
LOG.warn("MeshReconcile", `Acked-hold death signal: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read_chat failed ${failures}x consecutively after a live-confirmed ack \u2014 worker session presumed gone mid-turn; releasing the indefinite synth hold to the stranded-reclaim / orphan-prune nets`);
|
|
19042
|
+
}
|
|
19043
|
+
}
|
|
19044
|
+
continue;
|
|
19045
|
+
}
|
|
19046
|
+
const priorHoldState = getHoldState(synthKey, mesh.id);
|
|
19047
|
+
setHoldState(synthKey, mesh.id, {
|
|
19048
|
+
liveConfirmedSinceAck: true,
|
|
19049
|
+
consecutiveReadFailures: 0,
|
|
19050
|
+
...priorHoldState?.transcriptIdleSinceMs !== void 0 ? { transcriptIdleSinceMs: priorHoldState.transcriptIdleSinceMs } : {}
|
|
19051
|
+
});
|
|
19052
|
+
const nowMs = Date.now();
|
|
19053
|
+
if (readChatPayloadStatus(payload) !== "idle") {
|
|
19054
|
+
setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
|
|
19055
|
+
continue;
|
|
19056
|
+
}
|
|
19057
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
19058
|
+
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
19059
|
+
if (isAcked) {
|
|
19060
|
+
const ackedAtMs = Date.parse(readNonEmptyString2(dispatch.updatedAt));
|
|
19061
|
+
const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
|
|
19062
|
+
const deathDeadlineMs = resolveAckedDeathDeadlineMs();
|
|
19063
|
+
const holdState = getHoldState(synthKey, mesh.id);
|
|
19064
|
+
let fastTrackReady = false;
|
|
19065
|
+
if (evidence.finalSummary) {
|
|
19066
|
+
const idleSinceMs = holdState?.transcriptIdleSinceMs ?? nowMs;
|
|
19067
|
+
if (holdState && holdState.transcriptIdleSinceMs === void 0) {
|
|
19068
|
+
setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: idleSinceMs });
|
|
19069
|
+
}
|
|
19070
|
+
const fastTrackGraceMs = resolveAckedTranscriptFastTrackGraceMs();
|
|
19071
|
+
const idleHeldMs = nowMs - idleSinceMs;
|
|
19072
|
+
if (idleHeldMs >= fastTrackGraceMs) {
|
|
19073
|
+
fastTrackReady = true;
|
|
19074
|
+
backstopKind = "ackedHoldFastTrackFired";
|
|
19075
|
+
LOG.info("MeshReconcile", `Acked-hold transcript fast-track: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle WITH a final assistant message for ${Math.round(idleHeldMs / 1e3)}s continuous (grace ${Math.round(fastTrackGraceMs / 1e3)}s) \u2014 promoting the synth ahead of the ${Math.round(deathDeadlineMs / 1e3)}s death backstop; the worker's real emit was lost/late and a later one no-ops idempotently.`);
|
|
19076
|
+
}
|
|
19077
|
+
} else if (holdState?.transcriptIdleSinceMs !== void 0) {
|
|
19078
|
+
setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: void 0 });
|
|
19079
|
+
}
|
|
19080
|
+
if (!fastTrackReady && sinceAckMs < deathDeadlineMs) {
|
|
19081
|
+
LOG.info("MeshReconcile", `Acked-hold: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle ${Number.isFinite(sinceAckMs) ? Math.round(sinceAckMs / 1e3) + "s" : "\u221E"} since the generating_started ack \u2014 HOLDING synth (worker presumed alive; a later real emit is idempotent). Transcript fast-track promotes at ${Math.round(resolveAckedTranscriptFastTrackGraceMs() / 1e3)}s continuous idle-with-final-assistant; death backstop at ${Math.round(deathDeadlineMs / 1e3)}s or on consecutive read failures.`);
|
|
19082
|
+
continue;
|
|
19083
|
+
}
|
|
19084
|
+
if (!fastTrackReady) {
|
|
19085
|
+
backstopKind = "ackedHoldDeathDeadlineFired";
|
|
19086
|
+
LOG.warn("MeshReconcile", `Acked-hold death deadline reached: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) still idle ${Math.round(sinceAckMs / 1e3)}s after the ack (deadline ${Math.round(deathDeadlineMs / 1e3)}s) \u2014 synthesizing the missing completion as a notification-loss net (a real emit, if it ever lands, no-ops idempotently).`);
|
|
19087
|
+
}
|
|
19088
|
+
}
|
|
19089
|
+
if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
|
|
19090
|
+
deleteHoldState(synthKey, mesh.id);
|
|
19091
|
+
LOG.info("MeshReconcile", `Worker-emit priority: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) has a real terminal completion already queued \u2014 yielding synth to the worker's own emit`);
|
|
19092
|
+
continue;
|
|
19093
|
+
}
|
|
19094
|
+
if (!evidence.finalSummary) continue;
|
|
19095
|
+
const dispatchedAtMs = Date.parse(readNonEmptyString2(dispatch.dispatchedAt));
|
|
19096
|
+
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
|
|
19097
|
+
if (Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs < dispatchedAtMs) {
|
|
19098
|
+
LOG.info("MeshReconcile", `Stale-summary guard: skipping transcript reconcile for task ${taskId} on node ${nodeId} (mesh ${mesh.id}) \u2014 final assistant message (${evidence.transcriptMessageAt}) predates this task's dispatch (${dispatch.dispatchedAt}); it is a prior task's summary`);
|
|
19099
|
+
traceMeshEventDrop("reconcile_stale_summary_before_dispatch", {
|
|
19100
|
+
taskId,
|
|
19101
|
+
sessionId,
|
|
19102
|
+
nodeId,
|
|
19103
|
+
meshId: mesh.id,
|
|
19104
|
+
event: "agent:generating_completed"
|
|
19105
|
+
}, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
|
|
19106
|
+
continue;
|
|
19107
|
+
}
|
|
19108
|
+
const reprobeStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
|
|
19109
|
+
if (reprobeStatus && reprobeStatus !== "idle") {
|
|
19110
|
+
deleteHoldState(synthKey, mesh.id);
|
|
19111
|
+
LOG.info("MeshReconcile", `Live re-probe defer: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read '${reprobeStatus}' at synth-commit time \u2014 worker resumed generating; deferring synth to a later tick`);
|
|
19112
|
+
continue;
|
|
19113
|
+
}
|
|
19114
|
+
const providerSessionId = readNonEmptyString2(payload.providerSessionId);
|
|
19115
|
+
const coordinatorDaemonId = selfIds.find((id) => !!id);
|
|
19116
|
+
try {
|
|
19117
|
+
const result = reconcileDirectDispatchCompletionFromTranscript({
|
|
19118
|
+
meshId: mesh.id,
|
|
19119
|
+
nodeId,
|
|
19120
|
+
sessionId,
|
|
19121
|
+
providerType: providerType || void 0,
|
|
19122
|
+
providerSessionId: providerSessionId || void 0,
|
|
19123
|
+
taskId,
|
|
19124
|
+
finalSummary: evidence.finalSummary,
|
|
19125
|
+
...evidence.transcriptMessageAt ? { transcriptMessageAt: evidence.transcriptMessageAt } : {},
|
|
19126
|
+
...coordinatorDaemonId ? { targetCoordinatorDaemonId: coordinatorDaemonId } : {},
|
|
19127
|
+
source: "daemon_reconcile_transcript_completion"
|
|
19128
|
+
});
|
|
19129
|
+
if (result.reconciled) {
|
|
19130
|
+
recordBackstopFire(backstopKind ?? "phase4SynthesisFired", `task ${taskId} on node ${nodeId} (mesh ${mesh.id}), kind=${result.kind}`);
|
|
19131
|
+
LOG.info("MeshReconcile", `Synthesized missing completion (${result.kind}) for task ${taskId} on node ${nodeId} (mesh ${mesh.id})`);
|
|
19132
|
+
}
|
|
19133
|
+
} catch (e) {
|
|
19134
|
+
LOG.warn("MeshReconcile", `Transcript completion reconcile threw for task ${taskId}: ${e?.message || e}`);
|
|
18592
19135
|
}
|
|
18593
19136
|
}
|
|
18594
|
-
return heldKeys;
|
|
18595
19137
|
}
|
|
18596
|
-
|
|
18597
|
-
|
|
18598
|
-
|
|
19138
|
+
async function autoPruneStaleDirectDispatches(components, mesh, selfIds, localDaemonId, minAgeMs) {
|
|
19139
|
+
const directDispatches = getActiveDirectDispatches(mesh.id);
|
|
19140
|
+
if (directDispatches.length === 0) return;
|
|
19141
|
+
const liveNodes = await collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId);
|
|
19142
|
+
const result = pruneStaleDirectDispatches({
|
|
19143
|
+
meshId: mesh.id,
|
|
19144
|
+
queue: getQueue(mesh.id),
|
|
19145
|
+
ledgerEntries: readLedgerEntries(mesh.id, { tail: 500 }),
|
|
19146
|
+
directDispatches,
|
|
19147
|
+
nodes: liveNodes,
|
|
19148
|
+
execute: true,
|
|
19149
|
+
minAgeMs,
|
|
19150
|
+
source: "daemon_reconcile_auto_prune"
|
|
19151
|
+
});
|
|
19152
|
+
if (result.prunedCount > 0) {
|
|
19153
|
+
LOG.info("MeshReconcile", `Auto-pruned ${result.prunedCount} orphaned direct dispatch record(s) for mesh ${mesh.id}`);
|
|
19154
|
+
}
|
|
19155
|
+
}
|
|
19156
|
+
var init_mesh_completion_synthesis = __esm({
|
|
19157
|
+
"src/mesh/mesh-completion-synthesis.ts"() {
|
|
18599
19158
|
"use strict";
|
|
18600
19159
|
init_logger();
|
|
18601
|
-
init_mesh_runtime_store();
|
|
18602
19160
|
init_mesh_events_utils();
|
|
18603
|
-
|
|
18604
|
-
|
|
18605
|
-
|
|
19161
|
+
init_mesh_event_trace();
|
|
19162
|
+
init_dist();
|
|
19163
|
+
init_mesh_reconcile_identity();
|
|
19164
|
+
init_mesh_work_queue();
|
|
19165
|
+
init_mesh_ledger();
|
|
19166
|
+
init_mesh_active_work();
|
|
19167
|
+
init_mesh_events_stale();
|
|
19168
|
+
init_chat_message_normalization();
|
|
19169
|
+
init_mesh_reconcile_v2_backstop();
|
|
19170
|
+
init_mesh_reconcile_acked_hold();
|
|
19171
|
+
init_mesh_remote_event_pull();
|
|
18606
19172
|
}
|
|
18607
19173
|
});
|
|
18608
19174
|
|
|
18609
19175
|
// src/mesh/mesh-reconcile-loop.ts
|
|
18610
|
-
function resolveAutoPruneMinAgeMs() {
|
|
18611
|
-
const raw = readNonEmptyString2(process.env.MESH_AUTO_PRUNE_MIN_AGE_MS);
|
|
18612
|
-
if (raw) {
|
|
18613
|
-
const parsed = Number.parseInt(raw, 10);
|
|
18614
|
-
if (Number.isFinite(parsed) && parsed >= 60 * 6e4 && parsed <= 30 * 24 * 60 * 6e4) return parsed;
|
|
18615
|
-
}
|
|
18616
|
-
return DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
18617
|
-
}
|
|
18618
|
-
function resolvePendingHeldDrainEscalateMs() {
|
|
18619
|
-
return resolveTunedReconcileMs("MESH_PENDING_HELD_DRAIN_ESCALATE_MS", DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, 4e3, 5 * 6e4);
|
|
18620
|
-
}
|
|
18621
|
-
function resolveReconcileIntervalMs() {
|
|
18622
|
-
const raw = readNonEmptyString2(process.env.MESH_RECONCILE_INTERVAL_MS);
|
|
18623
|
-
if (raw) {
|
|
18624
|
-
const parsed = Number.parseInt(raw, 10);
|
|
18625
|
-
if (Number.isFinite(parsed) && parsed >= 1e3 && parsed <= 6e4) return parsed;
|
|
18626
|
-
}
|
|
18627
|
-
return DEFAULT_RECONCILE_INTERVAL_MS;
|
|
18628
|
-
}
|
|
18629
19176
|
function findLiveCoordinators(components) {
|
|
18630
19177
|
const out = [];
|
|
18631
19178
|
for (const inst of components.instanceManager.getByCategory("cli")) {
|
|
@@ -19304,349 +19851,6 @@ async function retryUnresolvedDelegateForwards(components) {
|
|
|
19304
19851
|
LOG.info("MeshReconcile", `Retried+delivered unresolved-delegate ${readNonEmptyString2(entry.payload.event)} to coordinator ${entry.coordinatorDaemonId}`);
|
|
19305
19852
|
}
|
|
19306
19853
|
}
|
|
19307
|
-
async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDaemonIds) {
|
|
19308
|
-
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
19309
|
-
if (!dispatchMeshCommand) return;
|
|
19310
|
-
const meshId = mesh.id;
|
|
19311
|
-
const pulls = candidateDaemonIds.length > 0 ? candidateDaemonIds.map((id) => ({ meshId, coordinatorDaemonId: id })) : [{ meshId }];
|
|
19312
|
-
for (const node of mesh.nodes) {
|
|
19313
|
-
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
19314
|
-
if (!nodeDaemonId) continue;
|
|
19315
|
-
if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) continue;
|
|
19316
|
-
if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) continue;
|
|
19317
|
-
for (const pendingEventArgs of pulls) {
|
|
19318
|
-
let events;
|
|
19319
|
-
try {
|
|
19320
|
-
events = await dispatchMeshCommand(nodeDaemonId, "get_pending_mesh_events", pendingEventArgs);
|
|
19321
|
-
} catch {
|
|
19322
|
-
break;
|
|
19323
|
-
}
|
|
19324
|
-
const list = extractPendingEvents(events).filter((e) => readNonEmptyString2(e?.meshId) === meshId);
|
|
19325
|
-
for (const event of list) {
|
|
19326
|
-
const payload = buildForwardPayloadFromPending(event);
|
|
19327
|
-
if (!payload.event || !payload.meshId) continue;
|
|
19328
|
-
try {
|
|
19329
|
-
handleMeshForwardEvent(components, payload);
|
|
19330
|
-
} catch {
|
|
19331
|
-
}
|
|
19332
|
-
}
|
|
19333
|
-
}
|
|
19334
|
-
}
|
|
19335
|
-
}
|
|
19336
|
-
function unwrapReadChatPayload(raw) {
|
|
19337
|
-
let cursor = raw;
|
|
19338
|
-
for (let depth = 0; depth < 4 && cursor && typeof cursor === "object"; depth++) {
|
|
19339
|
-
const record = cursor;
|
|
19340
|
-
if (Array.isArray(record.messages)) return record;
|
|
19341
|
-
if (record.payload && typeof record.payload === "object") {
|
|
19342
|
-
cursor = record.payload;
|
|
19343
|
-
continue;
|
|
19344
|
-
}
|
|
19345
|
-
if (record.result && typeof record.result === "object") {
|
|
19346
|
-
cursor = record.result;
|
|
19347
|
-
continue;
|
|
19348
|
-
}
|
|
19349
|
-
if (record.data && typeof record.data === "object") {
|
|
19350
|
-
cursor = record.data;
|
|
19351
|
-
continue;
|
|
19352
|
-
}
|
|
19353
|
-
break;
|
|
19354
|
-
}
|
|
19355
|
-
return cursor && typeof cursor === "object" ? cursor : null;
|
|
19356
|
-
}
|
|
19357
|
-
function readChatPayloadStatus(payload) {
|
|
19358
|
-
return readNonEmptyString2(payload?.status).toLowerCase();
|
|
19359
|
-
}
|
|
19360
|
-
function realTerminalEmitPendingForTask(meshId, taskId) {
|
|
19361
|
-
let pending;
|
|
19362
|
-
try {
|
|
19363
|
-
pending = getPendingMeshCoordinatorEvents(meshId);
|
|
19364
|
-
} catch {
|
|
19365
|
-
return false;
|
|
19366
|
-
}
|
|
19367
|
-
return pending.some((e) => readNonEmptyString2(e.metadataEvent?.taskId) === taskId && (e.event === "agent:generating_completed" || e.event === "agent:stopped"));
|
|
19368
|
-
}
|
|
19369
|
-
async function reprobeWorkerStatus(components, args) {
|
|
19370
|
-
try {
|
|
19371
|
-
if (args.isLocalNode) {
|
|
19372
|
-
const r = await components.commandHandler.handle("read_chat", args.readArgs);
|
|
19373
|
-
if (r && r.success === false) return null;
|
|
19374
|
-
return readChatPayloadStatus(unwrapReadChatPayload(r));
|
|
19375
|
-
}
|
|
19376
|
-
if (components.dispatchMeshCommand) {
|
|
19377
|
-
const r = await components.dispatchMeshCommand(args.nodeDaemonId, "read_chat", args.readArgs);
|
|
19378
|
-
const p = unwrapReadChatPayload(r);
|
|
19379
|
-
if (p && p.success === false) return null;
|
|
19380
|
-
return readChatPayloadStatus(p);
|
|
19381
|
-
}
|
|
19382
|
-
} catch {
|
|
19383
|
-
return null;
|
|
19384
|
-
}
|
|
19385
|
-
return null;
|
|
19386
|
-
}
|
|
19387
|
-
async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds, localDaemonId) {
|
|
19388
|
-
const dispatches = getActiveDirectDispatches(mesh.id);
|
|
19389
|
-
rehydrateAckedHoldsForMesh(mesh.id);
|
|
19390
|
-
const activeTaskKeys = new Set(
|
|
19391
|
-
dispatches.map((d) => readNonEmptyString2(d.taskId)).filter(Boolean).map((taskId) => inFlightSynthKey(mesh.id, taskId))
|
|
19392
|
-
);
|
|
19393
|
-
const heldKeys = collectHeldSynthKeysForMesh(mesh.id);
|
|
19394
|
-
for (const key2 of heldKeys) {
|
|
19395
|
-
if (!activeTaskKeys.has(key2)) deleteHoldState(key2, mesh.id);
|
|
19396
|
-
}
|
|
19397
|
-
if (dispatches.length === 0) return;
|
|
19398
|
-
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
19399
|
-
const nodeById = new Map(mesh.nodes.map((n) => [n.id, n]));
|
|
19400
|
-
for (const dispatch of dispatches) {
|
|
19401
|
-
const sessionId = readNonEmptyString2(dispatch.sessionId);
|
|
19402
|
-
const nodeId = readNonEmptyString2(dispatch.nodeId);
|
|
19403
|
-
const taskId = readNonEmptyString2(dispatch.taskId);
|
|
19404
|
-
if (!sessionId || !nodeId || !taskId) continue;
|
|
19405
|
-
const node = nodeById.get(nodeId);
|
|
19406
|
-
const nodeDaemonId = readNonEmptyString2(node?.daemonId);
|
|
19407
|
-
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId) || !!components.instanceManager.getInstance(sessionId);
|
|
19408
|
-
const providerType = readNonEmptyString2(dispatch.providerType);
|
|
19409
|
-
const readArgs = {
|
|
19410
|
-
sessionId,
|
|
19411
|
-
targetSessionId: sessionId,
|
|
19412
|
-
tailLimit: 10,
|
|
19413
|
-
...node?.workspace ? { workspace: node.workspace } : {},
|
|
19414
|
-
...providerType ? { agentType: providerType, providerType } : {}
|
|
19415
|
-
};
|
|
19416
|
-
const synthKey = inFlightSynthKey(mesh.id, taskId);
|
|
19417
|
-
const isAcked = dispatch.status === "acked";
|
|
19418
|
-
let backstopKind;
|
|
19419
|
-
let payload = null;
|
|
19420
|
-
let readFailed = false;
|
|
19421
|
-
try {
|
|
19422
|
-
if (isLocalNode) {
|
|
19423
|
-
const result = await components.commandHandler.handle("read_chat", readArgs);
|
|
19424
|
-
if (result && result.success === false) {
|
|
19425
|
-
readFailed = true;
|
|
19426
|
-
} else {
|
|
19427
|
-
payload = unwrapReadChatPayload(result);
|
|
19428
|
-
}
|
|
19429
|
-
} else if (dispatchMeshCommand) {
|
|
19430
|
-
const result = await dispatchMeshCommand(nodeDaemonId, "read_chat", readArgs);
|
|
19431
|
-
payload = unwrapReadChatPayload(result);
|
|
19432
|
-
if (payload && payload.success === false) {
|
|
19433
|
-
payload = null;
|
|
19434
|
-
readFailed = true;
|
|
19435
|
-
}
|
|
19436
|
-
} else {
|
|
19437
|
-
continue;
|
|
19438
|
-
}
|
|
19439
|
-
} catch {
|
|
19440
|
-
readFailed = true;
|
|
19441
|
-
}
|
|
19442
|
-
if (!payload && !readFailed) continue;
|
|
19443
|
-
if (readFailed || !payload) {
|
|
19444
|
-
if (isAcked) {
|
|
19445
|
-
const prior = getHoldState(synthKey, mesh.id);
|
|
19446
|
-
const failures = (prior?.consecutiveReadFailures ?? 0) + 1;
|
|
19447
|
-
const liveConfirmedSinceAck = prior?.liveConfirmedSinceAck ?? false;
|
|
19448
|
-
setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck, consecutiveReadFailures: failures });
|
|
19449
|
-
if (liveConfirmedSinceAck && failures >= ACKED_DEATH_CONSECUTIVE_READ_FAILURES) {
|
|
19450
|
-
LOG.warn("MeshReconcile", `Acked-hold death signal: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read_chat failed ${failures}x consecutively after a live-confirmed ack \u2014 worker session presumed gone mid-turn; releasing the indefinite synth hold to the stranded-reclaim / orphan-prune nets`);
|
|
19451
|
-
}
|
|
19452
|
-
}
|
|
19453
|
-
continue;
|
|
19454
|
-
}
|
|
19455
|
-
const priorHoldState = getHoldState(synthKey, mesh.id);
|
|
19456
|
-
setHoldState(synthKey, mesh.id, {
|
|
19457
|
-
liveConfirmedSinceAck: true,
|
|
19458
|
-
consecutiveReadFailures: 0,
|
|
19459
|
-
...priorHoldState?.transcriptIdleSinceMs !== void 0 ? { transcriptIdleSinceMs: priorHoldState.transcriptIdleSinceMs } : {}
|
|
19460
|
-
});
|
|
19461
|
-
const nowMs = Date.now();
|
|
19462
|
-
if (readChatPayloadStatus(payload) !== "idle") {
|
|
19463
|
-
setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
|
|
19464
|
-
continue;
|
|
19465
|
-
}
|
|
19466
|
-
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
19467
|
-
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
19468
|
-
if (isAcked) {
|
|
19469
|
-
const ackedAtMs = Date.parse(readNonEmptyString2(dispatch.updatedAt));
|
|
19470
|
-
const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
|
|
19471
|
-
const deathDeadlineMs = resolveAckedDeathDeadlineMs();
|
|
19472
|
-
const holdState = getHoldState(synthKey, mesh.id);
|
|
19473
|
-
let fastTrackReady = false;
|
|
19474
|
-
if (evidence.finalSummary) {
|
|
19475
|
-
const idleSinceMs = holdState?.transcriptIdleSinceMs ?? nowMs;
|
|
19476
|
-
if (holdState && holdState.transcriptIdleSinceMs === void 0) {
|
|
19477
|
-
setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: idleSinceMs });
|
|
19478
|
-
}
|
|
19479
|
-
const fastTrackGraceMs = resolveAckedTranscriptFastTrackGraceMs();
|
|
19480
|
-
const idleHeldMs = nowMs - idleSinceMs;
|
|
19481
|
-
if (idleHeldMs >= fastTrackGraceMs) {
|
|
19482
|
-
fastTrackReady = true;
|
|
19483
|
-
backstopKind = "ackedHoldFastTrackFired";
|
|
19484
|
-
LOG.info("MeshReconcile", `Acked-hold transcript fast-track: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle WITH a final assistant message for ${Math.round(idleHeldMs / 1e3)}s continuous (grace ${Math.round(fastTrackGraceMs / 1e3)}s) \u2014 promoting the synth ahead of the ${Math.round(deathDeadlineMs / 1e3)}s death backstop; the worker's real emit was lost/late and a later one no-ops idempotently.`);
|
|
19485
|
-
}
|
|
19486
|
-
} else if (holdState?.transcriptIdleSinceMs !== void 0) {
|
|
19487
|
-
setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: void 0 });
|
|
19488
|
-
}
|
|
19489
|
-
if (!fastTrackReady && sinceAckMs < deathDeadlineMs) {
|
|
19490
|
-
LOG.info("MeshReconcile", `Acked-hold: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle ${Number.isFinite(sinceAckMs) ? Math.round(sinceAckMs / 1e3) + "s" : "\u221E"} since the generating_started ack \u2014 HOLDING synth (worker presumed alive; a later real emit is idempotent). Transcript fast-track promotes at ${Math.round(resolveAckedTranscriptFastTrackGraceMs() / 1e3)}s continuous idle-with-final-assistant; death backstop at ${Math.round(deathDeadlineMs / 1e3)}s or on consecutive read failures.`);
|
|
19491
|
-
continue;
|
|
19492
|
-
}
|
|
19493
|
-
if (!fastTrackReady) {
|
|
19494
|
-
backstopKind = "ackedHoldDeathDeadlineFired";
|
|
19495
|
-
LOG.warn("MeshReconcile", `Acked-hold death deadline reached: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) still idle ${Math.round(sinceAckMs / 1e3)}s after the ack (deadline ${Math.round(deathDeadlineMs / 1e3)}s) \u2014 synthesizing the missing completion as a notification-loss net (a real emit, if it ever lands, no-ops idempotently).`);
|
|
19496
|
-
}
|
|
19497
|
-
}
|
|
19498
|
-
if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
|
|
19499
|
-
deleteHoldState(synthKey, mesh.id);
|
|
19500
|
-
LOG.info("MeshReconcile", `Worker-emit priority: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) has a real terminal completion already queued \u2014 yielding synth to the worker's own emit`);
|
|
19501
|
-
continue;
|
|
19502
|
-
}
|
|
19503
|
-
if (!evidence.finalSummary) continue;
|
|
19504
|
-
const dispatchedAtMs = Date.parse(readNonEmptyString2(dispatch.dispatchedAt));
|
|
19505
|
-
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
|
|
19506
|
-
if (Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs < dispatchedAtMs) {
|
|
19507
|
-
LOG.info("MeshReconcile", `Stale-summary guard: skipping transcript reconcile for task ${taskId} on node ${nodeId} (mesh ${mesh.id}) \u2014 final assistant message (${evidence.transcriptMessageAt}) predates this task's dispatch (${dispatch.dispatchedAt}); it is a prior task's summary`);
|
|
19508
|
-
traceMeshEventDrop("reconcile_stale_summary_before_dispatch", {
|
|
19509
|
-
taskId,
|
|
19510
|
-
sessionId,
|
|
19511
|
-
nodeId,
|
|
19512
|
-
meshId: mesh.id,
|
|
19513
|
-
event: "agent:generating_completed"
|
|
19514
|
-
}, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
|
|
19515
|
-
continue;
|
|
19516
|
-
}
|
|
19517
|
-
const reprobeStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
|
|
19518
|
-
if (reprobeStatus && reprobeStatus !== "idle") {
|
|
19519
|
-
deleteHoldState(synthKey, mesh.id);
|
|
19520
|
-
LOG.info("MeshReconcile", `Live re-probe defer: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read '${reprobeStatus}' at synth-commit time \u2014 worker resumed generating; deferring synth to a later tick`);
|
|
19521
|
-
continue;
|
|
19522
|
-
}
|
|
19523
|
-
const providerSessionId = readNonEmptyString2(payload.providerSessionId);
|
|
19524
|
-
const coordinatorDaemonId = selfIds.find((id) => !!id);
|
|
19525
|
-
try {
|
|
19526
|
-
const result = reconcileDirectDispatchCompletionFromTranscript({
|
|
19527
|
-
meshId: mesh.id,
|
|
19528
|
-
nodeId,
|
|
19529
|
-
sessionId,
|
|
19530
|
-
providerType: providerType || void 0,
|
|
19531
|
-
providerSessionId: providerSessionId || void 0,
|
|
19532
|
-
taskId,
|
|
19533
|
-
finalSummary: evidence.finalSummary,
|
|
19534
|
-
...evidence.transcriptMessageAt ? { transcriptMessageAt: evidence.transcriptMessageAt } : {},
|
|
19535
|
-
...coordinatorDaemonId ? { targetCoordinatorDaemonId: coordinatorDaemonId } : {},
|
|
19536
|
-
source: "daemon_reconcile_transcript_completion"
|
|
19537
|
-
});
|
|
19538
|
-
if (result.reconciled) {
|
|
19539
|
-
recordBackstopFire(backstopKind ?? "phase4SynthesisFired", `task ${taskId} on node ${nodeId} (mesh ${mesh.id}), kind=${result.kind}`);
|
|
19540
|
-
LOG.info("MeshReconcile", `Synthesized missing completion (${result.kind}) for task ${taskId} on node ${nodeId} (mesh ${mesh.id})`);
|
|
19541
|
-
}
|
|
19542
|
-
} catch (e) {
|
|
19543
|
-
LOG.warn("MeshReconcile", `Transcript completion reconcile threw for task ${taskId}: ${e?.message || e}`);
|
|
19544
|
-
}
|
|
19545
|
-
}
|
|
19546
|
-
}
|
|
19547
|
-
async function autoPruneStaleDirectDispatches(components, mesh, selfIds, localDaemonId, minAgeMs) {
|
|
19548
|
-
const directDispatches = getActiveDirectDispatches(mesh.id);
|
|
19549
|
-
if (directDispatches.length === 0) return;
|
|
19550
|
-
const liveNodes = await collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId);
|
|
19551
|
-
const result = pruneStaleDirectDispatches({
|
|
19552
|
-
meshId: mesh.id,
|
|
19553
|
-
queue: getQueue(mesh.id),
|
|
19554
|
-
ledgerEntries: readLedgerEntries(mesh.id, { tail: 500 }),
|
|
19555
|
-
directDispatches,
|
|
19556
|
-
nodes: liveNodes,
|
|
19557
|
-
execute: true,
|
|
19558
|
-
minAgeMs,
|
|
19559
|
-
source: "daemon_reconcile_auto_prune"
|
|
19560
|
-
});
|
|
19561
|
-
if (result.prunedCount > 0) {
|
|
19562
|
-
LOG.info("MeshReconcile", `Auto-pruned ${result.prunedCount} orphaned direct dispatch record(s) for mesh ${mesh.id}`);
|
|
19563
|
-
}
|
|
19564
|
-
}
|
|
19565
|
-
async function collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId) {
|
|
19566
|
-
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
19567
|
-
return Promise.all(mesh.nodes.map(async (node) => {
|
|
19568
|
-
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
19569
|
-
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId);
|
|
19570
|
-
let statusResult;
|
|
19571
|
-
try {
|
|
19572
|
-
if (isLocalNode) {
|
|
19573
|
-
statusResult = await components.commandHandler.handle("get_status_metadata", {});
|
|
19574
|
-
} else if (dispatchMeshCommand) {
|
|
19575
|
-
statusResult = await dispatchMeshCommand(nodeDaemonId, "get_status_metadata", {});
|
|
19576
|
-
} else {
|
|
19577
|
-
return node;
|
|
19578
|
-
}
|
|
19579
|
-
} catch {
|
|
19580
|
-
return node;
|
|
19581
|
-
}
|
|
19582
|
-
const sessions = extractStatusMetadataSessions(statusResult);
|
|
19583
|
-
return sessions.length > 0 ? { ...node, sessions } : node;
|
|
19584
|
-
}));
|
|
19585
|
-
}
|
|
19586
|
-
function extractStatusMetadataSessions(raw) {
|
|
19587
|
-
let cursor = raw;
|
|
19588
|
-
for (let depth = 0; depth < 4 && cursor && typeof cursor === "object"; depth++) {
|
|
19589
|
-
const record = cursor;
|
|
19590
|
-
const status = record.status && typeof record.status === "object" ? record.status : void 0;
|
|
19591
|
-
if (status && Array.isArray(status.sessions)) return status.sessions;
|
|
19592
|
-
if (Array.isArray(record.sessions)) return record.sessions;
|
|
19593
|
-
if (record.payload && typeof record.payload === "object") {
|
|
19594
|
-
cursor = record.payload;
|
|
19595
|
-
continue;
|
|
19596
|
-
}
|
|
19597
|
-
if (record.result && typeof record.result === "object") {
|
|
19598
|
-
cursor = record.result;
|
|
19599
|
-
continue;
|
|
19600
|
-
}
|
|
19601
|
-
if (record.data && typeof record.data === "object") {
|
|
19602
|
-
cursor = record.data;
|
|
19603
|
-
continue;
|
|
19604
|
-
}
|
|
19605
|
-
break;
|
|
19606
|
-
}
|
|
19607
|
-
return [];
|
|
19608
|
-
}
|
|
19609
|
-
function extractPendingEvents(raw) {
|
|
19610
|
-
if (Array.isArray(raw)) return raw;
|
|
19611
|
-
if (raw && typeof raw === "object") {
|
|
19612
|
-
const events = raw.events;
|
|
19613
|
-
if (Array.isArray(events)) return events;
|
|
19614
|
-
}
|
|
19615
|
-
return [];
|
|
19616
|
-
}
|
|
19617
|
-
function buildForwardPayloadFromPending(event) {
|
|
19618
|
-
const metadata = event?.metadataEvent && typeof event.metadataEvent === "object" ? event.metadataEvent : {};
|
|
19619
|
-
return {
|
|
19620
|
-
event: readNonEmptyString2(event?.event),
|
|
19621
|
-
meshId: readNonEmptyString2(event?.meshId),
|
|
19622
|
-
nodeId: readNonEmptyString2(event?.nodeId) || readNonEmptyString2(metadata.meshNodeId),
|
|
19623
|
-
workspace: readNonEmptyString2(event?.workspace) || readNonEmptyString2(metadata.workspace),
|
|
19624
|
-
// Preserve the originating coordinator session id across the relay. It is normally
|
|
19625
|
-
// carried inside metadataEvent.meshCoordinatorSessionId (spread below), but pass the
|
|
19626
|
-
// top-level field through explicitly too so the handleMeshForwardEvent whitelist
|
|
19627
|
-
// recovers it regardless of which carrier the producing daemon used.
|
|
19628
|
-
...readNonEmptyString2(event?.targetCoordinatorSessionId) ? { targetCoordinatorSessionId: readNonEmptyString2(event.targetCoordinatorSessionId) } : {},
|
|
19629
|
-
...metadata,
|
|
19630
|
-
// NOTIF-MISS (FIX 3): surface the dispatch task id at the TOP LEVEL so the relay's
|
|
19631
|
-
// received-stage trace (and buildRelayMetadataEvent) recovers it regardless of which
|
|
19632
|
-
// carrier the producing daemon used. The metadata spread above may carry the id only as
|
|
19633
|
-
// `meshActiveTaskId` (a worker provider event), leaving top-level `taskId` unset and the
|
|
19634
|
-
// received stage rendering `task=-`. Resolve both carriers into an explicit `taskId` so
|
|
19635
|
-
// dedup stays task-scoped end-to-end. Only set when a non-empty id exists (no clobber to
|
|
19636
|
-
// undefined when neither is present).
|
|
19637
|
-
...(() => {
|
|
19638
|
-
const tid = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(metadata.meshActiveTaskId);
|
|
19639
|
-
return tid ? { taskId: tid } : {};
|
|
19640
|
-
})(),
|
|
19641
|
-
// T4 (B3b): carry the v2 envelope (protocolVersion/eventId/scope/dispatchedBy/
|
|
19642
|
-
// intendedFor) across the P2P relay boundary at the TOP LEVEL. These live on the
|
|
19643
|
-
// pending event itself, not inside metadataEvent, so without this the remote pull
|
|
19644
|
-
// re-queue would re-stamp a fresh eventId — breaking cross-machine idempotency and
|
|
19645
|
-
// downgrading the relayed completion to v1 broadcast routing. Spread LAST so the
|
|
19646
|
-
// authoritative envelope always wins over any stale key the metadata spread carried.
|
|
19647
|
-
...serializeV2EnvelopeToWire(event)
|
|
19648
|
-
};
|
|
19649
|
-
}
|
|
19650
19854
|
function setupMeshReconcileLoop(components) {
|
|
19651
19855
|
const intervalMs = resolveReconcileIntervalMs();
|
|
19652
19856
|
let running = false;
|
|
@@ -19666,7 +19870,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
19666
19870
|
}
|
|
19667
19871
|
};
|
|
19668
19872
|
}
|
|
19669
|
-
var
|
|
19873
|
+
var coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
|
|
19670
19874
|
var init_mesh_reconcile_loop = __esm({
|
|
19671
19875
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
19672
19876
|
"use strict";
|
|
@@ -19685,17 +19889,13 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
19685
19889
|
init_mesh_work_queue();
|
|
19686
19890
|
init_mesh_queue_assignment();
|
|
19687
19891
|
init_mesh_ledger();
|
|
19688
|
-
init_mesh_active_work();
|
|
19689
19892
|
init_mesh_events_stale();
|
|
19690
|
-
init_chat_message_normalization();
|
|
19691
19893
|
init_mesh_reconcile_identity();
|
|
19894
|
+
init_mesh_reconcile_config();
|
|
19895
|
+
init_mesh_remote_event_pull();
|
|
19896
|
+
init_mesh_completion_synthesis();
|
|
19692
19897
|
init_mesh_reconcile_v2_backstop();
|
|
19693
19898
|
init_mesh_reconcile_acked_hold();
|
|
19694
|
-
init_mesh_reconcile_v2_backstop();
|
|
19695
|
-
init_mesh_reconcile_acked_hold();
|
|
19696
|
-
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
19697
|
-
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
19698
|
-
DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS = 12e3;
|
|
19699
19899
|
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
19700
19900
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
19701
19901
|
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
@@ -19725,6 +19925,7 @@ __export(mesh_events_exports, {
|
|
|
19725
19925
|
queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
|
|
19726
19926
|
readV2EnvelopeFromWire: () => readV2EnvelopeFromWire,
|
|
19727
19927
|
reconcileDirectDispatchCompletionFromTranscript: () => reconcileDirectDispatchCompletionFromTranscript,
|
|
19928
|
+
requeueHeldMeshCoordinatorEvents: () => requeueHeldMeshCoordinatorEvents,
|
|
19728
19929
|
resolveCoordinatorDrainDeliverability: () => resolveCoordinatorDrainDeliverability,
|
|
19729
19930
|
runMeshReconcileTick: () => runMeshReconcileTick,
|
|
19730
19931
|
serializeV2EnvelopeToWire: () => serializeV2EnvelopeToWire,
|
|
@@ -26611,6 +26812,7 @@ init_mesh_config();
|
|
|
26611
26812
|
init_dist();
|
|
26612
26813
|
init_dist();
|
|
26613
26814
|
init_dist();
|
|
26815
|
+
init_dist();
|
|
26614
26816
|
init_coordinator_prompt();
|
|
26615
26817
|
init_mesh_missions();
|
|
26616
26818
|
init_mesh_task_stats();
|
|
@@ -42306,7 +42508,7 @@ async function waitForCliAdapterReady(adapter, options) {
|
|
|
42306
42508
|
throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
|
|
42307
42509
|
}
|
|
42308
42510
|
|
|
42309
|
-
// src/providers/cli-provider-instance.ts
|
|
42511
|
+
// src/providers/cli-provider-instance-types.ts
|
|
42310
42512
|
var STATUS_HYDRATION_TAIL_LIMIT = 200;
|
|
42311
42513
|
var COMPLETED_FINALIZATION_RETRY_MS = 1e3;
|
|
42312
42514
|
var COMPLETED_FINALIZATION_MAX_WAIT_MS = 3e4;
|
|
@@ -42318,6 +42520,123 @@ var TERMINAL_MESH_EVENTS = /* @__PURE__ */ new Set([
|
|
|
42318
42520
|
"agent:stopped",
|
|
42319
42521
|
"agent:ready"
|
|
42320
42522
|
]);
|
|
42523
|
+
|
|
42524
|
+
// src/providers/cli-provider-transcript-merge.ts
|
|
42525
|
+
init_contracts2();
|
|
42526
|
+
init_chat_message_normalization();
|
|
42527
|
+
function mergeConversationMessages(runtimeMessages, parsedMessages) {
|
|
42528
|
+
if (runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
42529
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
42530
|
+
message,
|
|
42531
|
+
index,
|
|
42532
|
+
source: "parsed"
|
|
42533
|
+
}));
|
|
42534
|
+
const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
42535
|
+
const runtimeEntries = runtimeMessages.map((entry, index) => ({
|
|
42536
|
+
message: entry.message,
|
|
42537
|
+
index: parsedMessages.length + index,
|
|
42538
|
+
source: "runtime",
|
|
42539
|
+
runtimeKey: entry.key
|
|
42540
|
+
})).filter((entry) => {
|
|
42541
|
+
const meta = entry.message.meta && typeof entry.message.meta === "object" && !Array.isArray(entry.message.meta) ? entry.message.meta : {};
|
|
42542
|
+
if (meta.runtimeInputAck !== true) return true;
|
|
42543
|
+
const runtimeText = flattenContent(entry.message.content).replace(/\s+/g, " ").trim();
|
|
42544
|
+
if (!runtimeText) return false;
|
|
42545
|
+
return !parsedEntries.some((parsedEntry) => {
|
|
42546
|
+
const parsedRole = getRole(parsedEntry.message);
|
|
42547
|
+
if (parsedRole !== "user" && parsedRole !== "human") return false;
|
|
42548
|
+
const parsedText = flattenContent(parsedEntry.message.content).replace(/\s+/g, " ").trim();
|
|
42549
|
+
return parsedText === runtimeText;
|
|
42550
|
+
});
|
|
42551
|
+
});
|
|
42552
|
+
const getTime = (message) => {
|
|
42553
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
42554
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
42555
|
+
};
|
|
42556
|
+
const isRuntimeOverlay = (entry) => {
|
|
42557
|
+
if (entry.source !== "runtime") return false;
|
|
42558
|
+
const key2 = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
|
|
42559
|
+
if (key2.startsWith("auto_approval:")) return true;
|
|
42560
|
+
return !isUserFacingChatMessage(entry.message);
|
|
42561
|
+
};
|
|
42562
|
+
const shouldKeepParsedBeforeUntimedRuntime = (message) => {
|
|
42563
|
+
const role = getRole(message);
|
|
42564
|
+
return role === "user" || role === "human";
|
|
42565
|
+
};
|
|
42566
|
+
const shouldKeepParsedAfterUntimedRuntime = (message) => {
|
|
42567
|
+
const role = getRole(message);
|
|
42568
|
+
if (role !== "assistant") return false;
|
|
42569
|
+
const kind = resolveChatMessageKind(message);
|
|
42570
|
+
return kind === "standard" || kind === "terminal";
|
|
42571
|
+
};
|
|
42572
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
42573
|
+
const aTime = getTime(a.message);
|
|
42574
|
+
const bTime = getTime(b.message);
|
|
42575
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
42576
|
+
if (a.source !== b.source && aTime !== bTime) {
|
|
42577
|
+
const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
|
|
42578
|
+
const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
|
|
42579
|
+
if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
|
|
42580
|
+
if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
|
|
42581
|
+
return a.source === "parsed" ? -1 : 1;
|
|
42582
|
+
}
|
|
42583
|
+
if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
|
|
42584
|
+
return a.source === "parsed" ? 1 : -1;
|
|
42585
|
+
}
|
|
42586
|
+
}
|
|
42587
|
+
}
|
|
42588
|
+
return a.index - b.index;
|
|
42589
|
+
}).map((entry) => entry.message));
|
|
42590
|
+
}
|
|
42591
|
+
function buildExternalTranscriptProbe(messages, sourcePath, sourceMtimeMs) {
|
|
42592
|
+
const visibleMessages = messages.filter((message) => isUserFacingChatMessage(message));
|
|
42593
|
+
const lastVisible = visibleMessages[visibleMessages.length - 1];
|
|
42594
|
+
const readAt = Date.now();
|
|
42595
|
+
const mtimeMs = Number(sourceMtimeMs) || 0;
|
|
42596
|
+
return {
|
|
42597
|
+
readAt,
|
|
42598
|
+
msgCount: messages.length,
|
|
42599
|
+
lastRole: typeof lastVisible?.role === "string" ? lastVisible.role.trim().toLowerCase() : null,
|
|
42600
|
+
lastKind: typeof lastVisible?.kind === "string" ? lastVisible.kind : null,
|
|
42601
|
+
contentLen: lastVisible ? flattenContent(lastVisible.content).trim().length : 0,
|
|
42602
|
+
sourcePath: typeof sourcePath === "string" && sourcePath ? sourcePath : null,
|
|
42603
|
+
sourceMtimeMs: mtimeMs || null,
|
|
42604
|
+
mtimeAgeMs: mtimeMs ? Math.max(0, readAt - mtimeMs) : null
|
|
42605
|
+
};
|
|
42606
|
+
}
|
|
42607
|
+
|
|
42608
|
+
// src/providers/cli-provider-effect-format.ts
|
|
42609
|
+
function getEffectDedupKey(effect) {
|
|
42610
|
+
if (effect.id) return `provider_effect:${effect.id}`;
|
|
42611
|
+
if (effect.type === "message") {
|
|
42612
|
+
const content = typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
|
|
42613
|
+
return `provider_effect:message:${content}`;
|
|
42614
|
+
}
|
|
42615
|
+
if (effect.type === "notification") {
|
|
42616
|
+
return `provider_effect:notification:${effect.notification?.title || ""}:${effect.notification?.body || ""}`;
|
|
42617
|
+
}
|
|
42618
|
+
return `provider_effect:toast:${effect.toast?.message || ""}`;
|
|
42619
|
+
}
|
|
42620
|
+
function formatApprovalRequestMessage(modalMessage, buttons) {
|
|
42621
|
+
const lines = ["Approval requested"];
|
|
42622
|
+
const cleanMessage = String(modalMessage || "").trim();
|
|
42623
|
+
if (cleanMessage) lines.push(cleanMessage);
|
|
42624
|
+
const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
|
|
42625
|
+
if (labels.length > 0) {
|
|
42626
|
+
lines.push(labels.map((label) => `[${label}]`).join(" "));
|
|
42627
|
+
}
|
|
42628
|
+
return lines.join("\n");
|
|
42629
|
+
}
|
|
42630
|
+
function formatMarkerTimestamp(timestamp) {
|
|
42631
|
+
const date = new Date(timestamp);
|
|
42632
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
42633
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
42634
|
+
}
|
|
42635
|
+
|
|
42636
|
+
// src/providers/cli-provider-instance.ts
|
|
42637
|
+
function approvalModalSignature(message, affirmativeAnchor) {
|
|
42638
|
+
return [typeof message === "string" ? message.trim() : "", affirmativeAnchor].join("::");
|
|
42639
|
+
}
|
|
42321
42640
|
var CliProviderInstance = class _CliProviderInstance {
|
|
42322
42641
|
constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
|
|
42323
42642
|
this.provider = provider;
|
|
@@ -42565,7 +42884,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
42565
42884
|
const resumedAt = Date.now();
|
|
42566
42885
|
this.historyWriter.appendSystemMarker(
|
|
42567
42886
|
this.type,
|
|
42568
|
-
`Resumed saved session at ${
|
|
42887
|
+
`Resumed saved session at ${formatMarkerTimestamp(resumedAt)}`,
|
|
42569
42888
|
{
|
|
42570
42889
|
instanceId: this.instanceId,
|
|
42571
42890
|
historySessionId: this.providerSessionId,
|
|
@@ -42677,7 +42996,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
42677
42996
|
if (historyMessageCount !== null) {
|
|
42678
42997
|
parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
|
|
42679
42998
|
}
|
|
42680
|
-
const mergedMessages = this.
|
|
42999
|
+
const mergedMessages = mergeConversationMessages(this.runtimeMessages, parsedMessages);
|
|
42681
43000
|
const canonicalBackedHistory = this.shouldHydrateExistingProviderHistory() ? this.syncCanonicalSavedHistoryIfNeeded() : false;
|
|
42682
43001
|
const statusMessages = canonicalBackedHistory && this.lastPersistedHistoryMessages.length > 0 ? this.lastPersistedHistoryMessages.map((message) => ({
|
|
42683
43002
|
role: message.role,
|
|
@@ -43142,22 +43461,6 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43142
43461
|
}
|
|
43143
43462
|
return true;
|
|
43144
43463
|
}
|
|
43145
|
-
buildExternalTranscriptProbe(messages, sourcePath, sourceMtimeMs) {
|
|
43146
|
-
const visibleMessages = messages.filter((message) => isUserFacingChatMessage(message));
|
|
43147
|
-
const lastVisible = visibleMessages[visibleMessages.length - 1];
|
|
43148
|
-
const readAt = Date.now();
|
|
43149
|
-
const mtimeMs = Number(sourceMtimeMs) || 0;
|
|
43150
|
-
return {
|
|
43151
|
-
readAt,
|
|
43152
|
-
msgCount: messages.length,
|
|
43153
|
-
lastRole: typeof lastVisible?.role === "string" ? lastVisible.role.trim().toLowerCase() : null,
|
|
43154
|
-
lastKind: typeof lastVisible?.kind === "string" ? lastVisible.kind : null,
|
|
43155
|
-
contentLen: lastVisible ? flattenContent(lastVisible.content).trim().length : 0,
|
|
43156
|
-
sourcePath: typeof sourcePath === "string" && sourcePath ? sourcePath : null,
|
|
43157
|
-
sourceMtimeMs: mtimeMs || null,
|
|
43158
|
-
mtimeAgeMs: mtimeMs ? Math.max(0, readAt - mtimeMs) : null
|
|
43159
|
-
};
|
|
43160
|
-
}
|
|
43161
43464
|
recordPendingTranscriptProbe(pending) {
|
|
43162
43465
|
const probe = this.lastExternalCompletionProbe;
|
|
43163
43466
|
if (!probe) return null;
|
|
@@ -43209,7 +43512,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43209
43512
|
this.lastExternalCompletionProbe = null;
|
|
43210
43513
|
return null;
|
|
43211
43514
|
}
|
|
43212
|
-
this.lastExternalCompletionProbe =
|
|
43515
|
+
this.lastExternalCompletionProbe = buildExternalTranscriptProbe(
|
|
43213
43516
|
restoredHistory.messages,
|
|
43214
43517
|
restoredHistory.sourcePath,
|
|
43215
43518
|
restoredHistory.sourceMtimeMs
|
|
@@ -43457,6 +43760,27 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43457
43760
|
autoApproveContinuityWindowMs() {
|
|
43458
43761
|
return this.autoApproveMaskSince > 0 && this.isMeshWorkerSession() ? _CliProviderInstance.AUTO_APPROVE_FLAP_CONTINUITY_MS : _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS;
|
|
43459
43762
|
}
|
|
43763
|
+
/**
|
|
43764
|
+
* The settle-gate identity signature for a raw activeModal, or null when the
|
|
43765
|
+
* modal is NOT a concrete auto-approvable consent prompt (no captured buttons,
|
|
43766
|
+
* a picker/confirm kind, or no reliable affirmative+decline anchor). Mirrors the
|
|
43767
|
+
* gates the auto-approve fire path applies before computing modalSignature, so
|
|
43768
|
+
* the mask-stall nudge can ask the SAME question the settle gate is tracking —
|
|
43769
|
+
* "is THIS frame's modal the identity the settle clock is accruing against?" —
|
|
43770
|
+
* without duplicating the button-pick logic. The signature is message +
|
|
43771
|
+
* normalized affirmative label only (no volatile counters/button set), matching
|
|
43772
|
+
* the fire path exactly (AUTOAPPROVE-SETTLE-FLAP).
|
|
43773
|
+
*/
|
|
43774
|
+
approvableModalSignature(modal) {
|
|
43775
|
+
const buttons = Array.isArray(modal?.buttons) ? modal.buttons.map((b) => String(b || "").trim()).filter(Boolean) : [];
|
|
43776
|
+
if (!modal || buttons.length === 0) return null;
|
|
43777
|
+
const modalKind = typeof modal?.kind === "string" ? modal.kind : "approval";
|
|
43778
|
+
if (modalKind !== "approval") return null;
|
|
43779
|
+
const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(buttons, this.provider);
|
|
43780
|
+
const hasReliableConsentAnchor = hasNegativeApprovalOption(buttons) || hasReliableApprovalAffirmative(buttons);
|
|
43781
|
+
if (buttonIndex < 0 || !hasReliableConsentAnchor) return null;
|
|
43782
|
+
return approvalModalSignature(modal?.message, normalizeApprovalLabel(buttonLabel));
|
|
43783
|
+
}
|
|
43460
43784
|
// FALSE-IDLE (self-coordinator settle): an autonomously-progressing mesh session
|
|
43461
43785
|
// is either a delegated worker (isMeshWorkerSession) OR the coordinator's OWN
|
|
43462
43786
|
// claude-cli session (meshCoordinatorFor). Both run auto-approved tool turns whose
|
|
@@ -43760,10 +44084,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43760
44084
|
return autoApproveActive;
|
|
43761
44085
|
}
|
|
43762
44086
|
const affirmativeAnchor = normalizeApprovalLabel(buttonLabel);
|
|
43763
|
-
const modalSignature =
|
|
43764
|
-
typeof modal?.message === "string" ? modal.message.trim() : "",
|
|
43765
|
-
affirmativeAnchor
|
|
43766
|
-
].join("::");
|
|
44087
|
+
const modalSignature = approvalModalSignature(modal?.message, affirmativeAnchor);
|
|
43767
44088
|
const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
|
|
43768
44089
|
const busySignature = `${approvalEntrySeq}::${modalSignature}`;
|
|
43769
44090
|
if (this.autoApproveBusy && busySignature === this.lastAutoApprovalSignature) {
|
|
@@ -43996,7 +44317,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43996
44317
|
if (approvalFingerprint !== this.lastApprovalEventFingerprint) {
|
|
43997
44318
|
this.lastApprovalEventFingerprint = approvalFingerprint;
|
|
43998
44319
|
this.appendRuntimeSystemMessage(
|
|
43999
|
-
|
|
44320
|
+
formatApprovalRequestMessage(modal?.message, modal?.buttons),
|
|
44000
44321
|
`approval_request:${now}`,
|
|
44001
44322
|
now
|
|
44002
44323
|
);
|
|
@@ -44297,7 +44618,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44297
44618
|
const effectWhen = effect.when || "immediate";
|
|
44298
44619
|
if (effectWhen === "turn_completed" && options.phase !== "turn_completed") continue;
|
|
44299
44620
|
if (effectWhen === "immediate" && options.phase === "turn_completed") continue;
|
|
44300
|
-
const effectKey =
|
|
44621
|
+
const effectKey = getEffectDedupKey(effect);
|
|
44301
44622
|
if (this.appliedEffectKeys.has(effectKey)) continue;
|
|
44302
44623
|
this.appliedEffectKeys.add(effectKey);
|
|
44303
44624
|
if (effect.persist !== false) {
|
|
@@ -44340,34 +44661,6 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44340
44661
|
this.appliedEffectKeys = new Set(Array.from(this.appliedEffectKeys).slice(-100));
|
|
44341
44662
|
}
|
|
44342
44663
|
}
|
|
44343
|
-
getEffectDedupKey(effect) {
|
|
44344
|
-
if (effect.id) return `provider_effect:${effect.id}`;
|
|
44345
|
-
if (effect.type === "message") {
|
|
44346
|
-
const content = typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
|
|
44347
|
-
return `provider_effect:message:${content}`;
|
|
44348
|
-
}
|
|
44349
|
-
if (effect.type === "notification") {
|
|
44350
|
-
return `provider_effect:notification:${effect.notification?.title || ""}:${effect.notification?.body || ""}`;
|
|
44351
|
-
}
|
|
44352
|
-
return `provider_effect:toast:${effect.toast?.message || ""}`;
|
|
44353
|
-
}
|
|
44354
|
-
getPersistedEffectContent(effect) {
|
|
44355
|
-
if (effect.type === "message") {
|
|
44356
|
-
return typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
|
|
44357
|
-
}
|
|
44358
|
-
if (effect.type === "toast") {
|
|
44359
|
-
return effect.toast?.message || null;
|
|
44360
|
-
}
|
|
44361
|
-
if (effect.type === "notification") {
|
|
44362
|
-
if (typeof effect.notification?.bubbleContent === "string") return effect.notification.bubbleContent;
|
|
44363
|
-
if (typeof effect.notification?.title === "string" && effect.notification.title.trim()) {
|
|
44364
|
-
return `${effect.notification.title}
|
|
44365
|
-
${effect.notification.body || ""}`.trim();
|
|
44366
|
-
}
|
|
44367
|
-
return effect.notification?.body || null;
|
|
44368
|
-
}
|
|
44369
|
-
return null;
|
|
44370
|
-
}
|
|
44371
44664
|
// ─── Adapter access (backward compat) ──────────────────
|
|
44372
44665
|
getAdapter() {
|
|
44373
44666
|
return this.adapter;
|
|
@@ -44439,15 +44732,16 @@ ${effect.notification.body || ""}`.trim();
|
|
|
44439
44732
|
if (!this.isMeshWorkerSession()) return;
|
|
44440
44733
|
if (adapterStatus?.status !== "waiting_approval") return;
|
|
44441
44734
|
if (!this.autoApproveMaskStalled(now)) return;
|
|
44442
|
-
const
|
|
44443
|
-
|
|
44735
|
+
const currentSignature = this.approvableModalSignature(adapterStatus.activeModal);
|
|
44736
|
+
const settleProgressing = !!currentSignature && this.pendingAutoApprovalSince > 0 && currentSignature === this.pendingAutoApprovalSignature;
|
|
44737
|
+
if (settleProgressing) return;
|
|
44444
44738
|
if (this.stalledApprovalNudgeEpisode === this.autoApproveMaskSince) return;
|
|
44445
44739
|
this.stalledApprovalNudgeEpisode = this.autoApproveMaskSince;
|
|
44446
44740
|
const modal = adapterStatus.activeModal;
|
|
44447
44741
|
const dirName = workingDirBasename(this.workingDir);
|
|
44448
44742
|
const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
|
|
44449
44743
|
this.appendRuntimeSystemMessage(
|
|
44450
|
-
|
|
44744
|
+
formatApprovalRequestMessage(modal?.message, modal?.buttons),
|
|
44451
44745
|
`approval_request:${now}`,
|
|
44452
44746
|
now
|
|
44453
44747
|
);
|
|
@@ -44477,11 +44771,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
44477
44771
|
now
|
|
44478
44772
|
);
|
|
44479
44773
|
}
|
|
44480
|
-
formatMarkerTimestamp(timestamp) {
|
|
44481
|
-
const date = new Date(timestamp);
|
|
44482
|
-
const pad = (value) => String(value).padStart(2, "0");
|
|
44483
|
-
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
44484
|
-
}
|
|
44485
44774
|
maybeAppendRuntimeRecoveryMessage(runtime) {
|
|
44486
44775
|
if (!runtime?.restoredFromStorage || !runtime.runtimeId) return;
|
|
44487
44776
|
const recoveryState = String(runtime.recoveryState || "").trim();
|
|
@@ -44542,81 +44831,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
44542
44831
|
}
|
|
44543
44832
|
}
|
|
44544
44833
|
mergeRuntimeChatMessages(parsedMessages) {
|
|
44545
|
-
return this.
|
|
44546
|
-
}
|
|
44547
|
-
mergeConversationMessages(parsedMessages) {
|
|
44548
|
-
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
44549
|
-
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
44550
|
-
message,
|
|
44551
|
-
index,
|
|
44552
|
-
source: "parsed"
|
|
44553
|
-
}));
|
|
44554
|
-
const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
44555
|
-
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
44556
|
-
message: entry.message,
|
|
44557
|
-
index: parsedMessages.length + index,
|
|
44558
|
-
source: "runtime",
|
|
44559
|
-
runtimeKey: entry.key
|
|
44560
|
-
})).filter((entry) => {
|
|
44561
|
-
const meta = entry.message.meta && typeof entry.message.meta === "object" && !Array.isArray(entry.message.meta) ? entry.message.meta : {};
|
|
44562
|
-
if (meta.runtimeInputAck !== true) return true;
|
|
44563
|
-
const runtimeText = flattenContent(entry.message.content).replace(/\s+/g, " ").trim();
|
|
44564
|
-
if (!runtimeText) return false;
|
|
44565
|
-
return !parsedEntries.some((parsedEntry) => {
|
|
44566
|
-
const parsedRole = getRole(parsedEntry.message);
|
|
44567
|
-
if (parsedRole !== "user" && parsedRole !== "human") return false;
|
|
44568
|
-
const parsedText = flattenContent(parsedEntry.message.content).replace(/\s+/g, " ").trim();
|
|
44569
|
-
return parsedText === runtimeText;
|
|
44570
|
-
});
|
|
44571
|
-
});
|
|
44572
|
-
const getTime = (message) => {
|
|
44573
|
-
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
44574
|
-
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
44575
|
-
};
|
|
44576
|
-
const isRuntimeOverlay = (entry) => {
|
|
44577
|
-
if (entry.source !== "runtime") return false;
|
|
44578
|
-
const key2 = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
|
|
44579
|
-
if (key2.startsWith("auto_approval:")) return true;
|
|
44580
|
-
return !isUserFacingChatMessage(entry.message);
|
|
44581
|
-
};
|
|
44582
|
-
const shouldKeepParsedBeforeUntimedRuntime = (message) => {
|
|
44583
|
-
const role = getRole(message);
|
|
44584
|
-
return role === "user" || role === "human";
|
|
44585
|
-
};
|
|
44586
|
-
const shouldKeepParsedAfterUntimedRuntime = (message) => {
|
|
44587
|
-
const role = getRole(message);
|
|
44588
|
-
if (role !== "assistant") return false;
|
|
44589
|
-
const kind = resolveChatMessageKind(message);
|
|
44590
|
-
return kind === "standard" || kind === "terminal";
|
|
44591
|
-
};
|
|
44592
|
-
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
44593
|
-
const aTime = getTime(a.message);
|
|
44594
|
-
const bTime = getTime(b.message);
|
|
44595
|
-
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
44596
|
-
if (a.source !== b.source && aTime !== bTime) {
|
|
44597
|
-
const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
|
|
44598
|
-
const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
|
|
44599
|
-
if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
|
|
44600
|
-
if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
|
|
44601
|
-
return a.source === "parsed" ? -1 : 1;
|
|
44602
|
-
}
|
|
44603
|
-
if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
|
|
44604
|
-
return a.source === "parsed" ? 1 : -1;
|
|
44605
|
-
}
|
|
44606
|
-
}
|
|
44607
|
-
}
|
|
44608
|
-
return a.index - b.index;
|
|
44609
|
-
}).map((entry) => entry.message));
|
|
44610
|
-
}
|
|
44611
|
-
formatApprovalRequestMessage(modalMessage, buttons) {
|
|
44612
|
-
const lines = ["Approval requested"];
|
|
44613
|
-
const cleanMessage = String(modalMessage || "").trim();
|
|
44614
|
-
if (cleanMessage) lines.push(cleanMessage);
|
|
44615
|
-
const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
|
|
44616
|
-
if (labels.length > 0) {
|
|
44617
|
-
lines.push(labels.map((label) => `[${label}]`).join(" "));
|
|
44618
|
-
}
|
|
44619
|
-
return lines.join("\n");
|
|
44834
|
+
return mergeConversationMessages(this.runtimeMessages, parsedMessages);
|
|
44620
44835
|
}
|
|
44621
44836
|
promoteProviderSessionId(sessionId, opts = {}) {
|
|
44622
44837
|
const nextSessionId = String(sessionId || "").trim();
|
|
@@ -68322,6 +68537,8 @@ export {
|
|
|
68322
68537
|
AcpProviderInstance,
|
|
68323
68538
|
AgentStreamPoller,
|
|
68324
68539
|
BUILTIN_CHAT_MESSAGE_KINDS,
|
|
68540
|
+
CANONICAL_MESH_TOOL_COUNT,
|
|
68541
|
+
CANONICAL_MESH_TOOL_NAMES,
|
|
68325
68542
|
CHANGE_IMPACT_CONFIG_LOCATIONS,
|
|
68326
68543
|
CHANGE_IMPACT_CONFIG_SCHEMA,
|
|
68327
68544
|
CHAT_MESSAGE_ACTIVITY_SOURCES,
|
|
@@ -68379,11 +68596,13 @@ export {
|
|
|
68379
68596
|
MESH_REFINE_CONFIG_LOCATIONS,
|
|
68380
68597
|
MESH_REFINE_CONFIG_SCHEMA,
|
|
68381
68598
|
MESH_SCHEDULING_STRATEGIES,
|
|
68599
|
+
MESH_TASK_PRIORITIES,
|
|
68382
68600
|
MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS,
|
|
68383
68601
|
MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA,
|
|
68384
68602
|
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
68385
68603
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
68386
68604
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
68605
|
+
NOT_BEFORE_RELATIVE_THRESHOLD_MS,
|
|
68387
68606
|
NodePtyTransportFactory,
|
|
68388
68607
|
OPERATING_NOTE_DEDUPE_WINDOW,
|
|
68389
68608
|
OPERATING_NOTE_KEEP_LATEST,
|
|
@@ -68531,7 +68750,6 @@ export {
|
|
|
68531
68750
|
getQueue,
|
|
68532
68751
|
getRecentActivity,
|
|
68533
68752
|
getRecentCommands,
|
|
68534
|
-
getRecentCompletionConflicts,
|
|
68535
68753
|
getRecentDebugTrace,
|
|
68536
68754
|
getRecentLogs,
|
|
68537
68755
|
getSavedProviderSessions,
|
|
@@ -68595,6 +68813,8 @@ export {
|
|
|
68595
68813
|
maybeRunDaemonUpgradeHelperFromEnv,
|
|
68596
68814
|
mergeAndNormalizePolicy,
|
|
68597
68815
|
meshNodeIdMatches,
|
|
68816
|
+
meshTaskNotBeforeReady,
|
|
68817
|
+
meshTaskPriorityRank,
|
|
68598
68818
|
namedKeyToAnsi,
|
|
68599
68819
|
namedKeysToAnsi,
|
|
68600
68820
|
nodeSatisfiesRequiredTags,
|
|
@@ -68617,6 +68837,7 @@ export {
|
|
|
68617
68837
|
normalizeMeshNodeId,
|
|
68618
68838
|
normalizeMeshSchedulingStrategy,
|
|
68619
68839
|
normalizeMeshTaskMode,
|
|
68840
|
+
normalizeMeshTaskPriority,
|
|
68620
68841
|
normalizeMeshWorkerResult,
|
|
68621
68842
|
normalizeMessageParts,
|
|
68622
68843
|
normalizeRepoIdentity,
|
|
@@ -68645,7 +68866,6 @@ export {
|
|
|
68645
68866
|
readOperatingNotes,
|
|
68646
68867
|
readV2EnvelopeFromWire,
|
|
68647
68868
|
reconcileDirectDispatchCompletionFromTranscript,
|
|
68648
|
-
recordCompletionConflict,
|
|
68649
68869
|
recordDebugTrace,
|
|
68650
68870
|
recordDirectDispatchTask,
|
|
68651
68871
|
recordMeshToolCall,
|
|
@@ -68655,6 +68875,7 @@ export {
|
|
|
68655
68875
|
removeMagiPanel,
|
|
68656
68876
|
removeNode,
|
|
68657
68877
|
removeWorktree,
|
|
68878
|
+
requeueHeldMeshCoordinatorEvents,
|
|
68658
68879
|
requeueTask,
|
|
68659
68880
|
requireMeshHostQueueOwner,
|
|
68660
68881
|
resetConfig,
|
|
@@ -68675,6 +68896,7 @@ export {
|
|
|
68675
68896
|
resolveMeshRefineValidationPlan,
|
|
68676
68897
|
resolveMeshSurfacedSessionPreview,
|
|
68677
68898
|
resolveNodeSchedulingPriority,
|
|
68899
|
+
resolveNotBefore,
|
|
68678
68900
|
resolveProviderMaxParallel,
|
|
68679
68901
|
resolveSessionHostAppName,
|
|
68680
68902
|
resolveSessionHostAppNameResolution,
|