@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.js
CHANGED
|
@@ -409,10 +409,10 @@ function readInjected(value) {
|
|
|
409
409
|
}
|
|
410
410
|
function getDaemonBuildInfo() {
|
|
411
411
|
if (cached) return cached;
|
|
412
|
-
const commit = readInjected(true ? "
|
|
413
|
-
const commitShort = readInjected(true ? "
|
|
414
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
415
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
412
|
+
const commit = readInjected(true ? "7e34ff6bc7c6528fca49478a57e0a83620f3a063" : void 0) ?? "unknown";
|
|
413
|
+
const commitShort = readInjected(true ? "7e34ff6b" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
414
|
+
const version = readInjected(true ? "0.9.82-rc.469" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
415
|
+
const builtAt = readInjected(true ? "2026-07-05T12:18:38.077Z" : void 0);
|
|
416
416
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
417
417
|
return cached;
|
|
418
418
|
}
|
|
@@ -2771,12 +2771,57 @@ function summarizeGitShape(status) {
|
|
|
2771
2771
|
submodules
|
|
2772
2772
|
};
|
|
2773
2773
|
}
|
|
2774
|
-
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP;
|
|
2774
|
+
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP, CANONICAL_MESH_TOOL_NAMES, CANONICAL_MESH_TOOL_COUNT;
|
|
2775
2775
|
var init_dist = __esm({
|
|
2776
2776
|
"../mesh-shared/dist/index.mjs"() {
|
|
2777
2777
|
"use strict";
|
|
2778
2778
|
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
2779
2779
|
MAGI_RAW_ANSWER_CAP = 4e3;
|
|
2780
|
+
CANONICAL_MESH_TOOL_NAMES = [
|
|
2781
|
+
"mesh_status",
|
|
2782
|
+
"mesh_list_nodes",
|
|
2783
|
+
"mesh_enqueue_task",
|
|
2784
|
+
"mesh_view_queue",
|
|
2785
|
+
"mesh_queue_cancel",
|
|
2786
|
+
"mesh_queue_requeue",
|
|
2787
|
+
"mesh_send_task",
|
|
2788
|
+
"mesh_read_chat",
|
|
2789
|
+
"mesh_read_debug",
|
|
2790
|
+
"mesh_launch_session",
|
|
2791
|
+
"mesh_git_status",
|
|
2792
|
+
"mesh_read_node_logs",
|
|
2793
|
+
"mesh_fast_forward_node",
|
|
2794
|
+
"mesh_restart_daemon",
|
|
2795
|
+
"mesh_checkpoint",
|
|
2796
|
+
"mesh_approve",
|
|
2797
|
+
"mesh_clone_node",
|
|
2798
|
+
"mesh_remove_node",
|
|
2799
|
+
"mesh_refine_node",
|
|
2800
|
+
"mesh_refine_batch",
|
|
2801
|
+
"mesh_refine_config",
|
|
2802
|
+
"mesh_change_impact_config",
|
|
2803
|
+
"mesh_init",
|
|
2804
|
+
"mesh_reinit",
|
|
2805
|
+
"mesh_write_mesh_json_config",
|
|
2806
|
+
"mesh_refine_plan",
|
|
2807
|
+
"mesh_cleanup_sessions",
|
|
2808
|
+
"mesh_prune_stale_direct",
|
|
2809
|
+
"mesh_task_history",
|
|
2810
|
+
"mesh_record_note",
|
|
2811
|
+
"mesh_forget_note",
|
|
2812
|
+
"mesh_reconcile_ledger",
|
|
2813
|
+
"mesh_requeue_held_events",
|
|
2814
|
+
"mesh_mission_upsert",
|
|
2815
|
+
"mesh_mission_list",
|
|
2816
|
+
"mesh_review_inbox",
|
|
2817
|
+
"mesh_magi_review",
|
|
2818
|
+
"mesh_magi_collect",
|
|
2819
|
+
"mesh_magi_panel_set",
|
|
2820
|
+
"mesh_magi_panel_list",
|
|
2821
|
+
"mesh_magi_kind_panel_set",
|
|
2822
|
+
"mesh_magi_kind_panel_list"
|
|
2823
|
+
];
|
|
2824
|
+
CANONICAL_MESH_TOOL_COUNT = CANONICAL_MESH_TOOL_NAMES.length;
|
|
2780
2825
|
}
|
|
2781
2826
|
});
|
|
2782
2827
|
|
|
@@ -3798,24 +3843,39 @@ var init_coordinator_prompt = __esm({
|
|
|
3798
3843
|
| \`mesh_queue_cancel\` | Cancel a queue task without deleting audit history |
|
|
3799
3844
|
| \`mesh_queue_requeue\` | Return a task to pending for retry; clears stale session targets |
|
|
3800
3845
|
| \`mesh_send_task\` | Legacy push: enqueue a task targeted at a specific node |
|
|
3846
|
+
| \`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 |
|
|
3847
|
+
| \`mesh_mission_list\` | List every mission with goal, status, and live task progress \u2014 the authority for "what work remains" (never hidden by status) |
|
|
3801
3848
|
| \`mesh_launch_session\` | Start a new agent session on a node |
|
|
3802
3849
|
| \`mesh_read_chat\` | Read recent chat messages from a delegated agent session |
|
|
3803
3850
|
| \`mesh_read_debug\` | Collect a daemon-side chat/parser debug bundle for a session |
|
|
3804
3851
|
| \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
|
|
3852
|
+
| \`mesh_reconcile_ledger\` | Reconcile daemon-local ledgers over P2P \u2014 import missing entries from remote nodes into the coordinator local ledger |
|
|
3853
|
+
| \`mesh_requeue_held_events\` | Restore recoverable held coordinator events (T6 quarantine / pending-trim) back to the pending queue; lossless, no double-requeue |
|
|
3854
|
+
| \`mesh_review_inbox\` | List local worktree nodes needing human review \u2014 merge candidates and Refinery-blocked results with evidence/diff summaries |
|
|
3805
3855
|
| \`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 |
|
|
3806
3856
|
| \`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) |
|
|
3807
3857
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
3808
3858
|
| \`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 |
|
|
3809
3859
|
| \`mesh_fast_forward_node\` | Safely dry-run or explicitly execute an obvious clean fast-forward without launching an agent session |
|
|
3860
|
+
| \`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) |
|
|
3810
3861
|
| \`mesh_checkpoint\` | Create a git checkpoint on a node |
|
|
3811
3862
|
| \`mesh_approve\` | Approve/reject a pending agent action |
|
|
3812
3863
|
| \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
|
|
3813
3864
|
| \`mesh_refine_node\` | Validate and merge a completed worktree node back into its base branch |
|
|
3865
|
+
| \`mesh_refine_batch\` | Batch Refinery: converge multiple sibling worktree nodes onto the base branch in one conflict-aware sequential pipeline |
|
|
3866
|
+
| \`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 |
|
|
3867
|
+
| \`mesh_refine_config\` | Refinery config helper (read-only) \u2014 unified entry for schema/validate/suggest via a required \`mode\` |
|
|
3868
|
+
| \`mesh_change_impact_config\` | Change Impact config helper \u2014 unified entry for schema/validate/suggest via a required \`mode\` |
|
|
3814
3869
|
| \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |
|
|
3815
3870
|
| \`mesh_cleanup_sessions\` | Manually clean up delegated session records for a node |
|
|
3871
|
+
| \`mesh_prune_stale_direct\` | Prune orphaned staleDirect dispatch records (dry-run by default); live/pending work and audit history preserved |
|
|
3816
3872
|
| \`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 |
|
|
3817
3873
|
| \`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 |
|
|
3818
3874
|
| \`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 |
|
|
3875
|
+
| \`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 |
|
|
3876
|
+
| \`mesh_magi_collect\` | Collect + synthesize a previously dispatched MAGI fan-out by its consensus group id (async companion to mesh_magi_review wait:false) |
|
|
3877
|
+
| \`mesh_magi_panel_set\` | Upsert a named MAGI panel (standing set of independent node\xD7provider members) into machine-local config |
|
|
3878
|
+
| \`mesh_magi_panel_list\` | List configured MAGI panels and resolve each member's availability against the current mesh (read-only) |
|
|
3819
3879
|
| \`mesh_magi_kind_panel_set\` | Bind a task_kind \u2192 MAGI kind-panel slots (machine-local, wholesale replacement \u2014 approve current-vs-new first) |
|
|
3820
3880
|
| \`mesh_magi_kind_panel_list\` | List configured task_kind \u2192 MAGI kind-panel slot bindings (machine-local, read-only) |`;
|
|
3821
3881
|
TOOL_EXPOSURE_PREFLIGHT_SECTION = `## Tool Exposure Preflight
|
|
@@ -5273,29 +5333,6 @@ function getActiveSessionDeliveries(meshId, sessionId) {
|
|
|
5273
5333
|
return [];
|
|
5274
5334
|
}
|
|
5275
5335
|
}
|
|
5276
|
-
function recordCompletionConflict(opts) {
|
|
5277
|
-
try {
|
|
5278
|
-
MeshRuntimeStore.getInstance().recordCompletionConflict({
|
|
5279
|
-
id: (0, import_crypto5.randomUUID)(),
|
|
5280
|
-
meshId: opts.meshId,
|
|
5281
|
-
fingerprint: opts.fingerprint,
|
|
5282
|
-
conflictingTaskId: opts.conflictingTaskId,
|
|
5283
|
-
conflictingSessionId: opts.conflictingSessionId,
|
|
5284
|
-
originalTaskId: opts.originalTaskId,
|
|
5285
|
-
originalSessionId: opts.originalSessionId,
|
|
5286
|
-
event: opts.event,
|
|
5287
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5288
|
-
});
|
|
5289
|
-
} catch {
|
|
5290
|
-
}
|
|
5291
|
-
}
|
|
5292
|
-
function getRecentCompletionConflicts(meshId, limitMs) {
|
|
5293
|
-
try {
|
|
5294
|
-
return MeshRuntimeStore.getInstance().getRecentCompletionConflicts(meshId, limitMs);
|
|
5295
|
-
} catch {
|
|
5296
|
-
return [];
|
|
5297
|
-
}
|
|
5298
|
-
}
|
|
5299
5336
|
function markSessionDeliveriesTerminal(meshId, sessionId, terminalStatus) {
|
|
5300
5337
|
try {
|
|
5301
5338
|
const active = MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
|
|
@@ -5370,6 +5407,8 @@ __export(mesh_work_queue_exports, {
|
|
|
5370
5407
|
ACTIVE_MESH_QUEUE_STATUSES: () => ACTIVE_MESH_QUEUE_STATUSES,
|
|
5371
5408
|
HISTORICAL_MESH_QUEUE_STATUSES: () => HISTORICAL_MESH_QUEUE_STATUSES,
|
|
5372
5409
|
MESH_TASK_MODES: () => MESH_TASK_MODES,
|
|
5410
|
+
MESH_TASK_PRIORITIES: () => MESH_TASK_PRIORITIES,
|
|
5411
|
+
NOT_BEFORE_RELATIVE_THRESHOLD_MS: () => NOT_BEFORE_RELATIVE_THRESHOLD_MS,
|
|
5373
5412
|
__clearDirectDispatchesForTests: () => __clearDirectDispatchesForTests,
|
|
5374
5413
|
__clearMeshQueueForTests: () => __clearMeshQueueForTests,
|
|
5375
5414
|
__replaceMeshQueueForTests: () => __replaceMeshQueueForTests,
|
|
@@ -5390,21 +5429,60 @@ __export(mesh_work_queue_exports, {
|
|
|
5390
5429
|
insertDirectDispatch: () => insertDirectDispatch,
|
|
5391
5430
|
isTaskReadonly: () => isTaskReadonly,
|
|
5392
5431
|
markStaleDirectDispatches: () => markStaleDirectDispatches,
|
|
5432
|
+
meshTaskNotBeforeReady: () => meshTaskNotBeforeReady,
|
|
5433
|
+
meshTaskPriorityRank: () => meshTaskPriorityRank,
|
|
5393
5434
|
nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
|
|
5394
5435
|
normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
|
|
5395
5436
|
normalizeMeshTaskMode: () => normalizeMeshTaskMode,
|
|
5437
|
+
normalizeMeshTaskPriority: () => normalizeMeshTaskPriority,
|
|
5396
5438
|
reclaimStrandedAssignedTask: () => reclaimStrandedAssignedTask,
|
|
5397
5439
|
recordDirectDispatchTask: () => recordDirectDispatchTask,
|
|
5398
5440
|
recordMeshToolCall: () => recordMeshToolCall,
|
|
5399
5441
|
recordTaskAutoLaunch: () => recordTaskAutoLaunch,
|
|
5400
5442
|
requeueTask: () => requeueTask,
|
|
5401
5443
|
resolveConvergeRequiredTags: () => resolveConvergeRequiredTags,
|
|
5444
|
+
resolveNotBefore: () => resolveNotBefore,
|
|
5402
5445
|
taskDependenciesSatisfied: () => taskDependenciesSatisfied,
|
|
5403
5446
|
updateDirectDispatchStatus: () => updateDirectDispatchStatus,
|
|
5404
5447
|
updateSessionTaskStatus: () => updateSessionTaskStatus,
|
|
5405
5448
|
updateTaskStatus: () => updateTaskStatus,
|
|
5406
5449
|
validateMeshTaskModeRequest: () => validateMeshTaskModeRequest
|
|
5407
5450
|
});
|
|
5451
|
+
function meshTaskPriorityRank(priority) {
|
|
5452
|
+
switch (priority) {
|
|
5453
|
+
case "high":
|
|
5454
|
+
return 2;
|
|
5455
|
+
case "low":
|
|
5456
|
+
return 0;
|
|
5457
|
+
default:
|
|
5458
|
+
return 1;
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
function normalizeMeshTaskPriority(value) {
|
|
5462
|
+
return value === "low" || value === "normal" || value === "high" ? value : void 0;
|
|
5463
|
+
}
|
|
5464
|
+
function resolveNotBefore(value, nowMs = Date.now()) {
|
|
5465
|
+
if (value === void 0 || value === null) return void 0;
|
|
5466
|
+
let absMs;
|
|
5467
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
5468
|
+
absMs = value < NOT_BEFORE_RELATIVE_THRESHOLD_MS ? nowMs + value : value;
|
|
5469
|
+
} else if (typeof value === "string" && value.trim()) {
|
|
5470
|
+
const parsed = Date.parse(value.trim());
|
|
5471
|
+
if (Number.isNaN(parsed)) return void 0;
|
|
5472
|
+
absMs = parsed;
|
|
5473
|
+
} else {
|
|
5474
|
+
return void 0;
|
|
5475
|
+
}
|
|
5476
|
+
if (absMs <= nowMs) return new Date(nowMs).toISOString();
|
|
5477
|
+
return new Date(absMs).toISOString();
|
|
5478
|
+
}
|
|
5479
|
+
function meshTaskNotBeforeReady(task, nowMs = Date.now()) {
|
|
5480
|
+
const nb = task?.notBefore;
|
|
5481
|
+
if (!nb) return true;
|
|
5482
|
+
const parsed = Date.parse(nb);
|
|
5483
|
+
if (Number.isNaN(parsed)) return true;
|
|
5484
|
+
return parsed <= nowMs;
|
|
5485
|
+
}
|
|
5408
5486
|
function isTaskReadonly(task) {
|
|
5409
5487
|
if (!task) return false;
|
|
5410
5488
|
return task.readonly === true || task.taskMode === "live_debug_readonly";
|
|
@@ -5732,6 +5810,9 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5732
5810
|
}
|
|
5733
5811
|
const id = typeof opts?.id === "string" && opts.id.trim() ? opts.id.trim() : (0, import_crypto6.randomUUID)();
|
|
5734
5812
|
const dependsOn = normalizeDependsOn(opts?.dependsOn);
|
|
5813
|
+
const priority = normalizeMeshTaskPriority(opts?.priority);
|
|
5814
|
+
const notBefore = resolveNotBefore(opts?.notBefore);
|
|
5815
|
+
const maxRetries = typeof opts?.maxRetries === "number" && Number.isFinite(opts.maxRetries) && opts.maxRetries >= 0 ? Math.floor(opts.maxRetries) : void 0;
|
|
5735
5816
|
return withQueueLock(meshId, () => {
|
|
5736
5817
|
if (MeshRuntimeStore.getInstance().findQueueEntryById(meshId, id)) {
|
|
5737
5818
|
throw new Error(`duplicate_task_id: task '${id}' already exists in mesh '${meshId}'`);
|
|
@@ -5755,6 +5836,12 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5755
5836
|
targetSessionId: opts?.targetSessionId,
|
|
5756
5837
|
requiredTags: resolvedRequiredTags,
|
|
5757
5838
|
...dependsOn.length > 0 ? { dependsOn } : {},
|
|
5839
|
+
// G6: only persist a non-default priority so legacy/normal rows stay minimal.
|
|
5840
|
+
...priority && priority !== "normal" ? { priority } : {},
|
|
5841
|
+
// G7: hold-until gate (stored ISO). Omitted when absent/immediate.
|
|
5842
|
+
...notBefore ? { notBefore } : {},
|
|
5843
|
+
// P3: explicit retry cap. Omitted → requeue path falls back to policy default.
|
|
5844
|
+
...maxRetries !== void 0 ? { maxRetries } : {},
|
|
5758
5845
|
...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
|
|
5759
5846
|
...typeof opts?.consensusGroupId === "string" && opts.consensusGroupId.trim() ? { consensusGroupId: opts.consensusGroupId.trim() } : {},
|
|
5760
5847
|
...typeof opts?.model === "string" && opts.model.trim() ? { model: opts.model.trim() } : {},
|
|
@@ -6095,7 +6182,7 @@ function recordMeshToolCall(opts) {
|
|
|
6095
6182
|
return { rateLimitExceeded: false, callsInWindow: 0, advisory: null };
|
|
6096
6183
|
}
|
|
6097
6184
|
}
|
|
6098
|
-
var import_crypto6, 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;
|
|
6185
|
+
var import_crypto6, 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;
|
|
6099
6186
|
var init_mesh_work_queue = __esm({
|
|
6100
6187
|
"src/mesh/mesh-work-queue.ts"() {
|
|
6101
6188
|
"use strict";
|
|
@@ -6112,6 +6199,8 @@ var init_mesh_work_queue = __esm({
|
|
|
6112
6199
|
ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
|
|
6113
6200
|
HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
|
|
6114
6201
|
MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
|
|
6202
|
+
MESH_TASK_PRIORITIES = ["low", "normal", "high"];
|
|
6203
|
+
NOT_BEFORE_RELATIVE_THRESHOLD_MS = 365 * 24 * 60 * 60 * 1e3;
|
|
6115
6204
|
LIVE_DEBUG_READONLY_FORBIDDEN = [
|
|
6116
6205
|
{ 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 },
|
|
6117
6206
|
{ label: "checkpoint", pattern: /\b(checkpoint|mesh_checkpoint)\b/i },
|
|
@@ -6177,9 +6266,28 @@ function safeMeshId(meshId) {
|
|
|
6177
6266
|
function legacyQueuePath(meshId) {
|
|
6178
6267
|
return (0, import_path5.join)(getLedgerDir(), `${safeMeshId(meshId)}.queue.json`);
|
|
6179
6268
|
}
|
|
6269
|
+
function cleanupStrayRootRuntimeDb(canonicalPath) {
|
|
6270
|
+
try {
|
|
6271
|
+
const strayPath = (0, import_path5.join)(getConfigDir(), "mesh-runtime.db");
|
|
6272
|
+
if (strayPath === canonicalPath) return;
|
|
6273
|
+
if (!(0, import_fs5.existsSync)(strayPath)) return;
|
|
6274
|
+
if ((0, import_fs5.statSync)(strayPath).size !== 0) return;
|
|
6275
|
+
(0, import_fs5.unlinkSync)(strayPath);
|
|
6276
|
+
if (!loggedStrayCleanup) {
|
|
6277
|
+
loggedStrayCleanup = true;
|
|
6278
|
+
LOG.info("MeshRuntimeStore", `Removed stray 0-byte root mesh-runtime.db at ${strayPath}`);
|
|
6279
|
+
}
|
|
6280
|
+
} catch (err) {
|
|
6281
|
+
if (!loggedStrayCleanup) {
|
|
6282
|
+
loggedStrayCleanup = true;
|
|
6283
|
+
LOG.warn("MeshRuntimeStore", `Stray root mesh-runtime.db cleanup failed (ignored): ${err?.message || err}`);
|
|
6284
|
+
}
|
|
6285
|
+
}
|
|
6286
|
+
}
|
|
6180
6287
|
function meshRuntimeStorePath() {
|
|
6181
6288
|
const dir = getLedgerDir();
|
|
6182
6289
|
const nextPath = (0, import_path5.join)(dir, "mesh-runtime.db");
|
|
6290
|
+
cleanupStrayRootRuntimeDb(nextPath);
|
|
6183
6291
|
if ((0, import_fs5.existsSync)(nextPath)) return nextPath;
|
|
6184
6292
|
const legacyPath = (0, import_path5.join)(dir, "beads.db");
|
|
6185
6293
|
if (!(0, import_fs5.existsSync)(legacyPath)) return nextPath;
|
|
@@ -6203,7 +6311,7 @@ function meshRuntimeStorePath() {
|
|
|
6203
6311
|
}
|
|
6204
6312
|
return nextPath;
|
|
6205
6313
|
}
|
|
6206
|
-
var import_fs5, import_path5, DatabaseCtor, loggedMigrationFailure, MeshRuntimeStore;
|
|
6314
|
+
var import_fs5, import_path5, DatabaseCtor, loggedMigrationFailure, loggedStrayCleanup, MeshRuntimeStore;
|
|
6207
6315
|
var init_mesh_runtime_store = __esm({
|
|
6208
6316
|
"src/mesh/mesh-runtime-store.ts"() {
|
|
6209
6317
|
"use strict";
|
|
@@ -6211,10 +6319,12 @@ var init_mesh_runtime_store = __esm({
|
|
|
6211
6319
|
import_path5 = require("path");
|
|
6212
6320
|
init_logger();
|
|
6213
6321
|
init_load_better_sqlite3();
|
|
6322
|
+
init_config();
|
|
6214
6323
|
init_mesh_ledger();
|
|
6215
6324
|
init_mesh_work_queue();
|
|
6216
6325
|
init_dist();
|
|
6217
6326
|
loggedMigrationFailure = false;
|
|
6327
|
+
loggedStrayCleanup = false;
|
|
6218
6328
|
MeshRuntimeStore = class _MeshRuntimeStore {
|
|
6219
6329
|
static instance;
|
|
6220
6330
|
db;
|
|
@@ -6363,20 +6473,9 @@ var init_mesh_runtime_store = __esm({
|
|
|
6363
6473
|
CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_task
|
|
6364
6474
|
ON mesh_session_delivery(mesh_id, task_id);
|
|
6365
6475
|
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
fingerprint TEXT NOT NULL,
|
|
6370
|
-
conflicting_task_id TEXT,
|
|
6371
|
-
conflicting_session_id TEXT,
|
|
6372
|
-
original_task_id TEXT,
|
|
6373
|
-
original_session_id TEXT,
|
|
6374
|
-
event TEXT NOT NULL,
|
|
6375
|
-
created_at TEXT NOT NULL
|
|
6376
|
-
);
|
|
6377
|
-
|
|
6378
|
-
CREATE INDEX IF NOT EXISTS idx_mesh_completion_conflicts_mesh
|
|
6379
|
-
ON mesh_completion_conflicts(mesh_id, created_at);
|
|
6476
|
+
-- MESH-COMPLEXITY-AUDIT Part 8-2: mesh_completion_conflicts removed
|
|
6477
|
+
-- (write-only fingerprint-collision diagnostic, no production reader,
|
|
6478
|
+
-- no no-loss role). Dropped in migrateMeshIsolationColumns step 6.
|
|
6380
6479
|
|
|
6381
6480
|
CREATE TABLE IF NOT EXISTS mesh_tool_call_log (
|
|
6382
6481
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -6557,6 +6656,8 @@ var init_mesh_runtime_store = __esm({
|
|
|
6557
6656
|
ON mesh_pending_events(mesh_id, event_id)
|
|
6558
6657
|
WHERE event_id IS NOT NULL
|
|
6559
6658
|
`);
|
|
6659
|
+
this.db.exec(`DROP TABLE IF EXISTS mesh_direct_delivered_events`);
|
|
6660
|
+
this.db.exec(`DROP TABLE IF EXISTS mesh_completion_conflicts`);
|
|
6560
6661
|
} catch (err) {
|
|
6561
6662
|
if (!loggedMigrationFailure) {
|
|
6562
6663
|
loggedMigrationFailure = true;
|
|
@@ -6866,24 +6967,27 @@ var init_mesh_runtime_store = __esm({
|
|
|
6866
6967
|
}
|
|
6867
6968
|
const nodeIdForms = expandDaemonIdForms(nodeId);
|
|
6868
6969
|
const nodePinnedPlaceholders = nodeIdForms.map(() => "?").join(", ");
|
|
6869
|
-
const
|
|
6870
|
-
|
|
6970
|
+
const parseTier = (query, ...params) => {
|
|
6971
|
+
const tierRows = this.db.prepare(query).all(...params);
|
|
6972
|
+
return tierRows.map((row) => JSON.parse(row.payload)).sort((a, b) => meshTaskPriorityRank(b.priority) - meshTaskPriorityRank(a.priority));
|
|
6973
|
+
};
|
|
6974
|
+
const candidates = [
|
|
6975
|
+
...parseTier(`
|
|
6871
6976
|
SELECT payload FROM mesh_queue
|
|
6872
6977
|
WHERE mesh_id = ? AND status = 'pending' AND target_session_id = ?
|
|
6873
6978
|
ORDER BY created_at ASC
|
|
6874
|
-
|
|
6875
|
-
...
|
|
6979
|
+
`, meshId, sessionId),
|
|
6980
|
+
...parseTier(`
|
|
6876
6981
|
SELECT payload FROM mesh_queue
|
|
6877
6982
|
WHERE mesh_id = ? AND status = 'pending' AND target_node_id IN (${nodePinnedPlaceholders}) AND target_session_id IS NULL
|
|
6878
6983
|
ORDER BY created_at ASC
|
|
6879
|
-
|
|
6880
|
-
...
|
|
6984
|
+
`, meshId, ...nodeIdForms),
|
|
6985
|
+
...parseTier(`
|
|
6881
6986
|
SELECT payload FROM mesh_queue
|
|
6882
6987
|
WHERE mesh_id = ? AND status = 'pending' AND target_node_id IS NULL AND target_session_id IS NULL
|
|
6883
6988
|
ORDER BY created_at ASC
|
|
6884
|
-
|
|
6989
|
+
`, meshId)
|
|
6885
6990
|
];
|
|
6886
|
-
const candidates = rows.map((row) => JSON.parse(row.payload));
|
|
6887
6991
|
const depIds = [...new Set(candidates.flatMap((c) => Array.isArray(c.dependsOn) ? c.dependsOn : []))];
|
|
6888
6992
|
const depStatus = /* @__PURE__ */ new Map();
|
|
6889
6993
|
if (depIds.length > 0) {
|
|
@@ -6898,6 +7002,8 @@ var init_mesh_runtime_store = __esm({
|
|
|
6898
7002
|
if (isTaskReadonly(candidate)) return true;
|
|
6899
7003
|
return !nodeBusy;
|
|
6900
7004
|
};
|
|
7005
|
+
const claimNowMs = Date.now();
|
|
7006
|
+
const notBeforeReady = (candidate) => meshTaskNotBeforeReady(candidate, claimNowMs);
|
|
6901
7007
|
const nodeIsWorktree = opts?.nodeIsWorktree === true;
|
|
6902
7008
|
const convergenceAllows = (candidate) => candidate.taskMode !== "convergence" || !nodeIsWorktree;
|
|
6903
7009
|
const targetMatches = (candidate) => {
|
|
@@ -6907,7 +7013,7 @@ var init_mesh_runtime_store = __esm({
|
|
|
6907
7013
|
}
|
|
6908
7014
|
return true;
|
|
6909
7015
|
};
|
|
6910
|
-
const entry = candidates.find((candidate) => nodeSatisfiesRequiredTags(candidate.requiredTags, capabilityTags) && dependenciesSatisfied(candidate) && convergenceAllows(candidate) && targetMatches(candidate) && nodeConflictAllows(candidate));
|
|
7016
|
+
const entry = candidates.find((candidate) => nodeSatisfiesRequiredTags(candidate.requiredTags, capabilityTags) && dependenciesSatisfied(candidate) && notBeforeReady(candidate) && convergenceAllows(candidate) && targetMatches(candidate) && nodeConflictAllows(candidate));
|
|
6911
7017
|
if (!entry) return null;
|
|
6912
7018
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6913
7019
|
entry.status = "assigned";
|
|
@@ -7267,43 +7373,11 @@ var init_mesh_runtime_store = __esm({
|
|
|
7267
7373
|
this.db.prepare("DELETE FROM mesh_session_delivery WHERE mesh_id = ?").run(meshId);
|
|
7268
7374
|
}
|
|
7269
7375
|
// ── Completion Conflict Diagnostics ──────────────────────────────────────
|
|
7270
|
-
recordCompletionConflict
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
VALUES (@id, @meshId, @fingerprint, @conflictingTaskId, @conflictingSessionId,
|
|
7276
|
-
@originalTaskId, @originalSessionId, @event, @createdAt)
|
|
7277
|
-
`).run({
|
|
7278
|
-
id: entry.id,
|
|
7279
|
-
meshId: entry.meshId,
|
|
7280
|
-
fingerprint: entry.fingerprint,
|
|
7281
|
-
conflictingTaskId: entry.conflictingTaskId ?? null,
|
|
7282
|
-
conflictingSessionId: entry.conflictingSessionId ?? null,
|
|
7283
|
-
originalTaskId: entry.originalTaskId ?? null,
|
|
7284
|
-
originalSessionId: entry.originalSessionId ?? null,
|
|
7285
|
-
event: entry.event,
|
|
7286
|
-
createdAt: entry.createdAt
|
|
7287
|
-
});
|
|
7288
|
-
this.maybeCheckpointWal();
|
|
7289
|
-
}
|
|
7290
|
-
getRecentCompletionConflicts(meshId, limitMs = 60 * 60 * 1e3) {
|
|
7291
|
-
const cutoff = new Date(Date.now() - limitMs).toISOString();
|
|
7292
|
-
const rows = this.db.prepare(
|
|
7293
|
-
"SELECT * FROM mesh_completion_conflicts WHERE mesh_id = ? AND created_at >= ? ORDER BY created_at DESC LIMIT 50"
|
|
7294
|
-
).all(meshId, cutoff);
|
|
7295
|
-
return rows.map((r) => ({
|
|
7296
|
-
id: r.id,
|
|
7297
|
-
meshId: r.mesh_id,
|
|
7298
|
-
fingerprint: r.fingerprint,
|
|
7299
|
-
conflictingTaskId: r.conflicting_task_id,
|
|
7300
|
-
conflictingSessionId: r.conflicting_session_id,
|
|
7301
|
-
originalTaskId: r.original_task_id,
|
|
7302
|
-
originalSessionId: r.original_session_id,
|
|
7303
|
-
event: r.event,
|
|
7304
|
-
createdAt: r.created_at
|
|
7305
|
-
}));
|
|
7306
|
-
}
|
|
7376
|
+
// MESH-COMPLEXITY-AUDIT Part 8-2: recordCompletionConflict /
|
|
7377
|
+
// getRecentCompletionConflicts (and their mesh_completion_conflicts table)
|
|
7378
|
+
// were removed. They were a write-only diagnostic of fingerprint-dedup
|
|
7379
|
+
// collisions with no production reader and no part in the no-loss delivery
|
|
7380
|
+
// contract; the table is dropped in migrateMeshIsolationColumns (step 6).
|
|
7307
7381
|
/**
|
|
7308
7382
|
* Record a mesh tool call and check whether this mesh+tool combination is
|
|
7309
7383
|
* being called too rapidly (sliding window rate guard).
|
|
@@ -11541,7 +11615,11 @@ function ledgerRecordQuarantinedEvent(event, reason) {
|
|
|
11541
11615
|
targetCoordinatorDaemonId: event.targetCoordinatorDaemonId ?? null,
|
|
11542
11616
|
...readNonEmptyString2(event.eventId) ? { eventId: event.eventId } : {},
|
|
11543
11617
|
queuedAt: event.queuedAt,
|
|
11544
|
-
...finalSummary ? { finalSummary } : {}
|
|
11618
|
+
...finalSummary ? { finalSummary } : {},
|
|
11619
|
+
// Full original event so mesh_requeue_held_events can restore it
|
|
11620
|
+
// losslessly (event_held→pending). The summary/label fields above stay
|
|
11621
|
+
// for human-readable audit; `heldEvent` is the machine recovery copy.
|
|
11622
|
+
heldEvent: event
|
|
11545
11623
|
}
|
|
11546
11624
|
});
|
|
11547
11625
|
} catch (e) {
|
|
@@ -11852,8 +11930,11 @@ function trimPendingEventsIfNeeded(path45) {
|
|
|
11852
11930
|
nodeLabel: event.nodeLabel,
|
|
11853
11931
|
...event.workspace ? { workspace: event.workspace } : {},
|
|
11854
11932
|
targetCoordinatorDaemonId: event.targetCoordinatorDaemonId ?? null,
|
|
11933
|
+
...readNonEmptyString2(event.eventId) ? { eventId: event.eventId } : {},
|
|
11855
11934
|
queuedAt: event.queuedAt,
|
|
11856
|
-
...finalSummary ? { finalSummary } : {}
|
|
11935
|
+
...finalSummary ? { finalSummary } : {},
|
|
11936
|
+
// Full original event for lossless mesh_requeue_held_events restore.
|
|
11937
|
+
heldEvent: event
|
|
11857
11938
|
}
|
|
11858
11939
|
});
|
|
11859
11940
|
LOG.warn("MeshEvents", `Pending-events trim dropping undelivered ${event.event} for mesh ${event.meshId} \u2014 recorded to ledger (recoverable)`);
|
|
@@ -12180,6 +12261,83 @@ function getPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId, opts) {
|
|
|
12180
12261
|
});
|
|
12181
12262
|
return reconcilePendingMeshCoordinatorEvents(meshId, routed);
|
|
12182
12263
|
}
|
|
12264
|
+
function readHeldTaskId(restored, payload) {
|
|
12265
|
+
const fromMeta = restored?.metadataEvent && typeof restored.metadataEvent === "object" ? readNonEmptyString2(restored.metadataEvent.taskId) : "";
|
|
12266
|
+
return fromMeta || readNonEmptyString2(payload.taskId) || "";
|
|
12267
|
+
}
|
|
12268
|
+
function requeueHeldMeshCoordinatorEvents(meshId, filter) {
|
|
12269
|
+
const result = {
|
|
12270
|
+
meshId,
|
|
12271
|
+
matched: 0,
|
|
12272
|
+
alreadyRequeued: 0,
|
|
12273
|
+
unrecoverable: 0,
|
|
12274
|
+
requeued: 0,
|
|
12275
|
+
dedupSuppressed: 0,
|
|
12276
|
+
entries: []
|
|
12277
|
+
};
|
|
12278
|
+
const all = readLedgerEntries(meshId);
|
|
12279
|
+
const requeuedIds = /* @__PURE__ */ new Set();
|
|
12280
|
+
for (const entry of all) {
|
|
12281
|
+
if (entry.kind !== "event_held_requeued") continue;
|
|
12282
|
+
const id = readNonEmptyString2(entry.payload?.heldEntryId);
|
|
12283
|
+
if (id) requeuedIds.add(id);
|
|
12284
|
+
}
|
|
12285
|
+
const sinceMs = filter?.since ? new Date(filter.since).getTime() : NaN;
|
|
12286
|
+
const wantEvent = readNonEmptyString2(filter?.event);
|
|
12287
|
+
const wantNode = readNonEmptyString2(filter?.nodeId);
|
|
12288
|
+
const wantTask = readNonEmptyString2(filter?.taskId);
|
|
12289
|
+
const wantReason = readNonEmptyString2(filter?.reason);
|
|
12290
|
+
for (const entry of all) {
|
|
12291
|
+
if (entry.kind !== "event_held") continue;
|
|
12292
|
+
const payload = entry.payload && typeof entry.payload === "object" ? entry.payload : {};
|
|
12293
|
+
if (payload.recoverable !== true) continue;
|
|
12294
|
+
const restored = payload.heldEvent && typeof payload.heldEvent === "object" ? { ...payload.heldEvent } : void 0;
|
|
12295
|
+
const eventName = restored?.event || readNonEmptyString2(payload.event);
|
|
12296
|
+
const nodeId = restored?.nodeId || entry.nodeId || readNonEmptyString2(payload.nodeId) || void 0;
|
|
12297
|
+
const taskId = readHeldTaskId(restored, payload);
|
|
12298
|
+
const reason = readNonEmptyString2(payload.reason) || void 0;
|
|
12299
|
+
if (wantEvent && eventName !== wantEvent) continue;
|
|
12300
|
+
if (wantNode && nodeId !== wantNode) continue;
|
|
12301
|
+
if (wantTask && taskId !== wantTask) continue;
|
|
12302
|
+
if (wantReason && reason !== wantReason) continue;
|
|
12303
|
+
if (filter?.since && !Number.isNaN(sinceMs) && new Date(entry.timestamp).getTime() < sinceMs) continue;
|
|
12304
|
+
result.matched++;
|
|
12305
|
+
if (requeuedIds.has(entry.id)) {
|
|
12306
|
+
result.alreadyRequeued++;
|
|
12307
|
+
result.entries.push({ heldEntryId: entry.id, event: eventName, ...nodeId ? { nodeId } : {}, ...taskId ? { taskId } : {}, ...reason ? { reason } : {}, outcome: "already_requeued" });
|
|
12308
|
+
continue;
|
|
12309
|
+
}
|
|
12310
|
+
if (!restored || !readNonEmptyString2(restored.event) || !readNonEmptyString2(restored.meshId)) {
|
|
12311
|
+
result.unrecoverable++;
|
|
12312
|
+
result.entries.push({ heldEntryId: entry.id, event: eventName, ...nodeId ? { nodeId } : {}, ...taskId ? { taskId } : {}, ...reason ? { reason } : {}, outcome: "unrecoverable" });
|
|
12313
|
+
continue;
|
|
12314
|
+
}
|
|
12315
|
+
const beforeDup = hasPendingCoordinatorEventDuplicate(restored);
|
|
12316
|
+
let ok = false;
|
|
12317
|
+
try {
|
|
12318
|
+
ok = queuePendingMeshCoordinatorEvent(restored);
|
|
12319
|
+
} catch (e) {
|
|
12320
|
+
LOG.warn("MeshEvents", `Requeue of held ${eventName} for mesh ${meshId} failed: ${e?.message || e}`);
|
|
12321
|
+
}
|
|
12322
|
+
appendLedgerEntry(meshId, {
|
|
12323
|
+
kind: "event_held_requeued",
|
|
12324
|
+
...nodeId ? { nodeId } : {},
|
|
12325
|
+
payload: {
|
|
12326
|
+
heldEntryId: entry.id,
|
|
12327
|
+
event: eventName,
|
|
12328
|
+
requeued: ok,
|
|
12329
|
+
...taskId ? { taskId } : {},
|
|
12330
|
+
...reason ? { reason } : {},
|
|
12331
|
+
...beforeDup ? { dedupSuppressed: true } : {}
|
|
12332
|
+
}
|
|
12333
|
+
});
|
|
12334
|
+
requeuedIds.add(entry.id);
|
|
12335
|
+
result.requeued++;
|
|
12336
|
+
if (beforeDup) result.dedupSuppressed++;
|
|
12337
|
+
result.entries.push({ heldEntryId: entry.id, event: eventName, ...nodeId ? { nodeId } : {}, ...taskId ? { taskId } : {}, ...reason ? { reason } : {}, outcome: "requeued" });
|
|
12338
|
+
}
|
|
12339
|
+
return result;
|
|
12340
|
+
}
|
|
12183
12341
|
function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
12184
12342
|
if (!meshId) return;
|
|
12185
12343
|
try {
|
|
@@ -14214,7 +14372,7 @@ function driveExpiredAwaitClaim(components, meshId, task, ctx) {
|
|
|
14214
14372
|
async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
14215
14373
|
const queue = getQueue(meshId);
|
|
14216
14374
|
const statusById = new Map(queue.map((task) => [task.id, task.status]));
|
|
14217
|
-
const pending = queue.filter((task) => task.status === "pending");
|
|
14375
|
+
const pending = queue.filter((task) => task.status === "pending").sort((a, b) => meshTaskPriorityRank(b.priority) - meshTaskPriorityRank(a.priority));
|
|
14218
14376
|
{
|
|
14219
14377
|
const pendingIds = new Set(pending.map((t) => t.id));
|
|
14220
14378
|
const prefix = `${meshId}::`;
|
|
@@ -14230,6 +14388,10 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
14230
14388
|
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "dependencies_unsatisfied" });
|
|
14231
14389
|
continue;
|
|
14232
14390
|
}
|
|
14391
|
+
if (!meshTaskNotBeforeReady(task)) {
|
|
14392
|
+
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "not_before_delayed" });
|
|
14393
|
+
continue;
|
|
14394
|
+
}
|
|
14233
14395
|
const isReadonly = isTaskReadonly(task);
|
|
14234
14396
|
if (isReadonly) {
|
|
14235
14397
|
if (activeReadonlyAssignedCount(meshId) >= maxReadonlyParallelTasks) {
|
|
@@ -17366,15 +17528,6 @@ function isDuplicateMeshCompletionEvent(args) {
|
|
|
17366
17528
|
const fingerprint = buildMeshCompletionFingerprint(args);
|
|
17367
17529
|
if (!fingerprint) return false;
|
|
17368
17530
|
if (hasFingerprintSeen(args.meshId, fingerprint)) {
|
|
17369
|
-
if (args.taskId) {
|
|
17370
|
-
recordCompletionConflict({
|
|
17371
|
-
meshId: args.meshId,
|
|
17372
|
-
fingerprint,
|
|
17373
|
-
conflictingTaskId: args.taskId,
|
|
17374
|
-
conflictingSessionId: args.sessionId,
|
|
17375
|
-
event: args.event
|
|
17376
|
-
});
|
|
17377
|
-
}
|
|
17378
17531
|
return true;
|
|
17379
17532
|
}
|
|
17380
17533
|
recordFingerprintSeen(args.meshId, fingerprint);
|
|
@@ -18452,6 +18605,347 @@ var init_mesh_reconcile_identity = __esm({
|
|
|
18452
18605
|
}
|
|
18453
18606
|
});
|
|
18454
18607
|
|
|
18608
|
+
// src/mesh/mesh-reconcile-acked-hold.ts
|
|
18609
|
+
function resolveTunedReconcileMs(envName, def, min, max) {
|
|
18610
|
+
const raw = readNonEmptyString2(process.env[envName]);
|
|
18611
|
+
if (raw) {
|
|
18612
|
+
const parsed = Number.parseInt(raw, 10);
|
|
18613
|
+
if (Number.isFinite(parsed) && parsed >= min && parsed <= max) return parsed;
|
|
18614
|
+
}
|
|
18615
|
+
return def;
|
|
18616
|
+
}
|
|
18617
|
+
function resolveAckedDeathDeadlineMs() {
|
|
18618
|
+
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
|
|
18619
|
+
}
|
|
18620
|
+
function resolveAckedTranscriptFastTrackGraceMs() {
|
|
18621
|
+
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
|
|
18622
|
+
}
|
|
18623
|
+
function inFlightSynthKey(meshId, taskId) {
|
|
18624
|
+
return `${meshId}::${taskId}`;
|
|
18625
|
+
}
|
|
18626
|
+
function taskIdFromSynthKey(meshId, synthKey) {
|
|
18627
|
+
const prefix = `${meshId}::`;
|
|
18628
|
+
return synthKey.startsWith(prefix) ? synthKey.slice(prefix.length) : synthKey;
|
|
18629
|
+
}
|
|
18630
|
+
function holdStore() {
|
|
18631
|
+
try {
|
|
18632
|
+
return MeshRuntimeStore.getInstance();
|
|
18633
|
+
} catch {
|
|
18634
|
+
return void 0;
|
|
18635
|
+
}
|
|
18636
|
+
}
|
|
18637
|
+
function getHoldState(synthKey, meshId) {
|
|
18638
|
+
const cached3 = inFlightAckedHoldState.get(synthKey);
|
|
18639
|
+
if (cached3) return cached3;
|
|
18640
|
+
const store = holdStore();
|
|
18641
|
+
if (!store) return void 0;
|
|
18642
|
+
let row;
|
|
18643
|
+
try {
|
|
18644
|
+
row = store.getInflightHold(taskIdFromSynthKey(meshId, synthKey));
|
|
18645
|
+
} catch {
|
|
18646
|
+
return void 0;
|
|
18647
|
+
}
|
|
18648
|
+
if (!row) return void 0;
|
|
18649
|
+
const state = {
|
|
18650
|
+
liveConfirmedSinceAck: row.holdReason === "live",
|
|
18651
|
+
consecutiveReadFailures: row.readFailureCount ?? 0,
|
|
18652
|
+
...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {}
|
|
18653
|
+
};
|
|
18654
|
+
inFlightAckedHoldState.set(synthKey, state);
|
|
18655
|
+
return state;
|
|
18656
|
+
}
|
|
18657
|
+
function setHoldState(synthKey, meshId, state) {
|
|
18658
|
+
inFlightAckedHoldState.set(synthKey, state);
|
|
18659
|
+
const store = holdStore();
|
|
18660
|
+
if (!store) return;
|
|
18661
|
+
try {
|
|
18662
|
+
store.upsertInflightHold({
|
|
18663
|
+
taskId: taskIdFromSynthKey(meshId, synthKey),
|
|
18664
|
+
meshId,
|
|
18665
|
+
holdReason: state.liveConfirmedSinceAck ? "live" : "unconfirmed",
|
|
18666
|
+
firstIdleSinceAck: state.transcriptIdleSinceMs ?? null,
|
|
18667
|
+
readFailureCount: state.consecutiveReadFailures
|
|
18668
|
+
});
|
|
18669
|
+
} catch {
|
|
18670
|
+
}
|
|
18671
|
+
}
|
|
18672
|
+
function deleteHoldState(synthKey, meshId) {
|
|
18673
|
+
inFlightAckedHoldState.delete(synthKey);
|
|
18674
|
+
const store = holdStore();
|
|
18675
|
+
if (!store) return;
|
|
18676
|
+
try {
|
|
18677
|
+
store.deleteInflightHold(taskIdFromSynthKey(meshId, synthKey));
|
|
18678
|
+
} catch {
|
|
18679
|
+
}
|
|
18680
|
+
}
|
|
18681
|
+
function rehydrateAckedHoldsForMesh(meshId) {
|
|
18682
|
+
if (rehydratedHoldMeshes.has(meshId)) return;
|
|
18683
|
+
rehydratedHoldMeshes.add(meshId);
|
|
18684
|
+
const store = holdStore();
|
|
18685
|
+
if (!store) return;
|
|
18686
|
+
let rows;
|
|
18687
|
+
try {
|
|
18688
|
+
rows = store.listInflightHoldsByMesh(meshId);
|
|
18689
|
+
} catch {
|
|
18690
|
+
return;
|
|
18691
|
+
}
|
|
18692
|
+
for (const row of rows) {
|
|
18693
|
+
const synthKey = inFlightSynthKey(meshId, row.taskId);
|
|
18694
|
+
if (inFlightAckedHoldState.has(synthKey)) continue;
|
|
18695
|
+
inFlightAckedHoldState.set(synthKey, {
|
|
18696
|
+
liveConfirmedSinceAck: row.holdReason === "live",
|
|
18697
|
+
consecutiveReadFailures: row.readFailureCount ?? 0,
|
|
18698
|
+
...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {}
|
|
18699
|
+
});
|
|
18700
|
+
}
|
|
18701
|
+
if (rows.length > 0) {
|
|
18702
|
+
LOG.info("MeshReconcile", `Rehydrated ${rows.length} persisted acked-hold row(s) for mesh ${meshId} after (re)start`);
|
|
18703
|
+
}
|
|
18704
|
+
}
|
|
18705
|
+
function collectHeldSynthKeysForMesh(meshId) {
|
|
18706
|
+
const heldKeys = /* @__PURE__ */ new Set();
|
|
18707
|
+
for (const key2 of inFlightAckedHoldState.keys()) {
|
|
18708
|
+
if (key2.startsWith(`${meshId}::`)) heldKeys.add(key2);
|
|
18709
|
+
}
|
|
18710
|
+
const store = holdStore();
|
|
18711
|
+
if (store) {
|
|
18712
|
+
try {
|
|
18713
|
+
for (const row of store.listInflightHoldsByMesh(meshId)) {
|
|
18714
|
+
heldKeys.add(inFlightSynthKey(meshId, row.taskId));
|
|
18715
|
+
}
|
|
18716
|
+
} catch {
|
|
18717
|
+
}
|
|
18718
|
+
}
|
|
18719
|
+
return heldKeys;
|
|
18720
|
+
}
|
|
18721
|
+
var ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, rehydratedHoldMeshes;
|
|
18722
|
+
var init_mesh_reconcile_acked_hold = __esm({
|
|
18723
|
+
"src/mesh/mesh-reconcile-acked-hold.ts"() {
|
|
18724
|
+
"use strict";
|
|
18725
|
+
init_logger();
|
|
18726
|
+
init_mesh_runtime_store();
|
|
18727
|
+
init_mesh_events_utils();
|
|
18728
|
+
ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
|
|
18729
|
+
inFlightAckedHoldState = /* @__PURE__ */ new Map();
|
|
18730
|
+
rehydratedHoldMeshes = /* @__PURE__ */ new Set();
|
|
18731
|
+
}
|
|
18732
|
+
});
|
|
18733
|
+
|
|
18734
|
+
// src/mesh/mesh-reconcile-config.ts
|
|
18735
|
+
function resolveAutoPruneMinAgeMs() {
|
|
18736
|
+
const raw = readNonEmptyString2(process.env.MESH_AUTO_PRUNE_MIN_AGE_MS);
|
|
18737
|
+
if (raw) {
|
|
18738
|
+
const parsed = Number.parseInt(raw, 10);
|
|
18739
|
+
if (Number.isFinite(parsed) && parsed >= 60 * 6e4 && parsed <= 30 * 24 * 60 * 6e4) return parsed;
|
|
18740
|
+
}
|
|
18741
|
+
return DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
18742
|
+
}
|
|
18743
|
+
function resolvePendingHeldDrainEscalateMs() {
|
|
18744
|
+
return resolveTunedReconcileMs("MESH_PENDING_HELD_DRAIN_ESCALATE_MS", DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, 4e3, 5 * 6e4);
|
|
18745
|
+
}
|
|
18746
|
+
function resolveReconcileIntervalMs() {
|
|
18747
|
+
const raw = readNonEmptyString2(process.env.MESH_RECONCILE_INTERVAL_MS);
|
|
18748
|
+
if (raw) {
|
|
18749
|
+
const parsed = Number.parseInt(raw, 10);
|
|
18750
|
+
if (Number.isFinite(parsed) && parsed >= 1e3 && parsed <= 6e4) return parsed;
|
|
18751
|
+
}
|
|
18752
|
+
return DEFAULT_RECONCILE_INTERVAL_MS;
|
|
18753
|
+
}
|
|
18754
|
+
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS;
|
|
18755
|
+
var init_mesh_reconcile_config = __esm({
|
|
18756
|
+
"src/mesh/mesh-reconcile-config.ts"() {
|
|
18757
|
+
"use strict";
|
|
18758
|
+
init_mesh_events_utils();
|
|
18759
|
+
init_mesh_reconcile_acked_hold();
|
|
18760
|
+
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
18761
|
+
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
18762
|
+
DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS = 12e3;
|
|
18763
|
+
}
|
|
18764
|
+
});
|
|
18765
|
+
|
|
18766
|
+
// src/mesh/mesh-remote-event-pull.ts
|
|
18767
|
+
async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDaemonIds) {
|
|
18768
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
18769
|
+
if (!dispatchMeshCommand) return;
|
|
18770
|
+
const meshId = mesh.id;
|
|
18771
|
+
const pulls = candidateDaemonIds.length > 0 ? candidateDaemonIds.map((id) => ({ meshId, coordinatorDaemonId: id })) : [{ meshId }];
|
|
18772
|
+
await Promise.allSettled(mesh.nodes.map(async (node) => {
|
|
18773
|
+
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
18774
|
+
if (!nodeDaemonId) return;
|
|
18775
|
+
if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) return;
|
|
18776
|
+
if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) return;
|
|
18777
|
+
const peerSnapshot = components.getMeshPeerConnectionStatus?.(nodeDaemonId);
|
|
18778
|
+
if (peerSnapshot && String(peerSnapshot.state) !== "connected") return;
|
|
18779
|
+
for (const pendingEventArgs of pulls) {
|
|
18780
|
+
let events;
|
|
18781
|
+
try {
|
|
18782
|
+
events = await dispatchMeshCommand(nodeDaemonId, "get_pending_mesh_events", pendingEventArgs);
|
|
18783
|
+
} catch {
|
|
18784
|
+
break;
|
|
18785
|
+
}
|
|
18786
|
+
const list = extractPendingEvents(events).filter((e) => readNonEmptyString2(e?.meshId) === meshId);
|
|
18787
|
+
for (const event of list) {
|
|
18788
|
+
const payload = buildForwardPayloadFromPending(event);
|
|
18789
|
+
if (!payload.event || !payload.meshId) continue;
|
|
18790
|
+
try {
|
|
18791
|
+
handleMeshForwardEvent(components, payload);
|
|
18792
|
+
} catch {
|
|
18793
|
+
}
|
|
18794
|
+
}
|
|
18795
|
+
}
|
|
18796
|
+
}));
|
|
18797
|
+
}
|
|
18798
|
+
function unwrapReadChatPayload(raw) {
|
|
18799
|
+
let cursor = raw;
|
|
18800
|
+
for (let depth = 0; depth < 4 && cursor && typeof cursor === "object"; depth++) {
|
|
18801
|
+
const record = cursor;
|
|
18802
|
+
if (Array.isArray(record.messages)) return record;
|
|
18803
|
+
if (record.payload && typeof record.payload === "object") {
|
|
18804
|
+
cursor = record.payload;
|
|
18805
|
+
continue;
|
|
18806
|
+
}
|
|
18807
|
+
if (record.result && typeof record.result === "object") {
|
|
18808
|
+
cursor = record.result;
|
|
18809
|
+
continue;
|
|
18810
|
+
}
|
|
18811
|
+
if (record.data && typeof record.data === "object") {
|
|
18812
|
+
cursor = record.data;
|
|
18813
|
+
continue;
|
|
18814
|
+
}
|
|
18815
|
+
break;
|
|
18816
|
+
}
|
|
18817
|
+
return cursor && typeof cursor === "object" ? cursor : null;
|
|
18818
|
+
}
|
|
18819
|
+
function readChatPayloadStatus(payload) {
|
|
18820
|
+
return readNonEmptyString2(payload?.status).toLowerCase();
|
|
18821
|
+
}
|
|
18822
|
+
function realTerminalEmitPendingForTask(meshId, taskId) {
|
|
18823
|
+
let pending;
|
|
18824
|
+
try {
|
|
18825
|
+
pending = getPendingMeshCoordinatorEvents(meshId);
|
|
18826
|
+
} catch {
|
|
18827
|
+
return false;
|
|
18828
|
+
}
|
|
18829
|
+
return pending.some((e) => readNonEmptyString2(e.metadataEvent?.taskId) === taskId && (e.event === "agent:generating_completed" || e.event === "agent:stopped"));
|
|
18830
|
+
}
|
|
18831
|
+
async function reprobeWorkerStatus(components, args) {
|
|
18832
|
+
try {
|
|
18833
|
+
if (args.isLocalNode) {
|
|
18834
|
+
const r = await components.commandHandler.handle("read_chat", args.readArgs);
|
|
18835
|
+
if (r && r.success === false) return null;
|
|
18836
|
+
return readChatPayloadStatus(unwrapReadChatPayload(r));
|
|
18837
|
+
}
|
|
18838
|
+
if (components.dispatchMeshCommand) {
|
|
18839
|
+
const r = await components.dispatchMeshCommand(args.nodeDaemonId, "read_chat", args.readArgs);
|
|
18840
|
+
const p = unwrapReadChatPayload(r);
|
|
18841
|
+
if (p && p.success === false) return null;
|
|
18842
|
+
return readChatPayloadStatus(p);
|
|
18843
|
+
}
|
|
18844
|
+
} catch {
|
|
18845
|
+
return null;
|
|
18846
|
+
}
|
|
18847
|
+
return null;
|
|
18848
|
+
}
|
|
18849
|
+
async function collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId) {
|
|
18850
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
18851
|
+
return Promise.all(mesh.nodes.map(async (node) => {
|
|
18852
|
+
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
18853
|
+
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId);
|
|
18854
|
+
if (!isLocalNode) {
|
|
18855
|
+
const peerSnapshot = components.getMeshPeerConnectionStatus?.(nodeDaemonId);
|
|
18856
|
+
if (peerSnapshot && String(peerSnapshot.state) !== "connected") return node;
|
|
18857
|
+
}
|
|
18858
|
+
let statusResult;
|
|
18859
|
+
try {
|
|
18860
|
+
if (isLocalNode) {
|
|
18861
|
+
statusResult = await components.commandHandler.handle("get_status_metadata", {});
|
|
18862
|
+
} else if (dispatchMeshCommand) {
|
|
18863
|
+
statusResult = await dispatchMeshCommand(nodeDaemonId, "get_status_metadata", {});
|
|
18864
|
+
} else {
|
|
18865
|
+
return node;
|
|
18866
|
+
}
|
|
18867
|
+
} catch {
|
|
18868
|
+
return node;
|
|
18869
|
+
}
|
|
18870
|
+
const sessions = extractStatusMetadataSessions(statusResult);
|
|
18871
|
+
return sessions.length > 0 ? { ...node, sessions } : node;
|
|
18872
|
+
}));
|
|
18873
|
+
}
|
|
18874
|
+
function extractStatusMetadataSessions(raw) {
|
|
18875
|
+
let cursor = raw;
|
|
18876
|
+
for (let depth = 0; depth < 4 && cursor && typeof cursor === "object"; depth++) {
|
|
18877
|
+
const record = cursor;
|
|
18878
|
+
const status = record.status && typeof record.status === "object" ? record.status : void 0;
|
|
18879
|
+
if (status && Array.isArray(status.sessions)) return status.sessions;
|
|
18880
|
+
if (Array.isArray(record.sessions)) return record.sessions;
|
|
18881
|
+
if (record.payload && typeof record.payload === "object") {
|
|
18882
|
+
cursor = record.payload;
|
|
18883
|
+
continue;
|
|
18884
|
+
}
|
|
18885
|
+
if (record.result && typeof record.result === "object") {
|
|
18886
|
+
cursor = record.result;
|
|
18887
|
+
continue;
|
|
18888
|
+
}
|
|
18889
|
+
if (record.data && typeof record.data === "object") {
|
|
18890
|
+
cursor = record.data;
|
|
18891
|
+
continue;
|
|
18892
|
+
}
|
|
18893
|
+
break;
|
|
18894
|
+
}
|
|
18895
|
+
return [];
|
|
18896
|
+
}
|
|
18897
|
+
function extractPendingEvents(raw) {
|
|
18898
|
+
if (Array.isArray(raw)) return raw;
|
|
18899
|
+
if (raw && typeof raw === "object") {
|
|
18900
|
+
const events = raw.events;
|
|
18901
|
+
if (Array.isArray(events)) return events;
|
|
18902
|
+
}
|
|
18903
|
+
return [];
|
|
18904
|
+
}
|
|
18905
|
+
function buildForwardPayloadFromPending(event) {
|
|
18906
|
+
const metadata = event?.metadataEvent && typeof event.metadataEvent === "object" ? event.metadataEvent : {};
|
|
18907
|
+
return {
|
|
18908
|
+
event: readNonEmptyString2(event?.event),
|
|
18909
|
+
meshId: readNonEmptyString2(event?.meshId),
|
|
18910
|
+
nodeId: readNonEmptyString2(event?.nodeId) || readNonEmptyString2(metadata.meshNodeId),
|
|
18911
|
+
workspace: readNonEmptyString2(event?.workspace) || readNonEmptyString2(metadata.workspace),
|
|
18912
|
+
// Preserve the originating coordinator session id across the relay. It is normally
|
|
18913
|
+
// carried inside metadataEvent.meshCoordinatorSessionId (spread below), but pass the
|
|
18914
|
+
// top-level field through explicitly too so the handleMeshForwardEvent whitelist
|
|
18915
|
+
// recovers it regardless of which carrier the producing daemon used.
|
|
18916
|
+
...readNonEmptyString2(event?.targetCoordinatorSessionId) ? { targetCoordinatorSessionId: readNonEmptyString2(event.targetCoordinatorSessionId) } : {},
|
|
18917
|
+
...metadata,
|
|
18918
|
+
// NOTIF-MISS (FIX 3): surface the dispatch task id at the TOP LEVEL so the relay's
|
|
18919
|
+
// received-stage trace (and buildRelayMetadataEvent) recovers it regardless of which
|
|
18920
|
+
// carrier the producing daemon used. The metadata spread above may carry the id only as
|
|
18921
|
+
// `meshActiveTaskId` (a worker provider event), leaving top-level `taskId` unset and the
|
|
18922
|
+
// received stage rendering `task=-`. Resolve both carriers into an explicit `taskId` so
|
|
18923
|
+
// dedup stays task-scoped end-to-end. Only set when a non-empty id exists (no clobber to
|
|
18924
|
+
// undefined when neither is present).
|
|
18925
|
+
...(() => {
|
|
18926
|
+
const tid = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(metadata.meshActiveTaskId);
|
|
18927
|
+
return tid ? { taskId: tid } : {};
|
|
18928
|
+
})(),
|
|
18929
|
+
// T4 (B3b): carry the v2 envelope (protocolVersion/eventId/scope/dispatchedBy/
|
|
18930
|
+
// intendedFor) across the P2P relay boundary at the TOP LEVEL. These live on the
|
|
18931
|
+
// pending event itself, not inside metadataEvent, so without this the remote pull
|
|
18932
|
+
// re-queue would re-stamp a fresh eventId — breaking cross-machine idempotency and
|
|
18933
|
+
// downgrading the relayed completion to v1 broadcast routing. Spread LAST so the
|
|
18934
|
+
// authoritative envelope always wins over any stale key the metadata spread carried.
|
|
18935
|
+
...serializeV2EnvelopeToWire(event)
|
|
18936
|
+
};
|
|
18937
|
+
}
|
|
18938
|
+
var init_mesh_remote_event_pull = __esm({
|
|
18939
|
+
"src/mesh/mesh-remote-event-pull.ts"() {
|
|
18940
|
+
"use strict";
|
|
18941
|
+
init_mesh_events_pending();
|
|
18942
|
+
init_mesh_events_coordinator();
|
|
18943
|
+
init_mesh_events_utils();
|
|
18944
|
+
init_dist();
|
|
18945
|
+
init_mesh_reconcile_identity();
|
|
18946
|
+
}
|
|
18947
|
+
});
|
|
18948
|
+
|
|
18455
18949
|
// src/mesh/mesh-reconcile-v2-backstop.ts
|
|
18456
18950
|
function getMeshV2BackstopCounters() {
|
|
18457
18951
|
return { ...meshV2BackstopCounters };
|
|
@@ -18484,152 +18978,205 @@ var init_mesh_reconcile_v2_backstop = __esm({
|
|
|
18484
18978
|
}
|
|
18485
18979
|
});
|
|
18486
18980
|
|
|
18487
|
-
// src/mesh/mesh-
|
|
18488
|
-
function
|
|
18489
|
-
const
|
|
18490
|
-
|
|
18491
|
-
|
|
18492
|
-
|
|
18493
|
-
|
|
18494
|
-
|
|
18495
|
-
|
|
18496
|
-
|
|
18497
|
-
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
|
|
18498
|
-
}
|
|
18499
|
-
function resolveAckedTranscriptFastTrackGraceMs() {
|
|
18500
|
-
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
|
|
18501
|
-
}
|
|
18502
|
-
function inFlightSynthKey(meshId, taskId) {
|
|
18503
|
-
return `${meshId}::${taskId}`;
|
|
18504
|
-
}
|
|
18505
|
-
function taskIdFromSynthKey(meshId, synthKey) {
|
|
18506
|
-
const prefix = `${meshId}::`;
|
|
18507
|
-
return synthKey.startsWith(prefix) ? synthKey.slice(prefix.length) : synthKey;
|
|
18508
|
-
}
|
|
18509
|
-
function holdStore() {
|
|
18510
|
-
try {
|
|
18511
|
-
return MeshRuntimeStore.getInstance();
|
|
18512
|
-
} catch {
|
|
18513
|
-
return void 0;
|
|
18514
|
-
}
|
|
18515
|
-
}
|
|
18516
|
-
function getHoldState(synthKey, meshId) {
|
|
18517
|
-
const cached3 = inFlightAckedHoldState.get(synthKey);
|
|
18518
|
-
if (cached3) return cached3;
|
|
18519
|
-
const store = holdStore();
|
|
18520
|
-
if (!store) return void 0;
|
|
18521
|
-
let row;
|
|
18522
|
-
try {
|
|
18523
|
-
row = store.getInflightHold(taskIdFromSynthKey(meshId, synthKey));
|
|
18524
|
-
} catch {
|
|
18525
|
-
return void 0;
|
|
18526
|
-
}
|
|
18527
|
-
if (!row) return void 0;
|
|
18528
|
-
const state = {
|
|
18529
|
-
liveConfirmedSinceAck: row.holdReason === "live",
|
|
18530
|
-
consecutiveReadFailures: row.readFailureCount ?? 0,
|
|
18531
|
-
...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {}
|
|
18532
|
-
};
|
|
18533
|
-
inFlightAckedHoldState.set(synthKey, state);
|
|
18534
|
-
return state;
|
|
18535
|
-
}
|
|
18536
|
-
function setHoldState(synthKey, meshId, state) {
|
|
18537
|
-
inFlightAckedHoldState.set(synthKey, state);
|
|
18538
|
-
const store = holdStore();
|
|
18539
|
-
if (!store) return;
|
|
18540
|
-
try {
|
|
18541
|
-
store.upsertInflightHold({
|
|
18542
|
-
taskId: taskIdFromSynthKey(meshId, synthKey),
|
|
18543
|
-
meshId,
|
|
18544
|
-
holdReason: state.liveConfirmedSinceAck ? "live" : "unconfirmed",
|
|
18545
|
-
firstIdleSinceAck: state.transcriptIdleSinceMs ?? null,
|
|
18546
|
-
readFailureCount: state.consecutiveReadFailures
|
|
18547
|
-
});
|
|
18548
|
-
} catch {
|
|
18549
|
-
}
|
|
18550
|
-
}
|
|
18551
|
-
function deleteHoldState(synthKey, meshId) {
|
|
18552
|
-
inFlightAckedHoldState.delete(synthKey);
|
|
18553
|
-
const store = holdStore();
|
|
18554
|
-
if (!store) return;
|
|
18555
|
-
try {
|
|
18556
|
-
store.deleteInflightHold(taskIdFromSynthKey(meshId, synthKey));
|
|
18557
|
-
} catch {
|
|
18558
|
-
}
|
|
18559
|
-
}
|
|
18560
|
-
function rehydrateAckedHoldsForMesh(meshId) {
|
|
18561
|
-
if (rehydratedHoldMeshes.has(meshId)) return;
|
|
18562
|
-
rehydratedHoldMeshes.add(meshId);
|
|
18563
|
-
const store = holdStore();
|
|
18564
|
-
if (!store) return;
|
|
18565
|
-
let rows;
|
|
18566
|
-
try {
|
|
18567
|
-
rows = store.listInflightHoldsByMesh(meshId);
|
|
18568
|
-
} catch {
|
|
18569
|
-
return;
|
|
18570
|
-
}
|
|
18571
|
-
for (const row of rows) {
|
|
18572
|
-
const synthKey = inFlightSynthKey(meshId, row.taskId);
|
|
18573
|
-
if (inFlightAckedHoldState.has(synthKey)) continue;
|
|
18574
|
-
inFlightAckedHoldState.set(synthKey, {
|
|
18575
|
-
liveConfirmedSinceAck: row.holdReason === "live",
|
|
18576
|
-
consecutiveReadFailures: row.readFailureCount ?? 0,
|
|
18577
|
-
...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {}
|
|
18578
|
-
});
|
|
18579
|
-
}
|
|
18580
|
-
if (rows.length > 0) {
|
|
18581
|
-
LOG.info("MeshReconcile", `Rehydrated ${rows.length} persisted acked-hold row(s) for mesh ${meshId} after (re)start`);
|
|
18582
|
-
}
|
|
18583
|
-
}
|
|
18584
|
-
function collectHeldSynthKeysForMesh(meshId) {
|
|
18585
|
-
const heldKeys = /* @__PURE__ */ new Set();
|
|
18586
|
-
for (const key2 of inFlightAckedHoldState.keys()) {
|
|
18587
|
-
if (key2.startsWith(`${meshId}::`)) heldKeys.add(key2);
|
|
18981
|
+
// src/mesh/mesh-completion-synthesis.ts
|
|
18982
|
+
async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds, localDaemonId) {
|
|
18983
|
+
const dispatches = getActiveDirectDispatches(mesh.id);
|
|
18984
|
+
rehydrateAckedHoldsForMesh(mesh.id);
|
|
18985
|
+
const activeTaskKeys = new Set(
|
|
18986
|
+
dispatches.map((d) => readNonEmptyString2(d.taskId)).filter(Boolean).map((taskId) => inFlightSynthKey(mesh.id, taskId))
|
|
18987
|
+
);
|
|
18988
|
+
const heldKeys = collectHeldSynthKeysForMesh(mesh.id);
|
|
18989
|
+
for (const key2 of heldKeys) {
|
|
18990
|
+
if (!activeTaskKeys.has(key2)) deleteHoldState(key2, mesh.id);
|
|
18588
18991
|
}
|
|
18589
|
-
|
|
18590
|
-
|
|
18992
|
+
if (dispatches.length === 0) return;
|
|
18993
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
18994
|
+
const nodeById = new Map(mesh.nodes.map((n) => [n.id, n]));
|
|
18995
|
+
for (const dispatch of dispatches) {
|
|
18996
|
+
const sessionId = readNonEmptyString2(dispatch.sessionId);
|
|
18997
|
+
const nodeId = readNonEmptyString2(dispatch.nodeId);
|
|
18998
|
+
const taskId = readNonEmptyString2(dispatch.taskId);
|
|
18999
|
+
if (!sessionId || !nodeId || !taskId) continue;
|
|
19000
|
+
const node = nodeById.get(nodeId);
|
|
19001
|
+
const nodeDaemonId = readNonEmptyString2(node?.daemonId);
|
|
19002
|
+
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId) || !!components.instanceManager.getInstance(sessionId);
|
|
19003
|
+
const providerType = readNonEmptyString2(dispatch.providerType);
|
|
19004
|
+
const readArgs = {
|
|
19005
|
+
sessionId,
|
|
19006
|
+
targetSessionId: sessionId,
|
|
19007
|
+
tailLimit: 10,
|
|
19008
|
+
...node?.workspace ? { workspace: node.workspace } : {},
|
|
19009
|
+
...providerType ? { agentType: providerType, providerType } : {}
|
|
19010
|
+
};
|
|
19011
|
+
const synthKey = inFlightSynthKey(mesh.id, taskId);
|
|
19012
|
+
const isAcked = dispatch.status === "acked";
|
|
19013
|
+
let backstopKind;
|
|
19014
|
+
let payload = null;
|
|
19015
|
+
let readFailed = false;
|
|
18591
19016
|
try {
|
|
18592
|
-
|
|
18593
|
-
|
|
19017
|
+
if (isLocalNode) {
|
|
19018
|
+
const result = await components.commandHandler.handle("read_chat", readArgs);
|
|
19019
|
+
if (result && result.success === false) {
|
|
19020
|
+
readFailed = true;
|
|
19021
|
+
} else {
|
|
19022
|
+
payload = unwrapReadChatPayload(result);
|
|
19023
|
+
}
|
|
19024
|
+
} else if (dispatchMeshCommand) {
|
|
19025
|
+
const result = await dispatchMeshCommand(nodeDaemonId, "read_chat", readArgs);
|
|
19026
|
+
payload = unwrapReadChatPayload(result);
|
|
19027
|
+
if (payload && payload.success === false) {
|
|
19028
|
+
payload = null;
|
|
19029
|
+
readFailed = true;
|
|
19030
|
+
}
|
|
19031
|
+
} else {
|
|
19032
|
+
continue;
|
|
18594
19033
|
}
|
|
18595
19034
|
} catch {
|
|
19035
|
+
readFailed = true;
|
|
19036
|
+
}
|
|
19037
|
+
if (!payload && !readFailed) continue;
|
|
19038
|
+
if (readFailed || !payload) {
|
|
19039
|
+
if (isAcked) {
|
|
19040
|
+
const prior = getHoldState(synthKey, mesh.id);
|
|
19041
|
+
const failures = (prior?.consecutiveReadFailures ?? 0) + 1;
|
|
19042
|
+
const liveConfirmedSinceAck = prior?.liveConfirmedSinceAck ?? false;
|
|
19043
|
+
setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck, consecutiveReadFailures: failures });
|
|
19044
|
+
if (liveConfirmedSinceAck && failures >= ACKED_DEATH_CONSECUTIVE_READ_FAILURES) {
|
|
19045
|
+
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`);
|
|
19046
|
+
}
|
|
19047
|
+
}
|
|
19048
|
+
continue;
|
|
19049
|
+
}
|
|
19050
|
+
const priorHoldState = getHoldState(synthKey, mesh.id);
|
|
19051
|
+
setHoldState(synthKey, mesh.id, {
|
|
19052
|
+
liveConfirmedSinceAck: true,
|
|
19053
|
+
consecutiveReadFailures: 0,
|
|
19054
|
+
...priorHoldState?.transcriptIdleSinceMs !== void 0 ? { transcriptIdleSinceMs: priorHoldState.transcriptIdleSinceMs } : {}
|
|
19055
|
+
});
|
|
19056
|
+
const nowMs = Date.now();
|
|
19057
|
+
if (readChatPayloadStatus(payload) !== "idle") {
|
|
19058
|
+
setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
|
|
19059
|
+
continue;
|
|
19060
|
+
}
|
|
19061
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
19062
|
+
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
19063
|
+
if (isAcked) {
|
|
19064
|
+
const ackedAtMs = Date.parse(readNonEmptyString2(dispatch.updatedAt));
|
|
19065
|
+
const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
|
|
19066
|
+
const deathDeadlineMs = resolveAckedDeathDeadlineMs();
|
|
19067
|
+
const holdState = getHoldState(synthKey, mesh.id);
|
|
19068
|
+
let fastTrackReady = false;
|
|
19069
|
+
if (evidence.finalSummary) {
|
|
19070
|
+
const idleSinceMs = holdState?.transcriptIdleSinceMs ?? nowMs;
|
|
19071
|
+
if (holdState && holdState.transcriptIdleSinceMs === void 0) {
|
|
19072
|
+
setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: idleSinceMs });
|
|
19073
|
+
}
|
|
19074
|
+
const fastTrackGraceMs = resolveAckedTranscriptFastTrackGraceMs();
|
|
19075
|
+
const idleHeldMs = nowMs - idleSinceMs;
|
|
19076
|
+
if (idleHeldMs >= fastTrackGraceMs) {
|
|
19077
|
+
fastTrackReady = true;
|
|
19078
|
+
backstopKind = "ackedHoldFastTrackFired";
|
|
19079
|
+
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.`);
|
|
19080
|
+
}
|
|
19081
|
+
} else if (holdState?.transcriptIdleSinceMs !== void 0) {
|
|
19082
|
+
setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: void 0 });
|
|
19083
|
+
}
|
|
19084
|
+
if (!fastTrackReady && sinceAckMs < deathDeadlineMs) {
|
|
19085
|
+
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.`);
|
|
19086
|
+
continue;
|
|
19087
|
+
}
|
|
19088
|
+
if (!fastTrackReady) {
|
|
19089
|
+
backstopKind = "ackedHoldDeathDeadlineFired";
|
|
19090
|
+
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).`);
|
|
19091
|
+
}
|
|
19092
|
+
}
|
|
19093
|
+
if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
|
|
19094
|
+
deleteHoldState(synthKey, mesh.id);
|
|
19095
|
+
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`);
|
|
19096
|
+
continue;
|
|
19097
|
+
}
|
|
19098
|
+
if (!evidence.finalSummary) continue;
|
|
19099
|
+
const dispatchedAtMs = Date.parse(readNonEmptyString2(dispatch.dispatchedAt));
|
|
19100
|
+
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
|
|
19101
|
+
if (Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs < dispatchedAtMs) {
|
|
19102
|
+
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`);
|
|
19103
|
+
traceMeshEventDrop("reconcile_stale_summary_before_dispatch", {
|
|
19104
|
+
taskId,
|
|
19105
|
+
sessionId,
|
|
19106
|
+
nodeId,
|
|
19107
|
+
meshId: mesh.id,
|
|
19108
|
+
event: "agent:generating_completed"
|
|
19109
|
+
}, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
|
|
19110
|
+
continue;
|
|
19111
|
+
}
|
|
19112
|
+
const reprobeStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
|
|
19113
|
+
if (reprobeStatus && reprobeStatus !== "idle") {
|
|
19114
|
+
deleteHoldState(synthKey, mesh.id);
|
|
19115
|
+
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`);
|
|
19116
|
+
continue;
|
|
19117
|
+
}
|
|
19118
|
+
const providerSessionId = readNonEmptyString2(payload.providerSessionId);
|
|
19119
|
+
const coordinatorDaemonId = selfIds.find((id) => !!id);
|
|
19120
|
+
try {
|
|
19121
|
+
const result = reconcileDirectDispatchCompletionFromTranscript({
|
|
19122
|
+
meshId: mesh.id,
|
|
19123
|
+
nodeId,
|
|
19124
|
+
sessionId,
|
|
19125
|
+
providerType: providerType || void 0,
|
|
19126
|
+
providerSessionId: providerSessionId || void 0,
|
|
19127
|
+
taskId,
|
|
19128
|
+
finalSummary: evidence.finalSummary,
|
|
19129
|
+
...evidence.transcriptMessageAt ? { transcriptMessageAt: evidence.transcriptMessageAt } : {},
|
|
19130
|
+
...coordinatorDaemonId ? { targetCoordinatorDaemonId: coordinatorDaemonId } : {},
|
|
19131
|
+
source: "daemon_reconcile_transcript_completion"
|
|
19132
|
+
});
|
|
19133
|
+
if (result.reconciled) {
|
|
19134
|
+
recordBackstopFire(backstopKind ?? "phase4SynthesisFired", `task ${taskId} on node ${nodeId} (mesh ${mesh.id}), kind=${result.kind}`);
|
|
19135
|
+
LOG.info("MeshReconcile", `Synthesized missing completion (${result.kind}) for task ${taskId} on node ${nodeId} (mesh ${mesh.id})`);
|
|
19136
|
+
}
|
|
19137
|
+
} catch (e) {
|
|
19138
|
+
LOG.warn("MeshReconcile", `Transcript completion reconcile threw for task ${taskId}: ${e?.message || e}`);
|
|
18596
19139
|
}
|
|
18597
19140
|
}
|
|
18598
|
-
return heldKeys;
|
|
18599
19141
|
}
|
|
18600
|
-
|
|
18601
|
-
|
|
18602
|
-
|
|
19142
|
+
async function autoPruneStaleDirectDispatches(components, mesh, selfIds, localDaemonId, minAgeMs) {
|
|
19143
|
+
const directDispatches = getActiveDirectDispatches(mesh.id);
|
|
19144
|
+
if (directDispatches.length === 0) return;
|
|
19145
|
+
const liveNodes = await collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId);
|
|
19146
|
+
const result = pruneStaleDirectDispatches({
|
|
19147
|
+
meshId: mesh.id,
|
|
19148
|
+
queue: getQueue(mesh.id),
|
|
19149
|
+
ledgerEntries: readLedgerEntries(mesh.id, { tail: 500 }),
|
|
19150
|
+
directDispatches,
|
|
19151
|
+
nodes: liveNodes,
|
|
19152
|
+
execute: true,
|
|
19153
|
+
minAgeMs,
|
|
19154
|
+
source: "daemon_reconcile_auto_prune"
|
|
19155
|
+
});
|
|
19156
|
+
if (result.prunedCount > 0) {
|
|
19157
|
+
LOG.info("MeshReconcile", `Auto-pruned ${result.prunedCount} orphaned direct dispatch record(s) for mesh ${mesh.id}`);
|
|
19158
|
+
}
|
|
19159
|
+
}
|
|
19160
|
+
var init_mesh_completion_synthesis = __esm({
|
|
19161
|
+
"src/mesh/mesh-completion-synthesis.ts"() {
|
|
18603
19162
|
"use strict";
|
|
18604
19163
|
init_logger();
|
|
18605
|
-
init_mesh_runtime_store();
|
|
18606
19164
|
init_mesh_events_utils();
|
|
18607
|
-
|
|
18608
|
-
|
|
18609
|
-
|
|
19165
|
+
init_mesh_event_trace();
|
|
19166
|
+
init_dist();
|
|
19167
|
+
init_mesh_reconcile_identity();
|
|
19168
|
+
init_mesh_work_queue();
|
|
19169
|
+
init_mesh_ledger();
|
|
19170
|
+
init_mesh_active_work();
|
|
19171
|
+
init_mesh_events_stale();
|
|
19172
|
+
init_chat_message_normalization();
|
|
19173
|
+
init_mesh_reconcile_v2_backstop();
|
|
19174
|
+
init_mesh_reconcile_acked_hold();
|
|
19175
|
+
init_mesh_remote_event_pull();
|
|
18610
19176
|
}
|
|
18611
19177
|
});
|
|
18612
19178
|
|
|
18613
19179
|
// src/mesh/mesh-reconcile-loop.ts
|
|
18614
|
-
function resolveAutoPruneMinAgeMs() {
|
|
18615
|
-
const raw = readNonEmptyString2(process.env.MESH_AUTO_PRUNE_MIN_AGE_MS);
|
|
18616
|
-
if (raw) {
|
|
18617
|
-
const parsed = Number.parseInt(raw, 10);
|
|
18618
|
-
if (Number.isFinite(parsed) && parsed >= 60 * 6e4 && parsed <= 30 * 24 * 60 * 6e4) return parsed;
|
|
18619
|
-
}
|
|
18620
|
-
return DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
18621
|
-
}
|
|
18622
|
-
function resolvePendingHeldDrainEscalateMs() {
|
|
18623
|
-
return resolveTunedReconcileMs("MESH_PENDING_HELD_DRAIN_ESCALATE_MS", DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, 4e3, 5 * 6e4);
|
|
18624
|
-
}
|
|
18625
|
-
function resolveReconcileIntervalMs() {
|
|
18626
|
-
const raw = readNonEmptyString2(process.env.MESH_RECONCILE_INTERVAL_MS);
|
|
18627
|
-
if (raw) {
|
|
18628
|
-
const parsed = Number.parseInt(raw, 10);
|
|
18629
|
-
if (Number.isFinite(parsed) && parsed >= 1e3 && parsed <= 6e4) return parsed;
|
|
18630
|
-
}
|
|
18631
|
-
return DEFAULT_RECONCILE_INTERVAL_MS;
|
|
18632
|
-
}
|
|
18633
19180
|
function findLiveCoordinators(components) {
|
|
18634
19181
|
const out = [];
|
|
18635
19182
|
for (const inst of components.instanceManager.getByCategory("cli")) {
|
|
@@ -19308,349 +19855,6 @@ async function retryUnresolvedDelegateForwards(components) {
|
|
|
19308
19855
|
LOG.info("MeshReconcile", `Retried+delivered unresolved-delegate ${readNonEmptyString2(entry.payload.event)} to coordinator ${entry.coordinatorDaemonId}`);
|
|
19309
19856
|
}
|
|
19310
19857
|
}
|
|
19311
|
-
async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDaemonIds) {
|
|
19312
|
-
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
19313
|
-
if (!dispatchMeshCommand) return;
|
|
19314
|
-
const meshId = mesh.id;
|
|
19315
|
-
const pulls = candidateDaemonIds.length > 0 ? candidateDaemonIds.map((id) => ({ meshId, coordinatorDaemonId: id })) : [{ meshId }];
|
|
19316
|
-
for (const node of mesh.nodes) {
|
|
19317
|
-
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
19318
|
-
if (!nodeDaemonId) continue;
|
|
19319
|
-
if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) continue;
|
|
19320
|
-
if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) continue;
|
|
19321
|
-
for (const pendingEventArgs of pulls) {
|
|
19322
|
-
let events;
|
|
19323
|
-
try {
|
|
19324
|
-
events = await dispatchMeshCommand(nodeDaemonId, "get_pending_mesh_events", pendingEventArgs);
|
|
19325
|
-
} catch {
|
|
19326
|
-
break;
|
|
19327
|
-
}
|
|
19328
|
-
const list = extractPendingEvents(events).filter((e) => readNonEmptyString2(e?.meshId) === meshId);
|
|
19329
|
-
for (const event of list) {
|
|
19330
|
-
const payload = buildForwardPayloadFromPending(event);
|
|
19331
|
-
if (!payload.event || !payload.meshId) continue;
|
|
19332
|
-
try {
|
|
19333
|
-
handleMeshForwardEvent(components, payload);
|
|
19334
|
-
} catch {
|
|
19335
|
-
}
|
|
19336
|
-
}
|
|
19337
|
-
}
|
|
19338
|
-
}
|
|
19339
|
-
}
|
|
19340
|
-
function unwrapReadChatPayload(raw) {
|
|
19341
|
-
let cursor = raw;
|
|
19342
|
-
for (let depth = 0; depth < 4 && cursor && typeof cursor === "object"; depth++) {
|
|
19343
|
-
const record = cursor;
|
|
19344
|
-
if (Array.isArray(record.messages)) return record;
|
|
19345
|
-
if (record.payload && typeof record.payload === "object") {
|
|
19346
|
-
cursor = record.payload;
|
|
19347
|
-
continue;
|
|
19348
|
-
}
|
|
19349
|
-
if (record.result && typeof record.result === "object") {
|
|
19350
|
-
cursor = record.result;
|
|
19351
|
-
continue;
|
|
19352
|
-
}
|
|
19353
|
-
if (record.data && typeof record.data === "object") {
|
|
19354
|
-
cursor = record.data;
|
|
19355
|
-
continue;
|
|
19356
|
-
}
|
|
19357
|
-
break;
|
|
19358
|
-
}
|
|
19359
|
-
return cursor && typeof cursor === "object" ? cursor : null;
|
|
19360
|
-
}
|
|
19361
|
-
function readChatPayloadStatus(payload) {
|
|
19362
|
-
return readNonEmptyString2(payload?.status).toLowerCase();
|
|
19363
|
-
}
|
|
19364
|
-
function realTerminalEmitPendingForTask(meshId, taskId) {
|
|
19365
|
-
let pending;
|
|
19366
|
-
try {
|
|
19367
|
-
pending = getPendingMeshCoordinatorEvents(meshId);
|
|
19368
|
-
} catch {
|
|
19369
|
-
return false;
|
|
19370
|
-
}
|
|
19371
|
-
return pending.some((e) => readNonEmptyString2(e.metadataEvent?.taskId) === taskId && (e.event === "agent:generating_completed" || e.event === "agent:stopped"));
|
|
19372
|
-
}
|
|
19373
|
-
async function reprobeWorkerStatus(components, args) {
|
|
19374
|
-
try {
|
|
19375
|
-
if (args.isLocalNode) {
|
|
19376
|
-
const r = await components.commandHandler.handle("read_chat", args.readArgs);
|
|
19377
|
-
if (r && r.success === false) return null;
|
|
19378
|
-
return readChatPayloadStatus(unwrapReadChatPayload(r));
|
|
19379
|
-
}
|
|
19380
|
-
if (components.dispatchMeshCommand) {
|
|
19381
|
-
const r = await components.dispatchMeshCommand(args.nodeDaemonId, "read_chat", args.readArgs);
|
|
19382
|
-
const p = unwrapReadChatPayload(r);
|
|
19383
|
-
if (p && p.success === false) return null;
|
|
19384
|
-
return readChatPayloadStatus(p);
|
|
19385
|
-
}
|
|
19386
|
-
} catch {
|
|
19387
|
-
return null;
|
|
19388
|
-
}
|
|
19389
|
-
return null;
|
|
19390
|
-
}
|
|
19391
|
-
async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds, localDaemonId) {
|
|
19392
|
-
const dispatches = getActiveDirectDispatches(mesh.id);
|
|
19393
|
-
rehydrateAckedHoldsForMesh(mesh.id);
|
|
19394
|
-
const activeTaskKeys = new Set(
|
|
19395
|
-
dispatches.map((d) => readNonEmptyString2(d.taskId)).filter(Boolean).map((taskId) => inFlightSynthKey(mesh.id, taskId))
|
|
19396
|
-
);
|
|
19397
|
-
const heldKeys = collectHeldSynthKeysForMesh(mesh.id);
|
|
19398
|
-
for (const key2 of heldKeys) {
|
|
19399
|
-
if (!activeTaskKeys.has(key2)) deleteHoldState(key2, mesh.id);
|
|
19400
|
-
}
|
|
19401
|
-
if (dispatches.length === 0) return;
|
|
19402
|
-
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
19403
|
-
const nodeById = new Map(mesh.nodes.map((n) => [n.id, n]));
|
|
19404
|
-
for (const dispatch of dispatches) {
|
|
19405
|
-
const sessionId = readNonEmptyString2(dispatch.sessionId);
|
|
19406
|
-
const nodeId = readNonEmptyString2(dispatch.nodeId);
|
|
19407
|
-
const taskId = readNonEmptyString2(dispatch.taskId);
|
|
19408
|
-
if (!sessionId || !nodeId || !taskId) continue;
|
|
19409
|
-
const node = nodeById.get(nodeId);
|
|
19410
|
-
const nodeDaemonId = readNonEmptyString2(node?.daemonId);
|
|
19411
|
-
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId) || !!components.instanceManager.getInstance(sessionId);
|
|
19412
|
-
const providerType = readNonEmptyString2(dispatch.providerType);
|
|
19413
|
-
const readArgs = {
|
|
19414
|
-
sessionId,
|
|
19415
|
-
targetSessionId: sessionId,
|
|
19416
|
-
tailLimit: 10,
|
|
19417
|
-
...node?.workspace ? { workspace: node.workspace } : {},
|
|
19418
|
-
...providerType ? { agentType: providerType, providerType } : {}
|
|
19419
|
-
};
|
|
19420
|
-
const synthKey = inFlightSynthKey(mesh.id, taskId);
|
|
19421
|
-
const isAcked = dispatch.status === "acked";
|
|
19422
|
-
let backstopKind;
|
|
19423
|
-
let payload = null;
|
|
19424
|
-
let readFailed = false;
|
|
19425
|
-
try {
|
|
19426
|
-
if (isLocalNode) {
|
|
19427
|
-
const result = await components.commandHandler.handle("read_chat", readArgs);
|
|
19428
|
-
if (result && result.success === false) {
|
|
19429
|
-
readFailed = true;
|
|
19430
|
-
} else {
|
|
19431
|
-
payload = unwrapReadChatPayload(result);
|
|
19432
|
-
}
|
|
19433
|
-
} else if (dispatchMeshCommand) {
|
|
19434
|
-
const result = await dispatchMeshCommand(nodeDaemonId, "read_chat", readArgs);
|
|
19435
|
-
payload = unwrapReadChatPayload(result);
|
|
19436
|
-
if (payload && payload.success === false) {
|
|
19437
|
-
payload = null;
|
|
19438
|
-
readFailed = true;
|
|
19439
|
-
}
|
|
19440
|
-
} else {
|
|
19441
|
-
continue;
|
|
19442
|
-
}
|
|
19443
|
-
} catch {
|
|
19444
|
-
readFailed = true;
|
|
19445
|
-
}
|
|
19446
|
-
if (!payload && !readFailed) continue;
|
|
19447
|
-
if (readFailed || !payload) {
|
|
19448
|
-
if (isAcked) {
|
|
19449
|
-
const prior = getHoldState(synthKey, mesh.id);
|
|
19450
|
-
const failures = (prior?.consecutiveReadFailures ?? 0) + 1;
|
|
19451
|
-
const liveConfirmedSinceAck = prior?.liveConfirmedSinceAck ?? false;
|
|
19452
|
-
setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck, consecutiveReadFailures: failures });
|
|
19453
|
-
if (liveConfirmedSinceAck && failures >= ACKED_DEATH_CONSECUTIVE_READ_FAILURES) {
|
|
19454
|
-
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`);
|
|
19455
|
-
}
|
|
19456
|
-
}
|
|
19457
|
-
continue;
|
|
19458
|
-
}
|
|
19459
|
-
const priorHoldState = getHoldState(synthKey, mesh.id);
|
|
19460
|
-
setHoldState(synthKey, mesh.id, {
|
|
19461
|
-
liveConfirmedSinceAck: true,
|
|
19462
|
-
consecutiveReadFailures: 0,
|
|
19463
|
-
...priorHoldState?.transcriptIdleSinceMs !== void 0 ? { transcriptIdleSinceMs: priorHoldState.transcriptIdleSinceMs } : {}
|
|
19464
|
-
});
|
|
19465
|
-
const nowMs = Date.now();
|
|
19466
|
-
if (readChatPayloadStatus(payload) !== "idle") {
|
|
19467
|
-
setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
|
|
19468
|
-
continue;
|
|
19469
|
-
}
|
|
19470
|
-
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
19471
|
-
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
19472
|
-
if (isAcked) {
|
|
19473
|
-
const ackedAtMs = Date.parse(readNonEmptyString2(dispatch.updatedAt));
|
|
19474
|
-
const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
|
|
19475
|
-
const deathDeadlineMs = resolveAckedDeathDeadlineMs();
|
|
19476
|
-
const holdState = getHoldState(synthKey, mesh.id);
|
|
19477
|
-
let fastTrackReady = false;
|
|
19478
|
-
if (evidence.finalSummary) {
|
|
19479
|
-
const idleSinceMs = holdState?.transcriptIdleSinceMs ?? nowMs;
|
|
19480
|
-
if (holdState && holdState.transcriptIdleSinceMs === void 0) {
|
|
19481
|
-
setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: idleSinceMs });
|
|
19482
|
-
}
|
|
19483
|
-
const fastTrackGraceMs = resolveAckedTranscriptFastTrackGraceMs();
|
|
19484
|
-
const idleHeldMs = nowMs - idleSinceMs;
|
|
19485
|
-
if (idleHeldMs >= fastTrackGraceMs) {
|
|
19486
|
-
fastTrackReady = true;
|
|
19487
|
-
backstopKind = "ackedHoldFastTrackFired";
|
|
19488
|
-
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.`);
|
|
19489
|
-
}
|
|
19490
|
-
} else if (holdState?.transcriptIdleSinceMs !== void 0) {
|
|
19491
|
-
setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: void 0 });
|
|
19492
|
-
}
|
|
19493
|
-
if (!fastTrackReady && sinceAckMs < deathDeadlineMs) {
|
|
19494
|
-
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.`);
|
|
19495
|
-
continue;
|
|
19496
|
-
}
|
|
19497
|
-
if (!fastTrackReady) {
|
|
19498
|
-
backstopKind = "ackedHoldDeathDeadlineFired";
|
|
19499
|
-
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).`);
|
|
19500
|
-
}
|
|
19501
|
-
}
|
|
19502
|
-
if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
|
|
19503
|
-
deleteHoldState(synthKey, mesh.id);
|
|
19504
|
-
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`);
|
|
19505
|
-
continue;
|
|
19506
|
-
}
|
|
19507
|
-
if (!evidence.finalSummary) continue;
|
|
19508
|
-
const dispatchedAtMs = Date.parse(readNonEmptyString2(dispatch.dispatchedAt));
|
|
19509
|
-
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
|
|
19510
|
-
if (Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs < dispatchedAtMs) {
|
|
19511
|
-
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`);
|
|
19512
|
-
traceMeshEventDrop("reconcile_stale_summary_before_dispatch", {
|
|
19513
|
-
taskId,
|
|
19514
|
-
sessionId,
|
|
19515
|
-
nodeId,
|
|
19516
|
-
meshId: mesh.id,
|
|
19517
|
-
event: "agent:generating_completed"
|
|
19518
|
-
}, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
|
|
19519
|
-
continue;
|
|
19520
|
-
}
|
|
19521
|
-
const reprobeStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
|
|
19522
|
-
if (reprobeStatus && reprobeStatus !== "idle") {
|
|
19523
|
-
deleteHoldState(synthKey, mesh.id);
|
|
19524
|
-
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`);
|
|
19525
|
-
continue;
|
|
19526
|
-
}
|
|
19527
|
-
const providerSessionId = readNonEmptyString2(payload.providerSessionId);
|
|
19528
|
-
const coordinatorDaemonId = selfIds.find((id) => !!id);
|
|
19529
|
-
try {
|
|
19530
|
-
const result = reconcileDirectDispatchCompletionFromTranscript({
|
|
19531
|
-
meshId: mesh.id,
|
|
19532
|
-
nodeId,
|
|
19533
|
-
sessionId,
|
|
19534
|
-
providerType: providerType || void 0,
|
|
19535
|
-
providerSessionId: providerSessionId || void 0,
|
|
19536
|
-
taskId,
|
|
19537
|
-
finalSummary: evidence.finalSummary,
|
|
19538
|
-
...evidence.transcriptMessageAt ? { transcriptMessageAt: evidence.transcriptMessageAt } : {},
|
|
19539
|
-
...coordinatorDaemonId ? { targetCoordinatorDaemonId: coordinatorDaemonId } : {},
|
|
19540
|
-
source: "daemon_reconcile_transcript_completion"
|
|
19541
|
-
});
|
|
19542
|
-
if (result.reconciled) {
|
|
19543
|
-
recordBackstopFire(backstopKind ?? "phase4SynthesisFired", `task ${taskId} on node ${nodeId} (mesh ${mesh.id}), kind=${result.kind}`);
|
|
19544
|
-
LOG.info("MeshReconcile", `Synthesized missing completion (${result.kind}) for task ${taskId} on node ${nodeId} (mesh ${mesh.id})`);
|
|
19545
|
-
}
|
|
19546
|
-
} catch (e) {
|
|
19547
|
-
LOG.warn("MeshReconcile", `Transcript completion reconcile threw for task ${taskId}: ${e?.message || e}`);
|
|
19548
|
-
}
|
|
19549
|
-
}
|
|
19550
|
-
}
|
|
19551
|
-
async function autoPruneStaleDirectDispatches(components, mesh, selfIds, localDaemonId, minAgeMs) {
|
|
19552
|
-
const directDispatches = getActiveDirectDispatches(mesh.id);
|
|
19553
|
-
if (directDispatches.length === 0) return;
|
|
19554
|
-
const liveNodes = await collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId);
|
|
19555
|
-
const result = pruneStaleDirectDispatches({
|
|
19556
|
-
meshId: mesh.id,
|
|
19557
|
-
queue: getQueue(mesh.id),
|
|
19558
|
-
ledgerEntries: readLedgerEntries(mesh.id, { tail: 500 }),
|
|
19559
|
-
directDispatches,
|
|
19560
|
-
nodes: liveNodes,
|
|
19561
|
-
execute: true,
|
|
19562
|
-
minAgeMs,
|
|
19563
|
-
source: "daemon_reconcile_auto_prune"
|
|
19564
|
-
});
|
|
19565
|
-
if (result.prunedCount > 0) {
|
|
19566
|
-
LOG.info("MeshReconcile", `Auto-pruned ${result.prunedCount} orphaned direct dispatch record(s) for mesh ${mesh.id}`);
|
|
19567
|
-
}
|
|
19568
|
-
}
|
|
19569
|
-
async function collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId) {
|
|
19570
|
-
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
19571
|
-
return Promise.all(mesh.nodes.map(async (node) => {
|
|
19572
|
-
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
19573
|
-
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId);
|
|
19574
|
-
let statusResult;
|
|
19575
|
-
try {
|
|
19576
|
-
if (isLocalNode) {
|
|
19577
|
-
statusResult = await components.commandHandler.handle("get_status_metadata", {});
|
|
19578
|
-
} else if (dispatchMeshCommand) {
|
|
19579
|
-
statusResult = await dispatchMeshCommand(nodeDaemonId, "get_status_metadata", {});
|
|
19580
|
-
} else {
|
|
19581
|
-
return node;
|
|
19582
|
-
}
|
|
19583
|
-
} catch {
|
|
19584
|
-
return node;
|
|
19585
|
-
}
|
|
19586
|
-
const sessions = extractStatusMetadataSessions(statusResult);
|
|
19587
|
-
return sessions.length > 0 ? { ...node, sessions } : node;
|
|
19588
|
-
}));
|
|
19589
|
-
}
|
|
19590
|
-
function extractStatusMetadataSessions(raw) {
|
|
19591
|
-
let cursor = raw;
|
|
19592
|
-
for (let depth = 0; depth < 4 && cursor && typeof cursor === "object"; depth++) {
|
|
19593
|
-
const record = cursor;
|
|
19594
|
-
const status = record.status && typeof record.status === "object" ? record.status : void 0;
|
|
19595
|
-
if (status && Array.isArray(status.sessions)) return status.sessions;
|
|
19596
|
-
if (Array.isArray(record.sessions)) return record.sessions;
|
|
19597
|
-
if (record.payload && typeof record.payload === "object") {
|
|
19598
|
-
cursor = record.payload;
|
|
19599
|
-
continue;
|
|
19600
|
-
}
|
|
19601
|
-
if (record.result && typeof record.result === "object") {
|
|
19602
|
-
cursor = record.result;
|
|
19603
|
-
continue;
|
|
19604
|
-
}
|
|
19605
|
-
if (record.data && typeof record.data === "object") {
|
|
19606
|
-
cursor = record.data;
|
|
19607
|
-
continue;
|
|
19608
|
-
}
|
|
19609
|
-
break;
|
|
19610
|
-
}
|
|
19611
|
-
return [];
|
|
19612
|
-
}
|
|
19613
|
-
function extractPendingEvents(raw) {
|
|
19614
|
-
if (Array.isArray(raw)) return raw;
|
|
19615
|
-
if (raw && typeof raw === "object") {
|
|
19616
|
-
const events = raw.events;
|
|
19617
|
-
if (Array.isArray(events)) return events;
|
|
19618
|
-
}
|
|
19619
|
-
return [];
|
|
19620
|
-
}
|
|
19621
|
-
function buildForwardPayloadFromPending(event) {
|
|
19622
|
-
const metadata = event?.metadataEvent && typeof event.metadataEvent === "object" ? event.metadataEvent : {};
|
|
19623
|
-
return {
|
|
19624
|
-
event: readNonEmptyString2(event?.event),
|
|
19625
|
-
meshId: readNonEmptyString2(event?.meshId),
|
|
19626
|
-
nodeId: readNonEmptyString2(event?.nodeId) || readNonEmptyString2(metadata.meshNodeId),
|
|
19627
|
-
workspace: readNonEmptyString2(event?.workspace) || readNonEmptyString2(metadata.workspace),
|
|
19628
|
-
// Preserve the originating coordinator session id across the relay. It is normally
|
|
19629
|
-
// carried inside metadataEvent.meshCoordinatorSessionId (spread below), but pass the
|
|
19630
|
-
// top-level field through explicitly too so the handleMeshForwardEvent whitelist
|
|
19631
|
-
// recovers it regardless of which carrier the producing daemon used.
|
|
19632
|
-
...readNonEmptyString2(event?.targetCoordinatorSessionId) ? { targetCoordinatorSessionId: readNonEmptyString2(event.targetCoordinatorSessionId) } : {},
|
|
19633
|
-
...metadata,
|
|
19634
|
-
// NOTIF-MISS (FIX 3): surface the dispatch task id at the TOP LEVEL so the relay's
|
|
19635
|
-
// received-stage trace (and buildRelayMetadataEvent) recovers it regardless of which
|
|
19636
|
-
// carrier the producing daemon used. The metadata spread above may carry the id only as
|
|
19637
|
-
// `meshActiveTaskId` (a worker provider event), leaving top-level `taskId` unset and the
|
|
19638
|
-
// received stage rendering `task=-`. Resolve both carriers into an explicit `taskId` so
|
|
19639
|
-
// dedup stays task-scoped end-to-end. Only set when a non-empty id exists (no clobber to
|
|
19640
|
-
// undefined when neither is present).
|
|
19641
|
-
...(() => {
|
|
19642
|
-
const tid = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(metadata.meshActiveTaskId);
|
|
19643
|
-
return tid ? { taskId: tid } : {};
|
|
19644
|
-
})(),
|
|
19645
|
-
// T4 (B3b): carry the v2 envelope (protocolVersion/eventId/scope/dispatchedBy/
|
|
19646
|
-
// intendedFor) across the P2P relay boundary at the TOP LEVEL. These live on the
|
|
19647
|
-
// pending event itself, not inside metadataEvent, so without this the remote pull
|
|
19648
|
-
// re-queue would re-stamp a fresh eventId — breaking cross-machine idempotency and
|
|
19649
|
-
// downgrading the relayed completion to v1 broadcast routing. Spread LAST so the
|
|
19650
|
-
// authoritative envelope always wins over any stale key the metadata spread carried.
|
|
19651
|
-
...serializeV2EnvelopeToWire(event)
|
|
19652
|
-
};
|
|
19653
|
-
}
|
|
19654
19858
|
function setupMeshReconcileLoop(components) {
|
|
19655
19859
|
const intervalMs = resolveReconcileIntervalMs();
|
|
19656
19860
|
let running = false;
|
|
@@ -19670,7 +19874,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
19670
19874
|
}
|
|
19671
19875
|
};
|
|
19672
19876
|
}
|
|
19673
|
-
var
|
|
19877
|
+
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;
|
|
19674
19878
|
var init_mesh_reconcile_loop = __esm({
|
|
19675
19879
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
19676
19880
|
"use strict";
|
|
@@ -19689,17 +19893,13 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
19689
19893
|
init_mesh_work_queue();
|
|
19690
19894
|
init_mesh_queue_assignment();
|
|
19691
19895
|
init_mesh_ledger();
|
|
19692
|
-
init_mesh_active_work();
|
|
19693
19896
|
init_mesh_events_stale();
|
|
19694
|
-
init_chat_message_normalization();
|
|
19695
19897
|
init_mesh_reconcile_identity();
|
|
19898
|
+
init_mesh_reconcile_config();
|
|
19899
|
+
init_mesh_remote_event_pull();
|
|
19900
|
+
init_mesh_completion_synthesis();
|
|
19696
19901
|
init_mesh_reconcile_v2_backstop();
|
|
19697
19902
|
init_mesh_reconcile_acked_hold();
|
|
19698
|
-
init_mesh_reconcile_v2_backstop();
|
|
19699
|
-
init_mesh_reconcile_acked_hold();
|
|
19700
|
-
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
19701
|
-
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
19702
|
-
DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS = 12e3;
|
|
19703
19903
|
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
19704
19904
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
19705
19905
|
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
@@ -19729,6 +19929,7 @@ __export(mesh_events_exports, {
|
|
|
19729
19929
|
queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
|
|
19730
19930
|
readV2EnvelopeFromWire: () => readV2EnvelopeFromWire,
|
|
19731
19931
|
reconcileDirectDispatchCompletionFromTranscript: () => reconcileDirectDispatchCompletionFromTranscript,
|
|
19932
|
+
requeueHeldMeshCoordinatorEvents: () => requeueHeldMeshCoordinatorEvents,
|
|
19732
19933
|
resolveCoordinatorDrainDeliverability: () => resolveCoordinatorDrainDeliverability,
|
|
19733
19934
|
runMeshReconcileTick: () => runMeshReconcileTick,
|
|
19734
19935
|
serializeV2EnvelopeToWire: () => serializeV2EnvelopeToWire,
|
|
@@ -25353,6 +25554,8 @@ __export(index_exports, {
|
|
|
25353
25554
|
AcpProviderInstance: () => AcpProviderInstance,
|
|
25354
25555
|
AgentStreamPoller: () => AgentStreamPoller,
|
|
25355
25556
|
BUILTIN_CHAT_MESSAGE_KINDS: () => BUILTIN_CHAT_MESSAGE_KINDS,
|
|
25557
|
+
CANONICAL_MESH_TOOL_COUNT: () => CANONICAL_MESH_TOOL_COUNT,
|
|
25558
|
+
CANONICAL_MESH_TOOL_NAMES: () => CANONICAL_MESH_TOOL_NAMES,
|
|
25356
25559
|
CHANGE_IMPACT_CONFIG_LOCATIONS: () => CHANGE_IMPACT_CONFIG_LOCATIONS,
|
|
25357
25560
|
CHANGE_IMPACT_CONFIG_SCHEMA: () => CHANGE_IMPACT_CONFIG_SCHEMA,
|
|
25358
25561
|
CHAT_MESSAGE_ACTIVITY_SOURCES: () => CHAT_MESSAGE_ACTIVITY_SOURCES,
|
|
@@ -25410,11 +25613,13 @@ __export(index_exports, {
|
|
|
25410
25613
|
MESH_REFINE_CONFIG_LOCATIONS: () => MESH_REFINE_CONFIG_LOCATIONS,
|
|
25411
25614
|
MESH_REFINE_CONFIG_SCHEMA: () => MESH_REFINE_CONFIG_SCHEMA,
|
|
25412
25615
|
MESH_SCHEDULING_STRATEGIES: () => MESH_SCHEDULING_STRATEGIES,
|
|
25616
|
+
MESH_TASK_PRIORITIES: () => MESH_TASK_PRIORITIES,
|
|
25413
25617
|
MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS: () => MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS,
|
|
25414
25618
|
MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA: () => MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA,
|
|
25415
25619
|
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS: () => MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
25416
25620
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
25417
25621
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
25622
|
+
NOT_BEFORE_RELATIVE_THRESHOLD_MS: () => NOT_BEFORE_RELATIVE_THRESHOLD_MS,
|
|
25418
25623
|
NodePtyTransportFactory: () => NodePtyTransportFactory,
|
|
25419
25624
|
OPERATING_NOTE_DEDUPE_WINDOW: () => OPERATING_NOTE_DEDUPE_WINDOW,
|
|
25420
25625
|
OPERATING_NOTE_KEEP_LATEST: () => OPERATING_NOTE_KEEP_LATEST,
|
|
@@ -25562,7 +25767,6 @@ __export(index_exports, {
|
|
|
25562
25767
|
getQueue: () => getQueue,
|
|
25563
25768
|
getRecentActivity: () => getRecentActivity,
|
|
25564
25769
|
getRecentCommands: () => getRecentCommands,
|
|
25565
|
-
getRecentCompletionConflicts: () => getRecentCompletionConflicts,
|
|
25566
25770
|
getRecentDebugTrace: () => getRecentDebugTrace,
|
|
25567
25771
|
getRecentLogs: () => getRecentLogs,
|
|
25568
25772
|
getSavedProviderSessions: () => getSavedProviderSessions,
|
|
@@ -25626,6 +25830,8 @@ __export(index_exports, {
|
|
|
25626
25830
|
maybeRunDaemonUpgradeHelperFromEnv: () => maybeRunDaemonUpgradeHelperFromEnv,
|
|
25627
25831
|
mergeAndNormalizePolicy: () => mergeAndNormalizePolicy,
|
|
25628
25832
|
meshNodeIdMatches: () => meshNodeIdMatches,
|
|
25833
|
+
meshTaskNotBeforeReady: () => meshTaskNotBeforeReady,
|
|
25834
|
+
meshTaskPriorityRank: () => meshTaskPriorityRank,
|
|
25629
25835
|
namedKeyToAnsi: () => namedKeyToAnsi,
|
|
25630
25836
|
namedKeysToAnsi: () => namedKeysToAnsi,
|
|
25631
25837
|
nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
|
|
@@ -25648,6 +25854,7 @@ __export(index_exports, {
|
|
|
25648
25854
|
normalizeMeshNodeId: () => normalizeMeshNodeId,
|
|
25649
25855
|
normalizeMeshSchedulingStrategy: () => normalizeMeshSchedulingStrategy,
|
|
25650
25856
|
normalizeMeshTaskMode: () => normalizeMeshTaskMode,
|
|
25857
|
+
normalizeMeshTaskPriority: () => normalizeMeshTaskPriority,
|
|
25651
25858
|
normalizeMeshWorkerResult: () => normalizeMeshWorkerResult,
|
|
25652
25859
|
normalizeMessageParts: () => normalizeMessageParts,
|
|
25653
25860
|
normalizeRepoIdentity: () => normalizeRepoIdentity,
|
|
@@ -25676,7 +25883,6 @@ __export(index_exports, {
|
|
|
25676
25883
|
readOperatingNotes: () => readOperatingNotes,
|
|
25677
25884
|
readV2EnvelopeFromWire: () => readV2EnvelopeFromWire,
|
|
25678
25885
|
reconcileDirectDispatchCompletionFromTranscript: () => reconcileDirectDispatchCompletionFromTranscript,
|
|
25679
|
-
recordCompletionConflict: () => recordCompletionConflict,
|
|
25680
25886
|
recordDebugTrace: () => recordDebugTrace,
|
|
25681
25887
|
recordDirectDispatchTask: () => recordDirectDispatchTask,
|
|
25682
25888
|
recordMeshToolCall: () => recordMeshToolCall,
|
|
@@ -25686,6 +25892,7 @@ __export(index_exports, {
|
|
|
25686
25892
|
removeMagiPanel: () => removeMagiPanel,
|
|
25687
25893
|
removeNode: () => removeNode,
|
|
25688
25894
|
removeWorktree: () => removeWorktree,
|
|
25895
|
+
requeueHeldMeshCoordinatorEvents: () => requeueHeldMeshCoordinatorEvents,
|
|
25689
25896
|
requeueTask: () => requeueTask,
|
|
25690
25897
|
requireMeshHostQueueOwner: () => requireMeshHostQueueOwner,
|
|
25691
25898
|
resetConfig: () => resetConfig,
|
|
@@ -25706,6 +25913,7 @@ __export(index_exports, {
|
|
|
25706
25913
|
resolveMeshRefineValidationPlan: () => resolveMeshRefineValidationPlan,
|
|
25707
25914
|
resolveMeshSurfacedSessionPreview: () => resolveMeshSurfacedSessionPreview,
|
|
25708
25915
|
resolveNodeSchedulingPriority: () => resolveNodeSchedulingPriority,
|
|
25916
|
+
resolveNotBefore: () => resolveNotBefore,
|
|
25709
25917
|
resolveProviderMaxParallel: () => resolveProviderMaxParallel,
|
|
25710
25918
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
25711
25919
|
resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
|
|
@@ -27028,6 +27236,7 @@ init_mesh_config();
|
|
|
27028
27236
|
init_dist();
|
|
27029
27237
|
init_dist();
|
|
27030
27238
|
init_dist();
|
|
27239
|
+
init_dist();
|
|
27031
27240
|
init_coordinator_prompt();
|
|
27032
27241
|
init_mesh_missions();
|
|
27033
27242
|
init_mesh_task_stats();
|
|
@@ -42716,7 +42925,7 @@ async function waitForCliAdapterReady(adapter, options) {
|
|
|
42716
42925
|
throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
|
|
42717
42926
|
}
|
|
42718
42927
|
|
|
42719
|
-
// src/providers/cli-provider-instance.ts
|
|
42928
|
+
// src/providers/cli-provider-instance-types.ts
|
|
42720
42929
|
var STATUS_HYDRATION_TAIL_LIMIT = 200;
|
|
42721
42930
|
var COMPLETED_FINALIZATION_RETRY_MS = 1e3;
|
|
42722
42931
|
var COMPLETED_FINALIZATION_MAX_WAIT_MS = 3e4;
|
|
@@ -42728,6 +42937,123 @@ var TERMINAL_MESH_EVENTS = /* @__PURE__ */ new Set([
|
|
|
42728
42937
|
"agent:stopped",
|
|
42729
42938
|
"agent:ready"
|
|
42730
42939
|
]);
|
|
42940
|
+
|
|
42941
|
+
// src/providers/cli-provider-transcript-merge.ts
|
|
42942
|
+
init_contracts2();
|
|
42943
|
+
init_chat_message_normalization();
|
|
42944
|
+
function mergeConversationMessages(runtimeMessages, parsedMessages) {
|
|
42945
|
+
if (runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
42946
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
42947
|
+
message,
|
|
42948
|
+
index,
|
|
42949
|
+
source: "parsed"
|
|
42950
|
+
}));
|
|
42951
|
+
const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
42952
|
+
const runtimeEntries = runtimeMessages.map((entry, index) => ({
|
|
42953
|
+
message: entry.message,
|
|
42954
|
+
index: parsedMessages.length + index,
|
|
42955
|
+
source: "runtime",
|
|
42956
|
+
runtimeKey: entry.key
|
|
42957
|
+
})).filter((entry) => {
|
|
42958
|
+
const meta = entry.message.meta && typeof entry.message.meta === "object" && !Array.isArray(entry.message.meta) ? entry.message.meta : {};
|
|
42959
|
+
if (meta.runtimeInputAck !== true) return true;
|
|
42960
|
+
const runtimeText = flattenContent(entry.message.content).replace(/\s+/g, " ").trim();
|
|
42961
|
+
if (!runtimeText) return false;
|
|
42962
|
+
return !parsedEntries.some((parsedEntry) => {
|
|
42963
|
+
const parsedRole = getRole(parsedEntry.message);
|
|
42964
|
+
if (parsedRole !== "user" && parsedRole !== "human") return false;
|
|
42965
|
+
const parsedText = flattenContent(parsedEntry.message.content).replace(/\s+/g, " ").trim();
|
|
42966
|
+
return parsedText === runtimeText;
|
|
42967
|
+
});
|
|
42968
|
+
});
|
|
42969
|
+
const getTime = (message) => {
|
|
42970
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
42971
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
42972
|
+
};
|
|
42973
|
+
const isRuntimeOverlay = (entry) => {
|
|
42974
|
+
if (entry.source !== "runtime") return false;
|
|
42975
|
+
const key2 = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
|
|
42976
|
+
if (key2.startsWith("auto_approval:")) return true;
|
|
42977
|
+
return !isUserFacingChatMessage(entry.message);
|
|
42978
|
+
};
|
|
42979
|
+
const shouldKeepParsedBeforeUntimedRuntime = (message) => {
|
|
42980
|
+
const role = getRole(message);
|
|
42981
|
+
return role === "user" || role === "human";
|
|
42982
|
+
};
|
|
42983
|
+
const shouldKeepParsedAfterUntimedRuntime = (message) => {
|
|
42984
|
+
const role = getRole(message);
|
|
42985
|
+
if (role !== "assistant") return false;
|
|
42986
|
+
const kind = resolveChatMessageKind(message);
|
|
42987
|
+
return kind === "standard" || kind === "terminal";
|
|
42988
|
+
};
|
|
42989
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
42990
|
+
const aTime = getTime(a.message);
|
|
42991
|
+
const bTime = getTime(b.message);
|
|
42992
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
42993
|
+
if (a.source !== b.source && aTime !== bTime) {
|
|
42994
|
+
const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
|
|
42995
|
+
const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
|
|
42996
|
+
if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
|
|
42997
|
+
if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
|
|
42998
|
+
return a.source === "parsed" ? -1 : 1;
|
|
42999
|
+
}
|
|
43000
|
+
if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
|
|
43001
|
+
return a.source === "parsed" ? 1 : -1;
|
|
43002
|
+
}
|
|
43003
|
+
}
|
|
43004
|
+
}
|
|
43005
|
+
return a.index - b.index;
|
|
43006
|
+
}).map((entry) => entry.message));
|
|
43007
|
+
}
|
|
43008
|
+
function buildExternalTranscriptProbe(messages, sourcePath, sourceMtimeMs) {
|
|
43009
|
+
const visibleMessages = messages.filter((message) => isUserFacingChatMessage(message));
|
|
43010
|
+
const lastVisible = visibleMessages[visibleMessages.length - 1];
|
|
43011
|
+
const readAt = Date.now();
|
|
43012
|
+
const mtimeMs = Number(sourceMtimeMs) || 0;
|
|
43013
|
+
return {
|
|
43014
|
+
readAt,
|
|
43015
|
+
msgCount: messages.length,
|
|
43016
|
+
lastRole: typeof lastVisible?.role === "string" ? lastVisible.role.trim().toLowerCase() : null,
|
|
43017
|
+
lastKind: typeof lastVisible?.kind === "string" ? lastVisible.kind : null,
|
|
43018
|
+
contentLen: lastVisible ? flattenContent(lastVisible.content).trim().length : 0,
|
|
43019
|
+
sourcePath: typeof sourcePath === "string" && sourcePath ? sourcePath : null,
|
|
43020
|
+
sourceMtimeMs: mtimeMs || null,
|
|
43021
|
+
mtimeAgeMs: mtimeMs ? Math.max(0, readAt - mtimeMs) : null
|
|
43022
|
+
};
|
|
43023
|
+
}
|
|
43024
|
+
|
|
43025
|
+
// src/providers/cli-provider-effect-format.ts
|
|
43026
|
+
function getEffectDedupKey(effect) {
|
|
43027
|
+
if (effect.id) return `provider_effect:${effect.id}`;
|
|
43028
|
+
if (effect.type === "message") {
|
|
43029
|
+
const content = typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
|
|
43030
|
+
return `provider_effect:message:${content}`;
|
|
43031
|
+
}
|
|
43032
|
+
if (effect.type === "notification") {
|
|
43033
|
+
return `provider_effect:notification:${effect.notification?.title || ""}:${effect.notification?.body || ""}`;
|
|
43034
|
+
}
|
|
43035
|
+
return `provider_effect:toast:${effect.toast?.message || ""}`;
|
|
43036
|
+
}
|
|
43037
|
+
function formatApprovalRequestMessage(modalMessage, buttons) {
|
|
43038
|
+
const lines = ["Approval requested"];
|
|
43039
|
+
const cleanMessage = String(modalMessage || "").trim();
|
|
43040
|
+
if (cleanMessage) lines.push(cleanMessage);
|
|
43041
|
+
const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
|
|
43042
|
+
if (labels.length > 0) {
|
|
43043
|
+
lines.push(labels.map((label) => `[${label}]`).join(" "));
|
|
43044
|
+
}
|
|
43045
|
+
return lines.join("\n");
|
|
43046
|
+
}
|
|
43047
|
+
function formatMarkerTimestamp(timestamp) {
|
|
43048
|
+
const date = new Date(timestamp);
|
|
43049
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
43050
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
43051
|
+
}
|
|
43052
|
+
|
|
43053
|
+
// src/providers/cli-provider-instance.ts
|
|
43054
|
+
function approvalModalSignature(message, affirmativeAnchor) {
|
|
43055
|
+
return [typeof message === "string" ? message.trim() : "", affirmativeAnchor].join("::");
|
|
43056
|
+
}
|
|
42731
43057
|
var CliProviderInstance = class _CliProviderInstance {
|
|
42732
43058
|
constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
|
|
42733
43059
|
this.provider = provider;
|
|
@@ -42975,7 +43301,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
42975
43301
|
const resumedAt = Date.now();
|
|
42976
43302
|
this.historyWriter.appendSystemMarker(
|
|
42977
43303
|
this.type,
|
|
42978
|
-
`Resumed saved session at ${
|
|
43304
|
+
`Resumed saved session at ${formatMarkerTimestamp(resumedAt)}`,
|
|
42979
43305
|
{
|
|
42980
43306
|
instanceId: this.instanceId,
|
|
42981
43307
|
historySessionId: this.providerSessionId,
|
|
@@ -43087,7 +43413,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43087
43413
|
if (historyMessageCount !== null) {
|
|
43088
43414
|
parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
|
|
43089
43415
|
}
|
|
43090
|
-
const mergedMessages = this.
|
|
43416
|
+
const mergedMessages = mergeConversationMessages(this.runtimeMessages, parsedMessages);
|
|
43091
43417
|
const canonicalBackedHistory = this.shouldHydrateExistingProviderHistory() ? this.syncCanonicalSavedHistoryIfNeeded() : false;
|
|
43092
43418
|
const statusMessages = canonicalBackedHistory && this.lastPersistedHistoryMessages.length > 0 ? this.lastPersistedHistoryMessages.map((message) => ({
|
|
43093
43419
|
role: message.role,
|
|
@@ -43552,22 +43878,6 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43552
43878
|
}
|
|
43553
43879
|
return true;
|
|
43554
43880
|
}
|
|
43555
|
-
buildExternalTranscriptProbe(messages, sourcePath, sourceMtimeMs) {
|
|
43556
|
-
const visibleMessages = messages.filter((message) => isUserFacingChatMessage(message));
|
|
43557
|
-
const lastVisible = visibleMessages[visibleMessages.length - 1];
|
|
43558
|
-
const readAt = Date.now();
|
|
43559
|
-
const mtimeMs = Number(sourceMtimeMs) || 0;
|
|
43560
|
-
return {
|
|
43561
|
-
readAt,
|
|
43562
|
-
msgCount: messages.length,
|
|
43563
|
-
lastRole: typeof lastVisible?.role === "string" ? lastVisible.role.trim().toLowerCase() : null,
|
|
43564
|
-
lastKind: typeof lastVisible?.kind === "string" ? lastVisible.kind : null,
|
|
43565
|
-
contentLen: lastVisible ? flattenContent(lastVisible.content).trim().length : 0,
|
|
43566
|
-
sourcePath: typeof sourcePath === "string" && sourcePath ? sourcePath : null,
|
|
43567
|
-
sourceMtimeMs: mtimeMs || null,
|
|
43568
|
-
mtimeAgeMs: mtimeMs ? Math.max(0, readAt - mtimeMs) : null
|
|
43569
|
-
};
|
|
43570
|
-
}
|
|
43571
43881
|
recordPendingTranscriptProbe(pending) {
|
|
43572
43882
|
const probe = this.lastExternalCompletionProbe;
|
|
43573
43883
|
if (!probe) return null;
|
|
@@ -43619,7 +43929,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43619
43929
|
this.lastExternalCompletionProbe = null;
|
|
43620
43930
|
return null;
|
|
43621
43931
|
}
|
|
43622
|
-
this.lastExternalCompletionProbe =
|
|
43932
|
+
this.lastExternalCompletionProbe = buildExternalTranscriptProbe(
|
|
43623
43933
|
restoredHistory.messages,
|
|
43624
43934
|
restoredHistory.sourcePath,
|
|
43625
43935
|
restoredHistory.sourceMtimeMs
|
|
@@ -43867,6 +44177,27 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
43867
44177
|
autoApproveContinuityWindowMs() {
|
|
43868
44178
|
return this.autoApproveMaskSince > 0 && this.isMeshWorkerSession() ? _CliProviderInstance.AUTO_APPROVE_FLAP_CONTINUITY_MS : _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS;
|
|
43869
44179
|
}
|
|
44180
|
+
/**
|
|
44181
|
+
* The settle-gate identity signature for a raw activeModal, or null when the
|
|
44182
|
+
* modal is NOT a concrete auto-approvable consent prompt (no captured buttons,
|
|
44183
|
+
* a picker/confirm kind, or no reliable affirmative+decline anchor). Mirrors the
|
|
44184
|
+
* gates the auto-approve fire path applies before computing modalSignature, so
|
|
44185
|
+
* the mask-stall nudge can ask the SAME question the settle gate is tracking —
|
|
44186
|
+
* "is THIS frame's modal the identity the settle clock is accruing against?" —
|
|
44187
|
+
* without duplicating the button-pick logic. The signature is message +
|
|
44188
|
+
* normalized affirmative label only (no volatile counters/button set), matching
|
|
44189
|
+
* the fire path exactly (AUTOAPPROVE-SETTLE-FLAP).
|
|
44190
|
+
*/
|
|
44191
|
+
approvableModalSignature(modal) {
|
|
44192
|
+
const buttons = Array.isArray(modal?.buttons) ? modal.buttons.map((b) => String(b || "").trim()).filter(Boolean) : [];
|
|
44193
|
+
if (!modal || buttons.length === 0) return null;
|
|
44194
|
+
const modalKind = typeof modal?.kind === "string" ? modal.kind : "approval";
|
|
44195
|
+
if (modalKind !== "approval") return null;
|
|
44196
|
+
const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(buttons, this.provider);
|
|
44197
|
+
const hasReliableConsentAnchor = hasNegativeApprovalOption(buttons) || hasReliableApprovalAffirmative(buttons);
|
|
44198
|
+
if (buttonIndex < 0 || !hasReliableConsentAnchor) return null;
|
|
44199
|
+
return approvalModalSignature(modal?.message, normalizeApprovalLabel(buttonLabel));
|
|
44200
|
+
}
|
|
43870
44201
|
// FALSE-IDLE (self-coordinator settle): an autonomously-progressing mesh session
|
|
43871
44202
|
// is either a delegated worker (isMeshWorkerSession) OR the coordinator's OWN
|
|
43872
44203
|
// claude-cli session (meshCoordinatorFor). Both run auto-approved tool turns whose
|
|
@@ -44170,10 +44501,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44170
44501
|
return autoApproveActive;
|
|
44171
44502
|
}
|
|
44172
44503
|
const affirmativeAnchor = normalizeApprovalLabel(buttonLabel);
|
|
44173
|
-
const modalSignature =
|
|
44174
|
-
typeof modal?.message === "string" ? modal.message.trim() : "",
|
|
44175
|
-
affirmativeAnchor
|
|
44176
|
-
].join("::");
|
|
44504
|
+
const modalSignature = approvalModalSignature(modal?.message, affirmativeAnchor);
|
|
44177
44505
|
const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
|
|
44178
44506
|
const busySignature = `${approvalEntrySeq}::${modalSignature}`;
|
|
44179
44507
|
if (this.autoApproveBusy && busySignature === this.lastAutoApprovalSignature) {
|
|
@@ -44406,7 +44734,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44406
44734
|
if (approvalFingerprint !== this.lastApprovalEventFingerprint) {
|
|
44407
44735
|
this.lastApprovalEventFingerprint = approvalFingerprint;
|
|
44408
44736
|
this.appendRuntimeSystemMessage(
|
|
44409
|
-
|
|
44737
|
+
formatApprovalRequestMessage(modal?.message, modal?.buttons),
|
|
44410
44738
|
`approval_request:${now}`,
|
|
44411
44739
|
now
|
|
44412
44740
|
);
|
|
@@ -44707,7 +45035,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44707
45035
|
const effectWhen = effect.when || "immediate";
|
|
44708
45036
|
if (effectWhen === "turn_completed" && options.phase !== "turn_completed") continue;
|
|
44709
45037
|
if (effectWhen === "immediate" && options.phase === "turn_completed") continue;
|
|
44710
|
-
const effectKey =
|
|
45038
|
+
const effectKey = getEffectDedupKey(effect);
|
|
44711
45039
|
if (this.appliedEffectKeys.has(effectKey)) continue;
|
|
44712
45040
|
this.appliedEffectKeys.add(effectKey);
|
|
44713
45041
|
if (effect.persist !== false) {
|
|
@@ -44750,34 +45078,6 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44750
45078
|
this.appliedEffectKeys = new Set(Array.from(this.appliedEffectKeys).slice(-100));
|
|
44751
45079
|
}
|
|
44752
45080
|
}
|
|
44753
|
-
getEffectDedupKey(effect) {
|
|
44754
|
-
if (effect.id) return `provider_effect:${effect.id}`;
|
|
44755
|
-
if (effect.type === "message") {
|
|
44756
|
-
const content = typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
|
|
44757
|
-
return `provider_effect:message:${content}`;
|
|
44758
|
-
}
|
|
44759
|
-
if (effect.type === "notification") {
|
|
44760
|
-
return `provider_effect:notification:${effect.notification?.title || ""}:${effect.notification?.body || ""}`;
|
|
44761
|
-
}
|
|
44762
|
-
return `provider_effect:toast:${effect.toast?.message || ""}`;
|
|
44763
|
-
}
|
|
44764
|
-
getPersistedEffectContent(effect) {
|
|
44765
|
-
if (effect.type === "message") {
|
|
44766
|
-
return typeof effect.message?.content === "string" ? effect.message.content : JSON.stringify(effect.message?.content || "");
|
|
44767
|
-
}
|
|
44768
|
-
if (effect.type === "toast") {
|
|
44769
|
-
return effect.toast?.message || null;
|
|
44770
|
-
}
|
|
44771
|
-
if (effect.type === "notification") {
|
|
44772
|
-
if (typeof effect.notification?.bubbleContent === "string") return effect.notification.bubbleContent;
|
|
44773
|
-
if (typeof effect.notification?.title === "string" && effect.notification.title.trim()) {
|
|
44774
|
-
return `${effect.notification.title}
|
|
44775
|
-
${effect.notification.body || ""}`.trim();
|
|
44776
|
-
}
|
|
44777
|
-
return effect.notification?.body || null;
|
|
44778
|
-
}
|
|
44779
|
-
return null;
|
|
44780
|
-
}
|
|
44781
45081
|
// ─── Adapter access (backward compat) ──────────────────
|
|
44782
45082
|
getAdapter() {
|
|
44783
45083
|
return this.adapter;
|
|
@@ -44849,15 +45149,16 @@ ${effect.notification.body || ""}`.trim();
|
|
|
44849
45149
|
if (!this.isMeshWorkerSession()) return;
|
|
44850
45150
|
if (adapterStatus?.status !== "waiting_approval") return;
|
|
44851
45151
|
if (!this.autoApproveMaskStalled(now)) return;
|
|
44852
|
-
const
|
|
44853
|
-
|
|
45152
|
+
const currentSignature = this.approvableModalSignature(adapterStatus.activeModal);
|
|
45153
|
+
const settleProgressing = !!currentSignature && this.pendingAutoApprovalSince > 0 && currentSignature === this.pendingAutoApprovalSignature;
|
|
45154
|
+
if (settleProgressing) return;
|
|
44854
45155
|
if (this.stalledApprovalNudgeEpisode === this.autoApproveMaskSince) return;
|
|
44855
45156
|
this.stalledApprovalNudgeEpisode = this.autoApproveMaskSince;
|
|
44856
45157
|
const modal = adapterStatus.activeModal;
|
|
44857
45158
|
const dirName = workingDirBasename(this.workingDir);
|
|
44858
45159
|
const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
|
|
44859
45160
|
this.appendRuntimeSystemMessage(
|
|
44860
|
-
|
|
45161
|
+
formatApprovalRequestMessage(modal?.message, modal?.buttons),
|
|
44861
45162
|
`approval_request:${now}`,
|
|
44862
45163
|
now
|
|
44863
45164
|
);
|
|
@@ -44887,11 +45188,6 @@ ${effect.notification.body || ""}`.trim();
|
|
|
44887
45188
|
now
|
|
44888
45189
|
);
|
|
44889
45190
|
}
|
|
44890
|
-
formatMarkerTimestamp(timestamp) {
|
|
44891
|
-
const date = new Date(timestamp);
|
|
44892
|
-
const pad = (value) => String(value).padStart(2, "0");
|
|
44893
|
-
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
44894
|
-
}
|
|
44895
45191
|
maybeAppendRuntimeRecoveryMessage(runtime) {
|
|
44896
45192
|
if (!runtime?.restoredFromStorage || !runtime.runtimeId) return;
|
|
44897
45193
|
const recoveryState = String(runtime.recoveryState || "").trim();
|
|
@@ -44952,81 +45248,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
44952
45248
|
}
|
|
44953
45249
|
}
|
|
44954
45250
|
mergeRuntimeChatMessages(parsedMessages) {
|
|
44955
|
-
return this.
|
|
44956
|
-
}
|
|
44957
|
-
mergeConversationMessages(parsedMessages) {
|
|
44958
|
-
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
44959
|
-
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
44960
|
-
message,
|
|
44961
|
-
index,
|
|
44962
|
-
source: "parsed"
|
|
44963
|
-
}));
|
|
44964
|
-
const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
44965
|
-
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
44966
|
-
message: entry.message,
|
|
44967
|
-
index: parsedMessages.length + index,
|
|
44968
|
-
source: "runtime",
|
|
44969
|
-
runtimeKey: entry.key
|
|
44970
|
-
})).filter((entry) => {
|
|
44971
|
-
const meta = entry.message.meta && typeof entry.message.meta === "object" && !Array.isArray(entry.message.meta) ? entry.message.meta : {};
|
|
44972
|
-
if (meta.runtimeInputAck !== true) return true;
|
|
44973
|
-
const runtimeText = flattenContent(entry.message.content).replace(/\s+/g, " ").trim();
|
|
44974
|
-
if (!runtimeText) return false;
|
|
44975
|
-
return !parsedEntries.some((parsedEntry) => {
|
|
44976
|
-
const parsedRole = getRole(parsedEntry.message);
|
|
44977
|
-
if (parsedRole !== "user" && parsedRole !== "human") return false;
|
|
44978
|
-
const parsedText = flattenContent(parsedEntry.message.content).replace(/\s+/g, " ").trim();
|
|
44979
|
-
return parsedText === runtimeText;
|
|
44980
|
-
});
|
|
44981
|
-
});
|
|
44982
|
-
const getTime = (message) => {
|
|
44983
|
-
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
44984
|
-
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
44985
|
-
};
|
|
44986
|
-
const isRuntimeOverlay = (entry) => {
|
|
44987
|
-
if (entry.source !== "runtime") return false;
|
|
44988
|
-
const key2 = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
|
|
44989
|
-
if (key2.startsWith("auto_approval:")) return true;
|
|
44990
|
-
return !isUserFacingChatMessage(entry.message);
|
|
44991
|
-
};
|
|
44992
|
-
const shouldKeepParsedBeforeUntimedRuntime = (message) => {
|
|
44993
|
-
const role = getRole(message);
|
|
44994
|
-
return role === "user" || role === "human";
|
|
44995
|
-
};
|
|
44996
|
-
const shouldKeepParsedAfterUntimedRuntime = (message) => {
|
|
44997
|
-
const role = getRole(message);
|
|
44998
|
-
if (role !== "assistant") return false;
|
|
44999
|
-
const kind = resolveChatMessageKind(message);
|
|
45000
|
-
return kind === "standard" || kind === "terminal";
|
|
45001
|
-
};
|
|
45002
|
-
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
45003
|
-
const aTime = getTime(a.message);
|
|
45004
|
-
const bTime = getTime(b.message);
|
|
45005
|
-
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
45006
|
-
if (a.source !== b.source && aTime !== bTime) {
|
|
45007
|
-
const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
|
|
45008
|
-
const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
|
|
45009
|
-
if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
|
|
45010
|
-
if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
|
|
45011
|
-
return a.source === "parsed" ? -1 : 1;
|
|
45012
|
-
}
|
|
45013
|
-
if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
|
|
45014
|
-
return a.source === "parsed" ? 1 : -1;
|
|
45015
|
-
}
|
|
45016
|
-
}
|
|
45017
|
-
}
|
|
45018
|
-
return a.index - b.index;
|
|
45019
|
-
}).map((entry) => entry.message));
|
|
45020
|
-
}
|
|
45021
|
-
formatApprovalRequestMessage(modalMessage, buttons) {
|
|
45022
|
-
const lines = ["Approval requested"];
|
|
45023
|
-
const cleanMessage = String(modalMessage || "").trim();
|
|
45024
|
-
if (cleanMessage) lines.push(cleanMessage);
|
|
45025
|
-
const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
|
|
45026
|
-
if (labels.length > 0) {
|
|
45027
|
-
lines.push(labels.map((label) => `[${label}]`).join(" "));
|
|
45028
|
-
}
|
|
45029
|
-
return lines.join("\n");
|
|
45251
|
+
return mergeConversationMessages(this.runtimeMessages, parsedMessages);
|
|
45030
45252
|
}
|
|
45031
45253
|
promoteProviderSessionId(sessionId, opts = {}) {
|
|
45032
45254
|
const nextSessionId = String(sessionId || "").trim();
|
|
@@ -68718,6 +68940,8 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
68718
68940
|
AcpProviderInstance,
|
|
68719
68941
|
AgentStreamPoller,
|
|
68720
68942
|
BUILTIN_CHAT_MESSAGE_KINDS,
|
|
68943
|
+
CANONICAL_MESH_TOOL_COUNT,
|
|
68944
|
+
CANONICAL_MESH_TOOL_NAMES,
|
|
68721
68945
|
CHANGE_IMPACT_CONFIG_LOCATIONS,
|
|
68722
68946
|
CHANGE_IMPACT_CONFIG_SCHEMA,
|
|
68723
68947
|
CHAT_MESSAGE_ACTIVITY_SOURCES,
|
|
@@ -68775,11 +68999,13 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
68775
68999
|
MESH_REFINE_CONFIG_LOCATIONS,
|
|
68776
69000
|
MESH_REFINE_CONFIG_SCHEMA,
|
|
68777
69001
|
MESH_SCHEDULING_STRATEGIES,
|
|
69002
|
+
MESH_TASK_PRIORITIES,
|
|
68778
69003
|
MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS,
|
|
68779
69004
|
MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA,
|
|
68780
69005
|
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
68781
69006
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
68782
69007
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
69008
|
+
NOT_BEFORE_RELATIVE_THRESHOLD_MS,
|
|
68783
69009
|
NodePtyTransportFactory,
|
|
68784
69010
|
OPERATING_NOTE_DEDUPE_WINDOW,
|
|
68785
69011
|
OPERATING_NOTE_KEEP_LATEST,
|
|
@@ -68927,7 +69153,6 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
68927
69153
|
getQueue,
|
|
68928
69154
|
getRecentActivity,
|
|
68929
69155
|
getRecentCommands,
|
|
68930
|
-
getRecentCompletionConflicts,
|
|
68931
69156
|
getRecentDebugTrace,
|
|
68932
69157
|
getRecentLogs,
|
|
68933
69158
|
getSavedProviderSessions,
|
|
@@ -68991,6 +69216,8 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
68991
69216
|
maybeRunDaemonUpgradeHelperFromEnv,
|
|
68992
69217
|
mergeAndNormalizePolicy,
|
|
68993
69218
|
meshNodeIdMatches,
|
|
69219
|
+
meshTaskNotBeforeReady,
|
|
69220
|
+
meshTaskPriorityRank,
|
|
68994
69221
|
namedKeyToAnsi,
|
|
68995
69222
|
namedKeysToAnsi,
|
|
68996
69223
|
nodeSatisfiesRequiredTags,
|
|
@@ -69013,6 +69240,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
69013
69240
|
normalizeMeshNodeId,
|
|
69014
69241
|
normalizeMeshSchedulingStrategy,
|
|
69015
69242
|
normalizeMeshTaskMode,
|
|
69243
|
+
normalizeMeshTaskPriority,
|
|
69016
69244
|
normalizeMeshWorkerResult,
|
|
69017
69245
|
normalizeMessageParts,
|
|
69018
69246
|
normalizeRepoIdentity,
|
|
@@ -69041,7 +69269,6 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
69041
69269
|
readOperatingNotes,
|
|
69042
69270
|
readV2EnvelopeFromWire,
|
|
69043
69271
|
reconcileDirectDispatchCompletionFromTranscript,
|
|
69044
|
-
recordCompletionConflict,
|
|
69045
69272
|
recordDebugTrace,
|
|
69046
69273
|
recordDirectDispatchTask,
|
|
69047
69274
|
recordMeshToolCall,
|
|
@@ -69051,6 +69278,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
69051
69278
|
removeMagiPanel,
|
|
69052
69279
|
removeNode,
|
|
69053
69280
|
removeWorktree,
|
|
69281
|
+
requeueHeldMeshCoordinatorEvents,
|
|
69054
69282
|
requeueTask,
|
|
69055
69283
|
requireMeshHostQueueOwner,
|
|
69056
69284
|
resetConfig,
|
|
@@ -69071,6 +69299,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
69071
69299
|
resolveMeshRefineValidationPlan,
|
|
69072
69300
|
resolveMeshSurfacedSessionPreview,
|
|
69073
69301
|
resolveNodeSchedulingPriority,
|
|
69302
|
+
resolveNotBefore,
|
|
69074
69303
|
resolveProviderMaxParallel,
|
|
69075
69304
|
resolveSessionHostAppName,
|
|
69076
69305
|
resolveSessionHostAppNameResolution,
|