@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.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-06-
|
|
412
|
+
const commit = readInjected(true ? "bf124fd471f6149d84a75594a6adaaff75793523" : void 0) ?? "unknown";
|
|
413
|
+
const commitShort = readInjected(true ? "bf124fd4" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
414
|
+
const version = readInjected(true ? "0.9.82-rc.433" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
415
|
+
const builtAt = readInjected(true ? "2026-06-30T14:21:42.763Z" : void 0);
|
|
416
416
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
417
417
|
return cached;
|
|
418
418
|
}
|
|
@@ -2504,17 +2504,285 @@ var init_hash = __esm({
|
|
|
2504
2504
|
}
|
|
2505
2505
|
});
|
|
2506
2506
|
|
|
2507
|
+
// ../mesh-shared/dist/index.mjs
|
|
2508
|
+
function readRecord(value) {
|
|
2509
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2510
|
+
}
|
|
2511
|
+
function readString2(...values) {
|
|
2512
|
+
for (const value of values) {
|
|
2513
|
+
if (typeof value !== "string") continue;
|
|
2514
|
+
const trimmed = value.trim();
|
|
2515
|
+
if (trimmed) return trimmed;
|
|
2516
|
+
}
|
|
2517
|
+
return void 0;
|
|
2518
|
+
}
|
|
2519
|
+
function readNumber(...values) {
|
|
2520
|
+
for (const value of values) {
|
|
2521
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2522
|
+
}
|
|
2523
|
+
return void 0;
|
|
2524
|
+
}
|
|
2525
|
+
function readBoolean(...values) {
|
|
2526
|
+
for (const value of values) {
|
|
2527
|
+
if (typeof value === "boolean") return value;
|
|
2528
|
+
}
|
|
2529
|
+
return void 0;
|
|
2530
|
+
}
|
|
2531
|
+
function joinRepoPath(root, relativePath) {
|
|
2532
|
+
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
2533
|
+
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
2534
|
+
if (!normalizedPath) return void 0;
|
|
2535
|
+
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
2536
|
+
if (!normalizedRoot) return void 0;
|
|
2537
|
+
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
2538
|
+
}
|
|
2539
|
+
function scoreGitUpstreamFreshness(status) {
|
|
2540
|
+
switch (status) {
|
|
2541
|
+
case "fresh":
|
|
2542
|
+
return 30;
|
|
2543
|
+
case "no_upstream":
|
|
2544
|
+
return 4;
|
|
2545
|
+
case "unchecked":
|
|
2546
|
+
case void 0:
|
|
2547
|
+
return 0;
|
|
2548
|
+
case "stale":
|
|
2549
|
+
return -10;
|
|
2550
|
+
case "unavailable":
|
|
2551
|
+
return -15;
|
|
2552
|
+
default:
|
|
2553
|
+
return 0;
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
function readGitSubmodules(value, parentRepoRoot) {
|
|
2557
|
+
if (!Array.isArray(value)) return void 0;
|
|
2558
|
+
const submodules = value.map((entry) => {
|
|
2559
|
+
const submodule = readRecord(entry);
|
|
2560
|
+
const path43 = readString2(submodule.path);
|
|
2561
|
+
const commit = readString2(submodule.commit);
|
|
2562
|
+
const repoPath = readString2(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path43);
|
|
2563
|
+
if (!path43 || !commit) return null;
|
|
2564
|
+
const result = {
|
|
2565
|
+
path: path43,
|
|
2566
|
+
commit,
|
|
2567
|
+
dirty: readBoolean(submodule.dirty) ?? false,
|
|
2568
|
+
outOfSync: readBoolean(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
2569
|
+
lastCheckedAt: readNumber(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now()
|
|
2570
|
+
};
|
|
2571
|
+
if (repoPath) result.repoPath = repoPath;
|
|
2572
|
+
const error = readString2(submodule.error);
|
|
2573
|
+
if (error) result.error = error;
|
|
2574
|
+
return result;
|
|
2575
|
+
}).filter((entry) => entry !== null);
|
|
2576
|
+
return submodules.length > 0 ? submodules : void 0;
|
|
2577
|
+
}
|
|
2578
|
+
function hasGitStatusEvidence(status) {
|
|
2579
|
+
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(
|
|
2580
|
+
status.ahead,
|
|
2581
|
+
status.behind,
|
|
2582
|
+
status.staged,
|
|
2583
|
+
status.modified,
|
|
2584
|
+
status.untracked,
|
|
2585
|
+
status.deleted,
|
|
2586
|
+
status.renamed,
|
|
2587
|
+
status.lastCheckedAt,
|
|
2588
|
+
status.last_checked_at
|
|
2589
|
+
) !== void 0 || Array.isArray(status.submodules) && status.submodules.length > 0;
|
|
2590
|
+
}
|
|
2591
|
+
function normalizeGitStatus(status, node, options) {
|
|
2592
|
+
const explicitIsGitRepo = readBoolean(status.isGitRepo);
|
|
2593
|
+
if (!Object.keys(status).length || !hasGitStatusEvidence(status)) return void 0;
|
|
2594
|
+
const isGitRepo = explicitIsGitRepo ?? true;
|
|
2595
|
+
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((entry) => typeof entry === "string") : [];
|
|
2596
|
+
const conflictCount = readNumber(status.conflicts) ?? conflictFiles.length;
|
|
2597
|
+
const hasConflicts = readBoolean(status.hasConflicts) ?? conflictCount > 0;
|
|
2598
|
+
const repoRoot = readString2(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
|
|
2599
|
+
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
2600
|
+
const upstreamStatus = readString2(status.upstreamStatus, status.upstream_status);
|
|
2601
|
+
const upstreamFetchedAt2 = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
|
|
2602
|
+
const upstreamFetchError = readString2(status.upstreamFetchError, status.upstream_fetch_error);
|
|
2603
|
+
const error = readString2(status.error);
|
|
2604
|
+
const staged = readNumber(status.staged) ?? 0;
|
|
2605
|
+
const modified = readNumber(status.modified) ?? 0;
|
|
2606
|
+
const untracked = readNumber(status.untracked) ?? 0;
|
|
2607
|
+
const deleted = readNumber(status.deleted) ?? 0;
|
|
2608
|
+
const renamed = readNumber(status.renamed) ?? 0;
|
|
2609
|
+
return {
|
|
2610
|
+
workspace: readString2(status.workspace, node.workspace) || "",
|
|
2611
|
+
repoRoot: repoRoot ?? null,
|
|
2612
|
+
isGitRepo,
|
|
2613
|
+
branch: readString2(status.branch) ?? null,
|
|
2614
|
+
headCommit: readString2(status.headCommit) ?? null,
|
|
2615
|
+
headMessage: readString2(status.headMessage) ?? null,
|
|
2616
|
+
upstream: readString2(status.upstream) ?? null,
|
|
2617
|
+
upstreamStatus: upstreamStatus ?? "unchecked",
|
|
2618
|
+
...upstreamFetchedAt2 !== void 0 ? { upstreamFetchedAt: upstreamFetchedAt2 } : {},
|
|
2619
|
+
...upstreamFetchError ? { upstreamFetchError } : {},
|
|
2620
|
+
ahead: readNumber(status.ahead) ?? 0,
|
|
2621
|
+
behind: readNumber(status.behind) ?? 0,
|
|
2622
|
+
staged,
|
|
2623
|
+
modified,
|
|
2624
|
+
untracked,
|
|
2625
|
+
deleted,
|
|
2626
|
+
renamed,
|
|
2627
|
+
dirty: readBoolean(status.dirty, status.isDirty, status.is_dirty) ?? (staged + modified + untracked + deleted + renamed > 0 || hasConflicts),
|
|
2628
|
+
hasConflicts,
|
|
2629
|
+
conflictFiles,
|
|
2630
|
+
stashCount: readNumber(status.stashCount, status.stash_count) ?? 0,
|
|
2631
|
+
lastCheckedAt: options?.lastCheckedAt ?? readNumber(status.lastCheckedAt, status.last_checked_at) ?? Date.now(),
|
|
2632
|
+
...submodules ? { submodules } : {},
|
|
2633
|
+
...error ? { error } : {}
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2636
|
+
function scoreGitStatusCandidate(git) {
|
|
2637
|
+
if (!git) return Number.NEGATIVE_INFINITY;
|
|
2638
|
+
let score = 0;
|
|
2639
|
+
if (git.isGitRepo === true) score += 50;
|
|
2640
|
+
if (git.isGitRepo === false) score -= 10;
|
|
2641
|
+
if (git.branch) score += 20;
|
|
2642
|
+
if (git.headCommit) score += 20;
|
|
2643
|
+
if (git.upstream) score += 10;
|
|
2644
|
+
score += scoreGitUpstreamFreshness(git.upstreamStatus);
|
|
2645
|
+
if (typeof git.ahead === "number") score += 2;
|
|
2646
|
+
if (typeof git.behind === "number") score += 2;
|
|
2647
|
+
if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
|
|
2648
|
+
if (git.error) score -= 20;
|
|
2649
|
+
return score;
|
|
2650
|
+
}
|
|
2651
|
+
function pickBestTransitGitStatus(node, options) {
|
|
2652
|
+
const rawGit = readRecord(node.lastGit ?? node.last_git);
|
|
2653
|
+
const gitResult = readRecord(rawGit.result);
|
|
2654
|
+
const directStatus = readRecord(rawGit.status);
|
|
2655
|
+
const nestedStatus = readRecord(gitResult.status);
|
|
2656
|
+
const rawProbe = readRecord(node.lastProbe ?? node.last_probe);
|
|
2657
|
+
const probeGit = readRecord(rawProbe.git);
|
|
2658
|
+
const probeGitResult = readRecord(probeGit.result);
|
|
2659
|
+
const probeDirectStatus = readRecord(probeGit.status);
|
|
2660
|
+
const probeNestedStatus = readRecord(probeGitResult.status);
|
|
2661
|
+
const lastCheckedAt = options?.lastCheckedAt;
|
|
2662
|
+
let best = null;
|
|
2663
|
+
for (const status of [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus]) {
|
|
2664
|
+
const normalized = normalizeGitStatus(status, node, { lastCheckedAt: lastCheckedAt ?? Date.now() });
|
|
2665
|
+
if (!normalized) continue;
|
|
2666
|
+
const score = scoreGitStatusCandidate(normalized);
|
|
2667
|
+
if (!best || score > best.score) best = { git: normalized, score };
|
|
2668
|
+
}
|
|
2669
|
+
return best?.git;
|
|
2670
|
+
}
|
|
2671
|
+
function normalizeMeshNodeId(node) {
|
|
2672
|
+
const record = node && typeof node === "object" ? node : {};
|
|
2673
|
+
return readString2(record.id, record.nodeId, record.node_id);
|
|
2674
|
+
}
|
|
2675
|
+
function meshNodeIdMatches(node, candidateId) {
|
|
2676
|
+
if (!candidateId) return false;
|
|
2677
|
+
const trimmed = candidateId.trim();
|
|
2678
|
+
if (!trimmed) return false;
|
|
2679
|
+
return normalizeMeshNodeId(node) === trimmed;
|
|
2680
|
+
}
|
|
2681
|
+
function normalizeMeshWorkspaceForCompare(dir) {
|
|
2682
|
+
if (typeof dir !== "string") return "";
|
|
2683
|
+
return dir.trim().replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
2684
|
+
}
|
|
2685
|
+
function meshWorkspacesEquivalent(a, b) {
|
|
2686
|
+
const left = normalizeMeshWorkspaceForCompare(a);
|
|
2687
|
+
const right = normalizeMeshWorkspaceForCompare(b);
|
|
2688
|
+
if (!left || !right) return false;
|
|
2689
|
+
return left === right;
|
|
2690
|
+
}
|
|
2691
|
+
function machineCoreFromDaemonId(id) {
|
|
2692
|
+
const trimmed = readString2(id);
|
|
2693
|
+
if (!trimmed) return void 0;
|
|
2694
|
+
for (const prefix of DAEMON_ID_PREFIXES) {
|
|
2695
|
+
if (trimmed.startsWith(prefix)) {
|
|
2696
|
+
const core = trimmed.slice(prefix.length).trim();
|
|
2697
|
+
return core || void 0;
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
return trimmed;
|
|
2701
|
+
}
|
|
2702
|
+
function canonicalDaemonId(id) {
|
|
2703
|
+
const core = machineCoreFromDaemonId(id);
|
|
2704
|
+
if (!core) return void 0;
|
|
2705
|
+
if (!core.startsWith("mach_")) return core;
|
|
2706
|
+
return `daemon_${core}`;
|
|
2707
|
+
}
|
|
2708
|
+
function daemonIdsEquivalent(a, b) {
|
|
2709
|
+
const coreA = machineCoreFromDaemonId(a);
|
|
2710
|
+
const coreB = machineCoreFromDaemonId(b);
|
|
2711
|
+
if (!coreA || !coreB) return false;
|
|
2712
|
+
return coreA === coreB;
|
|
2713
|
+
}
|
|
2714
|
+
function expandDaemonIdForms(ids) {
|
|
2715
|
+
const list = Array.isArray(ids) ? ids : ids != null ? [ids] : [];
|
|
2716
|
+
const out = [];
|
|
2717
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2718
|
+
const add = (value) => {
|
|
2719
|
+
if (!value || seen.has(value)) return;
|
|
2720
|
+
seen.add(value);
|
|
2721
|
+
out.push(value);
|
|
2722
|
+
};
|
|
2723
|
+
for (const raw of list) add(readString2(raw));
|
|
2724
|
+
for (const raw of list) {
|
|
2725
|
+
const core = machineCoreFromDaemonId(readString2(raw));
|
|
2726
|
+
if (!core || !core.startsWith("mach_")) continue;
|
|
2727
|
+
add(core);
|
|
2728
|
+
for (const prefix of DAEMON_ID_PREFIXES) add(`${prefix}${core}`);
|
|
2729
|
+
}
|
|
2730
|
+
return out;
|
|
2731
|
+
}
|
|
2732
|
+
function summarizeGitShape(status) {
|
|
2733
|
+
const record = readRecord(status);
|
|
2734
|
+
if (!Object.keys(record).length) return null;
|
|
2735
|
+
const submodules = Array.isArray(record.submodules) ? record.submodules.map((entry) => {
|
|
2736
|
+
const sub = readRecord(entry);
|
|
2737
|
+
return {
|
|
2738
|
+
path: readString2(sub.path) ?? null,
|
|
2739
|
+
commit: readString2(sub.commit)?.slice(0, 12) ?? null,
|
|
2740
|
+
dirty: readBoolean(sub.dirty) ?? false,
|
|
2741
|
+
outOfSync: readBoolean(sub.outOfSync, sub.out_of_sync) ?? false
|
|
2742
|
+
};
|
|
2743
|
+
}) : [];
|
|
2744
|
+
return {
|
|
2745
|
+
isGitRepo: readBoolean(record.isGitRepo),
|
|
2746
|
+
workspace: readString2(record.workspace) ?? null,
|
|
2747
|
+
repoRoot: readString2(record.repoRoot, record.repo_root) ?? null,
|
|
2748
|
+
branch: readString2(record.branch) ?? null,
|
|
2749
|
+
upstream: readString2(record.upstream) ?? null,
|
|
2750
|
+
upstreamStatus: readString2(record.upstreamStatus, record.upstream_status) ?? null,
|
|
2751
|
+
headCommit: readString2(record.headCommit, record.head_commit)?.slice(0, 12) ?? null,
|
|
2752
|
+
ahead: readNumber(record.ahead) ?? null,
|
|
2753
|
+
behind: readNumber(record.behind) ?? null,
|
|
2754
|
+
dirtyCounts: {
|
|
2755
|
+
staged: readNumber(record.staged) ?? 0,
|
|
2756
|
+
modified: readNumber(record.modified) ?? 0,
|
|
2757
|
+
untracked: readNumber(record.untracked) ?? 0,
|
|
2758
|
+
deleted: readNumber(record.deleted) ?? 0,
|
|
2759
|
+
renamed: readNumber(record.renamed) ?? 0
|
|
2760
|
+
},
|
|
2761
|
+
lastCheckedAt: readNumber(record.lastCheckedAt, record.last_checked_at) ?? null,
|
|
2762
|
+
submoduleCount: submodules.length,
|
|
2763
|
+
submodules
|
|
2764
|
+
};
|
|
2765
|
+
}
|
|
2766
|
+
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP;
|
|
2767
|
+
var init_dist = __esm({
|
|
2768
|
+
"../mesh-shared/dist/index.mjs"() {
|
|
2769
|
+
"use strict";
|
|
2770
|
+
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
2771
|
+
MAGI_RAW_ANSWER_CAP = 4e3;
|
|
2772
|
+
}
|
|
2773
|
+
});
|
|
2774
|
+
|
|
2507
2775
|
// src/mesh/mesh-host-ownership.ts
|
|
2508
2776
|
function readObject(value) {
|
|
2509
2777
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2510
2778
|
}
|
|
2511
|
-
function
|
|
2779
|
+
function readString3(value) {
|
|
2512
2780
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
2513
2781
|
}
|
|
2514
2782
|
function normalizeMeshDaemonRole(value) {
|
|
2515
2783
|
return value === "host" || value === "member" ? value : void 0;
|
|
2516
2784
|
}
|
|
2517
|
-
function resolveMeshHostStatus(mesh) {
|
|
2785
|
+
function resolveMeshHostStatus(mesh, opts) {
|
|
2518
2786
|
const meshRecord = readObject(mesh);
|
|
2519
2787
|
const raw = readObject(meshRecord?.meshHost);
|
|
2520
2788
|
const role = normalizeMeshDaemonRole(raw?.role) ?? "host";
|
|
@@ -2525,9 +2793,21 @@ function resolveMeshHostStatus(mesh) {
|
|
|
2525
2793
|
canOwnQueue: role === "host",
|
|
2526
2794
|
defaulted: !raw
|
|
2527
2795
|
};
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
const hostAddress =
|
|
2796
|
+
let hostDaemonId = readString3(raw?.hostDaemonId);
|
|
2797
|
+
let hostNodeId = readString3(raw?.hostNodeId);
|
|
2798
|
+
const hostAddress = readString3(raw?.hostAddress);
|
|
2799
|
+
const localDaemonId = readString3(opts?.localDaemonId);
|
|
2800
|
+
if (role === "host" && !hostDaemonId && localDaemonId) {
|
|
2801
|
+
hostDaemonId = localDaemonId;
|
|
2802
|
+
if (!hostNodeId && Array.isArray(meshRecord?.nodes)) {
|
|
2803
|
+
const selfNode = meshRecord.nodes.find((n) => {
|
|
2804
|
+
const nodeDaemonId = readString3(readObject(n)?.daemonId);
|
|
2805
|
+
return nodeDaemonId ? daemonIdsEquivalent(nodeDaemonId, localDaemonId) : false;
|
|
2806
|
+
});
|
|
2807
|
+
const selfNodeId = readString3(readObject(selfNode)?.id);
|
|
2808
|
+
if (selfNodeId) hostNodeId = selfNodeId;
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2531
2811
|
if (hostDaemonId) normalized.hostDaemonId = hostDaemonId;
|
|
2532
2812
|
if (hostNodeId) normalized.hostNodeId = hostNodeId;
|
|
2533
2813
|
if (hostAddress) normalized.hostAddress = hostAddress;
|
|
@@ -2535,11 +2815,11 @@ function resolveMeshHostStatus(mesh) {
|
|
|
2535
2815
|
const status = pairing.status === "pairing" || pairing.status === "paired" || pairing.status === "rejected" || pairing.status === "revoked" ? pairing.status : "not_configured";
|
|
2536
2816
|
normalized.pairing = {
|
|
2537
2817
|
status,
|
|
2538
|
-
...
|
|
2539
|
-
...
|
|
2540
|
-
...
|
|
2541
|
-
...
|
|
2542
|
-
...
|
|
2818
|
+
...readString3(pairing.tokenId) ? { tokenId: readString3(pairing.tokenId) } : {},
|
|
2819
|
+
...readString3(pairing.joinedAt) ? { joinedAt: readString3(pairing.joinedAt) } : {},
|
|
2820
|
+
...readString3(pairing.lastPairedAt) ? { lastPairedAt: readString3(pairing.lastPairedAt) } : {},
|
|
2821
|
+
...readString3(pairing.lastRejectedAt) ? { lastRejectedAt: readString3(pairing.lastRejectedAt) } : {},
|
|
2822
|
+
...readString3(pairing.expiresAt) ? { expiresAt: readString3(pairing.expiresAt) } : {}
|
|
2543
2823
|
};
|
|
2544
2824
|
}
|
|
2545
2825
|
return normalized;
|
|
@@ -2570,6 +2850,7 @@ function createDefaultMeshHostMetadata() {
|
|
|
2570
2850
|
var init_mesh_host_ownership = __esm({
|
|
2571
2851
|
"src/mesh/mesh-host-ownership.ts"() {
|
|
2572
2852
|
"use strict";
|
|
2853
|
+
init_dist();
|
|
2573
2854
|
}
|
|
2574
2855
|
});
|
|
2575
2856
|
|
|
@@ -3080,274 +3361,6 @@ var init_mesh_config = __esm({
|
|
|
3080
3361
|
}
|
|
3081
3362
|
});
|
|
3082
3363
|
|
|
3083
|
-
// ../mesh-shared/dist/index.mjs
|
|
3084
|
-
function readRecord(value) {
|
|
3085
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
3086
|
-
}
|
|
3087
|
-
function readString3(...values) {
|
|
3088
|
-
for (const value of values) {
|
|
3089
|
-
if (typeof value !== "string") continue;
|
|
3090
|
-
const trimmed = value.trim();
|
|
3091
|
-
if (trimmed) return trimmed;
|
|
3092
|
-
}
|
|
3093
|
-
return void 0;
|
|
3094
|
-
}
|
|
3095
|
-
function readNumber(...values) {
|
|
3096
|
-
for (const value of values) {
|
|
3097
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
3098
|
-
}
|
|
3099
|
-
return void 0;
|
|
3100
|
-
}
|
|
3101
|
-
function readBoolean(...values) {
|
|
3102
|
-
for (const value of values) {
|
|
3103
|
-
if (typeof value === "boolean") return value;
|
|
3104
|
-
}
|
|
3105
|
-
return void 0;
|
|
3106
|
-
}
|
|
3107
|
-
function joinRepoPath(root, relativePath) {
|
|
3108
|
-
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
3109
|
-
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
3110
|
-
if (!normalizedPath) return void 0;
|
|
3111
|
-
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
3112
|
-
if (!normalizedRoot) return void 0;
|
|
3113
|
-
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
3114
|
-
}
|
|
3115
|
-
function scoreGitUpstreamFreshness(status) {
|
|
3116
|
-
switch (status) {
|
|
3117
|
-
case "fresh":
|
|
3118
|
-
return 30;
|
|
3119
|
-
case "no_upstream":
|
|
3120
|
-
return 4;
|
|
3121
|
-
case "unchecked":
|
|
3122
|
-
case void 0:
|
|
3123
|
-
return 0;
|
|
3124
|
-
case "stale":
|
|
3125
|
-
return -10;
|
|
3126
|
-
case "unavailable":
|
|
3127
|
-
return -15;
|
|
3128
|
-
default:
|
|
3129
|
-
return 0;
|
|
3130
|
-
}
|
|
3131
|
-
}
|
|
3132
|
-
function readGitSubmodules(value, parentRepoRoot) {
|
|
3133
|
-
if (!Array.isArray(value)) return void 0;
|
|
3134
|
-
const submodules = value.map((entry) => {
|
|
3135
|
-
const submodule = readRecord(entry);
|
|
3136
|
-
const path43 = readString3(submodule.path);
|
|
3137
|
-
const commit = readString3(submodule.commit);
|
|
3138
|
-
const repoPath = readString3(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path43);
|
|
3139
|
-
if (!path43 || !commit) return null;
|
|
3140
|
-
const result = {
|
|
3141
|
-
path: path43,
|
|
3142
|
-
commit,
|
|
3143
|
-
dirty: readBoolean(submodule.dirty) ?? false,
|
|
3144
|
-
outOfSync: readBoolean(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
3145
|
-
lastCheckedAt: readNumber(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now()
|
|
3146
|
-
};
|
|
3147
|
-
if (repoPath) result.repoPath = repoPath;
|
|
3148
|
-
const error = readString3(submodule.error);
|
|
3149
|
-
if (error) result.error = error;
|
|
3150
|
-
return result;
|
|
3151
|
-
}).filter((entry) => entry !== null);
|
|
3152
|
-
return submodules.length > 0 ? submodules : void 0;
|
|
3153
|
-
}
|
|
3154
|
-
function hasGitStatusEvidence(status) {
|
|
3155
|
-
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(
|
|
3156
|
-
status.ahead,
|
|
3157
|
-
status.behind,
|
|
3158
|
-
status.staged,
|
|
3159
|
-
status.modified,
|
|
3160
|
-
status.untracked,
|
|
3161
|
-
status.deleted,
|
|
3162
|
-
status.renamed,
|
|
3163
|
-
status.lastCheckedAt,
|
|
3164
|
-
status.last_checked_at
|
|
3165
|
-
) !== void 0 || Array.isArray(status.submodules) && status.submodules.length > 0;
|
|
3166
|
-
}
|
|
3167
|
-
function normalizeGitStatus(status, node, options) {
|
|
3168
|
-
const explicitIsGitRepo = readBoolean(status.isGitRepo);
|
|
3169
|
-
if (!Object.keys(status).length || !hasGitStatusEvidence(status)) return void 0;
|
|
3170
|
-
const isGitRepo = explicitIsGitRepo ?? true;
|
|
3171
|
-
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((entry) => typeof entry === "string") : [];
|
|
3172
|
-
const conflictCount = readNumber(status.conflicts) ?? conflictFiles.length;
|
|
3173
|
-
const hasConflicts = readBoolean(status.hasConflicts) ?? conflictCount > 0;
|
|
3174
|
-
const repoRoot = readString3(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
|
|
3175
|
-
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
3176
|
-
const upstreamStatus = readString3(status.upstreamStatus, status.upstream_status);
|
|
3177
|
-
const upstreamFetchedAt2 = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
|
|
3178
|
-
const upstreamFetchError = readString3(status.upstreamFetchError, status.upstream_fetch_error);
|
|
3179
|
-
const error = readString3(status.error);
|
|
3180
|
-
const staged = readNumber(status.staged) ?? 0;
|
|
3181
|
-
const modified = readNumber(status.modified) ?? 0;
|
|
3182
|
-
const untracked = readNumber(status.untracked) ?? 0;
|
|
3183
|
-
const deleted = readNumber(status.deleted) ?? 0;
|
|
3184
|
-
const renamed = readNumber(status.renamed) ?? 0;
|
|
3185
|
-
return {
|
|
3186
|
-
workspace: readString3(status.workspace, node.workspace) || "",
|
|
3187
|
-
repoRoot: repoRoot ?? null,
|
|
3188
|
-
isGitRepo,
|
|
3189
|
-
branch: readString3(status.branch) ?? null,
|
|
3190
|
-
headCommit: readString3(status.headCommit) ?? null,
|
|
3191
|
-
headMessage: readString3(status.headMessage) ?? null,
|
|
3192
|
-
upstream: readString3(status.upstream) ?? null,
|
|
3193
|
-
upstreamStatus: upstreamStatus ?? "unchecked",
|
|
3194
|
-
...upstreamFetchedAt2 !== void 0 ? { upstreamFetchedAt: upstreamFetchedAt2 } : {},
|
|
3195
|
-
...upstreamFetchError ? { upstreamFetchError } : {},
|
|
3196
|
-
ahead: readNumber(status.ahead) ?? 0,
|
|
3197
|
-
behind: readNumber(status.behind) ?? 0,
|
|
3198
|
-
staged,
|
|
3199
|
-
modified,
|
|
3200
|
-
untracked,
|
|
3201
|
-
deleted,
|
|
3202
|
-
renamed,
|
|
3203
|
-
dirty: readBoolean(status.dirty, status.isDirty, status.is_dirty) ?? (staged + modified + untracked + deleted + renamed > 0 || hasConflicts),
|
|
3204
|
-
hasConflicts,
|
|
3205
|
-
conflictFiles,
|
|
3206
|
-
stashCount: readNumber(status.stashCount, status.stash_count) ?? 0,
|
|
3207
|
-
lastCheckedAt: options?.lastCheckedAt ?? readNumber(status.lastCheckedAt, status.last_checked_at) ?? Date.now(),
|
|
3208
|
-
...submodules ? { submodules } : {},
|
|
3209
|
-
...error ? { error } : {}
|
|
3210
|
-
};
|
|
3211
|
-
}
|
|
3212
|
-
function scoreGitStatusCandidate(git) {
|
|
3213
|
-
if (!git) return Number.NEGATIVE_INFINITY;
|
|
3214
|
-
let score = 0;
|
|
3215
|
-
if (git.isGitRepo === true) score += 50;
|
|
3216
|
-
if (git.isGitRepo === false) score -= 10;
|
|
3217
|
-
if (git.branch) score += 20;
|
|
3218
|
-
if (git.headCommit) score += 20;
|
|
3219
|
-
if (git.upstream) score += 10;
|
|
3220
|
-
score += scoreGitUpstreamFreshness(git.upstreamStatus);
|
|
3221
|
-
if (typeof git.ahead === "number") score += 2;
|
|
3222
|
-
if (typeof git.behind === "number") score += 2;
|
|
3223
|
-
if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
|
|
3224
|
-
if (git.error) score -= 20;
|
|
3225
|
-
return score;
|
|
3226
|
-
}
|
|
3227
|
-
function pickBestTransitGitStatus(node, options) {
|
|
3228
|
-
const rawGit = readRecord(node.lastGit ?? node.last_git);
|
|
3229
|
-
const gitResult = readRecord(rawGit.result);
|
|
3230
|
-
const directStatus = readRecord(rawGit.status);
|
|
3231
|
-
const nestedStatus = readRecord(gitResult.status);
|
|
3232
|
-
const rawProbe = readRecord(node.lastProbe ?? node.last_probe);
|
|
3233
|
-
const probeGit = readRecord(rawProbe.git);
|
|
3234
|
-
const probeGitResult = readRecord(probeGit.result);
|
|
3235
|
-
const probeDirectStatus = readRecord(probeGit.status);
|
|
3236
|
-
const probeNestedStatus = readRecord(probeGitResult.status);
|
|
3237
|
-
const lastCheckedAt = options?.lastCheckedAt;
|
|
3238
|
-
let best = null;
|
|
3239
|
-
for (const status of [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus]) {
|
|
3240
|
-
const normalized = normalizeGitStatus(status, node, { lastCheckedAt: lastCheckedAt ?? Date.now() });
|
|
3241
|
-
if (!normalized) continue;
|
|
3242
|
-
const score = scoreGitStatusCandidate(normalized);
|
|
3243
|
-
if (!best || score > best.score) best = { git: normalized, score };
|
|
3244
|
-
}
|
|
3245
|
-
return best?.git;
|
|
3246
|
-
}
|
|
3247
|
-
function normalizeMeshNodeId(node) {
|
|
3248
|
-
const record = node && typeof node === "object" ? node : {};
|
|
3249
|
-
return readString3(record.id, record.nodeId, record.node_id);
|
|
3250
|
-
}
|
|
3251
|
-
function meshNodeIdMatches(node, candidateId) {
|
|
3252
|
-
if (!candidateId) return false;
|
|
3253
|
-
const trimmed = candidateId.trim();
|
|
3254
|
-
if (!trimmed) return false;
|
|
3255
|
-
return normalizeMeshNodeId(node) === trimmed;
|
|
3256
|
-
}
|
|
3257
|
-
function normalizeMeshWorkspaceForCompare(dir) {
|
|
3258
|
-
if (typeof dir !== "string") return "";
|
|
3259
|
-
return dir.trim().replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
3260
|
-
}
|
|
3261
|
-
function meshWorkspacesEquivalent(a, b) {
|
|
3262
|
-
const left = normalizeMeshWorkspaceForCompare(a);
|
|
3263
|
-
const right = normalizeMeshWorkspaceForCompare(b);
|
|
3264
|
-
if (!left || !right) return false;
|
|
3265
|
-
return left === right;
|
|
3266
|
-
}
|
|
3267
|
-
function machineCoreFromDaemonId(id) {
|
|
3268
|
-
const trimmed = readString3(id);
|
|
3269
|
-
if (!trimmed) return void 0;
|
|
3270
|
-
for (const prefix of DAEMON_ID_PREFIXES) {
|
|
3271
|
-
if (trimmed.startsWith(prefix)) {
|
|
3272
|
-
const core = trimmed.slice(prefix.length).trim();
|
|
3273
|
-
return core || void 0;
|
|
3274
|
-
}
|
|
3275
|
-
}
|
|
3276
|
-
return trimmed;
|
|
3277
|
-
}
|
|
3278
|
-
function canonicalDaemonId(id) {
|
|
3279
|
-
const core = machineCoreFromDaemonId(id);
|
|
3280
|
-
if (!core) return void 0;
|
|
3281
|
-
if (!core.startsWith("mach_")) return core;
|
|
3282
|
-
return `daemon_${core}`;
|
|
3283
|
-
}
|
|
3284
|
-
function daemonIdsEquivalent(a, b) {
|
|
3285
|
-
const coreA = machineCoreFromDaemonId(a);
|
|
3286
|
-
const coreB = machineCoreFromDaemonId(b);
|
|
3287
|
-
if (!coreA || !coreB) return false;
|
|
3288
|
-
return coreA === coreB;
|
|
3289
|
-
}
|
|
3290
|
-
function expandDaemonIdForms(ids) {
|
|
3291
|
-
const list = Array.isArray(ids) ? ids : ids != null ? [ids] : [];
|
|
3292
|
-
const out = [];
|
|
3293
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3294
|
-
const add = (value) => {
|
|
3295
|
-
if (!value || seen.has(value)) return;
|
|
3296
|
-
seen.add(value);
|
|
3297
|
-
out.push(value);
|
|
3298
|
-
};
|
|
3299
|
-
for (const raw of list) add(readString3(raw));
|
|
3300
|
-
for (const raw of list) {
|
|
3301
|
-
const core = machineCoreFromDaemonId(readString3(raw));
|
|
3302
|
-
if (!core || !core.startsWith("mach_")) continue;
|
|
3303
|
-
add(core);
|
|
3304
|
-
for (const prefix of DAEMON_ID_PREFIXES) add(`${prefix}${core}`);
|
|
3305
|
-
}
|
|
3306
|
-
return out;
|
|
3307
|
-
}
|
|
3308
|
-
function summarizeGitShape(status) {
|
|
3309
|
-
const record = readRecord(status);
|
|
3310
|
-
if (!Object.keys(record).length) return null;
|
|
3311
|
-
const submodules = Array.isArray(record.submodules) ? record.submodules.map((entry) => {
|
|
3312
|
-
const sub = readRecord(entry);
|
|
3313
|
-
return {
|
|
3314
|
-
path: readString3(sub.path) ?? null,
|
|
3315
|
-
commit: readString3(sub.commit)?.slice(0, 12) ?? null,
|
|
3316
|
-
dirty: readBoolean(sub.dirty) ?? false,
|
|
3317
|
-
outOfSync: readBoolean(sub.outOfSync, sub.out_of_sync) ?? false
|
|
3318
|
-
};
|
|
3319
|
-
}) : [];
|
|
3320
|
-
return {
|
|
3321
|
-
isGitRepo: readBoolean(record.isGitRepo),
|
|
3322
|
-
workspace: readString3(record.workspace) ?? null,
|
|
3323
|
-
repoRoot: readString3(record.repoRoot, record.repo_root) ?? null,
|
|
3324
|
-
branch: readString3(record.branch) ?? null,
|
|
3325
|
-
upstream: readString3(record.upstream) ?? null,
|
|
3326
|
-
upstreamStatus: readString3(record.upstreamStatus, record.upstream_status) ?? null,
|
|
3327
|
-
headCommit: readString3(record.headCommit, record.head_commit)?.slice(0, 12) ?? null,
|
|
3328
|
-
ahead: readNumber(record.ahead) ?? null,
|
|
3329
|
-
behind: readNumber(record.behind) ?? null,
|
|
3330
|
-
dirtyCounts: {
|
|
3331
|
-
staged: readNumber(record.staged) ?? 0,
|
|
3332
|
-
modified: readNumber(record.modified) ?? 0,
|
|
3333
|
-
untracked: readNumber(record.untracked) ?? 0,
|
|
3334
|
-
deleted: readNumber(record.deleted) ?? 0,
|
|
3335
|
-
renamed: readNumber(record.renamed) ?? 0
|
|
3336
|
-
},
|
|
3337
|
-
lastCheckedAt: readNumber(record.lastCheckedAt, record.last_checked_at) ?? null,
|
|
3338
|
-
submoduleCount: submodules.length,
|
|
3339
|
-
submodules
|
|
3340
|
-
};
|
|
3341
|
-
}
|
|
3342
|
-
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP;
|
|
3343
|
-
var init_dist = __esm({
|
|
3344
|
-
"../mesh-shared/dist/index.mjs"() {
|
|
3345
|
-
"use strict";
|
|
3346
|
-
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
3347
|
-
MAGI_RAW_ANSWER_CAP = 4e3;
|
|
3348
|
-
}
|
|
3349
|
-
});
|
|
3350
|
-
|
|
3351
3364
|
// src/mesh/coordinator-prompt.ts
|
|
3352
3365
|
var coordinator_prompt_exports = {};
|
|
3353
3366
|
__export(coordinator_prompt_exports, {
|
|
@@ -16782,7 +16795,9 @@ function flushPendingForMeshIdleCoordinators(components, meshId) {
|
|
|
16782
16795
|
if (readNonEmptyString2(settings.meshCoordinatorFor) !== meshId) continue;
|
|
16783
16796
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
16784
16797
|
const modalParked = typeof inst.isModalParked === "function" ? inst.isModalParked() === true : status === "waiting_choice" || status === "waiting_approval";
|
|
16785
|
-
|
|
16798
|
+
const drainStatus = typeof inst.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
16799
|
+
const idle = drainStatus !== null ? drainStatus === "idle" : status === "idle";
|
|
16800
|
+
if (idle && !modalParked) {
|
|
16786
16801
|
idleCoordinators.push({ instance: inst, sessionId: readNonEmptyString2(state.instanceId) });
|
|
16787
16802
|
}
|
|
16788
16803
|
}
|
|
@@ -16955,6 +16970,9 @@ function resolveAutoPruneMinAgeMs() {
|
|
|
16955
16970
|
}
|
|
16956
16971
|
return DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
|
|
16957
16972
|
}
|
|
16973
|
+
function resolvePendingHeldDrainEscalateMs() {
|
|
16974
|
+
return resolveTunedReconcileMs("MESH_PENDING_HELD_DRAIN_ESCALATE_MS", DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, 4e3, 5 * 6e4);
|
|
16975
|
+
}
|
|
16958
16976
|
function resolveReconcileIntervalMs() {
|
|
16959
16977
|
const raw = readNonEmptyString2(process.env.MESH_RECONCILE_INTERVAL_MS);
|
|
16960
16978
|
if (raw) {
|
|
@@ -16974,6 +16992,9 @@ function resolveTunedReconcileMs(envName, def, min, max) {
|
|
|
16974
16992
|
function resolveAckedDeathDeadlineMs() {
|
|
16975
16993
|
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
|
|
16976
16994
|
}
|
|
16995
|
+
function resolveAckedTranscriptFastTrackGraceMs() {
|
|
16996
|
+
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
|
|
16997
|
+
}
|
|
16977
16998
|
function inFlightSynthKey(meshId, taskId) {
|
|
16978
16999
|
return `${meshId}::${taskId}`;
|
|
16979
17000
|
}
|
|
@@ -17017,6 +17038,8 @@ function findLiveCoordinators(components) {
|
|
|
17017
17038
|
if (!meshId) continue;
|
|
17018
17039
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
17019
17040
|
const modalParked = typeof inst.isModalParked === "function" ? inst.isModalParked() === true : status === "waiting_choice" || status === "waiting_approval";
|
|
17041
|
+
const drainStatus = typeof inst.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
17042
|
+
const idle = drainStatus !== null ? drainStatus === "idle" : status === "idle";
|
|
17020
17043
|
const sessionId = readNonEmptyString2(state.instanceId);
|
|
17021
17044
|
if (getLogLevel() === "debug") {
|
|
17022
17045
|
let adapterRaw = "?";
|
|
@@ -17031,7 +17054,7 @@ function findLiveCoordinators(components) {
|
|
|
17031
17054
|
const lastStatus = readNonEmptyString2(inst.lastStatus) || "?";
|
|
17032
17055
|
const autoApproveBusy = inst.autoApproveBusy;
|
|
17033
17056
|
const maskSince = inst.autoApproveMaskSince;
|
|
17034
|
-
LOG.debug("MeshReconcile", `coordDiag sess=${sessionId || "?"} mesh=${meshId} getState=${status || "?"} lastStatus=${lastStatus} adapterRaw=${adapterRaw} autoApproveBusy=${autoApproveBusy === true} maskSince=${maskSince || 0}`);
|
|
17057
|
+
LOG.debug("MeshReconcile", `coordDiag sess=${sessionId || "?"} mesh=${meshId} getState=${status || "?"} drainStatus=${drainStatus || "n/a"} lastStatus=${lastStatus} adapterRaw=${adapterRaw} autoApproveBusy=${autoApproveBusy === true} maskSince=${maskSince || 0}`);
|
|
17035
17058
|
}
|
|
17036
17059
|
const stateKey = `${meshId}::${sessionId || "?"}`;
|
|
17037
17060
|
const prevParked = coordinatorModalParkState.get(stateKey);
|
|
@@ -17043,7 +17066,7 @@ function findLiveCoordinators(components) {
|
|
|
17043
17066
|
LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) left modal-park (status=${status}) \u2014 held events will drain on this/next tick`);
|
|
17044
17067
|
}
|
|
17045
17068
|
}
|
|
17046
|
-
out.push({ meshId, instance: inst, sessionId, idle
|
|
17069
|
+
out.push({ meshId, instance: inst, sessionId, idle, modalParked });
|
|
17047
17070
|
}
|
|
17048
17071
|
return out;
|
|
17049
17072
|
}
|
|
@@ -17138,6 +17161,63 @@ function recordHeldTerminalEventsToLedger(meshId, drainDaemonIds, reason, heldFo
|
|
|
17138
17161
|
}
|
|
17139
17162
|
}
|
|
17140
17163
|
}
|
|
17164
|
+
function oldestHeldTerminalEventAgeMs(meshId, drainDaemonIds) {
|
|
17165
|
+
let pending;
|
|
17166
|
+
try {
|
|
17167
|
+
pending = getPendingMeshCoordinatorEvents(meshId, drainDaemonIds.length > 0 ? drainDaemonIds : void 0);
|
|
17168
|
+
} catch {
|
|
17169
|
+
return 0;
|
|
17170
|
+
}
|
|
17171
|
+
const now = Date.now();
|
|
17172
|
+
let maxAge = 0;
|
|
17173
|
+
for (const event of pending) {
|
|
17174
|
+
if (!shouldForceInjectMeshEvent(event.event)) continue;
|
|
17175
|
+
const queuedAt = typeof event.queuedAt === "number" ? event.queuedAt : now;
|
|
17176
|
+
const age = now - queuedAt;
|
|
17177
|
+
if (age > maxAge) maxAge = age;
|
|
17178
|
+
}
|
|
17179
|
+
return maxAge;
|
|
17180
|
+
}
|
|
17181
|
+
function reconfirmGenuinelyIdleCoordinators(generating) {
|
|
17182
|
+
const out = [];
|
|
17183
|
+
for (const c of generating) {
|
|
17184
|
+
const inst = c.instance;
|
|
17185
|
+
const drainStatus = typeof inst?.getDrainStatus === "function" ? inst.getDrainStatus() : null;
|
|
17186
|
+
const genuinelyIdle = drainStatus !== null ? drainStatus === "idle" : c.idle;
|
|
17187
|
+
if (genuinelyIdle) out.push({ ...c, idle: true });
|
|
17188
|
+
}
|
|
17189
|
+
return out;
|
|
17190
|
+
}
|
|
17191
|
+
function drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, targetCoordinators, logLabel) {
|
|
17192
|
+
let pendingEvents = [];
|
|
17193
|
+
try {
|
|
17194
|
+
pendingEvents = drainPendingMeshCoordinatorEvents(
|
|
17195
|
+
meshId,
|
|
17196
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
|
|
17197
|
+
);
|
|
17198
|
+
} catch (e) {
|
|
17199
|
+
LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
17200
|
+
return 0;
|
|
17201
|
+
}
|
|
17202
|
+
if (pendingEvents.length === 0) return 0;
|
|
17203
|
+
LOG.info("MeshReconcile", `Reconcile inject \u2192 ${logLabel}: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
|
|
17204
|
+
for (const pending of pendingEvents) {
|
|
17205
|
+
const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
|
|
17206
|
+
if (wantSession) {
|
|
17207
|
+
const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
|
|
17208
|
+
if (matched.length === 0) {
|
|
17209
|
+
holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
|
|
17210
|
+
continue;
|
|
17211
|
+
}
|
|
17212
|
+
for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
|
|
17213
|
+
continue;
|
|
17214
|
+
}
|
|
17215
|
+
for (const c of targetCoordinators) {
|
|
17216
|
+
injectPendingIntoCoordinator(c.instance, pending);
|
|
17217
|
+
}
|
|
17218
|
+
}
|
|
17219
|
+
return pendingEvents.length;
|
|
17220
|
+
}
|
|
17141
17221
|
function recoverStrandedAssignedDispatches(meshId, store) {
|
|
17142
17222
|
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
17143
17223
|
if (!assigned.length) return;
|
|
@@ -17349,6 +17429,19 @@ async function runMeshReconcileTick(components) {
|
|
|
17349
17429
|
}
|
|
17350
17430
|
}
|
|
17351
17431
|
if (hasPending) {
|
|
17432
|
+
const escalateMs = resolvePendingHeldDrainEscalateMs();
|
|
17433
|
+
const heldAgeMs = oldestHeldTerminalEventAgeMs(
|
|
17434
|
+
meshId,
|
|
17435
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId ? [localDaemonId] : []
|
|
17436
|
+
);
|
|
17437
|
+
if (heldAgeMs >= escalateMs) {
|
|
17438
|
+
const escapeTargets = reconfirmGenuinelyIdleCoordinators(generatingCoordinators);
|
|
17439
|
+
if (escapeTargets.length > 0) {
|
|
17440
|
+
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`);
|
|
17441
|
+
const drained = drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, escapeTargets, "age-escape");
|
|
17442
|
+
if (drained > 0) continue;
|
|
17443
|
+
}
|
|
17444
|
+
}
|
|
17352
17445
|
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)`);
|
|
17353
17446
|
if (getLogLevel() === "debug") {
|
|
17354
17447
|
LOG.debug("MeshReconcile", `coordHoldGenerating mesh=${meshId} heldFor=[${generatingCoordinators.map((c) => c.sessionId || "?").join(",")}] (these were classified busy; cross-ref same-tick coordDiag by sessionId)`);
|
|
@@ -17369,33 +17462,7 @@ async function runMeshReconcileTick(components) {
|
|
|
17369
17462
|
} catch {
|
|
17370
17463
|
}
|
|
17371
17464
|
}
|
|
17372
|
-
|
|
17373
|
-
try {
|
|
17374
|
-
pendingEvents = drainPendingMeshCoordinatorEvents(
|
|
17375
|
-
meshId,
|
|
17376
|
-
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
|
|
17377
|
-
);
|
|
17378
|
-
} catch (e) {
|
|
17379
|
-
LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
17380
|
-
continue;
|
|
17381
|
-
}
|
|
17382
|
-
if (pendingEvents.length === 0) continue;
|
|
17383
|
-
LOG.info("MeshReconcile", `Reconcile inject \u2192 idle: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
|
|
17384
|
-
for (const pending of pendingEvents) {
|
|
17385
|
-
const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
|
|
17386
|
-
if (wantSession) {
|
|
17387
|
-
const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
|
|
17388
|
-
if (matched.length === 0) {
|
|
17389
|
-
holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
|
|
17390
|
-
continue;
|
|
17391
|
-
}
|
|
17392
|
-
for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
|
|
17393
|
-
continue;
|
|
17394
|
-
}
|
|
17395
|
-
for (const c of targetCoordinators) {
|
|
17396
|
-
injectPendingIntoCoordinator(c.instance, pending);
|
|
17397
|
-
}
|
|
17398
|
-
}
|
|
17465
|
+
drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, targetCoordinators, "idle");
|
|
17399
17466
|
}
|
|
17400
17467
|
}
|
|
17401
17468
|
function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
@@ -17665,28 +17732,52 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
17665
17732
|
}
|
|
17666
17733
|
continue;
|
|
17667
17734
|
}
|
|
17668
|
-
inFlightAckedHoldState.
|
|
17735
|
+
const priorHoldState = inFlightAckedHoldState.get(synthKey);
|
|
17736
|
+
inFlightAckedHoldState.set(synthKey, {
|
|
17737
|
+
liveConfirmedSinceAck: true,
|
|
17738
|
+
consecutiveReadFailures: 0,
|
|
17739
|
+
...priorHoldState?.transcriptIdleSinceMs !== void 0 ? { transcriptIdleSinceMs: priorHoldState.transcriptIdleSinceMs } : {}
|
|
17740
|
+
});
|
|
17669
17741
|
const nowMs = Date.now();
|
|
17670
17742
|
if (readChatPayloadStatus(payload) !== "idle") {
|
|
17743
|
+
inFlightAckedHoldState.set(synthKey, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
|
|
17671
17744
|
continue;
|
|
17672
17745
|
}
|
|
17746
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
17747
|
+
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
17673
17748
|
if (isAcked) {
|
|
17674
17749
|
const ackedAtMs = Date.parse(readNonEmptyString2(dispatch.updatedAt));
|
|
17675
17750
|
const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
|
|
17676
17751
|
const deathDeadlineMs = resolveAckedDeathDeadlineMs();
|
|
17677
|
-
|
|
17678
|
-
|
|
17752
|
+
const holdState = inFlightAckedHoldState.get(synthKey);
|
|
17753
|
+
let fastTrackReady = false;
|
|
17754
|
+
if (evidence.finalSummary) {
|
|
17755
|
+
const idleSinceMs = holdState?.transcriptIdleSinceMs ?? nowMs;
|
|
17756
|
+
if (holdState && holdState.transcriptIdleSinceMs === void 0) {
|
|
17757
|
+
inFlightAckedHoldState.set(synthKey, { ...holdState, transcriptIdleSinceMs: idleSinceMs });
|
|
17758
|
+
}
|
|
17759
|
+
const fastTrackGraceMs = resolveAckedTranscriptFastTrackGraceMs();
|
|
17760
|
+
const idleHeldMs = nowMs - idleSinceMs;
|
|
17761
|
+
if (idleHeldMs >= fastTrackGraceMs) {
|
|
17762
|
+
fastTrackReady = true;
|
|
17763
|
+
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.`);
|
|
17764
|
+
}
|
|
17765
|
+
} else if (holdState?.transcriptIdleSinceMs !== void 0) {
|
|
17766
|
+
inFlightAckedHoldState.set(synthKey, { ...holdState, transcriptIdleSinceMs: void 0 });
|
|
17767
|
+
}
|
|
17768
|
+
if (!fastTrackReady && sinceAckMs < deathDeadlineMs) {
|
|
17769
|
+
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.`);
|
|
17679
17770
|
continue;
|
|
17680
17771
|
}
|
|
17681
|
-
|
|
17772
|
+
if (!fastTrackReady) {
|
|
17773
|
+
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).`);
|
|
17774
|
+
}
|
|
17682
17775
|
}
|
|
17683
17776
|
if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
|
|
17684
17777
|
inFlightAckedHoldState.delete(synthKey);
|
|
17685
17778
|
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`);
|
|
17686
17779
|
continue;
|
|
17687
17780
|
}
|
|
17688
|
-
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
17689
|
-
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
17690
17781
|
if (!evidence.finalSummary) continue;
|
|
17691
17782
|
const dispatchedAtMs = Date.parse(readNonEmptyString2(dispatch.dispatchedAt));
|
|
17692
17783
|
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
|
|
@@ -17845,7 +17936,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
17845
17936
|
}
|
|
17846
17937
|
};
|
|
17847
17938
|
}
|
|
17848
|
-
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;
|
|
17939
|
+
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;
|
|
17849
17940
|
var init_mesh_reconcile_loop = __esm({
|
|
17850
17941
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
17851
17942
|
"use strict";
|
|
@@ -17867,6 +17958,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
17867
17958
|
init_chat_message_normalization();
|
|
17868
17959
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
17869
17960
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
17961
|
+
DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS = 12e3;
|
|
17870
17962
|
ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
|
|
17871
17963
|
inFlightAckedHoldState = /* @__PURE__ */ new Map();
|
|
17872
17964
|
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
@@ -41239,6 +41331,49 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
41239
41331
|
isModalParked() {
|
|
41240
41332
|
return this.resolveModalParkStatus() !== null;
|
|
41241
41333
|
}
|
|
41334
|
+
/**
|
|
41335
|
+
* PTY-OVERTRUST-DRAIN (Defect B). The deliverability/drain status the mesh
|
|
41336
|
+
* reconcile loop must consult — the RAW adapter turn-state, with the
|
|
41337
|
+
* auto-approve "hold-idle" visual mask STRIPPED.
|
|
41338
|
+
*
|
|
41339
|
+
* getState().status overlays `autoApproveHoldIdle`/`autoApproveActive` to paint a
|
|
41340
|
+
* genuinely-idle adapter as `generating` (a UI-flicker suppression while an
|
|
41341
|
+
* auto-approve key-press settles — see getState() ~:800). That mask is correct
|
|
41342
|
+
* for the dashboard, but the reconcile loop trusts it as "the coordinator is
|
|
41343
|
+
* busy" and therefore HOLDS a worker's completion under
|
|
41344
|
+
* `generating_no_idle_coordinator` even though the coordinator's PTY is at a real
|
|
41345
|
+
* turn end and would accept the inject as a turn — the completion is stranded.
|
|
41346
|
+
*
|
|
41347
|
+
* This accessor reports the drain truth instead:
|
|
41348
|
+
* - 'modal_parked' — a GENUINE human-await modal (AskUserQuestion / a non-
|
|
41349
|
+
* transient tool-consent). Still excluded from drain (a force-inject here
|
|
41350
|
+
* writes raw keystrokes the modal eats → data corruption). Mirrors
|
|
41351
|
+
* isModalParked(), evaluated first so a parked session never reads idle.
|
|
41352
|
+
* - 'idle' — the RAW adapter is at a turn end (adapter.getStatus(allowParse:false)
|
|
41353
|
+
* === 'idle') and the session is not modal-parked. Drain-eligible REGARDLESS
|
|
41354
|
+
* of the auto-approve mask. This is the case the mask used to hide.
|
|
41355
|
+
* - 'generating' — the raw adapter is genuinely mid-turn. Held (a raw PTY write
|
|
41356
|
+
* into a generating claude-cli is not consumed as a turn → data loss). The
|
|
41357
|
+
* intentional removal of force-inject-into-generating is preserved.
|
|
41358
|
+
* - 'other' — any other raw status (error / starting / waiting_choice handled by
|
|
41359
|
+
* modal-park above). Not a drain target.
|
|
41360
|
+
*
|
|
41361
|
+
* Uses allowParse:false (engine.activeModal only, side-effect-free) so it never
|
|
41362
|
+
* mutates the very auto-approve mask state the diagnostics read.
|
|
41363
|
+
*/
|
|
41364
|
+
getDrainStatus() {
|
|
41365
|
+
if (this.isModalParked()) return "modal_parked";
|
|
41366
|
+
let rawStatus;
|
|
41367
|
+
try {
|
|
41368
|
+
const raw = this.adapter.getStatus({ allowParse: false })?.status;
|
|
41369
|
+
rawStatus = typeof raw === "string" ? raw.trim() : "";
|
|
41370
|
+
} catch {
|
|
41371
|
+
return "other";
|
|
41372
|
+
}
|
|
41373
|
+
if (rawStatus === "idle") return "idle";
|
|
41374
|
+
if (isCliGeneratingLikeStatus(rawStatus)) return "generating";
|
|
41375
|
+
return "other";
|
|
41376
|
+
}
|
|
41242
41377
|
onEvent(event, data) {
|
|
41243
41378
|
if (event === "send_message") {
|
|
41244
41379
|
const input = normalizeInputEnvelope(data);
|
|
@@ -51388,7 +51523,7 @@ var meshStatusHandlers = {
|
|
|
51388
51523
|
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
51389
51524
|
const mesh = meshRecord?.mesh;
|
|
51390
51525
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
51391
|
-
const meshHost = resolveMeshHostStatus(mesh);
|
|
51526
|
+
const meshHost = resolveMeshHostStatus(mesh, { localDaemonId: ctx.deps.statusInstanceId });
|
|
51392
51527
|
const refreshRequested = args?.refresh === true || args?.forceRefresh === true;
|
|
51393
51528
|
const verboseMissions = args?.verbose === true || args?.compact === false;
|
|
51394
51529
|
const peekScope = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : ctx.deps.statusInstanceId || void 0;
|