@adhdev/daemon-core 0.9.82-rc.431 → 0.9.82-rc.433
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +455 -320
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +455 -320
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-host-ownership.d.ts +21 -1
- package/dist/providers/cli-provider-instance.d.ts +31 -0
- package/package.json +2 -2
- package/src/commands/high-family/mesh-status.ts +5 -1
- package/src/mesh/mesh-event-forwarding.ts +10 -1
- package/src/mesh/mesh-host-ownership.ts +41 -3
- package/src/mesh/mesh-reconcile-loop.ts +270 -53
- package/src/providers/cli-provider-instance.ts +44 -0
package/dist/index.mjs
CHANGED
|
@@ -404,10 +404,10 @@ function readInjected(value) {
|
|
|
404
404
|
}
|
|
405
405
|
function getDaemonBuildInfo() {
|
|
406
406
|
if (cached) return cached;
|
|
407
|
-
const commit = readInjected(true ? "
|
|
408
|
-
const commitShort = readInjected(true ? "
|
|
409
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
410
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
407
|
+
const commit = readInjected(true ? "bf124fd471f6149d84a75594a6adaaff75793523" : void 0) ?? "unknown";
|
|
408
|
+
const commitShort = readInjected(true ? "bf124fd4" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
409
|
+
const version = readInjected(true ? "0.9.82-rc.433" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
410
|
+
const builtAt = readInjected(true ? "2026-06-30T14:21:42.763Z" : void 0);
|
|
411
411
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
412
412
|
return cached;
|
|
413
413
|
}
|
|
@@ -2498,17 +2498,285 @@ var init_hash = __esm({
|
|
|
2498
2498
|
}
|
|
2499
2499
|
});
|
|
2500
2500
|
|
|
2501
|
+
// ../mesh-shared/dist/index.mjs
|
|
2502
|
+
function readRecord(value) {
|
|
2503
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2504
|
+
}
|
|
2505
|
+
function readString2(...values) {
|
|
2506
|
+
for (const value of values) {
|
|
2507
|
+
if (typeof value !== "string") continue;
|
|
2508
|
+
const trimmed = value.trim();
|
|
2509
|
+
if (trimmed) return trimmed;
|
|
2510
|
+
}
|
|
2511
|
+
return void 0;
|
|
2512
|
+
}
|
|
2513
|
+
function readNumber(...values) {
|
|
2514
|
+
for (const value of values) {
|
|
2515
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2516
|
+
}
|
|
2517
|
+
return void 0;
|
|
2518
|
+
}
|
|
2519
|
+
function readBoolean(...values) {
|
|
2520
|
+
for (const value of values) {
|
|
2521
|
+
if (typeof value === "boolean") return value;
|
|
2522
|
+
}
|
|
2523
|
+
return void 0;
|
|
2524
|
+
}
|
|
2525
|
+
function joinRepoPath(root, relativePath) {
|
|
2526
|
+
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
2527
|
+
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
2528
|
+
if (!normalizedPath) return void 0;
|
|
2529
|
+
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
2530
|
+
if (!normalizedRoot) return void 0;
|
|
2531
|
+
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
2532
|
+
}
|
|
2533
|
+
function scoreGitUpstreamFreshness(status) {
|
|
2534
|
+
switch (status) {
|
|
2535
|
+
case "fresh":
|
|
2536
|
+
return 30;
|
|
2537
|
+
case "no_upstream":
|
|
2538
|
+
return 4;
|
|
2539
|
+
case "unchecked":
|
|
2540
|
+
case void 0:
|
|
2541
|
+
return 0;
|
|
2542
|
+
case "stale":
|
|
2543
|
+
return -10;
|
|
2544
|
+
case "unavailable":
|
|
2545
|
+
return -15;
|
|
2546
|
+
default:
|
|
2547
|
+
return 0;
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
function readGitSubmodules(value, parentRepoRoot) {
|
|
2551
|
+
if (!Array.isArray(value)) return void 0;
|
|
2552
|
+
const submodules = value.map((entry) => {
|
|
2553
|
+
const submodule = readRecord(entry);
|
|
2554
|
+
const path43 = readString2(submodule.path);
|
|
2555
|
+
const commit = readString2(submodule.commit);
|
|
2556
|
+
const repoPath = readString2(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path43);
|
|
2557
|
+
if (!path43 || !commit) return null;
|
|
2558
|
+
const result = {
|
|
2559
|
+
path: path43,
|
|
2560
|
+
commit,
|
|
2561
|
+
dirty: readBoolean(submodule.dirty) ?? false,
|
|
2562
|
+
outOfSync: readBoolean(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
2563
|
+
lastCheckedAt: readNumber(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now()
|
|
2564
|
+
};
|
|
2565
|
+
if (repoPath) result.repoPath = repoPath;
|
|
2566
|
+
const error = readString2(submodule.error);
|
|
2567
|
+
if (error) result.error = error;
|
|
2568
|
+
return result;
|
|
2569
|
+
}).filter((entry) => entry !== null);
|
|
2570
|
+
return submodules.length > 0 ? submodules : void 0;
|
|
2571
|
+
}
|
|
2572
|
+
function hasGitStatusEvidence(status) {
|
|
2573
|
+
return readBoolean(status.isGitRepo) !== void 0 || Boolean(readString2(status.branch, status.upstream, status.upstreamStatus, status.upstream_status, status.headCommit)) || Boolean(readString2(status.repoRoot, status.repo_root, status.workspace)) || readNumber(
|
|
2574
|
+
status.ahead,
|
|
2575
|
+
status.behind,
|
|
2576
|
+
status.staged,
|
|
2577
|
+
status.modified,
|
|
2578
|
+
status.untracked,
|
|
2579
|
+
status.deleted,
|
|
2580
|
+
status.renamed,
|
|
2581
|
+
status.lastCheckedAt,
|
|
2582
|
+
status.last_checked_at
|
|
2583
|
+
) !== void 0 || Array.isArray(status.submodules) && status.submodules.length > 0;
|
|
2584
|
+
}
|
|
2585
|
+
function normalizeGitStatus(status, node, options) {
|
|
2586
|
+
const explicitIsGitRepo = readBoolean(status.isGitRepo);
|
|
2587
|
+
if (!Object.keys(status).length || !hasGitStatusEvidence(status)) return void 0;
|
|
2588
|
+
const isGitRepo = explicitIsGitRepo ?? true;
|
|
2589
|
+
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((entry) => typeof entry === "string") : [];
|
|
2590
|
+
const conflictCount = readNumber(status.conflicts) ?? conflictFiles.length;
|
|
2591
|
+
const hasConflicts = readBoolean(status.hasConflicts) ?? conflictCount > 0;
|
|
2592
|
+
const repoRoot = readString2(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
|
|
2593
|
+
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
2594
|
+
const upstreamStatus = readString2(status.upstreamStatus, status.upstream_status);
|
|
2595
|
+
const upstreamFetchedAt2 = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
|
|
2596
|
+
const upstreamFetchError = readString2(status.upstreamFetchError, status.upstream_fetch_error);
|
|
2597
|
+
const error = readString2(status.error);
|
|
2598
|
+
const staged = readNumber(status.staged) ?? 0;
|
|
2599
|
+
const modified = readNumber(status.modified) ?? 0;
|
|
2600
|
+
const untracked = readNumber(status.untracked) ?? 0;
|
|
2601
|
+
const deleted = readNumber(status.deleted) ?? 0;
|
|
2602
|
+
const renamed = readNumber(status.renamed) ?? 0;
|
|
2603
|
+
return {
|
|
2604
|
+
workspace: readString2(status.workspace, node.workspace) || "",
|
|
2605
|
+
repoRoot: repoRoot ?? null,
|
|
2606
|
+
isGitRepo,
|
|
2607
|
+
branch: readString2(status.branch) ?? null,
|
|
2608
|
+
headCommit: readString2(status.headCommit) ?? null,
|
|
2609
|
+
headMessage: readString2(status.headMessage) ?? null,
|
|
2610
|
+
upstream: readString2(status.upstream) ?? null,
|
|
2611
|
+
upstreamStatus: upstreamStatus ?? "unchecked",
|
|
2612
|
+
...upstreamFetchedAt2 !== void 0 ? { upstreamFetchedAt: upstreamFetchedAt2 } : {},
|
|
2613
|
+
...upstreamFetchError ? { upstreamFetchError } : {},
|
|
2614
|
+
ahead: readNumber(status.ahead) ?? 0,
|
|
2615
|
+
behind: readNumber(status.behind) ?? 0,
|
|
2616
|
+
staged,
|
|
2617
|
+
modified,
|
|
2618
|
+
untracked,
|
|
2619
|
+
deleted,
|
|
2620
|
+
renamed,
|
|
2621
|
+
dirty: readBoolean(status.dirty, status.isDirty, status.is_dirty) ?? (staged + modified + untracked + deleted + renamed > 0 || hasConflicts),
|
|
2622
|
+
hasConflicts,
|
|
2623
|
+
conflictFiles,
|
|
2624
|
+
stashCount: readNumber(status.stashCount, status.stash_count) ?? 0,
|
|
2625
|
+
lastCheckedAt: options?.lastCheckedAt ?? readNumber(status.lastCheckedAt, status.last_checked_at) ?? Date.now(),
|
|
2626
|
+
...submodules ? { submodules } : {},
|
|
2627
|
+
...error ? { error } : {}
|
|
2628
|
+
};
|
|
2629
|
+
}
|
|
2630
|
+
function scoreGitStatusCandidate(git) {
|
|
2631
|
+
if (!git) return Number.NEGATIVE_INFINITY;
|
|
2632
|
+
let score = 0;
|
|
2633
|
+
if (git.isGitRepo === true) score += 50;
|
|
2634
|
+
if (git.isGitRepo === false) score -= 10;
|
|
2635
|
+
if (git.branch) score += 20;
|
|
2636
|
+
if (git.headCommit) score += 20;
|
|
2637
|
+
if (git.upstream) score += 10;
|
|
2638
|
+
score += scoreGitUpstreamFreshness(git.upstreamStatus);
|
|
2639
|
+
if (typeof git.ahead === "number") score += 2;
|
|
2640
|
+
if (typeof git.behind === "number") score += 2;
|
|
2641
|
+
if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
|
|
2642
|
+
if (git.error) score -= 20;
|
|
2643
|
+
return score;
|
|
2644
|
+
}
|
|
2645
|
+
function pickBestTransitGitStatus(node, options) {
|
|
2646
|
+
const rawGit = readRecord(node.lastGit ?? node.last_git);
|
|
2647
|
+
const gitResult = readRecord(rawGit.result);
|
|
2648
|
+
const directStatus = readRecord(rawGit.status);
|
|
2649
|
+
const nestedStatus = readRecord(gitResult.status);
|
|
2650
|
+
const rawProbe = readRecord(node.lastProbe ?? node.last_probe);
|
|
2651
|
+
const probeGit = readRecord(rawProbe.git);
|
|
2652
|
+
const probeGitResult = readRecord(probeGit.result);
|
|
2653
|
+
const probeDirectStatus = readRecord(probeGit.status);
|
|
2654
|
+
const probeNestedStatus = readRecord(probeGitResult.status);
|
|
2655
|
+
const lastCheckedAt = options?.lastCheckedAt;
|
|
2656
|
+
let best = null;
|
|
2657
|
+
for (const status of [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus]) {
|
|
2658
|
+
const normalized = normalizeGitStatus(status, node, { lastCheckedAt: lastCheckedAt ?? Date.now() });
|
|
2659
|
+
if (!normalized) continue;
|
|
2660
|
+
const score = scoreGitStatusCandidate(normalized);
|
|
2661
|
+
if (!best || score > best.score) best = { git: normalized, score };
|
|
2662
|
+
}
|
|
2663
|
+
return best?.git;
|
|
2664
|
+
}
|
|
2665
|
+
function normalizeMeshNodeId(node) {
|
|
2666
|
+
const record = node && typeof node === "object" ? node : {};
|
|
2667
|
+
return readString2(record.id, record.nodeId, record.node_id);
|
|
2668
|
+
}
|
|
2669
|
+
function meshNodeIdMatches(node, candidateId) {
|
|
2670
|
+
if (!candidateId) return false;
|
|
2671
|
+
const trimmed = candidateId.trim();
|
|
2672
|
+
if (!trimmed) return false;
|
|
2673
|
+
return normalizeMeshNodeId(node) === trimmed;
|
|
2674
|
+
}
|
|
2675
|
+
function normalizeMeshWorkspaceForCompare(dir) {
|
|
2676
|
+
if (typeof dir !== "string") return "";
|
|
2677
|
+
return dir.trim().replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
2678
|
+
}
|
|
2679
|
+
function meshWorkspacesEquivalent(a, b) {
|
|
2680
|
+
const left = normalizeMeshWorkspaceForCompare(a);
|
|
2681
|
+
const right = normalizeMeshWorkspaceForCompare(b);
|
|
2682
|
+
if (!left || !right) return false;
|
|
2683
|
+
return left === right;
|
|
2684
|
+
}
|
|
2685
|
+
function machineCoreFromDaemonId(id) {
|
|
2686
|
+
const trimmed = readString2(id);
|
|
2687
|
+
if (!trimmed) return void 0;
|
|
2688
|
+
for (const prefix of DAEMON_ID_PREFIXES) {
|
|
2689
|
+
if (trimmed.startsWith(prefix)) {
|
|
2690
|
+
const core = trimmed.slice(prefix.length).trim();
|
|
2691
|
+
return core || void 0;
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
return trimmed;
|
|
2695
|
+
}
|
|
2696
|
+
function canonicalDaemonId(id) {
|
|
2697
|
+
const core = machineCoreFromDaemonId(id);
|
|
2698
|
+
if (!core) return void 0;
|
|
2699
|
+
if (!core.startsWith("mach_")) return core;
|
|
2700
|
+
return `daemon_${core}`;
|
|
2701
|
+
}
|
|
2702
|
+
function daemonIdsEquivalent(a, b) {
|
|
2703
|
+
const coreA = machineCoreFromDaemonId(a);
|
|
2704
|
+
const coreB = machineCoreFromDaemonId(b);
|
|
2705
|
+
if (!coreA || !coreB) return false;
|
|
2706
|
+
return coreA === coreB;
|
|
2707
|
+
}
|
|
2708
|
+
function expandDaemonIdForms(ids) {
|
|
2709
|
+
const list = Array.isArray(ids) ? ids : ids != null ? [ids] : [];
|
|
2710
|
+
const out = [];
|
|
2711
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2712
|
+
const add = (value) => {
|
|
2713
|
+
if (!value || seen.has(value)) return;
|
|
2714
|
+
seen.add(value);
|
|
2715
|
+
out.push(value);
|
|
2716
|
+
};
|
|
2717
|
+
for (const raw of list) add(readString2(raw));
|
|
2718
|
+
for (const raw of list) {
|
|
2719
|
+
const core = machineCoreFromDaemonId(readString2(raw));
|
|
2720
|
+
if (!core || !core.startsWith("mach_")) continue;
|
|
2721
|
+
add(core);
|
|
2722
|
+
for (const prefix of DAEMON_ID_PREFIXES) add(`${prefix}${core}`);
|
|
2723
|
+
}
|
|
2724
|
+
return out;
|
|
2725
|
+
}
|
|
2726
|
+
function summarizeGitShape(status) {
|
|
2727
|
+
const record = readRecord(status);
|
|
2728
|
+
if (!Object.keys(record).length) return null;
|
|
2729
|
+
const submodules = Array.isArray(record.submodules) ? record.submodules.map((entry) => {
|
|
2730
|
+
const sub = readRecord(entry);
|
|
2731
|
+
return {
|
|
2732
|
+
path: readString2(sub.path) ?? null,
|
|
2733
|
+
commit: readString2(sub.commit)?.slice(0, 12) ?? null,
|
|
2734
|
+
dirty: readBoolean(sub.dirty) ?? false,
|
|
2735
|
+
outOfSync: readBoolean(sub.outOfSync, sub.out_of_sync) ?? false
|
|
2736
|
+
};
|
|
2737
|
+
}) : [];
|
|
2738
|
+
return {
|
|
2739
|
+
isGitRepo: readBoolean(record.isGitRepo),
|
|
2740
|
+
workspace: readString2(record.workspace) ?? null,
|
|
2741
|
+
repoRoot: readString2(record.repoRoot, record.repo_root) ?? null,
|
|
2742
|
+
branch: readString2(record.branch) ?? null,
|
|
2743
|
+
upstream: readString2(record.upstream) ?? null,
|
|
2744
|
+
upstreamStatus: readString2(record.upstreamStatus, record.upstream_status) ?? null,
|
|
2745
|
+
headCommit: readString2(record.headCommit, record.head_commit)?.slice(0, 12) ?? null,
|
|
2746
|
+
ahead: readNumber(record.ahead) ?? null,
|
|
2747
|
+
behind: readNumber(record.behind) ?? null,
|
|
2748
|
+
dirtyCounts: {
|
|
2749
|
+
staged: readNumber(record.staged) ?? 0,
|
|
2750
|
+
modified: readNumber(record.modified) ?? 0,
|
|
2751
|
+
untracked: readNumber(record.untracked) ?? 0,
|
|
2752
|
+
deleted: readNumber(record.deleted) ?? 0,
|
|
2753
|
+
renamed: readNumber(record.renamed) ?? 0
|
|
2754
|
+
},
|
|
2755
|
+
lastCheckedAt: readNumber(record.lastCheckedAt, record.last_checked_at) ?? null,
|
|
2756
|
+
submoduleCount: submodules.length,
|
|
2757
|
+
submodules
|
|
2758
|
+
};
|
|
2759
|
+
}
|
|
2760
|
+
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP;
|
|
2761
|
+
var init_dist = __esm({
|
|
2762
|
+
"../mesh-shared/dist/index.mjs"() {
|
|
2763
|
+
"use strict";
|
|
2764
|
+
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
2765
|
+
MAGI_RAW_ANSWER_CAP = 4e3;
|
|
2766
|
+
}
|
|
2767
|
+
});
|
|
2768
|
+
|
|
2501
2769
|
// src/mesh/mesh-host-ownership.ts
|
|
2502
2770
|
function readObject(value) {
|
|
2503
2771
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2504
2772
|
}
|
|
2505
|
-
function
|
|
2773
|
+
function readString3(value) {
|
|
2506
2774
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
2507
2775
|
}
|
|
2508
2776
|
function normalizeMeshDaemonRole(value) {
|
|
2509
2777
|
return value === "host" || value === "member" ? value : void 0;
|
|
2510
2778
|
}
|
|
2511
|
-
function resolveMeshHostStatus(mesh) {
|
|
2779
|
+
function resolveMeshHostStatus(mesh, opts) {
|
|
2512
2780
|
const meshRecord = readObject(mesh);
|
|
2513
2781
|
const raw = readObject(meshRecord?.meshHost);
|
|
2514
2782
|
const role = normalizeMeshDaemonRole(raw?.role) ?? "host";
|
|
@@ -2519,9 +2787,21 @@ function resolveMeshHostStatus(mesh) {
|
|
|
2519
2787
|
canOwnQueue: role === "host",
|
|
2520
2788
|
defaulted: !raw
|
|
2521
2789
|
};
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
const hostAddress =
|
|
2790
|
+
let hostDaemonId = readString3(raw?.hostDaemonId);
|
|
2791
|
+
let hostNodeId = readString3(raw?.hostNodeId);
|
|
2792
|
+
const hostAddress = readString3(raw?.hostAddress);
|
|
2793
|
+
const localDaemonId = readString3(opts?.localDaemonId);
|
|
2794
|
+
if (role === "host" && !hostDaemonId && localDaemonId) {
|
|
2795
|
+
hostDaemonId = localDaemonId;
|
|
2796
|
+
if (!hostNodeId && Array.isArray(meshRecord?.nodes)) {
|
|
2797
|
+
const selfNode = meshRecord.nodes.find((n) => {
|
|
2798
|
+
const nodeDaemonId = readString3(readObject(n)?.daemonId);
|
|
2799
|
+
return nodeDaemonId ? daemonIdsEquivalent(nodeDaemonId, localDaemonId) : false;
|
|
2800
|
+
});
|
|
2801
|
+
const selfNodeId = readString3(readObject(selfNode)?.id);
|
|
2802
|
+
if (selfNodeId) hostNodeId = selfNodeId;
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2525
2805
|
if (hostDaemonId) normalized.hostDaemonId = hostDaemonId;
|
|
2526
2806
|
if (hostNodeId) normalized.hostNodeId = hostNodeId;
|
|
2527
2807
|
if (hostAddress) normalized.hostAddress = hostAddress;
|
|
@@ -2529,11 +2809,11 @@ function resolveMeshHostStatus(mesh) {
|
|
|
2529
2809
|
const status = pairing.status === "pairing" || pairing.status === "paired" || pairing.status === "rejected" || pairing.status === "revoked" ? pairing.status : "not_configured";
|
|
2530
2810
|
normalized.pairing = {
|
|
2531
2811
|
status,
|
|
2532
|
-
...
|
|
2533
|
-
...
|
|
2534
|
-
...
|
|
2535
|
-
...
|
|
2536
|
-
...
|
|
2812
|
+
...readString3(pairing.tokenId) ? { tokenId: readString3(pairing.tokenId) } : {},
|
|
2813
|
+
...readString3(pairing.joinedAt) ? { joinedAt: readString3(pairing.joinedAt) } : {},
|
|
2814
|
+
...readString3(pairing.lastPairedAt) ? { lastPairedAt: readString3(pairing.lastPairedAt) } : {},
|
|
2815
|
+
...readString3(pairing.lastRejectedAt) ? { lastRejectedAt: readString3(pairing.lastRejectedAt) } : {},
|
|
2816
|
+
...readString3(pairing.expiresAt) ? { expiresAt: readString3(pairing.expiresAt) } : {}
|
|
2537
2817
|
};
|
|
2538
2818
|
}
|
|
2539
2819
|
return normalized;
|
|
@@ -2564,6 +2844,7 @@ function createDefaultMeshHostMetadata() {
|
|
|
2564
2844
|
var init_mesh_host_ownership = __esm({
|
|
2565
2845
|
"src/mesh/mesh-host-ownership.ts"() {
|
|
2566
2846
|
"use strict";
|
|
2847
|
+
init_dist();
|
|
2567
2848
|
}
|
|
2568
2849
|
});
|
|
2569
2850
|
|
|
@@ -3074,274 +3355,6 @@ var init_mesh_config = __esm({
|
|
|
3074
3355
|
}
|
|
3075
3356
|
});
|
|
3076
3357
|
|
|
3077
|
-
// ../mesh-shared/dist/index.mjs
|
|
3078
|
-
function readRecord(value) {
|
|
3079
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
3080
|
-
}
|
|
3081
|
-
function readString3(...values) {
|
|
3082
|
-
for (const value of values) {
|
|
3083
|
-
if (typeof value !== "string") continue;
|
|
3084
|
-
const trimmed = value.trim();
|
|
3085
|
-
if (trimmed) return trimmed;
|
|
3086
|
-
}
|
|
3087
|
-
return void 0;
|
|
3088
|
-
}
|
|
3089
|
-
function readNumber(...values) {
|
|
3090
|
-
for (const value of values) {
|
|
3091
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
3092
|
-
}
|
|
3093
|
-
return void 0;
|
|
3094
|
-
}
|
|
3095
|
-
function readBoolean(...values) {
|
|
3096
|
-
for (const value of values) {
|
|
3097
|
-
if (typeof value === "boolean") return value;
|
|
3098
|
-
}
|
|
3099
|
-
return void 0;
|
|
3100
|
-
}
|
|
3101
|
-
function joinRepoPath(root, relativePath) {
|
|
3102
|
-
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
3103
|
-
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
3104
|
-
if (!normalizedPath) return void 0;
|
|
3105
|
-
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
3106
|
-
if (!normalizedRoot) return void 0;
|
|
3107
|
-
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
3108
|
-
}
|
|
3109
|
-
function scoreGitUpstreamFreshness(status) {
|
|
3110
|
-
switch (status) {
|
|
3111
|
-
case "fresh":
|
|
3112
|
-
return 30;
|
|
3113
|
-
case "no_upstream":
|
|
3114
|
-
return 4;
|
|
3115
|
-
case "unchecked":
|
|
3116
|
-
case void 0:
|
|
3117
|
-
return 0;
|
|
3118
|
-
case "stale":
|
|
3119
|
-
return -10;
|
|
3120
|
-
case "unavailable":
|
|
3121
|
-
return -15;
|
|
3122
|
-
default:
|
|
3123
|
-
return 0;
|
|
3124
|
-
}
|
|
3125
|
-
}
|
|
3126
|
-
function readGitSubmodules(value, parentRepoRoot) {
|
|
3127
|
-
if (!Array.isArray(value)) return void 0;
|
|
3128
|
-
const submodules = value.map((entry) => {
|
|
3129
|
-
const submodule = readRecord(entry);
|
|
3130
|
-
const path43 = readString3(submodule.path);
|
|
3131
|
-
const commit = readString3(submodule.commit);
|
|
3132
|
-
const repoPath = readString3(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path43);
|
|
3133
|
-
if (!path43 || !commit) return null;
|
|
3134
|
-
const result = {
|
|
3135
|
-
path: path43,
|
|
3136
|
-
commit,
|
|
3137
|
-
dirty: readBoolean(submodule.dirty) ?? false,
|
|
3138
|
-
outOfSync: readBoolean(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
3139
|
-
lastCheckedAt: readNumber(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now()
|
|
3140
|
-
};
|
|
3141
|
-
if (repoPath) result.repoPath = repoPath;
|
|
3142
|
-
const error = readString3(submodule.error);
|
|
3143
|
-
if (error) result.error = error;
|
|
3144
|
-
return result;
|
|
3145
|
-
}).filter((entry) => entry !== null);
|
|
3146
|
-
return submodules.length > 0 ? submodules : void 0;
|
|
3147
|
-
}
|
|
3148
|
-
function hasGitStatusEvidence(status) {
|
|
3149
|
-
return readBoolean(status.isGitRepo) !== void 0 || Boolean(readString3(status.branch, status.upstream, status.upstreamStatus, status.upstream_status, status.headCommit)) || Boolean(readString3(status.repoRoot, status.repo_root, status.workspace)) || readNumber(
|
|
3150
|
-
status.ahead,
|
|
3151
|
-
status.behind,
|
|
3152
|
-
status.staged,
|
|
3153
|
-
status.modified,
|
|
3154
|
-
status.untracked,
|
|
3155
|
-
status.deleted,
|
|
3156
|
-
status.renamed,
|
|
3157
|
-
status.lastCheckedAt,
|
|
3158
|
-
status.last_checked_at
|
|
3159
|
-
) !== void 0 || Array.isArray(status.submodules) && status.submodules.length > 0;
|
|
3160
|
-
}
|
|
3161
|
-
function normalizeGitStatus(status, node, options) {
|
|
3162
|
-
const explicitIsGitRepo = readBoolean(status.isGitRepo);
|
|
3163
|
-
if (!Object.keys(status).length || !hasGitStatusEvidence(status)) return void 0;
|
|
3164
|
-
const isGitRepo = explicitIsGitRepo ?? true;
|
|
3165
|
-
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((entry) => typeof entry === "string") : [];
|
|
3166
|
-
const conflictCount = readNumber(status.conflicts) ?? conflictFiles.length;
|
|
3167
|
-
const hasConflicts = readBoolean(status.hasConflicts) ?? conflictCount > 0;
|
|
3168
|
-
const repoRoot = readString3(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
|
|
3169
|
-
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
3170
|
-
const upstreamStatus = readString3(status.upstreamStatus, status.upstream_status);
|
|
3171
|
-
const upstreamFetchedAt2 = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
|
|
3172
|
-
const upstreamFetchError = readString3(status.upstreamFetchError, status.upstream_fetch_error);
|
|
3173
|
-
const error = readString3(status.error);
|
|
3174
|
-
const staged = readNumber(status.staged) ?? 0;
|
|
3175
|
-
const modified = readNumber(status.modified) ?? 0;
|
|
3176
|
-
const untracked = readNumber(status.untracked) ?? 0;
|
|
3177
|
-
const deleted = readNumber(status.deleted) ?? 0;
|
|
3178
|
-
const renamed = readNumber(status.renamed) ?? 0;
|
|
3179
|
-
return {
|
|
3180
|
-
workspace: readString3(status.workspace, node.workspace) || "",
|
|
3181
|
-
repoRoot: repoRoot ?? null,
|
|
3182
|
-
isGitRepo,
|
|
3183
|
-
branch: readString3(status.branch) ?? null,
|
|
3184
|
-
headCommit: readString3(status.headCommit) ?? null,
|
|
3185
|
-
headMessage: readString3(status.headMessage) ?? null,
|
|
3186
|
-
upstream: readString3(status.upstream) ?? null,
|
|
3187
|
-
upstreamStatus: upstreamStatus ?? "unchecked",
|
|
3188
|
-
...upstreamFetchedAt2 !== void 0 ? { upstreamFetchedAt: upstreamFetchedAt2 } : {},
|
|
3189
|
-
...upstreamFetchError ? { upstreamFetchError } : {},
|
|
3190
|
-
ahead: readNumber(status.ahead) ?? 0,
|
|
3191
|
-
behind: readNumber(status.behind) ?? 0,
|
|
3192
|
-
staged,
|
|
3193
|
-
modified,
|
|
3194
|
-
untracked,
|
|
3195
|
-
deleted,
|
|
3196
|
-
renamed,
|
|
3197
|
-
dirty: readBoolean(status.dirty, status.isDirty, status.is_dirty) ?? (staged + modified + untracked + deleted + renamed > 0 || hasConflicts),
|
|
3198
|
-
hasConflicts,
|
|
3199
|
-
conflictFiles,
|
|
3200
|
-
stashCount: readNumber(status.stashCount, status.stash_count) ?? 0,
|
|
3201
|
-
lastCheckedAt: options?.lastCheckedAt ?? readNumber(status.lastCheckedAt, status.last_checked_at) ?? Date.now(),
|
|
3202
|
-
...submodules ? { submodules } : {},
|
|
3203
|
-
...error ? { error } : {}
|
|
3204
|
-
};
|
|
3205
|
-
}
|
|
3206
|
-
function scoreGitStatusCandidate(git) {
|
|
3207
|
-
if (!git) return Number.NEGATIVE_INFINITY;
|
|
3208
|
-
let score = 0;
|
|
3209
|
-
if (git.isGitRepo === true) score += 50;
|
|
3210
|
-
if (git.isGitRepo === false) score -= 10;
|
|
3211
|
-
if (git.branch) score += 20;
|
|
3212
|
-
if (git.headCommit) score += 20;
|
|
3213
|
-
if (git.upstream) score += 10;
|
|
3214
|
-
score += scoreGitUpstreamFreshness(git.upstreamStatus);
|
|
3215
|
-
if (typeof git.ahead === "number") score += 2;
|
|
3216
|
-
if (typeof git.behind === "number") score += 2;
|
|
3217
|
-
if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
|
|
3218
|
-
if (git.error) score -= 20;
|
|
3219
|
-
return score;
|
|
3220
|
-
}
|
|
3221
|
-
function pickBestTransitGitStatus(node, options) {
|
|
3222
|
-
const rawGit = readRecord(node.lastGit ?? node.last_git);
|
|
3223
|
-
const gitResult = readRecord(rawGit.result);
|
|
3224
|
-
const directStatus = readRecord(rawGit.status);
|
|
3225
|
-
const nestedStatus = readRecord(gitResult.status);
|
|
3226
|
-
const rawProbe = readRecord(node.lastProbe ?? node.last_probe);
|
|
3227
|
-
const probeGit = readRecord(rawProbe.git);
|
|
3228
|
-
const probeGitResult = readRecord(probeGit.result);
|
|
3229
|
-
const probeDirectStatus = readRecord(probeGit.status);
|
|
3230
|
-
const probeNestedStatus = readRecord(probeGitResult.status);
|
|
3231
|
-
const lastCheckedAt = options?.lastCheckedAt;
|
|
3232
|
-
let best = null;
|
|
3233
|
-
for (const status of [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus]) {
|
|
3234
|
-
const normalized = normalizeGitStatus(status, node, { lastCheckedAt: lastCheckedAt ?? Date.now() });
|
|
3235
|
-
if (!normalized) continue;
|
|
3236
|
-
const score = scoreGitStatusCandidate(normalized);
|
|
3237
|
-
if (!best || score > best.score) best = { git: normalized, score };
|
|
3238
|
-
}
|
|
3239
|
-
return best?.git;
|
|
3240
|
-
}
|
|
3241
|
-
function normalizeMeshNodeId(node) {
|
|
3242
|
-
const record = node && typeof node === "object" ? node : {};
|
|
3243
|
-
return readString3(record.id, record.nodeId, record.node_id);
|
|
3244
|
-
}
|
|
3245
|
-
function meshNodeIdMatches(node, candidateId) {
|
|
3246
|
-
if (!candidateId) return false;
|
|
3247
|
-
const trimmed = candidateId.trim();
|
|
3248
|
-
if (!trimmed) return false;
|
|
3249
|
-
return normalizeMeshNodeId(node) === trimmed;
|
|
3250
|
-
}
|
|
3251
|
-
function normalizeMeshWorkspaceForCompare(dir) {
|
|
3252
|
-
if (typeof dir !== "string") return "";
|
|
3253
|
-
return dir.trim().replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
3254
|
-
}
|
|
3255
|
-
function meshWorkspacesEquivalent(a, b) {
|
|
3256
|
-
const left = normalizeMeshWorkspaceForCompare(a);
|
|
3257
|
-
const right = normalizeMeshWorkspaceForCompare(b);
|
|
3258
|
-
if (!left || !right) return false;
|
|
3259
|
-
return left === right;
|
|
3260
|
-
}
|
|
3261
|
-
function machineCoreFromDaemonId(id) {
|
|
3262
|
-
const trimmed = readString3(id);
|
|
3263
|
-
if (!trimmed) return void 0;
|
|
3264
|
-
for (const prefix of DAEMON_ID_PREFIXES) {
|
|
3265
|
-
if (trimmed.startsWith(prefix)) {
|
|
3266
|
-
const core = trimmed.slice(prefix.length).trim();
|
|
3267
|
-
return core || void 0;
|
|
3268
|
-
}
|
|
3269
|
-
}
|
|
3270
|
-
return trimmed;
|
|
3271
|
-
}
|
|
3272
|
-
function canonicalDaemonId(id) {
|
|
3273
|
-
const core = machineCoreFromDaemonId(id);
|
|
3274
|
-
if (!core) return void 0;
|
|
3275
|
-
if (!core.startsWith("mach_")) return core;
|
|
3276
|
-
return `daemon_${core}`;
|
|
3277
|
-
}
|
|
3278
|
-
function daemonIdsEquivalent(a, b) {
|
|
3279
|
-
const coreA = machineCoreFromDaemonId(a);
|
|
3280
|
-
const coreB = machineCoreFromDaemonId(b);
|
|
3281
|
-
if (!coreA || !coreB) return false;
|
|
3282
|
-
return coreA === coreB;
|
|
3283
|
-
}
|
|
3284
|
-
function expandDaemonIdForms(ids) {
|
|
3285
|
-
const list = Array.isArray(ids) ? ids : ids != null ? [ids] : [];
|
|
3286
|
-
const out = [];
|
|
3287
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3288
|
-
const add = (value) => {
|
|
3289
|
-
if (!value || seen.has(value)) return;
|
|
3290
|
-
seen.add(value);
|
|
3291
|
-
out.push(value);
|
|
3292
|
-
};
|
|
3293
|
-
for (const raw of list) add(readString3(raw));
|
|
3294
|
-
for (const raw of list) {
|
|
3295
|
-
const core = machineCoreFromDaemonId(readString3(raw));
|
|
3296
|
-
if (!core || !core.startsWith("mach_")) continue;
|
|
3297
|
-
add(core);
|
|
3298
|
-
for (const prefix of DAEMON_ID_PREFIXES) add(`${prefix}${core}`);
|
|
3299
|
-
}
|
|
3300
|
-
return out;
|
|
3301
|
-
}
|
|
3302
|
-
function summarizeGitShape(status) {
|
|
3303
|
-
const record = readRecord(status);
|
|
3304
|
-
if (!Object.keys(record).length) return null;
|
|
3305
|
-
const submodules = Array.isArray(record.submodules) ? record.submodules.map((entry) => {
|
|
3306
|
-
const sub = readRecord(entry);
|
|
3307
|
-
return {
|
|
3308
|
-
path: readString3(sub.path) ?? null,
|
|
3309
|
-
commit: readString3(sub.commit)?.slice(0, 12) ?? null,
|
|
3310
|
-
dirty: readBoolean(sub.dirty) ?? false,
|
|
3311
|
-
outOfSync: readBoolean(sub.outOfSync, sub.out_of_sync) ?? false
|
|
3312
|
-
};
|
|
3313
|
-
}) : [];
|
|
3314
|
-
return {
|
|
3315
|
-
isGitRepo: readBoolean(record.isGitRepo),
|
|
3316
|
-
workspace: readString3(record.workspace) ?? null,
|
|
3317
|
-
repoRoot: readString3(record.repoRoot, record.repo_root) ?? null,
|
|
3318
|
-
branch: readString3(record.branch) ?? null,
|
|
3319
|
-
upstream: readString3(record.upstream) ?? null,
|
|
3320
|
-
upstreamStatus: readString3(record.upstreamStatus, record.upstream_status) ?? null,
|
|
3321
|
-
headCommit: readString3(record.headCommit, record.head_commit)?.slice(0, 12) ?? null,
|
|
3322
|
-
ahead: readNumber(record.ahead) ?? null,
|
|
3323
|
-
behind: readNumber(record.behind) ?? null,
|
|
3324
|
-
dirtyCounts: {
|
|
3325
|
-
staged: readNumber(record.staged) ?? 0,
|
|
3326
|
-
modified: readNumber(record.modified) ?? 0,
|
|
3327
|
-
untracked: readNumber(record.untracked) ?? 0,
|
|
3328
|
-
deleted: readNumber(record.deleted) ?? 0,
|
|
3329
|
-
renamed: readNumber(record.renamed) ?? 0
|
|
3330
|
-
},
|
|
3331
|
-
lastCheckedAt: readNumber(record.lastCheckedAt, record.last_checked_at) ?? null,
|
|
3332
|
-
submoduleCount: submodules.length,
|
|
3333
|
-
submodules
|
|
3334
|
-
};
|
|
3335
|
-
}
|
|
3336
|
-
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP;
|
|
3337
|
-
var init_dist = __esm({
|
|
3338
|
-
"../mesh-shared/dist/index.mjs"() {
|
|
3339
|
-
"use strict";
|
|
3340
|
-
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
3341
|
-
MAGI_RAW_ANSWER_CAP = 4e3;
|
|
3342
|
-
}
|
|
3343
|
-
});
|
|
3344
|
-
|
|
3345
3358
|
// src/mesh/coordinator-prompt.ts
|
|
3346
3359
|
var coordinator_prompt_exports = {};
|
|
3347
3360
|
__export(coordinator_prompt_exports, {
|
|
@@ -16777,7 +16790,9 @@ function flushPendingForMeshIdleCoordinators(components, meshId) {
|
|
|
16777
16790
|
if (readNonEmptyString2(settings.meshCoordinatorFor) !== meshId) continue;
|
|
16778
16791
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
16779
16792
|
const modalParked = typeof inst.isModalParked === "function" ? inst.isModalParked() === true : status === "waiting_choice" || status === "waiting_approval";
|
|
16780
|
-
|
|
16793
|
+
const drainStatus = typeof inst.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
16794
|
+
const idle = drainStatus !== null ? drainStatus === "idle" : status === "idle";
|
|
16795
|
+
if (idle && !modalParked) {
|
|
16781
16796
|
idleCoordinators.push({ instance: inst, sessionId: readNonEmptyString2(state.instanceId) });
|
|
16782
16797
|
}
|
|
16783
16798
|
}
|
|
@@ -16950,6 +16965,9 @@ function resolveAutoPruneMinAgeMs() {
|
|
|
16950
16965
|
}
|
|
16951
16966
|
return DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
16952
16967
|
}
|
|
16968
|
+
function resolvePendingHeldDrainEscalateMs() {
|
|
16969
|
+
return resolveTunedReconcileMs("MESH_PENDING_HELD_DRAIN_ESCALATE_MS", DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, 4e3, 5 * 6e4);
|
|
16970
|
+
}
|
|
16953
16971
|
function resolveReconcileIntervalMs() {
|
|
16954
16972
|
const raw = readNonEmptyString2(process.env.MESH_RECONCILE_INTERVAL_MS);
|
|
16955
16973
|
if (raw) {
|
|
@@ -16969,6 +16987,9 @@ function resolveTunedReconcileMs(envName, def, min, max) {
|
|
|
16969
16987
|
function resolveAckedDeathDeadlineMs() {
|
|
16970
16988
|
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
|
|
16971
16989
|
}
|
|
16990
|
+
function resolveAckedTranscriptFastTrackGraceMs() {
|
|
16991
|
+
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
|
|
16992
|
+
}
|
|
16972
16993
|
function inFlightSynthKey(meshId, taskId) {
|
|
16973
16994
|
return `${meshId}::${taskId}`;
|
|
16974
16995
|
}
|
|
@@ -17012,6 +17033,8 @@ function findLiveCoordinators(components) {
|
|
|
17012
17033
|
if (!meshId) continue;
|
|
17013
17034
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
17014
17035
|
const modalParked = typeof inst.isModalParked === "function" ? inst.isModalParked() === true : status === "waiting_choice" || status === "waiting_approval";
|
|
17036
|
+
const drainStatus = typeof inst.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
17037
|
+
const idle = drainStatus !== null ? drainStatus === "idle" : status === "idle";
|
|
17015
17038
|
const sessionId = readNonEmptyString2(state.instanceId);
|
|
17016
17039
|
if (getLogLevel() === "debug") {
|
|
17017
17040
|
let adapterRaw = "?";
|
|
@@ -17026,7 +17049,7 @@ function findLiveCoordinators(components) {
|
|
|
17026
17049
|
const lastStatus = readNonEmptyString2(inst.lastStatus) || "?";
|
|
17027
17050
|
const autoApproveBusy = inst.autoApproveBusy;
|
|
17028
17051
|
const maskSince = inst.autoApproveMaskSince;
|
|
17029
|
-
LOG.debug("MeshReconcile", `coordDiag sess=${sessionId || "?"} mesh=${meshId} getState=${status || "?"} lastStatus=${lastStatus} adapterRaw=${adapterRaw} autoApproveBusy=${autoApproveBusy === true} maskSince=${maskSince || 0}`);
|
|
17052
|
+
LOG.debug("MeshReconcile", `coordDiag sess=${sessionId || "?"} mesh=${meshId} getState=${status || "?"} drainStatus=${drainStatus || "n/a"} lastStatus=${lastStatus} adapterRaw=${adapterRaw} autoApproveBusy=${autoApproveBusy === true} maskSince=${maskSince || 0}`);
|
|
17030
17053
|
}
|
|
17031
17054
|
const stateKey = `${meshId}::${sessionId || "?"}`;
|
|
17032
17055
|
const prevParked = coordinatorModalParkState.get(stateKey);
|
|
@@ -17038,7 +17061,7 @@ function findLiveCoordinators(components) {
|
|
|
17038
17061
|
LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) left modal-park (status=${status}) \u2014 held events will drain on this/next tick`);
|
|
17039
17062
|
}
|
|
17040
17063
|
}
|
|
17041
|
-
out.push({ meshId, instance: inst, sessionId, idle
|
|
17064
|
+
out.push({ meshId, instance: inst, sessionId, idle, modalParked });
|
|
17042
17065
|
}
|
|
17043
17066
|
return out;
|
|
17044
17067
|
}
|
|
@@ -17133,6 +17156,63 @@ function recordHeldTerminalEventsToLedger(meshId, drainDaemonIds, reason, heldFo
|
|
|
17133
17156
|
}
|
|
17134
17157
|
}
|
|
17135
17158
|
}
|
|
17159
|
+
function oldestHeldTerminalEventAgeMs(meshId, drainDaemonIds) {
|
|
17160
|
+
let pending;
|
|
17161
|
+
try {
|
|
17162
|
+
pending = getPendingMeshCoordinatorEvents(meshId, drainDaemonIds.length > 0 ? drainDaemonIds : void 0);
|
|
17163
|
+
} catch {
|
|
17164
|
+
return 0;
|
|
17165
|
+
}
|
|
17166
|
+
const now = Date.now();
|
|
17167
|
+
let maxAge = 0;
|
|
17168
|
+
for (const event of pending) {
|
|
17169
|
+
if (!shouldForceInjectMeshEvent(event.event)) continue;
|
|
17170
|
+
const queuedAt = typeof event.queuedAt === "number" ? event.queuedAt : now;
|
|
17171
|
+
const age = now - queuedAt;
|
|
17172
|
+
if (age > maxAge) maxAge = age;
|
|
17173
|
+
}
|
|
17174
|
+
return maxAge;
|
|
17175
|
+
}
|
|
17176
|
+
function reconfirmGenuinelyIdleCoordinators(generating) {
|
|
17177
|
+
const out = [];
|
|
17178
|
+
for (const c of generating) {
|
|
17179
|
+
const inst = c.instance;
|
|
17180
|
+
const drainStatus = typeof inst?.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
17181
|
+
const genuinelyIdle = drainStatus !== null ? drainStatus === "idle" : c.idle;
|
|
17182
|
+
if (genuinelyIdle) out.push({ ...c, idle: true });
|
|
17183
|
+
}
|
|
17184
|
+
return out;
|
|
17185
|
+
}
|
|
17186
|
+
function drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, targetCoordinators, logLabel) {
|
|
17187
|
+
let pendingEvents = [];
|
|
17188
|
+
try {
|
|
17189
|
+
pendingEvents = drainPendingMeshCoordinatorEvents(
|
|
17190
|
+
meshId,
|
|
17191
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
|
|
17192
|
+
);
|
|
17193
|
+
} catch (e) {
|
|
17194
|
+
LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
17195
|
+
return 0;
|
|
17196
|
+
}
|
|
17197
|
+
if (pendingEvents.length === 0) return 0;
|
|
17198
|
+
LOG.info("MeshReconcile", `Reconcile inject \u2192 ${logLabel}: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
|
|
17199
|
+
for (const pending of pendingEvents) {
|
|
17200
|
+
const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
|
|
17201
|
+
if (wantSession) {
|
|
17202
|
+
const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
|
|
17203
|
+
if (matched.length === 0) {
|
|
17204
|
+
holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
|
|
17205
|
+
continue;
|
|
17206
|
+
}
|
|
17207
|
+
for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
|
|
17208
|
+
continue;
|
|
17209
|
+
}
|
|
17210
|
+
for (const c of targetCoordinators) {
|
|
17211
|
+
injectPendingIntoCoordinator(c.instance, pending);
|
|
17212
|
+
}
|
|
17213
|
+
}
|
|
17214
|
+
return pendingEvents.length;
|
|
17215
|
+
}
|
|
17136
17216
|
function recoverStrandedAssignedDispatches(meshId, store) {
|
|
17137
17217
|
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
17138
17218
|
if (!assigned.length) return;
|
|
@@ -17344,6 +17424,19 @@ async function runMeshReconcileTick(components) {
|
|
|
17344
17424
|
}
|
|
17345
17425
|
}
|
|
17346
17426
|
if (hasPending) {
|
|
17427
|
+
const escalateMs = resolvePendingHeldDrainEscalateMs();
|
|
17428
|
+
const heldAgeMs = oldestHeldTerminalEventAgeMs(
|
|
17429
|
+
meshId,
|
|
17430
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId ? [localDaemonId] : []
|
|
17431
|
+
);
|
|
17432
|
+
if (heldAgeMs >= escalateMs) {
|
|
17433
|
+
const escapeTargets = reconfirmGenuinelyIdleCoordinators(generatingCoordinators);
|
|
17434
|
+
if (escapeTargets.length > 0) {
|
|
17435
|
+
LOG.info("MeshReconcile", `Reconcile age-escape \u2192 generating-hold: held terminal event(s) for mesh ${meshId} aged ${Math.round(heldAgeMs / 1e3)}s (\u2265 ${Math.round(escalateMs / 1e3)}s) and ${escapeTargets.length} coordinator(s) re-confirmed genuinely idle on the raw adapter \u2014 draining once`);
|
|
17436
|
+
const drained = drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, escapeTargets, "age-escape");
|
|
17437
|
+
if (drained > 0) continue;
|
|
17438
|
+
}
|
|
17439
|
+
}
|
|
17347
17440
|
LOG.info("MeshReconcile", `Reconcile skip \u2192 generating: holding pending event(s) for mesh ${meshId} (${generatingCoordinators.length} coordinator(s) busy; events left queued for the next idle tick)`);
|
|
17348
17441
|
if (getLogLevel() === "debug") {
|
|
17349
17442
|
LOG.debug("MeshReconcile", `coordHoldGenerating mesh=${meshId} heldFor=[${generatingCoordinators.map((c) => c.sessionId || "?").join(",")}] (these were classified busy; cross-ref same-tick coordDiag by sessionId)`);
|
|
@@ -17364,33 +17457,7 @@ async function runMeshReconcileTick(components) {
|
|
|
17364
17457
|
} catch {
|
|
17365
17458
|
}
|
|
17366
17459
|
}
|
|
17367
|
-
|
|
17368
|
-
try {
|
|
17369
|
-
pendingEvents = drainPendingMeshCoordinatorEvents(
|
|
17370
|
-
meshId,
|
|
17371
|
-
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
|
|
17372
|
-
);
|
|
17373
|
-
} catch (e) {
|
|
17374
|
-
LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
17375
|
-
continue;
|
|
17376
|
-
}
|
|
17377
|
-
if (pendingEvents.length === 0) continue;
|
|
17378
|
-
LOG.info("MeshReconcile", `Reconcile inject \u2192 idle: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
|
|
17379
|
-
for (const pending of pendingEvents) {
|
|
17380
|
-
const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
|
|
17381
|
-
if (wantSession) {
|
|
17382
|
-
const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
|
|
17383
|
-
if (matched.length === 0) {
|
|
17384
|
-
holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
|
|
17385
|
-
continue;
|
|
17386
|
-
}
|
|
17387
|
-
for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
|
|
17388
|
-
continue;
|
|
17389
|
-
}
|
|
17390
|
-
for (const c of targetCoordinators) {
|
|
17391
|
-
injectPendingIntoCoordinator(c.instance, pending);
|
|
17392
|
-
}
|
|
17393
|
-
}
|
|
17460
|
+
drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, targetCoordinators, "idle");
|
|
17394
17461
|
}
|
|
17395
17462
|
}
|
|
17396
17463
|
function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
@@ -17660,28 +17727,52 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
17660
17727
|
}
|
|
17661
17728
|
continue;
|
|
17662
17729
|
}
|
|
17663
|
-
inFlightAckedHoldState.
|
|
17730
|
+
const priorHoldState = inFlightAckedHoldState.get(synthKey);
|
|
17731
|
+
inFlightAckedHoldState.set(synthKey, {
|
|
17732
|
+
liveConfirmedSinceAck: true,
|
|
17733
|
+
consecutiveReadFailures: 0,
|
|
17734
|
+
...priorHoldState?.transcriptIdleSinceMs !== void 0 ? { transcriptIdleSinceMs: priorHoldState.transcriptIdleSinceMs } : {}
|
|
17735
|
+
});
|
|
17664
17736
|
const nowMs = Date.now();
|
|
17665
17737
|
if (readChatPayloadStatus(payload) !== "idle") {
|
|
17738
|
+
inFlightAckedHoldState.set(synthKey, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
|
|
17666
17739
|
continue;
|
|
17667
17740
|
}
|
|
17741
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
17742
|
+
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
17668
17743
|
if (isAcked) {
|
|
17669
17744
|
const ackedAtMs = Date.parse(readNonEmptyString2(dispatch.updatedAt));
|
|
17670
17745
|
const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
|
|
17671
17746
|
const deathDeadlineMs = resolveAckedDeathDeadlineMs();
|
|
17672
|
-
|
|
17673
|
-
|
|
17747
|
+
const holdState = inFlightAckedHoldState.get(synthKey);
|
|
17748
|
+
let fastTrackReady = false;
|
|
17749
|
+
if (evidence.finalSummary) {
|
|
17750
|
+
const idleSinceMs = holdState?.transcriptIdleSinceMs ?? nowMs;
|
|
17751
|
+
if (holdState && holdState.transcriptIdleSinceMs === void 0) {
|
|
17752
|
+
inFlightAckedHoldState.set(synthKey, { ...holdState, transcriptIdleSinceMs: idleSinceMs });
|
|
17753
|
+
}
|
|
17754
|
+
const fastTrackGraceMs = resolveAckedTranscriptFastTrackGraceMs();
|
|
17755
|
+
const idleHeldMs = nowMs - idleSinceMs;
|
|
17756
|
+
if (idleHeldMs >= fastTrackGraceMs) {
|
|
17757
|
+
fastTrackReady = true;
|
|
17758
|
+
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.`);
|
|
17759
|
+
}
|
|
17760
|
+
} else if (holdState?.transcriptIdleSinceMs !== void 0) {
|
|
17761
|
+
inFlightAckedHoldState.set(synthKey, { ...holdState, transcriptIdleSinceMs: void 0 });
|
|
17762
|
+
}
|
|
17763
|
+
if (!fastTrackReady && sinceAckMs < deathDeadlineMs) {
|
|
17764
|
+
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.`);
|
|
17674
17765
|
continue;
|
|
17675
17766
|
}
|
|
17676
|
-
|
|
17767
|
+
if (!fastTrackReady) {
|
|
17768
|
+
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).`);
|
|
17769
|
+
}
|
|
17677
17770
|
}
|
|
17678
17771
|
if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
|
|
17679
17772
|
inFlightAckedHoldState.delete(synthKey);
|
|
17680
17773
|
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`);
|
|
17681
17774
|
continue;
|
|
17682
17775
|
}
|
|
17683
|
-
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
17684
|
-
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
17685
17776
|
if (!evidence.finalSummary) continue;
|
|
17686
17777
|
const dispatchedAtMs = Date.parse(readNonEmptyString2(dispatch.dispatchedAt));
|
|
17687
17778
|
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
|
|
@@ -17840,7 +17931,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
17840
17931
|
}
|
|
17841
17932
|
};
|
|
17842
17933
|
}
|
|
17843
|
-
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
|
|
17934
|
+
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
|
|
17844
17935
|
var init_mesh_reconcile_loop = __esm({
|
|
17845
17936
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
17846
17937
|
"use strict";
|
|
@@ -17862,6 +17953,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
17862
17953
|
init_chat_message_normalization();
|
|
17863
17954
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
17864
17955
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
17956
|
+
DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS = 12e3;
|
|
17865
17957
|
ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
|
|
17866
17958
|
inFlightAckedHoldState = /* @__PURE__ */ new Map();
|
|
17867
17959
|
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
@@ -40840,6 +40932,49 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
40840
40932
|
isModalParked() {
|
|
40841
40933
|
return this.resolveModalParkStatus() !== null;
|
|
40842
40934
|
}
|
|
40935
|
+
/**
|
|
40936
|
+
* PTY-OVERTRUST-DRAIN (Defect B). The deliverability/drain status the mesh
|
|
40937
|
+
* reconcile loop must consult — the RAW adapter turn-state, with the
|
|
40938
|
+
* auto-approve "hold-idle" visual mask STRIPPED.
|
|
40939
|
+
*
|
|
40940
|
+
* getState().status overlays `autoApproveHoldIdle`/`autoApproveActive` to paint a
|
|
40941
|
+
* genuinely-idle adapter as `generating` (a UI-flicker suppression while an
|
|
40942
|
+
* auto-approve key-press settles — see getState() ~:800). That mask is correct
|
|
40943
|
+
* for the dashboard, but the reconcile loop trusts it as "the coordinator is
|
|
40944
|
+
* busy" and therefore HOLDS a worker's completion under
|
|
40945
|
+
* `generating_no_idle_coordinator` even though the coordinator's PTY is at a real
|
|
40946
|
+
* turn end and would accept the inject as a turn — the completion is stranded.
|
|
40947
|
+
*
|
|
40948
|
+
* This accessor reports the drain truth instead:
|
|
40949
|
+
* - 'modal_parked' — a GENUINE human-await modal (AskUserQuestion / a non-
|
|
40950
|
+
* transient tool-consent). Still excluded from drain (a force-inject here
|
|
40951
|
+
* writes raw keystrokes the modal eats → data corruption). Mirrors
|
|
40952
|
+
* isModalParked(), evaluated first so a parked session never reads idle.
|
|
40953
|
+
* - 'idle' — the RAW adapter is at a turn end (adapter.getStatus(allowParse:false)
|
|
40954
|
+
* === 'idle') and the session is not modal-parked. Drain-eligible REGARDLESS
|
|
40955
|
+
* of the auto-approve mask. This is the case the mask used to hide.
|
|
40956
|
+
* - 'generating' — the raw adapter is genuinely mid-turn. Held (a raw PTY write
|
|
40957
|
+
* into a generating claude-cli is not consumed as a turn → data loss). The
|
|
40958
|
+
* intentional removal of force-inject-into-generating is preserved.
|
|
40959
|
+
* - 'other' — any other raw status (error / starting / waiting_choice handled by
|
|
40960
|
+
* modal-park above). Not a drain target.
|
|
40961
|
+
*
|
|
40962
|
+
* Uses allowParse:false (engine.activeModal only, side-effect-free) so it never
|
|
40963
|
+
* mutates the very auto-approve mask state the diagnostics read.
|
|
40964
|
+
*/
|
|
40965
|
+
getDrainStatus() {
|
|
40966
|
+
if (this.isModalParked()) return "modal_parked";
|
|
40967
|
+
let rawStatus;
|
|
40968
|
+
try {
|
|
40969
|
+
const raw = this.adapter.getStatus({ allowParse: false })?.status;
|
|
40970
|
+
rawStatus = typeof raw === "string" ? raw.trim() : "";
|
|
40971
|
+
} catch {
|
|
40972
|
+
return "other";
|
|
40973
|
+
}
|
|
40974
|
+
if (rawStatus === "idle") return "idle";
|
|
40975
|
+
if (isCliGeneratingLikeStatus(rawStatus)) return "generating";
|
|
40976
|
+
return "other";
|
|
40977
|
+
}
|
|
40843
40978
|
onEvent(event, data) {
|
|
40844
40979
|
if (event === "send_message") {
|
|
40845
40980
|
const input = normalizeInputEnvelope(data);
|
|
@@ -50994,7 +51129,7 @@ var meshStatusHandlers = {
|
|
|
50994
51129
|
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
50995
51130
|
const mesh = meshRecord?.mesh;
|
|
50996
51131
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
50997
|
-
const meshHost = resolveMeshHostStatus(mesh);
|
|
51132
|
+
const meshHost = resolveMeshHostStatus(mesh, { localDaemonId: ctx.deps.statusInstanceId });
|
|
50998
51133
|
const refreshRequested = args?.refresh === true || args?.forceRefresh === true;
|
|
50999
51134
|
const verboseMissions = args?.verbose === true || args?.compact === false;
|
|
51000
51135
|
const peekScope = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : ctx.deps.statusInstanceId || void 0;
|