@adhdev/daemon-core 0.9.82-rc.351 → 0.9.82-rc.353
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/router.d.ts +12 -0
- package/dist/commands/upgrade-helper.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +815 -500
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +812 -500
- package/dist/index.mjs.map +1 -1
- package/dist/logging/logger.d.ts +1 -1
- package/dist/mesh/mesh-ledger.d.ts +1 -1
- package/dist/mesh/mesh-runtime-store.d.ts +9 -0
- package/dist/mesh/mesh-work-queue.d.ts +28 -0
- package/dist/providers/approval-utils.d.ts +7 -0
- package/dist/providers/cli-provider-instance.d.ts +15 -0
- package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +1 -0
- package/package.json +2 -2
- package/src/commands/cli-manager.ts +13 -4
- package/src/commands/router.ts +133 -33
- package/src/commands/upgrade-helper.ts +57 -14
- package/src/index.ts +5 -0
- package/src/logging/command-log.ts +7 -5
- package/src/logging/logger.ts +12 -6
- package/src/mesh/mesh-events-coordinator.ts +165 -84
- package/src/mesh/mesh-events-pending.ts +14 -15
- package/src/mesh/mesh-ledger.ts +1 -0
- package/src/mesh/mesh-reconcile-loop.ts +67 -7
- package/src/mesh/mesh-runtime-store.ts +17 -0
- package/src/mesh/mesh-work-queue.ts +89 -0
- package/src/providers/approval-utils.d.ts +1 -0
- package/src/providers/approval-utils.ts +10 -0
- package/src/providers/cli-provider-instance.ts +73 -19
- package/src/providers/sdk/v1/builders/cli/detect-status.ts +51 -0
package/dist/index.js
CHANGED
|
@@ -316,10 +316,10 @@ function readInjected(value) {
|
|
|
316
316
|
}
|
|
317
317
|
function getDaemonBuildInfo() {
|
|
318
318
|
if (cached) return cached;
|
|
319
|
-
const commit = readInjected(true ? "
|
|
320
|
-
const commitShort = readInjected(true ? "
|
|
321
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
322
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
319
|
+
const commit = readInjected(true ? "a680b74d9b940b82f691ebb85a725a1a72445bfc" : void 0) ?? "unknown";
|
|
320
|
+
const commitShort = readInjected(true ? "a680b74d" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
321
|
+
const version = readInjected(true ? "0.9.82-rc.353" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
322
|
+
const builtAt = readInjected(true ? "2026-06-22T09:11:13.499Z" : void 0);
|
|
323
323
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
324
324
|
return cached;
|
|
325
325
|
}
|
|
@@ -2708,6 +2708,257 @@ var init_mesh_config = __esm({
|
|
|
2708
2708
|
}
|
|
2709
2709
|
});
|
|
2710
2710
|
|
|
2711
|
+
// ../mesh-shared/dist/index.mjs
|
|
2712
|
+
function readRecord(value) {
|
|
2713
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2714
|
+
}
|
|
2715
|
+
function readString3(...values) {
|
|
2716
|
+
for (const value of values) {
|
|
2717
|
+
if (typeof value !== "string") continue;
|
|
2718
|
+
const trimmed = value.trim();
|
|
2719
|
+
if (trimmed) return trimmed;
|
|
2720
|
+
}
|
|
2721
|
+
return void 0;
|
|
2722
|
+
}
|
|
2723
|
+
function readNumber(...values) {
|
|
2724
|
+
for (const value of values) {
|
|
2725
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2726
|
+
}
|
|
2727
|
+
return void 0;
|
|
2728
|
+
}
|
|
2729
|
+
function readBoolean(...values) {
|
|
2730
|
+
for (const value of values) {
|
|
2731
|
+
if (typeof value === "boolean") return value;
|
|
2732
|
+
}
|
|
2733
|
+
return void 0;
|
|
2734
|
+
}
|
|
2735
|
+
function joinRepoPath(root, relativePath) {
|
|
2736
|
+
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
2737
|
+
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
2738
|
+
if (!normalizedPath) return void 0;
|
|
2739
|
+
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
2740
|
+
if (!normalizedRoot) return void 0;
|
|
2741
|
+
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
2742
|
+
}
|
|
2743
|
+
function scoreGitUpstreamFreshness(status) {
|
|
2744
|
+
switch (status) {
|
|
2745
|
+
case "fresh":
|
|
2746
|
+
return 30;
|
|
2747
|
+
case "no_upstream":
|
|
2748
|
+
return 4;
|
|
2749
|
+
case "unchecked":
|
|
2750
|
+
case void 0:
|
|
2751
|
+
return 0;
|
|
2752
|
+
case "stale":
|
|
2753
|
+
return -10;
|
|
2754
|
+
case "unavailable":
|
|
2755
|
+
return -15;
|
|
2756
|
+
default:
|
|
2757
|
+
return 0;
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
function readGitSubmodules(value, parentRepoRoot) {
|
|
2761
|
+
if (!Array.isArray(value)) return void 0;
|
|
2762
|
+
const submodules = value.map((entry) => {
|
|
2763
|
+
const submodule = readRecord(entry);
|
|
2764
|
+
const path42 = readString3(submodule.path);
|
|
2765
|
+
const commit = readString3(submodule.commit);
|
|
2766
|
+
const repoPath = readString3(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path42);
|
|
2767
|
+
if (!path42 || !commit) return null;
|
|
2768
|
+
const result = {
|
|
2769
|
+
path: path42,
|
|
2770
|
+
commit,
|
|
2771
|
+
dirty: readBoolean(submodule.dirty) ?? false,
|
|
2772
|
+
outOfSync: readBoolean(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
2773
|
+
lastCheckedAt: readNumber(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now()
|
|
2774
|
+
};
|
|
2775
|
+
if (repoPath) result.repoPath = repoPath;
|
|
2776
|
+
const error = readString3(submodule.error);
|
|
2777
|
+
if (error) result.error = error;
|
|
2778
|
+
return result;
|
|
2779
|
+
}).filter((entry) => entry !== null);
|
|
2780
|
+
return submodules.length > 0 ? submodules : void 0;
|
|
2781
|
+
}
|
|
2782
|
+
function hasGitStatusEvidence(status) {
|
|
2783
|
+
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(
|
|
2784
|
+
status.ahead,
|
|
2785
|
+
status.behind,
|
|
2786
|
+
status.staged,
|
|
2787
|
+
status.modified,
|
|
2788
|
+
status.untracked,
|
|
2789
|
+
status.deleted,
|
|
2790
|
+
status.renamed,
|
|
2791
|
+
status.lastCheckedAt,
|
|
2792
|
+
status.last_checked_at
|
|
2793
|
+
) !== void 0 || Array.isArray(status.submodules) && status.submodules.length > 0;
|
|
2794
|
+
}
|
|
2795
|
+
function normalizeGitStatus(status, node, options) {
|
|
2796
|
+
const explicitIsGitRepo = readBoolean(status.isGitRepo);
|
|
2797
|
+
if (!Object.keys(status).length || !hasGitStatusEvidence(status)) return void 0;
|
|
2798
|
+
const isGitRepo = explicitIsGitRepo ?? true;
|
|
2799
|
+
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((entry) => typeof entry === "string") : [];
|
|
2800
|
+
const conflictCount = readNumber(status.conflicts) ?? conflictFiles.length;
|
|
2801
|
+
const hasConflicts = readBoolean(status.hasConflicts) ?? conflictCount > 0;
|
|
2802
|
+
const repoRoot = readString3(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
|
|
2803
|
+
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
2804
|
+
const upstreamStatus = readString3(status.upstreamStatus, status.upstream_status);
|
|
2805
|
+
const upstreamFetchedAt = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
|
|
2806
|
+
const upstreamFetchError = readString3(status.upstreamFetchError, status.upstream_fetch_error);
|
|
2807
|
+
const error = readString3(status.error);
|
|
2808
|
+
const staged = readNumber(status.staged) ?? 0;
|
|
2809
|
+
const modified = readNumber(status.modified) ?? 0;
|
|
2810
|
+
const untracked = readNumber(status.untracked) ?? 0;
|
|
2811
|
+
const deleted = readNumber(status.deleted) ?? 0;
|
|
2812
|
+
const renamed = readNumber(status.renamed) ?? 0;
|
|
2813
|
+
return {
|
|
2814
|
+
workspace: readString3(status.workspace, node.workspace) || "",
|
|
2815
|
+
repoRoot: repoRoot ?? null,
|
|
2816
|
+
isGitRepo,
|
|
2817
|
+
branch: readString3(status.branch) ?? null,
|
|
2818
|
+
headCommit: readString3(status.headCommit) ?? null,
|
|
2819
|
+
headMessage: readString3(status.headMessage) ?? null,
|
|
2820
|
+
upstream: readString3(status.upstream) ?? null,
|
|
2821
|
+
upstreamStatus: upstreamStatus ?? "unchecked",
|
|
2822
|
+
...upstreamFetchedAt !== void 0 ? { upstreamFetchedAt } : {},
|
|
2823
|
+
...upstreamFetchError ? { upstreamFetchError } : {},
|
|
2824
|
+
ahead: readNumber(status.ahead) ?? 0,
|
|
2825
|
+
behind: readNumber(status.behind) ?? 0,
|
|
2826
|
+
staged,
|
|
2827
|
+
modified,
|
|
2828
|
+
untracked,
|
|
2829
|
+
deleted,
|
|
2830
|
+
renamed,
|
|
2831
|
+
dirty: readBoolean(status.dirty, status.isDirty, status.is_dirty) ?? (staged + modified + untracked + deleted + renamed > 0 || hasConflicts),
|
|
2832
|
+
hasConflicts,
|
|
2833
|
+
conflictFiles,
|
|
2834
|
+
stashCount: readNumber(status.stashCount, status.stash_count) ?? 0,
|
|
2835
|
+
lastCheckedAt: options?.lastCheckedAt ?? readNumber(status.lastCheckedAt, status.last_checked_at) ?? Date.now(),
|
|
2836
|
+
...submodules ? { submodules } : {},
|
|
2837
|
+
...error ? { error } : {}
|
|
2838
|
+
};
|
|
2839
|
+
}
|
|
2840
|
+
function scoreGitStatusCandidate(git) {
|
|
2841
|
+
if (!git) return Number.NEGATIVE_INFINITY;
|
|
2842
|
+
let score = 0;
|
|
2843
|
+
if (git.isGitRepo === true) score += 50;
|
|
2844
|
+
if (git.isGitRepo === false) score -= 10;
|
|
2845
|
+
if (git.branch) score += 20;
|
|
2846
|
+
if (git.headCommit) score += 20;
|
|
2847
|
+
if (git.upstream) score += 10;
|
|
2848
|
+
score += scoreGitUpstreamFreshness(git.upstreamStatus);
|
|
2849
|
+
if (typeof git.ahead === "number") score += 2;
|
|
2850
|
+
if (typeof git.behind === "number") score += 2;
|
|
2851
|
+
if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
|
|
2852
|
+
if (git.error) score -= 20;
|
|
2853
|
+
return score;
|
|
2854
|
+
}
|
|
2855
|
+
function pickBestTransitGitStatus(node, options) {
|
|
2856
|
+
const rawGit = readRecord(node.lastGit ?? node.last_git);
|
|
2857
|
+
const gitResult = readRecord(rawGit.result);
|
|
2858
|
+
const directStatus = readRecord(rawGit.status);
|
|
2859
|
+
const nestedStatus = readRecord(gitResult.status);
|
|
2860
|
+
const rawProbe = readRecord(node.lastProbe ?? node.last_probe);
|
|
2861
|
+
const probeGit = readRecord(rawProbe.git);
|
|
2862
|
+
const probeGitResult = readRecord(probeGit.result);
|
|
2863
|
+
const probeDirectStatus = readRecord(probeGit.status);
|
|
2864
|
+
const probeNestedStatus = readRecord(probeGitResult.status);
|
|
2865
|
+
const lastCheckedAt = options?.lastCheckedAt;
|
|
2866
|
+
let best = null;
|
|
2867
|
+
for (const status of [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus]) {
|
|
2868
|
+
const normalized = normalizeGitStatus(status, node, { lastCheckedAt: lastCheckedAt ?? Date.now() });
|
|
2869
|
+
if (!normalized) continue;
|
|
2870
|
+
const score = scoreGitStatusCandidate(normalized);
|
|
2871
|
+
if (!best || score > best.score) best = { git: normalized, score };
|
|
2872
|
+
}
|
|
2873
|
+
return best?.git;
|
|
2874
|
+
}
|
|
2875
|
+
function normalizeMeshNodeId(node) {
|
|
2876
|
+
const record = node && typeof node === "object" ? node : {};
|
|
2877
|
+
return readString3(record.id, record.nodeId, record.node_id);
|
|
2878
|
+
}
|
|
2879
|
+
function meshNodeIdMatches(node, candidateId) {
|
|
2880
|
+
if (!candidateId) return false;
|
|
2881
|
+
const trimmed = candidateId.trim();
|
|
2882
|
+
if (!trimmed) return false;
|
|
2883
|
+
return normalizeMeshNodeId(node) === trimmed;
|
|
2884
|
+
}
|
|
2885
|
+
function machineCoreFromDaemonId(id) {
|
|
2886
|
+
const trimmed = readString3(id);
|
|
2887
|
+
if (!trimmed) return void 0;
|
|
2888
|
+
for (const prefix of DAEMON_ID_PREFIXES) {
|
|
2889
|
+
if (trimmed.startsWith(prefix)) {
|
|
2890
|
+
const core = trimmed.slice(prefix.length).trim();
|
|
2891
|
+
return core || void 0;
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
return trimmed;
|
|
2895
|
+
}
|
|
2896
|
+
function daemonIdsEquivalent(a, b) {
|
|
2897
|
+
const coreA = machineCoreFromDaemonId(a);
|
|
2898
|
+
const coreB = machineCoreFromDaemonId(b);
|
|
2899
|
+
if (!coreA || !coreB) return false;
|
|
2900
|
+
return coreA === coreB;
|
|
2901
|
+
}
|
|
2902
|
+
function expandDaemonIdForms(ids) {
|
|
2903
|
+
const list = Array.isArray(ids) ? ids : ids != null ? [ids] : [];
|
|
2904
|
+
const out = [];
|
|
2905
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2906
|
+
const add = (value) => {
|
|
2907
|
+
if (!value || seen.has(value)) return;
|
|
2908
|
+
seen.add(value);
|
|
2909
|
+
out.push(value);
|
|
2910
|
+
};
|
|
2911
|
+
for (const raw of list) add(readString3(raw));
|
|
2912
|
+
for (const raw of list) {
|
|
2913
|
+
const core = machineCoreFromDaemonId(readString3(raw));
|
|
2914
|
+
if (!core || !core.startsWith("mach_")) continue;
|
|
2915
|
+
add(core);
|
|
2916
|
+
for (const prefix of DAEMON_ID_PREFIXES) add(`${prefix}${core}`);
|
|
2917
|
+
}
|
|
2918
|
+
return out;
|
|
2919
|
+
}
|
|
2920
|
+
function summarizeGitShape(status) {
|
|
2921
|
+
const record = readRecord(status);
|
|
2922
|
+
if (!Object.keys(record).length) return null;
|
|
2923
|
+
const submodules = Array.isArray(record.submodules) ? record.submodules.map((entry) => {
|
|
2924
|
+
const sub = readRecord(entry);
|
|
2925
|
+
return {
|
|
2926
|
+
path: readString3(sub.path) ?? null,
|
|
2927
|
+
commit: readString3(sub.commit)?.slice(0, 12) ?? null,
|
|
2928
|
+
dirty: readBoolean(sub.dirty) ?? false,
|
|
2929
|
+
outOfSync: readBoolean(sub.outOfSync, sub.out_of_sync) ?? false
|
|
2930
|
+
};
|
|
2931
|
+
}) : [];
|
|
2932
|
+
return {
|
|
2933
|
+
isGitRepo: readBoolean(record.isGitRepo),
|
|
2934
|
+
workspace: readString3(record.workspace) ?? null,
|
|
2935
|
+
repoRoot: readString3(record.repoRoot, record.repo_root) ?? null,
|
|
2936
|
+
branch: readString3(record.branch) ?? null,
|
|
2937
|
+
upstream: readString3(record.upstream) ?? null,
|
|
2938
|
+
upstreamStatus: readString3(record.upstreamStatus, record.upstream_status) ?? null,
|
|
2939
|
+
headCommit: readString3(record.headCommit, record.head_commit)?.slice(0, 12) ?? null,
|
|
2940
|
+
ahead: readNumber(record.ahead) ?? null,
|
|
2941
|
+
behind: readNumber(record.behind) ?? null,
|
|
2942
|
+
dirtyCounts: {
|
|
2943
|
+
staged: readNumber(record.staged) ?? 0,
|
|
2944
|
+
modified: readNumber(record.modified) ?? 0,
|
|
2945
|
+
untracked: readNumber(record.untracked) ?? 0,
|
|
2946
|
+
deleted: readNumber(record.deleted) ?? 0,
|
|
2947
|
+
renamed: readNumber(record.renamed) ?? 0
|
|
2948
|
+
},
|
|
2949
|
+
lastCheckedAt: readNumber(record.lastCheckedAt, record.last_checked_at) ?? null,
|
|
2950
|
+
submoduleCount: submodules.length,
|
|
2951
|
+
submodules
|
|
2952
|
+
};
|
|
2953
|
+
}
|
|
2954
|
+
var DAEMON_ID_PREFIXES;
|
|
2955
|
+
var init_dist = __esm({
|
|
2956
|
+
"../mesh-shared/dist/index.mjs"() {
|
|
2957
|
+
"use strict";
|
|
2958
|
+
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
2959
|
+
}
|
|
2960
|
+
});
|
|
2961
|
+
|
|
2711
2962
|
// src/mesh/coordinator-prompt.ts
|
|
2712
2963
|
var coordinator_prompt_exports = {};
|
|
2713
2964
|
__export(coordinator_prompt_exports, {
|
|
@@ -3195,7 +3446,7 @@ function installGlobalInterceptor() {
|
|
|
3195
3446
|
function getLogPath() {
|
|
3196
3447
|
return currentLogFile;
|
|
3197
3448
|
}
|
|
3198
|
-
var fs4, path9, os3, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH, LOG_DIR_PATH;
|
|
3449
|
+
var fs4, path9, os3, LEVEL_NUM, LEVEL_LABEL, currentLevel, ADHDEV_HOME, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH, LOG_DIR_PATH;
|
|
3199
3450
|
var init_logger = __esm({
|
|
3200
3451
|
"src/logging/logger.ts"() {
|
|
3201
3452
|
"use strict";
|
|
@@ -3206,7 +3457,8 @@ var init_logger = __esm({
|
|
|
3206
3457
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
3207
3458
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
3208
3459
|
currentLevel = "info";
|
|
3209
|
-
|
|
3460
|
+
ADHDEV_HOME = process.env.ADHDEV_CONFIG_DIR && process.env.ADHDEV_CONFIG_DIR.trim() ? process.env.ADHDEV_CONFIG_DIR.trim() : path9.join(os3.homedir(), ".adhdev");
|
|
3461
|
+
LOG_DIR = path9.join(ADHDEV_HOME, "logs");
|
|
3210
3462
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
3211
3463
|
MAX_LOG_DAYS = 7;
|
|
3212
3464
|
try {
|
|
@@ -4007,6 +4259,7 @@ __export(mesh_work_queue_exports, {
|
|
|
4007
4259
|
nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
|
|
4008
4260
|
normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
|
|
4009
4261
|
normalizeMeshTaskMode: () => normalizeMeshTaskMode,
|
|
4262
|
+
reclaimStrandedAssignedTask: () => reclaimStrandedAssignedTask,
|
|
4010
4263
|
recordDirectDispatchTask: () => recordDirectDispatchTask,
|
|
4011
4264
|
recordMeshToolCall: () => recordMeshToolCall,
|
|
4012
4265
|
recordTaskAutoLaunch: () => recordTaskAutoLaunch,
|
|
@@ -4442,6 +4695,52 @@ function requeueTask(meshId, taskId, opts) {
|
|
|
4442
4695
|
return entry;
|
|
4443
4696
|
});
|
|
4444
4697
|
}
|
|
4698
|
+
function reclaimStrandedAssignedTask(meshId, taskId, opts) {
|
|
4699
|
+
requireMeshHostQueueOwner(opts);
|
|
4700
|
+
return withQueueLock(meshId, () => {
|
|
4701
|
+
const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
|
|
4702
|
+
if (!entry) return null;
|
|
4703
|
+
if (entry.status !== "assigned") return null;
|
|
4704
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4705
|
+
const reason = opts?.reason || "assigned_stranded_dispatch_unconfirmed";
|
|
4706
|
+
const reclaims = (entry.strandedReclaimCount || 0) + 1;
|
|
4707
|
+
const prevNode = entry.assignedNodeId;
|
|
4708
|
+
const prevSession = entry.assignedSessionId;
|
|
4709
|
+
delete entry.assignedNodeId;
|
|
4710
|
+
delete entry.assignedSessionId;
|
|
4711
|
+
delete entry.assignedProviderType;
|
|
4712
|
+
delete entry.dispatchTimestamp;
|
|
4713
|
+
entry.strandedReclaimCount = reclaims;
|
|
4714
|
+
entry.updatedAt = now;
|
|
4715
|
+
if (reclaims > MAX_STRANDED_RECLAIMS) {
|
|
4716
|
+
entry.status = "failed";
|
|
4717
|
+
entry.cancelReason = `stranded_dispatch_unrecovered: reclaimed ${reclaims - 1} time(s) without a confirmed dispatch`;
|
|
4718
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
4719
|
+
propagateDependencyFailure(meshId, taskId);
|
|
4720
|
+
} else {
|
|
4721
|
+
entry.status = "pending";
|
|
4722
|
+
entry.requeuedAt = now;
|
|
4723
|
+
entry.requeueReason = reason;
|
|
4724
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
4725
|
+
}
|
|
4726
|
+
try {
|
|
4727
|
+
appendLedgerEntry(meshId, {
|
|
4728
|
+
kind: "task_reclaimed",
|
|
4729
|
+
nodeId: prevNode,
|
|
4730
|
+
sessionId: prevSession,
|
|
4731
|
+
payload: {
|
|
4732
|
+
taskId,
|
|
4733
|
+
reason,
|
|
4734
|
+
...typeof opts?.ageMs === "number" ? { ageMs: opts.ageMs } : {},
|
|
4735
|
+
reclaimCount: reclaims,
|
|
4736
|
+
outcome: entry.status
|
|
4737
|
+
}
|
|
4738
|
+
});
|
|
4739
|
+
} catch {
|
|
4740
|
+
}
|
|
4741
|
+
return entry;
|
|
4742
|
+
});
|
|
4743
|
+
}
|
|
4445
4744
|
function updateSessionTaskStatus(meshId, sessionId, status, opts) {
|
|
4446
4745
|
return withQueueLock(meshId, () => {
|
|
4447
4746
|
const store = MeshRuntimeStore.getInstance();
|
|
@@ -4555,7 +4854,7 @@ function recordMeshToolCall(opts) {
|
|
|
4555
4854
|
return { rateLimitExceeded: false, callsInWindow: 0, advisory: null };
|
|
4556
4855
|
}
|
|
4557
4856
|
}
|
|
4558
|
-
var import_crypto5, ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES, MESH_TASK_MODES, LIVE_DEBUG_READONLY_FORBIDDEN, NEGATION_CUES, NEGATION_WINDOW_TOKENS, GIT_MUTATION_SUBCOMMANDS, GIT_STASH_READONLY_SUBCOMMANDS, DEPENDENCY_FAILURE_TERMINALS;
|
|
4857
|
+
var import_crypto5, ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES, MESH_TASK_MODES, LIVE_DEBUG_READONLY_FORBIDDEN, NEGATION_CUES, NEGATION_WINDOW_TOKENS, GIT_MUTATION_SUBCOMMANDS, GIT_STASH_READONLY_SUBCOMMANDS, DEPENDENCY_FAILURE_TERMINALS, MAX_STRANDED_RECLAIMS;
|
|
4559
4858
|
var init_mesh_work_queue = __esm({
|
|
4560
4859
|
"src/mesh/mesh-work-queue.ts"() {
|
|
4561
4860
|
"use strict";
|
|
@@ -4565,6 +4864,7 @@ var init_mesh_work_queue = __esm({
|
|
|
4565
4864
|
init_mesh_runtime_store();
|
|
4566
4865
|
init_mesh_config();
|
|
4567
4866
|
init_logger();
|
|
4867
|
+
init_mesh_ledger();
|
|
4568
4868
|
ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
|
|
4569
4869
|
HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
|
|
4570
4870
|
MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
|
|
@@ -4617,6 +4917,7 @@ var init_mesh_work_queue = __esm({
|
|
|
4617
4917
|
]);
|
|
4618
4918
|
GIT_STASH_READONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["list", "show"]);
|
|
4619
4919
|
DEPENDENCY_FAILURE_TERMINALS = /* @__PURE__ */ new Set(["failed", "cancelled"]);
|
|
4920
|
+
MAX_STRANDED_RECLAIMS = 3;
|
|
4620
4921
|
}
|
|
4621
4922
|
});
|
|
4622
4923
|
|
|
@@ -5502,6 +5803,22 @@ var init_mesh_runtime_store = __esm({
|
|
|
5502
5803
|
updatedAt: r.updated_at
|
|
5503
5804
|
}));
|
|
5504
5805
|
}
|
|
5806
|
+
/**
|
|
5807
|
+
* Bug B watchdog support: true when at least one delivery record for the task has
|
|
5808
|
+
* reached a confirmed-handed-off status (delivered / acked / completed). The
|
|
5809
|
+
* assigned-stranded watchdog uses this to distinguish a dispatch that was never
|
|
5810
|
+
* confirmed (reclaimable) from one that WAS handed to the worker (a genuinely
|
|
5811
|
+
* in-flight or completion-lost task, which is PHASE 4's responsibility, not this
|
|
5812
|
+
* watchdog's). Indexed by (mesh_id, task_id).
|
|
5813
|
+
*/
|
|
5814
|
+
taskHasConfirmedDelivery(meshId, taskId) {
|
|
5815
|
+
const row = this.db.prepare(`
|
|
5816
|
+
SELECT 1 FROM mesh_session_delivery
|
|
5817
|
+
WHERE mesh_id = ? AND task_id = ? AND status IN ('delivered','acked','completed')
|
|
5818
|
+
LIMIT 1
|
|
5819
|
+
`).get(meshId, taskId);
|
|
5820
|
+
return !!row;
|
|
5821
|
+
}
|
|
5505
5822
|
expireStaleSessionDeliveries(meshId) {
|
|
5506
5823
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5507
5824
|
this.db.prepare(`
|
|
@@ -6250,10 +6567,10 @@ var init_mesh_missions = __esm({
|
|
|
6250
6567
|
});
|
|
6251
6568
|
|
|
6252
6569
|
// src/mesh/mesh-refine-status.ts
|
|
6253
|
-
function
|
|
6570
|
+
function readString4(value) {
|
|
6254
6571
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
6255
6572
|
}
|
|
6256
|
-
function
|
|
6573
|
+
function readRecord2(value) {
|
|
6257
6574
|
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
6258
6575
|
}
|
|
6259
6576
|
function eventStatus(event, fallback) {
|
|
@@ -6276,7 +6593,7 @@ function instructionForStatus(status) {
|
|
|
6276
6593
|
return "Refine job failed; inspect result/finalBranchConvergenceState in mesh_task_history, fix the blocker, then rerun mesh_refine_node when ready.";
|
|
6277
6594
|
}
|
|
6278
6595
|
function mergeJob(jobs, patch) {
|
|
6279
|
-
const jobId =
|
|
6596
|
+
const jobId = readString4(patch.jobId);
|
|
6280
6597
|
if (!jobId) return;
|
|
6281
6598
|
const previous = jobs.get(jobId);
|
|
6282
6599
|
const status = patch.status || previous?.status || "running";
|
|
@@ -6294,54 +6611,54 @@ function mergeJob(jobs, patch) {
|
|
|
6294
6611
|
function buildMeshAsyncRefineJobs(args) {
|
|
6295
6612
|
const jobs = /* @__PURE__ */ new Map();
|
|
6296
6613
|
for (const entry of args.ledgerEntries || []) {
|
|
6297
|
-
const payload =
|
|
6614
|
+
const payload = readRecord2(entry.payload);
|
|
6298
6615
|
if (payload?.source !== "refine_mesh_node_async_job") continue;
|
|
6299
|
-
const refineJob =
|
|
6300
|
-
const result =
|
|
6301
|
-
const finalState =
|
|
6302
|
-
const jobId =
|
|
6616
|
+
const refineJob = readRecord2(payload.refineJob);
|
|
6617
|
+
const result = readRecord2(payload.result);
|
|
6618
|
+
const finalState = readRecord2(payload.finalBranchConvergenceState) || readRecord2(result?.finalBranchConvergenceState);
|
|
6619
|
+
const jobId = readString4(refineJob?.jobId);
|
|
6303
6620
|
if (!jobId) continue;
|
|
6304
|
-
const status = ledgerStatus(entry.kind,
|
|
6621
|
+
const status = ledgerStatus(entry.kind, readString4(refineJob?.status));
|
|
6305
6622
|
mergeJob(jobs, {
|
|
6306
6623
|
jobId,
|
|
6307
|
-
interactionId:
|
|
6624
|
+
interactionId: readString4(refineJob?.interactionId),
|
|
6308
6625
|
status,
|
|
6309
|
-
meshId:
|
|
6310
|
-
nodeId:
|
|
6311
|
-
targetNodeId:
|
|
6312
|
-
targetDaemonId:
|
|
6313
|
-
workspace:
|
|
6314
|
-
branch:
|
|
6315
|
-
into:
|
|
6316
|
-
startedAt:
|
|
6317
|
-
completedAt:
|
|
6318
|
-
retryOfJobId:
|
|
6626
|
+
meshId: readString4(refineJob?.meshId) || args.meshId,
|
|
6627
|
+
nodeId: readString4(refineJob?.nodeId) || entry.nodeId,
|
|
6628
|
+
targetNodeId: readString4(refineJob?.nodeId) || entry.nodeId,
|
|
6629
|
+
targetDaemonId: readString4(refineJob?.targetDaemonId),
|
|
6630
|
+
workspace: readString4(refineJob?.workspace),
|
|
6631
|
+
branch: readString4(result?.branch) || readString4(finalState?.branch),
|
|
6632
|
+
into: readString4(result?.into) || readString4(finalState?.baseBranch),
|
|
6633
|
+
startedAt: readString4(refineJob?.startedAt),
|
|
6634
|
+
completedAt: readString4(refineJob?.completedAt),
|
|
6635
|
+
retryOfJobId: readString4(refineJob?.retryOfJobId) || readString4(payload.retryOfJobId),
|
|
6319
6636
|
lastLedgerKind: entry.kind,
|
|
6320
6637
|
lastUpdatedAt: entry.timestamp
|
|
6321
6638
|
});
|
|
6322
6639
|
}
|
|
6323
6640
|
for (const event of args.pendingEvents || []) {
|
|
6324
|
-
const metadata =
|
|
6641
|
+
const metadata = readRecord2(event.metadataEvent);
|
|
6325
6642
|
if (metadata?.source !== "refine_mesh_node_async_job") continue;
|
|
6326
|
-
const result =
|
|
6327
|
-
const finalState =
|
|
6328
|
-
const jobId =
|
|
6643
|
+
const result = readRecord2(metadata.result);
|
|
6644
|
+
const finalState = readRecord2(result?.finalBranchConvergenceState);
|
|
6645
|
+
const jobId = readString4(metadata.jobId);
|
|
6329
6646
|
if (!jobId) continue;
|
|
6330
|
-
const status = eventStatus(event.event,
|
|
6647
|
+
const status = eventStatus(event.event, readString4(metadata.status));
|
|
6331
6648
|
mergeJob(jobs, {
|
|
6332
6649
|
jobId,
|
|
6333
|
-
interactionId:
|
|
6650
|
+
interactionId: readString4(metadata.interactionId),
|
|
6334
6651
|
...status ? { status } : {},
|
|
6335
|
-
meshId:
|
|
6336
|
-
nodeId:
|
|
6337
|
-
targetNodeId:
|
|
6338
|
-
targetDaemonId:
|
|
6339
|
-
workspace:
|
|
6340
|
-
branch:
|
|
6341
|
-
into:
|
|
6342
|
-
startedAt:
|
|
6343
|
-
completedAt:
|
|
6344
|
-
retryOfJobId:
|
|
6652
|
+
meshId: readString4(metadata.meshId) || event.meshId || args.meshId,
|
|
6653
|
+
nodeId: readString4(metadata.nodeId) || event.nodeId,
|
|
6654
|
+
targetNodeId: readString4(metadata.nodeId) || event.nodeId,
|
|
6655
|
+
targetDaemonId: readString4(metadata.targetDaemonId),
|
|
6656
|
+
workspace: readString4(metadata.workspace) || event.workspace,
|
|
6657
|
+
branch: readString4(result?.branch) || readString4(finalState?.branch),
|
|
6658
|
+
into: readString4(result?.into) || readString4(finalState?.baseBranch),
|
|
6659
|
+
startedAt: readString4(metadata.startedAt),
|
|
6660
|
+
completedAt: readString4(metadata.completedAt),
|
|
6661
|
+
retryOfJobId: readString4(metadata.retryOfJobId),
|
|
6345
6662
|
lastEvent: event.event,
|
|
6346
6663
|
lastUpdatedAt: new Date(event.queuedAt).toISOString()
|
|
6347
6664
|
});
|
|
@@ -6402,10 +6719,10 @@ var mesh_review_inbox_exports = {};
|
|
|
6402
6719
|
__export(mesh_review_inbox_exports, {
|
|
6403
6720
|
deriveMeshReviewInboxItems: () => deriveMeshReviewInboxItems
|
|
6404
6721
|
});
|
|
6405
|
-
function
|
|
6722
|
+
function readString5(value) {
|
|
6406
6723
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
6407
6724
|
}
|
|
6408
|
-
function
|
|
6725
|
+
function readRecord3(value) {
|
|
6409
6726
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
6410
6727
|
}
|
|
6411
6728
|
function readStringArray3(value, max) {
|
|
@@ -6415,20 +6732,20 @@ function readStringArray3(value, max) {
|
|
|
6415
6732
|
}
|
|
6416
6733
|
function isLocalNodeStatus(node) {
|
|
6417
6734
|
if (node.isLocalWorktree === true) return true;
|
|
6418
|
-
const connection =
|
|
6419
|
-
return
|
|
6735
|
+
const connection = readRecord3(node.connection);
|
|
6736
|
+
return readString5(connection?.state) === "self";
|
|
6420
6737
|
}
|
|
6421
6738
|
function readNodeConvergence(node) {
|
|
6422
|
-
const convergence =
|
|
6423
|
-
const status =
|
|
6739
|
+
const convergence = readRecord3(node.branchConvergence);
|
|
6740
|
+
const status = readString5(convergence?.status);
|
|
6424
6741
|
if (!convergence || !status) return null;
|
|
6425
6742
|
return {
|
|
6426
6743
|
status,
|
|
6427
|
-
reason:
|
|
6428
|
-
nextStep:
|
|
6744
|
+
reason: readString5(convergence.reason),
|
|
6745
|
+
nextStep: readString5(convergence.nextStep),
|
|
6429
6746
|
needsConvergence: convergence.needsConvergence === true,
|
|
6430
|
-
branch:
|
|
6431
|
-
defaultBranch:
|
|
6747
|
+
branch: readString5(convergence.branch),
|
|
6748
|
+
defaultBranch: readString5(convergence.defaultBranch)
|
|
6432
6749
|
};
|
|
6433
6750
|
}
|
|
6434
6751
|
function isMergeCandidate(convergence) {
|
|
@@ -6436,15 +6753,15 @@ function isMergeCandidate(convergence) {
|
|
|
6436
6753
|
return convergence.status === "cleanup_candidate" && convergence.reason === "clean_non_default_worktree_branch";
|
|
6437
6754
|
}
|
|
6438
6755
|
function readWorkerArtifact(value) {
|
|
6439
|
-
const worker =
|
|
6756
|
+
const worker = readRecord3(value);
|
|
6440
6757
|
if (!worker) return null;
|
|
6441
6758
|
const changed = readStringArray3(worker.changedFiles, MAX_CHANGED_FILES);
|
|
6442
6759
|
return {
|
|
6443
|
-
status:
|
|
6444
|
-
...
|
|
6760
|
+
status: readString5(worker.status) ?? "unknown",
|
|
6761
|
+
...readString5(worker.classification) ? { classification: readString5(worker.classification) } : {},
|
|
6445
6762
|
changedFiles: changed.values,
|
|
6446
6763
|
...changed.truncated ? { changedFilesTruncated: true } : {},
|
|
6447
|
-
validationResults: Array.isArray(worker.validationResults) ? worker.validationResults.map((item) =>
|
|
6764
|
+
validationResults: Array.isArray(worker.validationResults) ? worker.validationResults.map((item) => readRecord3(item)).filter((item) => item !== null) : [],
|
|
6448
6765
|
errors: readStringArray3(worker.errors, 20).values,
|
|
6449
6766
|
requiresUserAction: worker.requiresUserAction === true
|
|
6450
6767
|
};
|
|
@@ -6458,43 +6775,43 @@ function resolveNodeEvidence(nodeId, ledgerEntries) {
|
|
|
6458
6775
|
for (let i = ledgerEntries.length - 1; i >= 0; i--) {
|
|
6459
6776
|
const entry = ledgerEntries[i];
|
|
6460
6777
|
if (entry.nodeId !== nodeId || !isTerminalLedgerKind(entry.kind)) continue;
|
|
6461
|
-
const payload =
|
|
6778
|
+
const payload = readRecord3(entry.payload) ?? {};
|
|
6462
6779
|
if (!evidence.available) {
|
|
6463
6780
|
if (payload.source === "refine_mesh_node_async_job") {
|
|
6464
|
-
const result =
|
|
6465
|
-
const validationSummary =
|
|
6781
|
+
const result = readRecord3(payload.result);
|
|
6782
|
+
const validationSummary = readRecord3(result?.validationSummary);
|
|
6466
6783
|
evidence = {
|
|
6467
6784
|
available: true,
|
|
6468
6785
|
kind: entry.kind,
|
|
6469
6786
|
source: "refine_job",
|
|
6470
6787
|
timestamp: entry.timestamp,
|
|
6471
6788
|
...entry.sessionId ? { sessionId: entry.sessionId } : {},
|
|
6472
|
-
bootstrap:
|
|
6789
|
+
bootstrap: readRecord3(validationSummary?.bootstrap),
|
|
6473
6790
|
validation: validationSummary ? Object.fromEntries(Object.entries(validationSummary).filter(([key]) => key !== "bootstrap")) : null,
|
|
6474
|
-
checkpoint:
|
|
6791
|
+
checkpoint: readRecord3(result?.checkpoint),
|
|
6475
6792
|
worker: null,
|
|
6476
|
-
...
|
|
6477
|
-
...
|
|
6793
|
+
...readRecord3(payload.finalBranchConvergenceState) ?? readRecord3(result?.finalBranchConvergenceState) ? { finalBranchConvergenceState: readRecord3(payload.finalBranchConvergenceState) ?? readRecord3(result?.finalBranchConvergenceState) } : {},
|
|
6794
|
+
...readRecord3(payload.refineJob) ? { refineJob: readRecord3(payload.refineJob) } : {}
|
|
6478
6795
|
};
|
|
6479
6796
|
} else {
|
|
6480
|
-
const envelope =
|
|
6797
|
+
const envelope = readRecord3(payload.evidence);
|
|
6481
6798
|
evidence = {
|
|
6482
6799
|
available: true,
|
|
6483
6800
|
kind: entry.kind,
|
|
6484
6801
|
source: "task_completion",
|
|
6485
6802
|
timestamp: entry.timestamp,
|
|
6486
|
-
...
|
|
6803
|
+
...readString5(payload.taskId) ? { taskId: readString5(payload.taskId) } : {},
|
|
6487
6804
|
...entry.sessionId ? { sessionId: entry.sessionId } : {},
|
|
6488
6805
|
bootstrap: null,
|
|
6489
|
-
validation:
|
|
6490
|
-
checkpoint:
|
|
6806
|
+
validation: readRecord3(envelope?.validation),
|
|
6807
|
+
checkpoint: readRecord3(envelope?.checkpoint),
|
|
6491
6808
|
worker: readWorkerArtifact(envelope?.workerResult ?? payload.workerResult)
|
|
6492
6809
|
};
|
|
6493
6810
|
}
|
|
6494
6811
|
}
|
|
6495
6812
|
if (!transcriptHandle) {
|
|
6496
|
-
const envelope =
|
|
6497
|
-
transcriptHandle =
|
|
6813
|
+
const envelope = readRecord3(payload.evidence);
|
|
6814
|
+
transcriptHandle = readRecord3(envelope?.transcriptHandle);
|
|
6498
6815
|
}
|
|
6499
6816
|
if (evidence.available && transcriptHandle) break;
|
|
6500
6817
|
}
|
|
@@ -6504,11 +6821,11 @@ function hasBlockedReviewRefineResult(nodeId, ledgerEntries) {
|
|
|
6504
6821
|
for (let i = ledgerEntries.length - 1; i >= 0; i--) {
|
|
6505
6822
|
const entry = ledgerEntries[i];
|
|
6506
6823
|
if (entry.nodeId !== nodeId || !isTerminalLedgerKind(entry.kind)) continue;
|
|
6507
|
-
const payload =
|
|
6824
|
+
const payload = readRecord3(entry.payload) ?? {};
|
|
6508
6825
|
if (payload.source !== "refine_mesh_node_async_job") continue;
|
|
6509
|
-
const result =
|
|
6510
|
-
const finalState =
|
|
6511
|
-
return
|
|
6826
|
+
const result = readRecord3(payload.result);
|
|
6827
|
+
const finalState = readRecord3(payload.finalBranchConvergenceState) ?? readRecord3(result?.finalBranchConvergenceState);
|
|
6828
|
+
return readString5(finalState?.status) === "blocked_review" || readString5(result?.code) === "blocked_review";
|
|
6512
6829
|
}
|
|
6513
6830
|
return false;
|
|
6514
6831
|
}
|
|
@@ -6517,7 +6834,7 @@ function deriveMeshReviewInboxItems(args) {
|
|
|
6517
6834
|
const excludedRemoteNodeIds = [];
|
|
6518
6835
|
const refineJobs = buildMeshAsyncRefineJobs({ ledgerEntries: args.ledgerEntries });
|
|
6519
6836
|
for (const node of args.nodes) {
|
|
6520
|
-
const nodeId =
|
|
6837
|
+
const nodeId = readString5(node.nodeId) ?? readString5(node.id);
|
|
6521
6838
|
if (!nodeId) continue;
|
|
6522
6839
|
if (!isLocalNodeStatus(node)) {
|
|
6523
6840
|
excludedRemoteNodeIds.push(nodeId);
|
|
@@ -6539,8 +6856,8 @@ function deriveMeshReviewInboxItems(args) {
|
|
|
6539
6856
|
) ?? null;
|
|
6540
6857
|
items.push({
|
|
6541
6858
|
nodeId,
|
|
6542
|
-
workspace:
|
|
6543
|
-
branch: convergence.branch ??
|
|
6859
|
+
workspace: readString5(node.workspace),
|
|
6860
|
+
branch: convergence.branch ?? readString5(node.worktreeBranch),
|
|
6544
6861
|
defaultBranch: convergence.defaultBranch,
|
|
6545
6862
|
isLocalWorktree: node.isLocalWorktree === true,
|
|
6546
6863
|
reviewReason,
|
|
@@ -7751,220 +8068,6 @@ var init_mesh_fast_forward = __esm({
|
|
|
7751
8068
|
}
|
|
7752
8069
|
});
|
|
7753
8070
|
|
|
7754
|
-
// ../mesh-shared/dist/index.mjs
|
|
7755
|
-
function readRecord3(value) {
|
|
7756
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
7757
|
-
}
|
|
7758
|
-
function readString5(...values) {
|
|
7759
|
-
for (const value of values) {
|
|
7760
|
-
if (typeof value !== "string") continue;
|
|
7761
|
-
const trimmed = value.trim();
|
|
7762
|
-
if (trimmed) return trimmed;
|
|
7763
|
-
}
|
|
7764
|
-
return void 0;
|
|
7765
|
-
}
|
|
7766
|
-
function readNumber(...values) {
|
|
7767
|
-
for (const value of values) {
|
|
7768
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
7769
|
-
}
|
|
7770
|
-
return void 0;
|
|
7771
|
-
}
|
|
7772
|
-
function readBoolean(...values) {
|
|
7773
|
-
for (const value of values) {
|
|
7774
|
-
if (typeof value === "boolean") return value;
|
|
7775
|
-
}
|
|
7776
|
-
return void 0;
|
|
7777
|
-
}
|
|
7778
|
-
function joinRepoPath(root, relativePath) {
|
|
7779
|
-
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
7780
|
-
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
7781
|
-
if (!normalizedPath) return void 0;
|
|
7782
|
-
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
7783
|
-
if (!normalizedRoot) return void 0;
|
|
7784
|
-
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
7785
|
-
}
|
|
7786
|
-
function scoreGitUpstreamFreshness(status) {
|
|
7787
|
-
switch (status) {
|
|
7788
|
-
case "fresh":
|
|
7789
|
-
return 30;
|
|
7790
|
-
case "no_upstream":
|
|
7791
|
-
return 4;
|
|
7792
|
-
case "unchecked":
|
|
7793
|
-
case void 0:
|
|
7794
|
-
return 0;
|
|
7795
|
-
case "stale":
|
|
7796
|
-
return -10;
|
|
7797
|
-
case "unavailable":
|
|
7798
|
-
return -15;
|
|
7799
|
-
default:
|
|
7800
|
-
return 0;
|
|
7801
|
-
}
|
|
7802
|
-
}
|
|
7803
|
-
function readGitSubmodules(value, parentRepoRoot) {
|
|
7804
|
-
if (!Array.isArray(value)) return void 0;
|
|
7805
|
-
const submodules = value.map((entry) => {
|
|
7806
|
-
const submodule = readRecord3(entry);
|
|
7807
|
-
const path42 = readString5(submodule.path);
|
|
7808
|
-
const commit = readString5(submodule.commit);
|
|
7809
|
-
const repoPath = readString5(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path42);
|
|
7810
|
-
if (!path42 || !commit) return null;
|
|
7811
|
-
const result = {
|
|
7812
|
-
path: path42,
|
|
7813
|
-
commit,
|
|
7814
|
-
dirty: readBoolean(submodule.dirty) ?? false,
|
|
7815
|
-
outOfSync: readBoolean(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
7816
|
-
lastCheckedAt: readNumber(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now()
|
|
7817
|
-
};
|
|
7818
|
-
if (repoPath) result.repoPath = repoPath;
|
|
7819
|
-
const error = readString5(submodule.error);
|
|
7820
|
-
if (error) result.error = error;
|
|
7821
|
-
return result;
|
|
7822
|
-
}).filter((entry) => entry !== null);
|
|
7823
|
-
return submodules.length > 0 ? submodules : void 0;
|
|
7824
|
-
}
|
|
7825
|
-
function hasGitStatusEvidence(status) {
|
|
7826
|
-
return readBoolean(status.isGitRepo) !== void 0 || Boolean(readString5(status.branch, status.upstream, status.upstreamStatus, status.upstream_status, status.headCommit)) || Boolean(readString5(status.repoRoot, status.repo_root, status.workspace)) || readNumber(
|
|
7827
|
-
status.ahead,
|
|
7828
|
-
status.behind,
|
|
7829
|
-
status.staged,
|
|
7830
|
-
status.modified,
|
|
7831
|
-
status.untracked,
|
|
7832
|
-
status.deleted,
|
|
7833
|
-
status.renamed,
|
|
7834
|
-
status.lastCheckedAt,
|
|
7835
|
-
status.last_checked_at
|
|
7836
|
-
) !== void 0 || Array.isArray(status.submodules) && status.submodules.length > 0;
|
|
7837
|
-
}
|
|
7838
|
-
function normalizeGitStatus(status, node, options) {
|
|
7839
|
-
const explicitIsGitRepo = readBoolean(status.isGitRepo);
|
|
7840
|
-
if (!Object.keys(status).length || !hasGitStatusEvidence(status)) return void 0;
|
|
7841
|
-
const isGitRepo = explicitIsGitRepo ?? true;
|
|
7842
|
-
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((entry) => typeof entry === "string") : [];
|
|
7843
|
-
const conflictCount = readNumber(status.conflicts) ?? conflictFiles.length;
|
|
7844
|
-
const hasConflicts = readBoolean(status.hasConflicts) ?? conflictCount > 0;
|
|
7845
|
-
const repoRoot = readString5(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
|
|
7846
|
-
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
7847
|
-
const upstreamStatus = readString5(status.upstreamStatus, status.upstream_status);
|
|
7848
|
-
const upstreamFetchedAt = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
|
|
7849
|
-
const upstreamFetchError = readString5(status.upstreamFetchError, status.upstream_fetch_error);
|
|
7850
|
-
const error = readString5(status.error);
|
|
7851
|
-
const staged = readNumber(status.staged) ?? 0;
|
|
7852
|
-
const modified = readNumber(status.modified) ?? 0;
|
|
7853
|
-
const untracked = readNumber(status.untracked) ?? 0;
|
|
7854
|
-
const deleted = readNumber(status.deleted) ?? 0;
|
|
7855
|
-
const renamed = readNumber(status.renamed) ?? 0;
|
|
7856
|
-
return {
|
|
7857
|
-
workspace: readString5(status.workspace, node.workspace) || "",
|
|
7858
|
-
repoRoot: repoRoot ?? null,
|
|
7859
|
-
isGitRepo,
|
|
7860
|
-
branch: readString5(status.branch) ?? null,
|
|
7861
|
-
headCommit: readString5(status.headCommit) ?? null,
|
|
7862
|
-
headMessage: readString5(status.headMessage) ?? null,
|
|
7863
|
-
upstream: readString5(status.upstream) ?? null,
|
|
7864
|
-
upstreamStatus: upstreamStatus ?? "unchecked",
|
|
7865
|
-
...upstreamFetchedAt !== void 0 ? { upstreamFetchedAt } : {},
|
|
7866
|
-
...upstreamFetchError ? { upstreamFetchError } : {},
|
|
7867
|
-
ahead: readNumber(status.ahead) ?? 0,
|
|
7868
|
-
behind: readNumber(status.behind) ?? 0,
|
|
7869
|
-
staged,
|
|
7870
|
-
modified,
|
|
7871
|
-
untracked,
|
|
7872
|
-
deleted,
|
|
7873
|
-
renamed,
|
|
7874
|
-
dirty: readBoolean(status.dirty, status.isDirty, status.is_dirty) ?? (staged + modified + untracked + deleted + renamed > 0 || hasConflicts),
|
|
7875
|
-
hasConflicts,
|
|
7876
|
-
conflictFiles,
|
|
7877
|
-
stashCount: readNumber(status.stashCount, status.stash_count) ?? 0,
|
|
7878
|
-
lastCheckedAt: options?.lastCheckedAt ?? readNumber(status.lastCheckedAt, status.last_checked_at) ?? Date.now(),
|
|
7879
|
-
...submodules ? { submodules } : {},
|
|
7880
|
-
...error ? { error } : {}
|
|
7881
|
-
};
|
|
7882
|
-
}
|
|
7883
|
-
function scoreGitStatusCandidate(git) {
|
|
7884
|
-
if (!git) return Number.NEGATIVE_INFINITY;
|
|
7885
|
-
let score = 0;
|
|
7886
|
-
if (git.isGitRepo === true) score += 50;
|
|
7887
|
-
if (git.isGitRepo === false) score -= 10;
|
|
7888
|
-
if (git.branch) score += 20;
|
|
7889
|
-
if (git.headCommit) score += 20;
|
|
7890
|
-
if (git.upstream) score += 10;
|
|
7891
|
-
score += scoreGitUpstreamFreshness(git.upstreamStatus);
|
|
7892
|
-
if (typeof git.ahead === "number") score += 2;
|
|
7893
|
-
if (typeof git.behind === "number") score += 2;
|
|
7894
|
-
if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
|
|
7895
|
-
if (git.error) score -= 20;
|
|
7896
|
-
return score;
|
|
7897
|
-
}
|
|
7898
|
-
function pickBestTransitGitStatus(node, options) {
|
|
7899
|
-
const rawGit = readRecord3(node.lastGit ?? node.last_git);
|
|
7900
|
-
const gitResult = readRecord3(rawGit.result);
|
|
7901
|
-
const directStatus = readRecord3(rawGit.status);
|
|
7902
|
-
const nestedStatus = readRecord3(gitResult.status);
|
|
7903
|
-
const rawProbe = readRecord3(node.lastProbe ?? node.last_probe);
|
|
7904
|
-
const probeGit = readRecord3(rawProbe.git);
|
|
7905
|
-
const probeGitResult = readRecord3(probeGit.result);
|
|
7906
|
-
const probeDirectStatus = readRecord3(probeGit.status);
|
|
7907
|
-
const probeNestedStatus = readRecord3(probeGitResult.status);
|
|
7908
|
-
const lastCheckedAt = options?.lastCheckedAt;
|
|
7909
|
-
let best = null;
|
|
7910
|
-
for (const status of [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus]) {
|
|
7911
|
-
const normalized = normalizeGitStatus(status, node, { lastCheckedAt: lastCheckedAt ?? Date.now() });
|
|
7912
|
-
if (!normalized) continue;
|
|
7913
|
-
const score = scoreGitStatusCandidate(normalized);
|
|
7914
|
-
if (!best || score > best.score) best = { git: normalized, score };
|
|
7915
|
-
}
|
|
7916
|
-
return best?.git;
|
|
7917
|
-
}
|
|
7918
|
-
function normalizeMeshNodeId(node) {
|
|
7919
|
-
const record = node && typeof node === "object" ? node : {};
|
|
7920
|
-
return readString5(record.id, record.nodeId, record.node_id);
|
|
7921
|
-
}
|
|
7922
|
-
function meshNodeIdMatches(node, candidateId) {
|
|
7923
|
-
if (!candidateId) return false;
|
|
7924
|
-
const trimmed = candidateId.trim();
|
|
7925
|
-
if (!trimmed) return false;
|
|
7926
|
-
return normalizeMeshNodeId(node) === trimmed;
|
|
7927
|
-
}
|
|
7928
|
-
function summarizeGitShape(status) {
|
|
7929
|
-
const record = readRecord3(status);
|
|
7930
|
-
if (!Object.keys(record).length) return null;
|
|
7931
|
-
const submodules = Array.isArray(record.submodules) ? record.submodules.map((entry) => {
|
|
7932
|
-
const sub = readRecord3(entry);
|
|
7933
|
-
return {
|
|
7934
|
-
path: readString5(sub.path) ?? null,
|
|
7935
|
-
commit: readString5(sub.commit)?.slice(0, 12) ?? null,
|
|
7936
|
-
dirty: readBoolean(sub.dirty) ?? false,
|
|
7937
|
-
outOfSync: readBoolean(sub.outOfSync, sub.out_of_sync) ?? false
|
|
7938
|
-
};
|
|
7939
|
-
}) : [];
|
|
7940
|
-
return {
|
|
7941
|
-
isGitRepo: readBoolean(record.isGitRepo),
|
|
7942
|
-
workspace: readString5(record.workspace) ?? null,
|
|
7943
|
-
repoRoot: readString5(record.repoRoot, record.repo_root) ?? null,
|
|
7944
|
-
branch: readString5(record.branch) ?? null,
|
|
7945
|
-
upstream: readString5(record.upstream) ?? null,
|
|
7946
|
-
upstreamStatus: readString5(record.upstreamStatus, record.upstream_status) ?? null,
|
|
7947
|
-
headCommit: readString5(record.headCommit, record.head_commit)?.slice(0, 12) ?? null,
|
|
7948
|
-
ahead: readNumber(record.ahead) ?? null,
|
|
7949
|
-
behind: readNumber(record.behind) ?? null,
|
|
7950
|
-
dirtyCounts: {
|
|
7951
|
-
staged: readNumber(record.staged) ?? 0,
|
|
7952
|
-
modified: readNumber(record.modified) ?? 0,
|
|
7953
|
-
untracked: readNumber(record.untracked) ?? 0,
|
|
7954
|
-
deleted: readNumber(record.deleted) ?? 0,
|
|
7955
|
-
renamed: readNumber(record.renamed) ?? 0
|
|
7956
|
-
},
|
|
7957
|
-
lastCheckedAt: readNumber(record.lastCheckedAt, record.last_checked_at) ?? null,
|
|
7958
|
-
submoduleCount: submodules.length,
|
|
7959
|
-
submodules
|
|
7960
|
-
};
|
|
7961
|
-
}
|
|
7962
|
-
var init_dist = __esm({
|
|
7963
|
-
"../mesh-shared/dist/index.mjs"() {
|
|
7964
|
-
"use strict";
|
|
7965
|
-
}
|
|
7966
|
-
});
|
|
7967
|
-
|
|
7968
8071
|
// src/mesh/mesh-active-work.ts
|
|
7969
8072
|
function readString6(value) {
|
|
7970
8073
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
@@ -8618,17 +8721,7 @@ var init_mesh_events_utils = __esm({
|
|
|
8618
8721
|
|
|
8619
8722
|
// src/mesh/mesh-events-pending.ts
|
|
8620
8723
|
function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
|
|
8621
|
-
|
|
8622
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8623
|
-
const out = [];
|
|
8624
|
-
for (const id of raw) {
|
|
8625
|
-
if (typeof id !== "string") continue;
|
|
8626
|
-
const trimmed = id.trim();
|
|
8627
|
-
if (!trimmed || seen.has(trimmed)) continue;
|
|
8628
|
-
seen.add(trimmed);
|
|
8629
|
-
out.push(trimmed);
|
|
8630
|
-
}
|
|
8631
|
-
return out;
|
|
8724
|
+
return expandDaemonIdForms(coordinatorDaemonId);
|
|
8632
8725
|
}
|
|
8633
8726
|
function readRefineJobId2(event) {
|
|
8634
8727
|
const metadata = readRecord4(event.metadataEvent) || event;
|
|
@@ -9018,6 +9111,7 @@ var init_mesh_events_pending = __esm({
|
|
|
9018
9111
|
init_mesh_ledger();
|
|
9019
9112
|
init_mesh_runtime_store();
|
|
9020
9113
|
init_mesh_events_utils();
|
|
9114
|
+
init_dist();
|
|
9021
9115
|
REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
|
|
9022
9116
|
MAX_PENDING_EVENTS_BYTES = 100 * 1024;
|
|
9023
9117
|
MAX_PENDING_EVENTS_KEEP = 50;
|
|
@@ -12469,12 +12563,9 @@ var init_snapshot = __esm({
|
|
|
12469
12563
|
|
|
12470
12564
|
// src/mesh/mesh-events-coordinator.ts
|
|
12471
12565
|
function resolveCoordinatorDrainDaemonIds(components) {
|
|
12472
|
-
const ids = /* @__PURE__ */ new Set();
|
|
12473
12566
|
const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
|
|
12474
|
-
if (statusInstanceId) ids.add(statusInstanceId);
|
|
12475
12567
|
const machineId = readNonEmptyString2(loadConfig().machineId);
|
|
12476
|
-
|
|
12477
|
-
return [...ids];
|
|
12568
|
+
return expandDaemonIdForms([statusInstanceId, machineId]);
|
|
12478
12569
|
}
|
|
12479
12570
|
function getCachedMeshByWorkspace(workspace) {
|
|
12480
12571
|
const now = Date.now();
|
|
@@ -12625,6 +12716,55 @@ function resolveActiveDirectDispatchTaskId(meshId, sessionId) {
|
|
|
12625
12716
|
return void 0;
|
|
12626
12717
|
}
|
|
12627
12718
|
}
|
|
12719
|
+
function deliverTaskToSession(dispatchThunk, ctx) {
|
|
12720
|
+
const delivery = createSessionDelivery({
|
|
12721
|
+
meshId: ctx.meshId,
|
|
12722
|
+
nodeId: ctx.nodeId,
|
|
12723
|
+
sessionId: ctx.sessionId,
|
|
12724
|
+
providerType: ctx.providerType,
|
|
12725
|
+
taskId: ctx.task.id,
|
|
12726
|
+
kind: "task",
|
|
12727
|
+
message: ctx.task.message,
|
|
12728
|
+
status: "delivering",
|
|
12729
|
+
...ctx.sourceCoordinatorSessionId ? { sourceCoordinatorSessionId: ctx.sourceCoordinatorSessionId } : {},
|
|
12730
|
+
...ctx.sourceCoordinatorDaemonId ? { sourceCoordinatorDaemonId: ctx.sourceCoordinatorDaemonId } : {}
|
|
12731
|
+
});
|
|
12732
|
+
let dispatchPromise;
|
|
12733
|
+
try {
|
|
12734
|
+
dispatchPromise = Promise.resolve(dispatchThunk());
|
|
12735
|
+
} catch (e) {
|
|
12736
|
+
dispatchPromise = Promise.reject(e);
|
|
12737
|
+
}
|
|
12738
|
+
let timer;
|
|
12739
|
+
const guarded = Promise.race([
|
|
12740
|
+
dispatchPromise,
|
|
12741
|
+
new Promise((_, reject) => {
|
|
12742
|
+
timer = setTimeout(
|
|
12743
|
+
() => reject(new Error(`dispatch_confirm_timeout after ${DISPATCH_CONFIRM_TIMEOUT_MS}ms`)),
|
|
12744
|
+
DISPATCH_CONFIRM_TIMEOUT_MS
|
|
12745
|
+
);
|
|
12746
|
+
if (typeof timer?.unref === "function") timer.unref();
|
|
12747
|
+
})
|
|
12748
|
+
]);
|
|
12749
|
+
guarded.then(() => {
|
|
12750
|
+
if (timer) clearTimeout(timer);
|
|
12751
|
+
updateSessionDeliveryStatus(delivery.id, "delivered");
|
|
12752
|
+
}).catch((e) => {
|
|
12753
|
+
if (timer) clearTimeout(timer);
|
|
12754
|
+
LOG.error("MeshQueue", `Failed to dispatch task via ${ctx.transport} to node ${ctx.nodeId}: ${e?.message}`);
|
|
12755
|
+
updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
12756
|
+
updateTaskStatus(ctx.meshId, ctx.task.id, "pending");
|
|
12757
|
+
try {
|
|
12758
|
+
appendLedgerEntry(ctx.meshId, {
|
|
12759
|
+
kind: "dispatch_failed",
|
|
12760
|
+
nodeId: ctx.nodeId,
|
|
12761
|
+
sessionId: ctx.sessionId,
|
|
12762
|
+
payload: { taskId: ctx.task.id, deliveryId: delivery.id, error: e?.message, retryable: true, transport: ctx.transport }
|
|
12763
|
+
});
|
|
12764
|
+
} catch {
|
|
12765
|
+
}
|
|
12766
|
+
});
|
|
12767
|
+
}
|
|
12628
12768
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
12629
12769
|
const mesh = getMeshWithCache(components, meshId);
|
|
12630
12770
|
const node = mesh?.nodes.find((n) => readMeshNodeId(n) === nodeId);
|
|
@@ -12643,46 +12783,33 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
12643
12783
|
if (!isLocalNode) {
|
|
12644
12784
|
const localDaemonIdForDispatch = readNonEmptyString2(loadConfig().machineId) || void 0;
|
|
12645
12785
|
const sourceCoordinatorSessionId = readNonEmptyString2(task.sourceCoordinatorSessionId) || void 0;
|
|
12646
|
-
const
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
meshContext: {
|
|
12786
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
12787
|
+
const remoteDaemonId = node.daemonId;
|
|
12788
|
+
deliverTaskToSession(
|
|
12789
|
+
() => dispatchMeshCommand(remoteDaemonId, "agent_command", {
|
|
12790
|
+
targetSessionId: sessionId,
|
|
12791
|
+
cliType: providerType,
|
|
12792
|
+
action: "send_chat",
|
|
12793
|
+
message: task.message,
|
|
12794
|
+
meshContext: {
|
|
12795
|
+
meshId,
|
|
12796
|
+
nodeId,
|
|
12797
|
+
taskId: task.id,
|
|
12798
|
+
...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {},
|
|
12799
|
+
...sourceCoordinatorSessionId ? { coordinatorSessionId: sourceCoordinatorSessionId } : {}
|
|
12800
|
+
}
|
|
12801
|
+
}),
|
|
12802
|
+
{
|
|
12664
12803
|
meshId,
|
|
12665
12804
|
nodeId,
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12670
|
-
|
|
12671
|
-
|
|
12672
|
-
}).catch((e) => {
|
|
12673
|
-
LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
|
|
12674
|
-
updateSessionDeliveryStatus(delivery2.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
12675
|
-
updateTaskStatus(meshId, task.id, "pending");
|
|
12676
|
-
try {
|
|
12677
|
-
appendLedgerEntry(meshId, {
|
|
12678
|
-
kind: "dispatch_failed",
|
|
12679
|
-
nodeId,
|
|
12680
|
-
sessionId,
|
|
12681
|
-
payload: { taskId: task.id, deliveryId: delivery2.id, error: e?.message, retryable: true }
|
|
12682
|
-
});
|
|
12683
|
-
} catch {
|
|
12805
|
+
sessionId,
|
|
12806
|
+
providerType,
|
|
12807
|
+
task,
|
|
12808
|
+
transport: "remote",
|
|
12809
|
+
...sourceCoordinatorSessionId ? { sourceCoordinatorSessionId } : {},
|
|
12810
|
+
...localDaemonIdForDispatch ? { sourceCoordinatorDaemonId: localDaemonIdForDispatch } : {}
|
|
12684
12811
|
}
|
|
12685
|
-
|
|
12812
|
+
);
|
|
12686
12813
|
return true;
|
|
12687
12814
|
}
|
|
12688
12815
|
}
|
|
@@ -12704,39 +12831,24 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
12704
12831
|
}
|
|
12705
12832
|
} catch {
|
|
12706
12833
|
}
|
|
12707
|
-
|
|
12708
|
-
|
|
12709
|
-
|
|
12710
|
-
|
|
12711
|
-
|
|
12712
|
-
|
|
12713
|
-
|
|
12714
|
-
|
|
12715
|
-
|
|
12716
|
-
|
|
12717
|
-
|
|
12718
|
-
|
|
12719
|
-
|
|
12720
|
-
|
|
12721
|
-
|
|
12722
|
-
|
|
12723
|
-
message: task.message
|
|
12724
|
-
}).then(() => {
|
|
12725
|
-
updateSessionDeliveryStatus(delivery.id, "delivered");
|
|
12726
|
-
}).catch((e) => {
|
|
12727
|
-
LOG.error("MeshQueue", `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
|
|
12728
|
-
updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
12729
|
-
updateTaskStatus(meshId, task.id, "pending");
|
|
12730
|
-
try {
|
|
12731
|
-
appendLedgerEntry(meshId, {
|
|
12732
|
-
kind: "dispatch_failed",
|
|
12733
|
-
nodeId,
|
|
12734
|
-
sessionId,
|
|
12735
|
-
payload: { taskId: task.id, deliveryId: delivery.id, error: e?.message, retryable: true }
|
|
12736
|
-
});
|
|
12737
|
-
} catch {
|
|
12834
|
+
deliverTaskToSession(
|
|
12835
|
+
() => components.cliManager.handleCliCommand("agent_command", {
|
|
12836
|
+
targetSessionId: sessionId,
|
|
12837
|
+
cliType: providerType,
|
|
12838
|
+
action: "send_chat",
|
|
12839
|
+
message: task.message
|
|
12840
|
+
}),
|
|
12841
|
+
{
|
|
12842
|
+
meshId,
|
|
12843
|
+
nodeId,
|
|
12844
|
+
sessionId,
|
|
12845
|
+
providerType,
|
|
12846
|
+
task,
|
|
12847
|
+
transport: "local",
|
|
12848
|
+
...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { sourceCoordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {},
|
|
12849
|
+
...readNonEmptyString2(loadConfig().machineId) ? { sourceCoordinatorDaemonId: readNonEmptyString2(loadConfig().machineId) } : {}
|
|
12738
12850
|
}
|
|
12739
|
-
|
|
12851
|
+
);
|
|
12740
12852
|
return true;
|
|
12741
12853
|
}
|
|
12742
12854
|
function sweepExpiredCooldowns() {
|
|
@@ -13001,7 +13113,7 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
13001
13113
|
}
|
|
13002
13114
|
}
|
|
13003
13115
|
const candidateNodes = Array.isArray(mesh?.nodes) ? mesh.nodes.filter((node) => {
|
|
13004
|
-
if (task.targetNodeId &&
|
|
13116
|
+
if (task.targetNodeId && !meshNodeIdMatches(node, task.targetNodeId)) return false;
|
|
13005
13117
|
if (task.requiredTags?.length) {
|
|
13006
13118
|
const priorities = normalizeProviderPriority(node?.policy);
|
|
13007
13119
|
const providerCandidates = priorities.length ? priorities : [void 0];
|
|
@@ -13012,7 +13124,12 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
13012
13124
|
return true;
|
|
13013
13125
|
}) : [];
|
|
13014
13126
|
if (!candidateNodes.length) {
|
|
13015
|
-
|
|
13127
|
+
const targetPinUnmatched = !!task.targetNodeId && !(Array.isArray(mesh?.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, task.targetNodeId)));
|
|
13128
|
+
markAutoLaunch(meshId, task.id, {
|
|
13129
|
+
status: "skipped",
|
|
13130
|
+
reason: targetPinUnmatched ? "target_node_id_unmatched" : "no_node_satisfies_required_tags",
|
|
13131
|
+
nodeId: task.targetNodeId
|
|
13132
|
+
});
|
|
13016
13133
|
continue;
|
|
13017
13134
|
}
|
|
13018
13135
|
const strategy = resolveSchedulingStrategy(mesh);
|
|
@@ -13963,7 +14080,7 @@ function setupMeshEventForwarding(components) {
|
|
|
13963
14080
|
});
|
|
13964
14081
|
});
|
|
13965
14082
|
}
|
|
13966
|
-
var import_fs13, REMOTE_IDLE_SESSION_TTL_MS, meshByWorkspaceCache, MESH_WORKSPACE_CACHE_TTL_MS, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, MESH_FORCE_INJECT_EVENTS;
|
|
14083
|
+
var import_fs13, REMOTE_IDLE_SESSION_TTL_MS, meshByWorkspaceCache, MESH_WORKSPACE_CACHE_TTL_MS, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, DISPATCH_CONFIRM_TIMEOUT_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, MESH_FORCE_INJECT_EVENTS;
|
|
13967
14084
|
var init_mesh_events_coordinator = __esm({
|
|
13968
14085
|
"src/mesh/mesh-events-coordinator.ts"() {
|
|
13969
14086
|
"use strict";
|
|
@@ -13992,6 +14109,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
13992
14109
|
idleAutoFastForwardLastAttempt = /* @__PURE__ */ new Map();
|
|
13993
14110
|
INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
|
|
13994
14111
|
RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
|
|
14112
|
+
DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
|
|
13995
14113
|
autoLaunchInProgress = /* @__PURE__ */ new Set();
|
|
13996
14114
|
autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
|
|
13997
14115
|
AUTO_LAUNCH_COOLDOWN_MS = 5e3;
|
|
@@ -14047,12 +14165,9 @@ function resolveReconcileIntervalMs() {
|
|
|
14047
14165
|
return DEFAULT_RECONCILE_INTERVAL_MS;
|
|
14048
14166
|
}
|
|
14049
14167
|
function resolveCoordinatorDaemonIds(components) {
|
|
14050
|
-
const ids = /* @__PURE__ */ new Set();
|
|
14051
14168
|
const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
|
|
14052
|
-
if (statusInstanceId) ids.add(statusInstanceId);
|
|
14053
14169
|
const machineId = readNonEmptyString2(loadConfig().machineId);
|
|
14054
|
-
|
|
14055
|
-
return [...ids];
|
|
14170
|
+
return expandDaemonIdForms([statusInstanceId, machineId]);
|
|
14056
14171
|
}
|
|
14057
14172
|
function daemonHostsMesh(mesh, daemonIds) {
|
|
14058
14173
|
const host = mesh.meshHost;
|
|
@@ -14136,6 +14251,24 @@ function recordHeldTerminalEventsToLedger(meshId, drainDaemonIds, reason, heldFo
|
|
|
14136
14251
|
}
|
|
14137
14252
|
}
|
|
14138
14253
|
}
|
|
14254
|
+
function recoverStrandedAssignedDispatches(meshId, store) {
|
|
14255
|
+
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
14256
|
+
if (!assigned.length) return;
|
|
14257
|
+
const nowMs = Date.now();
|
|
14258
|
+
for (const row of assigned) {
|
|
14259
|
+
const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
|
|
14260
|
+
if (!Number.isFinite(dispatchedAtMs)) continue;
|
|
14261
|
+
if (nowMs - dispatchedAtMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
|
|
14262
|
+
if (store.taskHasConfirmedDelivery(meshId, row.id)) continue;
|
|
14263
|
+
const reclaimed = reclaimStrandedAssignedTask(meshId, row.id, {
|
|
14264
|
+
reason: "assigned_stranded_dispatch_unconfirmed",
|
|
14265
|
+
ageMs: nowMs - dispatchedAtMs
|
|
14266
|
+
});
|
|
14267
|
+
if (reclaimed) {
|
|
14268
|
+
LOG.warn("MeshReconcile", `Reclaimed stranded assigned task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}, dispatched ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s ago, never confirmed delivered \u2192 ${reclaimed.status})`);
|
|
14269
|
+
}
|
|
14270
|
+
}
|
|
14271
|
+
}
|
|
14139
14272
|
async function runMeshReconcileTick(components) {
|
|
14140
14273
|
const localDaemonId = readNonEmptyString2(loadConfig().machineId) || void 0;
|
|
14141
14274
|
const drainDaemonIds = resolveCoordinatorDaemonIds(components);
|
|
@@ -14165,6 +14298,17 @@ async function runMeshReconcileTick(components) {
|
|
|
14165
14298
|
}
|
|
14166
14299
|
}
|
|
14167
14300
|
}
|
|
14301
|
+
if (store) {
|
|
14302
|
+
for (const mesh of listMeshes()) {
|
|
14303
|
+
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
14304
|
+
if (!daemonHostsMesh(mesh, selfIds)) continue;
|
|
14305
|
+
try {
|
|
14306
|
+
recoverStrandedAssignedDispatches(mesh.id, store);
|
|
14307
|
+
} catch (e) {
|
|
14308
|
+
LOG.warn("MeshReconcile", `Assigned-stranded watchdog failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
14309
|
+
}
|
|
14310
|
+
}
|
|
14311
|
+
}
|
|
14168
14312
|
for (const mesh of listMeshes()) {
|
|
14169
14313
|
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
14170
14314
|
if (!daemonHostsMesh(mesh, selfIds)) continue;
|
|
@@ -14552,7 +14696,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
14552
14696
|
}
|
|
14553
14697
|
};
|
|
14554
14698
|
}
|
|
14555
|
-
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, heldEventLedgerRecorded, STRICT_SESSION_MATCH_TTL_MS;
|
|
14699
|
+
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS;
|
|
14556
14700
|
var init_mesh_reconcile_loop = __esm({
|
|
14557
14701
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
14558
14702
|
"use strict";
|
|
@@ -14565,6 +14709,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
14565
14709
|
init_mesh_events_coordinator();
|
|
14566
14710
|
init_mesh_unresolved_forward_outbox();
|
|
14567
14711
|
init_mesh_events_utils();
|
|
14712
|
+
init_dist();
|
|
14568
14713
|
init_mesh_work_queue();
|
|
14569
14714
|
init_mesh_ledger();
|
|
14570
14715
|
init_mesh_active_work();
|
|
@@ -14573,6 +14718,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
14573
14718
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
14574
14719
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
14575
14720
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
14721
|
+
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
14576
14722
|
STRICT_SESSION_MATCH_TTL_MS = 6e4;
|
|
14577
14723
|
}
|
|
14578
14724
|
});
|
|
@@ -14605,6 +14751,84 @@ var init_mesh_events = __esm({
|
|
|
14605
14751
|
}
|
|
14606
14752
|
});
|
|
14607
14753
|
|
|
14754
|
+
// src/providers/approval-utils.ts
|
|
14755
|
+
function normalizeApprovalLabel(value) {
|
|
14756
|
+
return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
|
|
14757
|
+
}
|
|
14758
|
+
function isNegativeApprovalLabel(value) {
|
|
14759
|
+
const label = normalizeApprovalLabel(value);
|
|
14760
|
+
return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
|
|
14761
|
+
}
|
|
14762
|
+
function hasNegativeApprovalOption(buttons) {
|
|
14763
|
+
return (buttons || []).some((button) => isNegativeApprovalLabel(String(button || "")));
|
|
14764
|
+
}
|
|
14765
|
+
function getApprovalPositiveHints(provider) {
|
|
14766
|
+
const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
|
|
14767
|
+
return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
|
|
14768
|
+
}
|
|
14769
|
+
function pickApprovalButton(buttons, provider) {
|
|
14770
|
+
const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
|
|
14771
|
+
if (labels.length === 0) {
|
|
14772
|
+
return { index: -1, label: "" };
|
|
14773
|
+
}
|
|
14774
|
+
const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
|
|
14775
|
+
const hints = getApprovalPositiveHints(provider);
|
|
14776
|
+
for (const hint of hints) {
|
|
14777
|
+
const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
|
|
14778
|
+
if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
|
|
14779
|
+
const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
|
|
14780
|
+
if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
|
|
14781
|
+
const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
|
|
14782
|
+
if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
|
|
14783
|
+
}
|
|
14784
|
+
return { index: -1, label: "" };
|
|
14785
|
+
}
|
|
14786
|
+
function pickAutoApprovalButton(buttons) {
|
|
14787
|
+
const labels = (buttons || []).map((button) => String(button || "").trim());
|
|
14788
|
+
const index = labels.findIndex(Boolean);
|
|
14789
|
+
return index >= 0 ? { index, label: labels[index] } : { index: -1, label: "" };
|
|
14790
|
+
}
|
|
14791
|
+
function formatAutoApprovalMessage(modalMessage, buttonLabel) {
|
|
14792
|
+
const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
|
|
14793
|
+
const cleanMessage = String(modalMessage || "").trim();
|
|
14794
|
+
if (cleanMessage) lines.push(cleanMessage);
|
|
14795
|
+
return lines.join("\n");
|
|
14796
|
+
}
|
|
14797
|
+
function looksLikeActiveApprovalPromptText(content) {
|
|
14798
|
+
const text = content.trim();
|
|
14799
|
+
if (!text || text.length > 2e3) return false;
|
|
14800
|
+
const hasApprovalQuestion = /do you want to (?:proceed|allow|run|make this edit|create)/i.test(text) || /this command requires approval/i.test(text) || /quick safety check/i.test(text) || /is this a project you trust/i.test(text);
|
|
14801
|
+
const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text) || /^\s*1[.)]\s+yes\b/im.test(text);
|
|
14802
|
+
if (hasApprovalQuestion && hasNumberedChoices) return true;
|
|
14803
|
+
const lastLines = text.split(/\r?\n/).slice(-12).join("\n");
|
|
14804
|
+
const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines) || /yes.*always allow/i.test(lastLines);
|
|
14805
|
+
const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
|
|
14806
|
+
if (hasDontAskAgain && hasNoOption) return true;
|
|
14807
|
+
if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
|
|
14808
|
+
return false;
|
|
14809
|
+
}
|
|
14810
|
+
var DEFAULT_APPROVAL_POSITIVE_HINTS;
|
|
14811
|
+
var init_approval_utils = __esm({
|
|
14812
|
+
"src/providers/approval-utils.ts"() {
|
|
14813
|
+
"use strict";
|
|
14814
|
+
DEFAULT_APPROVAL_POSITIVE_HINTS = [
|
|
14815
|
+
"yes",
|
|
14816
|
+
"allow once",
|
|
14817
|
+
"approve",
|
|
14818
|
+
"accept",
|
|
14819
|
+
"continue",
|
|
14820
|
+
"run",
|
|
14821
|
+
"proceed",
|
|
14822
|
+
"confirm",
|
|
14823
|
+
"save",
|
|
14824
|
+
"ok",
|
|
14825
|
+
"trust",
|
|
14826
|
+
"allow",
|
|
14827
|
+
"always allow"
|
|
14828
|
+
];
|
|
14829
|
+
}
|
|
14830
|
+
});
|
|
14831
|
+
|
|
14608
14832
|
// src/logging/debug-config.ts
|
|
14609
14833
|
function normalizeCategories(categories) {
|
|
14610
14834
|
if (!Array.isArray(categories)) return [];
|
|
@@ -15591,6 +15815,27 @@ function compileSettledPromptMatchers(spec) {
|
|
|
15591
15815
|
});
|
|
15592
15816
|
return { prompt, footers };
|
|
15593
15817
|
}
|
|
15818
|
+
function extractButtonLabels(spec, text) {
|
|
15819
|
+
if (!text) return [];
|
|
15820
|
+
const flags = spec.buttonFlags && spec.buttonFlags.includes("m") ? spec.buttonFlags : `${spec.buttonFlags ?? ""}m`;
|
|
15821
|
+
const buttonRe = compile2(spec.buttonPattern, flags);
|
|
15822
|
+
const labelGroup = Number.isInteger(spec.buttonLabelGroup) && (spec.buttonLabelGroup ?? 0) > 0 ? spec.buttonLabelGroup : 1;
|
|
15823
|
+
const out = [];
|
|
15824
|
+
for (const line of text.split("\n")) {
|
|
15825
|
+
buttonRe.lastIndex = 0;
|
|
15826
|
+
const m = buttonRe.exec(line);
|
|
15827
|
+
if (!m) continue;
|
|
15828
|
+
const captured = m[labelGroup] ?? (labelGroup === 1 && m.length > 2 ? m[m.length - 1] : void 0);
|
|
15829
|
+
if (captured && captured.trim()) out.push(captured.trim());
|
|
15830
|
+
}
|
|
15831
|
+
return out;
|
|
15832
|
+
}
|
|
15833
|
+
function buttonBlockApprovalCue(spec, text) {
|
|
15834
|
+
const labels = extractButtonLabels(spec, text);
|
|
15835
|
+
if (labels.length < 2) return false;
|
|
15836
|
+
if (pickApprovalButton(labels).index < 0) return false;
|
|
15837
|
+
return hasNegativeApprovalOption(labels);
|
|
15838
|
+
}
|
|
15594
15839
|
function modalMatches(spec, input) {
|
|
15595
15840
|
const text = input.screenText ?? "";
|
|
15596
15841
|
const question = compile2(spec.questionPattern, spec.questionFlags ?? "i");
|
|
@@ -15599,6 +15844,7 @@ function modalMatches(spec, input) {
|
|
|
15599
15844
|
const re = compile2(variant.regex, variant.flags ?? "i");
|
|
15600
15845
|
if (re.test(text)) return true;
|
|
15601
15846
|
}
|
|
15847
|
+
if (buttonBlockApprovalCue(spec, text)) return true;
|
|
15602
15848
|
return false;
|
|
15603
15849
|
}
|
|
15604
15850
|
function evaluateGroup(group, spec, input, compiled) {
|
|
@@ -15653,6 +15899,7 @@ var init_detect_status = __esm({
|
|
|
15653
15899
|
"src/providers/sdk/v1/builders/cli/detect-status.ts"() {
|
|
15654
15900
|
"use strict";
|
|
15655
15901
|
init_visible_region();
|
|
15902
|
+
init_approval_utils();
|
|
15656
15903
|
DEFAULT_ORDER = ["spinner", "modal", "settled-prompt"];
|
|
15657
15904
|
}
|
|
15658
15905
|
});
|
|
@@ -20098,6 +20345,7 @@ __export(index_exports, {
|
|
|
20098
20345
|
createNativeHistoryDispatcher: () => createNativeHistoryDispatcher,
|
|
20099
20346
|
createSessionDelivery: () => createSessionDelivery,
|
|
20100
20347
|
createWorktree: () => createWorktree,
|
|
20348
|
+
daemonIdsEquivalent: () => daemonIdsEquivalent,
|
|
20101
20349
|
deleteDirectDispatchesByTaskId: () => deleteDirectDispatchesByTaskId,
|
|
20102
20350
|
deleteMesh: () => deleteMesh,
|
|
20103
20351
|
deriveMeshReviewInboxItems: () => deriveMeshReviewInboxItems,
|
|
@@ -20111,6 +20359,7 @@ __export(index_exports, {
|
|
|
20111
20359
|
ensureSessionHostReady: () => ensureSessionHostReady,
|
|
20112
20360
|
evaluateFsm: () => evaluateFsm,
|
|
20113
20361
|
execNpmCommandSync: () => execNpmCommandSync,
|
|
20362
|
+
expandDaemonIdForms: () => expandDaemonIdForms,
|
|
20114
20363
|
fastForwardMeshNode: () => fastForwardMeshNode,
|
|
20115
20364
|
filterActivityChatMessages: () => filterActivityChatMessages,
|
|
20116
20365
|
filterChatMessagesByVisibility: () => filterChatMessagesByVisibility,
|
|
@@ -20201,6 +20450,7 @@ __export(index_exports, {
|
|
|
20201
20450
|
loadMeshWorktreeBootstrapConfig: () => loadMeshWorktreeBootstrapConfig,
|
|
20202
20451
|
loadState: () => loadState,
|
|
20203
20452
|
logCommand: () => logCommand,
|
|
20453
|
+
machineCoreFromDaemonId: () => machineCoreFromDaemonId,
|
|
20204
20454
|
markSessionDeliveriesTerminal: () => markSessionDeliveriesTerminal,
|
|
20205
20455
|
markSetupComplete: () => markSetupComplete,
|
|
20206
20456
|
markStaleDirectDispatches: () => markStaleDirectDispatches,
|
|
@@ -21559,6 +21809,7 @@ function getSavedProviderSessions(state, filters) {
|
|
|
21559
21809
|
|
|
21560
21810
|
// src/index.ts
|
|
21561
21811
|
init_mesh_config();
|
|
21812
|
+
init_dist();
|
|
21562
21813
|
init_coordinator_prompt();
|
|
21563
21814
|
init_mesh_missions();
|
|
21564
21815
|
init_mesh_task_stats();
|
|
@@ -26111,76 +26362,8 @@ function validateReadChatResultPayload(raw, source = "read_chat") {
|
|
|
26111
26362
|
return normalized;
|
|
26112
26363
|
}
|
|
26113
26364
|
|
|
26114
|
-
// src/providers/approval-utils.ts
|
|
26115
|
-
var DEFAULT_APPROVAL_POSITIVE_HINTS = [
|
|
26116
|
-
"yes",
|
|
26117
|
-
"allow once",
|
|
26118
|
-
"approve",
|
|
26119
|
-
"accept",
|
|
26120
|
-
"continue",
|
|
26121
|
-
"run",
|
|
26122
|
-
"proceed",
|
|
26123
|
-
"confirm",
|
|
26124
|
-
"save",
|
|
26125
|
-
"ok",
|
|
26126
|
-
"trust",
|
|
26127
|
-
"allow",
|
|
26128
|
-
"always allow"
|
|
26129
|
-
];
|
|
26130
|
-
function normalizeApprovalLabel(value) {
|
|
26131
|
-
return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
|
|
26132
|
-
}
|
|
26133
|
-
function isNegativeApprovalLabel(value) {
|
|
26134
|
-
const label = normalizeApprovalLabel(value);
|
|
26135
|
-
return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
|
|
26136
|
-
}
|
|
26137
|
-
function getApprovalPositiveHints(provider) {
|
|
26138
|
-
const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
|
|
26139
|
-
return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
|
|
26140
|
-
}
|
|
26141
|
-
function pickApprovalButton(buttons, provider) {
|
|
26142
|
-
const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
|
|
26143
|
-
if (labels.length === 0) {
|
|
26144
|
-
return { index: -1, label: "" };
|
|
26145
|
-
}
|
|
26146
|
-
const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
|
|
26147
|
-
const hints = getApprovalPositiveHints(provider);
|
|
26148
|
-
for (const hint of hints) {
|
|
26149
|
-
const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
|
|
26150
|
-
if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
|
|
26151
|
-
const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
|
|
26152
|
-
if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
|
|
26153
|
-
const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
|
|
26154
|
-
if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
|
|
26155
|
-
}
|
|
26156
|
-
return { index: -1, label: "" };
|
|
26157
|
-
}
|
|
26158
|
-
function pickAutoApprovalButton(buttons) {
|
|
26159
|
-
const labels = (buttons || []).map((button) => String(button || "").trim());
|
|
26160
|
-
const index = labels.findIndex(Boolean);
|
|
26161
|
-
return index >= 0 ? { index, label: labels[index] } : { index: -1, label: "" };
|
|
26162
|
-
}
|
|
26163
|
-
function formatAutoApprovalMessage(modalMessage, buttonLabel) {
|
|
26164
|
-
const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
|
|
26165
|
-
const cleanMessage = String(modalMessage || "").trim();
|
|
26166
|
-
if (cleanMessage) lines.push(cleanMessage);
|
|
26167
|
-
return lines.join("\n");
|
|
26168
|
-
}
|
|
26169
|
-
function looksLikeActiveApprovalPromptText(content) {
|
|
26170
|
-
const text = content.trim();
|
|
26171
|
-
if (!text || text.length > 2e3) return false;
|
|
26172
|
-
const hasApprovalQuestion = /do you want to (?:proceed|allow|run|make this edit|create)/i.test(text) || /this command requires approval/i.test(text) || /quick safety check/i.test(text) || /is this a project you trust/i.test(text);
|
|
26173
|
-
const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text) || /^\s*1[.)]\s+yes\b/im.test(text);
|
|
26174
|
-
if (hasApprovalQuestion && hasNumberedChoices) return true;
|
|
26175
|
-
const lastLines = text.split(/\r?\n/).slice(-12).join("\n");
|
|
26176
|
-
const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines) || /yes.*always allow/i.test(lastLines);
|
|
26177
|
-
const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
|
|
26178
|
-
if (hasDontAskAgain && hasNoOption) return true;
|
|
26179
|
-
if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
|
|
26180
|
-
return false;
|
|
26181
|
-
}
|
|
26182
|
-
|
|
26183
26365
|
// src/providers/ide-provider-instance.ts
|
|
26366
|
+
init_approval_utils();
|
|
26184
26367
|
init_provider_patch_state();
|
|
26185
26368
|
init_chat_message_normalization();
|
|
26186
26369
|
init_open_panel_support();
|
|
@@ -27264,6 +27447,7 @@ var path16 = __toESM(require("path"));
|
|
|
27264
27447
|
var import_node_crypto3 = require("crypto");
|
|
27265
27448
|
init_contracts();
|
|
27266
27449
|
init_provider_input_support();
|
|
27450
|
+
init_approval_utils();
|
|
27267
27451
|
init_coordinator_registry();
|
|
27268
27452
|
init_logger();
|
|
27269
27453
|
|
|
@@ -35252,6 +35436,7 @@ function createCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFact
|
|
|
35252
35436
|
// src/providers/cli-provider-instance.ts
|
|
35253
35437
|
init_logger();
|
|
35254
35438
|
init_control_effects();
|
|
35439
|
+
init_approval_utils();
|
|
35255
35440
|
init_provider_patch_state();
|
|
35256
35441
|
|
|
35257
35442
|
// src/providers/provider-session-id.ts
|
|
@@ -35513,6 +35698,20 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
35513
35698
|
* keystroke until the modal *content* has settled.
|
|
35514
35699
|
*/
|
|
35515
35700
|
static AUTO_APPROVE_SETTLE_MS = 600;
|
|
35701
|
+
/**
|
|
35702
|
+
* Busy-side hysteresis for the settle gate. A momentary `generating` flip
|
|
35703
|
+
* while the SAME approval modal's button block is still on screen (its
|
|
35704
|
+
* question line scrolled out of the captured frame, only the buttons + a
|
|
35705
|
+
* residual `esc to interrupt` spinner remain) briefly reports
|
|
35706
|
+
* status!=waiting_approval. Without hysteresis that flip wipes the settle
|
|
35707
|
+
* clock, and the modal→generating→modal flap restarts the 600ms window
|
|
35708
|
+
* every time so auto-approve never fires. We keep the in-progress settle
|
|
35709
|
+
* gate warm across an inactive blip up to this bound; only once the modal
|
|
35710
|
+
* has genuinely stayed gone this long (a real resolution → idle) is the
|
|
35711
|
+
* gate cleared. Bounded so a genuinely new, later approval still re-settles
|
|
35712
|
+
* from scratch rather than firing on a stale timestamp.
|
|
35713
|
+
*/
|
|
35714
|
+
static AUTO_APPROVE_GATE_HYSTERESIS_MS = 1500;
|
|
35516
35715
|
adapter;
|
|
35517
35716
|
context = null;
|
|
35518
35717
|
events = [];
|
|
@@ -35534,6 +35733,10 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
35534
35733
|
pendingAutoApprovalSignature = "";
|
|
35535
35734
|
pendingAutoApprovalSince = 0;
|
|
35536
35735
|
autoApproveSettleTimer = null;
|
|
35736
|
+
// Wall-clock when auto-approve first observed status!=waiting_approval while
|
|
35737
|
+
// a settle gate was in progress. Drives AUTO_APPROVE_GATE_HYSTERESIS_MS so a
|
|
35738
|
+
// brief generating flip does not immediately wipe the settle clock.
|
|
35739
|
+
autoApproveInactiveSince = 0;
|
|
35537
35740
|
controlValues = {};
|
|
35538
35741
|
summaryMetadata = void 0;
|
|
35539
35742
|
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
@@ -36354,14 +36557,28 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36354
36557
|
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
|
|
36355
36558
|
if (!autoApproveActive) {
|
|
36356
36559
|
this.lastAutoApprovalSignature = "";
|
|
36560
|
+
if (this.pendingAutoApprovalSince) {
|
|
36561
|
+
if (!this.autoApproveInactiveSince) this.autoApproveInactiveSince = now;
|
|
36562
|
+
const goneForMs = now - this.autoApproveInactiveSince;
|
|
36563
|
+
if (goneForMs < _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS) {
|
|
36564
|
+
if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
|
|
36565
|
+
this.autoApproveSettleTimer = setTimeout(() => {
|
|
36566
|
+
this.autoApproveSettleTimer = null;
|
|
36567
|
+
this.recheckAutoApproveSettled();
|
|
36568
|
+
}, _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS - goneForMs + 20);
|
|
36569
|
+
return autoApproveActive;
|
|
36570
|
+
}
|
|
36571
|
+
}
|
|
36357
36572
|
this.pendingAutoApprovalSignature = "";
|
|
36358
36573
|
this.pendingAutoApprovalSince = 0;
|
|
36574
|
+
this.autoApproveInactiveSince = 0;
|
|
36359
36575
|
if (this.autoApproveSettleTimer) {
|
|
36360
36576
|
clearTimeout(this.autoApproveSettleTimer);
|
|
36361
36577
|
this.autoApproveSettleTimer = null;
|
|
36362
36578
|
}
|
|
36363
36579
|
return autoApproveActive;
|
|
36364
36580
|
}
|
|
36581
|
+
this.autoApproveInactiveSince = 0;
|
|
36365
36582
|
const modal = adapterStatus.activeModal;
|
|
36366
36583
|
const buttons = Array.isArray(modal?.buttons) ? modal.buttons.map((b) => String(b || "").trim()).filter(Boolean) : [];
|
|
36367
36584
|
if (!modal || buttons.length === 0) {
|
|
@@ -36371,18 +36588,18 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36371
36588
|
if (buttonIndex < 0) {
|
|
36372
36589
|
return autoApproveActive;
|
|
36373
36590
|
}
|
|
36374
|
-
const
|
|
36375
|
-
const signature = [
|
|
36376
|
-
approvalEntrySeq,
|
|
36591
|
+
const modalSignature = [
|
|
36377
36592
|
typeof modal?.message === "string" ? modal.message.trim() : "",
|
|
36378
36593
|
buttons.join("|"),
|
|
36379
36594
|
buttonIndex
|
|
36380
36595
|
].join("::");
|
|
36381
|
-
|
|
36596
|
+
const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
|
|
36597
|
+
const busySignature = `${approvalEntrySeq}::${modalSignature}`;
|
|
36598
|
+
if (this.autoApproveBusy && busySignature === this.lastAutoApprovalSignature) {
|
|
36382
36599
|
return autoApproveActive;
|
|
36383
36600
|
}
|
|
36384
|
-
if (
|
|
36385
|
-
this.pendingAutoApprovalSignature =
|
|
36601
|
+
if (modalSignature !== this.pendingAutoApprovalSignature) {
|
|
36602
|
+
this.pendingAutoApprovalSignature = modalSignature;
|
|
36386
36603
|
this.pendingAutoApprovalSince = now;
|
|
36387
36604
|
}
|
|
36388
36605
|
const settledForMs = now - this.pendingAutoApprovalSince;
|
|
@@ -36399,9 +36616,10 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36399
36616
|
this.autoApproveSettleTimer = null;
|
|
36400
36617
|
}
|
|
36401
36618
|
this.autoApproveBusy = true;
|
|
36402
|
-
this.lastAutoApprovalSignature =
|
|
36619
|
+
this.lastAutoApprovalSignature = busySignature;
|
|
36403
36620
|
this.pendingAutoApprovalSignature = "";
|
|
36404
36621
|
this.pendingAutoApprovalSince = 0;
|
|
36622
|
+
this.autoApproveInactiveSince = 0;
|
|
36405
36623
|
if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
|
|
36406
36624
|
this.autoApproveBusyTimer = setTimeout(() => {
|
|
36407
36625
|
this.autoApproveBusy = false;
|
|
@@ -39183,9 +39401,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
39183
39401
|
}
|
|
39184
39402
|
}
|
|
39185
39403
|
}
|
|
39186
|
-
|
|
39187
|
-
|
|
39188
|
-
|
|
39404
|
+
if (!opts?.instanceKey) {
|
|
39405
|
+
for (const [k, a] of this.adapters) {
|
|
39406
|
+
if (a.cliType === agentType) {
|
|
39407
|
+
return { adapter: a, key: k };
|
|
39408
|
+
}
|
|
39189
39409
|
}
|
|
39190
39410
|
}
|
|
39191
39411
|
return null;
|
|
@@ -43288,7 +43508,8 @@ init_logger();
|
|
|
43288
43508
|
var fs23 = __toESM(require("fs"));
|
|
43289
43509
|
var path35 = __toESM(require("path"));
|
|
43290
43510
|
var os26 = __toESM(require("os"));
|
|
43291
|
-
var
|
|
43511
|
+
var ADHDEV_HOME2 = process.env.ADHDEV_CONFIG_DIR && process.env.ADHDEV_CONFIG_DIR.trim() ? process.env.ADHDEV_CONFIG_DIR.trim() : path35.join(os26.homedir(), ".adhdev");
|
|
43512
|
+
var LOG_DIR2 = path35.join(ADHDEV_HOME2, "logs");
|
|
43292
43513
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
43293
43514
|
var MAX_DAYS = 7;
|
|
43294
43515
|
try {
|
|
@@ -44143,13 +44364,14 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
44143
44364
|
}
|
|
44144
44365
|
}
|
|
44145
44366
|
}
|
|
44146
|
-
function stopSessionHostProcesses(appName) {
|
|
44367
|
+
async function stopSessionHostProcesses(appName) {
|
|
44147
44368
|
const pidFile = path36.join(os27.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
44369
|
+
let killedPid = null;
|
|
44148
44370
|
try {
|
|
44149
44371
|
if (fs25.existsSync(pidFile)) {
|
|
44150
44372
|
const pid = Number.parseInt(fs25.readFileSync(pidFile, "utf8").trim(), 10);
|
|
44151
44373
|
if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
|
|
44152
|
-
killPid(pid);
|
|
44374
|
+
if (killPid(pid)) killedPid = pid;
|
|
44153
44375
|
}
|
|
44154
44376
|
}
|
|
44155
44377
|
} catch {
|
|
@@ -44159,6 +44381,15 @@ function stopSessionHostProcesses(appName) {
|
|
|
44159
44381
|
} catch {
|
|
44160
44382
|
}
|
|
44161
44383
|
}
|
|
44384
|
+
if (killedPid !== null) {
|
|
44385
|
+
await waitForPidExit(killedPid, 15e3);
|
|
44386
|
+
}
|
|
44387
|
+
}
|
|
44388
|
+
function isRetriableInstallLockError(error) {
|
|
44389
|
+
const code = error?.code;
|
|
44390
|
+
if (code === "EBUSY" || code === "EPERM") return true;
|
|
44391
|
+
const text = `${error?.message || ""} ${error?.stderr || ""}`;
|
|
44392
|
+
return /\bEBUSY\b|\bEPERM\b|resource busy or locked/i.test(text);
|
|
44162
44393
|
}
|
|
44163
44394
|
function removeDaemonPidFile() {
|
|
44164
44395
|
const pidFile = path36.join(os27.homedir(), ".adhdev", "daemon.pid");
|
|
@@ -44238,22 +44469,37 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
44238
44469
|
appendUpgradeLog(`Waiting for parent pid ${payload.parentPid} to exit`);
|
|
44239
44470
|
await waitForPidExit(payload.parentPid, 15e3);
|
|
44240
44471
|
}
|
|
44241
|
-
stopSessionHostProcesses(sessionHostAppName);
|
|
44472
|
+
await stopSessionHostProcesses(sessionHostAppName);
|
|
44242
44473
|
removeDaemonPidFile();
|
|
44243
44474
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
44244
44475
|
const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
|
|
44245
44476
|
appendUpgradeLog(`Installing ${spec}`);
|
|
44246
|
-
const
|
|
44247
|
-
|
|
44248
|
-
|
|
44249
|
-
{
|
|
44250
|
-
|
|
44251
|
-
|
|
44252
|
-
|
|
44253
|
-
|
|
44254
|
-
|
|
44477
|
+
const maxInstallAttempts = process.platform === "win32" ? 3 : 1;
|
|
44478
|
+
let installOutput = "";
|
|
44479
|
+
for (let attempt = 1; attempt <= maxInstallAttempts; attempt++) {
|
|
44480
|
+
try {
|
|
44481
|
+
installOutput = String((0, import_child_process8.execFileSync)(
|
|
44482
|
+
installCommand.command,
|
|
44483
|
+
installCommand.args,
|
|
44484
|
+
{
|
|
44485
|
+
encoding: "utf8",
|
|
44486
|
+
stdio: "pipe",
|
|
44487
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
44488
|
+
env: buildInstallEnvWithNodeOnPath(),
|
|
44489
|
+
...installCommand.execOptions
|
|
44490
|
+
}
|
|
44491
|
+
));
|
|
44492
|
+
break;
|
|
44493
|
+
} catch (error) {
|
|
44494
|
+
if (attempt < maxInstallAttempts && isRetriableInstallLockError(error)) {
|
|
44495
|
+
appendUpgradeLog(`Install attempt ${attempt} hit a file lock (${error?.code || "lock"}); cleaning staging and retrying after backoff`);
|
|
44496
|
+
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
44497
|
+
await new Promise((resolve24) => setTimeout(resolve24, attempt * 1500));
|
|
44498
|
+
continue;
|
|
44499
|
+
}
|
|
44500
|
+
throw error;
|
|
44255
44501
|
}
|
|
44256
|
-
|
|
44502
|
+
}
|
|
44257
44503
|
if (installOutput.trim()) {
|
|
44258
44504
|
appendUpgradeLog(installOutput.trim());
|
|
44259
44505
|
}
|
|
@@ -46516,7 +46762,14 @@ var MESH_FORWARDABLE_SESSION_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
46516
46762
|
"resolve_action",
|
|
46517
46763
|
"set_mode",
|
|
46518
46764
|
"change_model",
|
|
46519
|
-
"set_thought_level"
|
|
46765
|
+
"set_thought_level",
|
|
46766
|
+
// agent_command (send_chat / clear_history / stop) is session-scoped too: a command
|
|
46767
|
+
// explicitly naming a targetSessionId MUST reach that session wherever it lives, never a
|
|
46768
|
+
// different local session. Without forwarding, a misrouted/relayed send_chat for a REMOTE
|
|
46769
|
+
// worker session that reaches the wrong daemon used to fuzzy-inject the task body into that
|
|
46770
|
+
// daemon's own CLI session (TASKECHO coordinator self-echo). Forwarding to the owning daemon
|
|
46771
|
+
// delivers it to the real worker instead. (findAdapter is also fail-closed as the backstop.)
|
|
46772
|
+
"agent_command"
|
|
46520
46773
|
]);
|
|
46521
46774
|
var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
|
|
46522
46775
|
function normalizeCommandSource(source) {
|
|
@@ -46869,7 +47122,7 @@ var DaemonCommandRouter = class {
|
|
|
46869
47122
|
if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
|
|
46870
47123
|
const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
|
|
46871
47124
|
if (!nodeDaemonId) continue;
|
|
46872
|
-
if (selfDaemonId && nodeDaemonId
|
|
47125
|
+
if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
|
|
46873
47126
|
return nodeDaemonId;
|
|
46874
47127
|
}
|
|
46875
47128
|
return void 0;
|
|
@@ -47024,6 +47277,38 @@ var DaemonCommandRouter = class {
|
|
|
47024
47277
|
if (record?.meta?.meshNodeId === nodeId) return true;
|
|
47025
47278
|
return false;
|
|
47026
47279
|
}
|
|
47280
|
+
/**
|
|
47281
|
+
* Best-effort recursive removal of a managed worktree directory.
|
|
47282
|
+
*
|
|
47283
|
+
* The git-registry de-registration is the safety-critical step of worktree
|
|
47284
|
+
* teardown; a leftover directory must never gate dropping the node from the
|
|
47285
|
+
* mesh. On Windows, `fs.rmSync` can throw EINVAL/EPERM/EBUSY on submodule
|
|
47286
|
+
* gitlink (`.git`) files, long paths, junctions, or while a just-stopped
|
|
47287
|
+
* delegate session is still releasing a handle/cwd on the directory. This
|
|
47288
|
+
* helper absorbs those errors (never throws), with bounded retries + backoff
|
|
47289
|
+
* to give handles time to release, and reports whether residue remains.
|
|
47290
|
+
*/
|
|
47291
|
+
async bestEffortRemoveWorktreeDir(dir) {
|
|
47292
|
+
if (!dir || !fs26.existsSync(dir)) return { removed: true, residue: false };
|
|
47293
|
+
const sleep3 = (ms) => new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
47294
|
+
const ABSORB = /* @__PURE__ */ new Set(["EINVAL", "EPERM", "EBUSY", "ENOTEMPTY", "EACCES", "EMFILE", "ENFILE"]);
|
|
47295
|
+
let lastErr;
|
|
47296
|
+
for (let attempt = 0; attempt < 4; attempt++) {
|
|
47297
|
+
try {
|
|
47298
|
+
fs26.rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
47299
|
+
if (!fs26.existsSync(dir)) return { removed: true, residue: false };
|
|
47300
|
+
lastErr = new Error("directory still present after rmSync");
|
|
47301
|
+
} catch (e) {
|
|
47302
|
+
lastErr = e;
|
|
47303
|
+
const code = typeof e?.code === "string" ? e.code : "";
|
|
47304
|
+
if (code && !ABSORB.has(code)) {
|
|
47305
|
+
break;
|
|
47306
|
+
}
|
|
47307
|
+
}
|
|
47308
|
+
await sleep3(150 * (attempt + 1));
|
|
47309
|
+
}
|
|
47310
|
+
return fs26.existsSync(dir) ? { removed: false, residue: true, error: String(lastErr?.message || lastErr || "unknown rm error") } : { removed: true, residue: false };
|
|
47311
|
+
}
|
|
47027
47312
|
async cleanupLocalWorktreeNode(args) {
|
|
47028
47313
|
const workspace = typeof args.node?.workspace === "string" ? args.node.workspace.trim() : "";
|
|
47029
47314
|
if (!workspace) {
|
|
@@ -47078,11 +47363,31 @@ var DaemonCommandRouter = class {
|
|
|
47078
47363
|
const entries = await listWorktrees2(repoRoot);
|
|
47079
47364
|
const managedEntry = entries.find((entry) => normalizePath(entry.path) === actualPath);
|
|
47080
47365
|
if (!managedEntry) {
|
|
47366
|
+
try {
|
|
47367
|
+
const { execFile: execFile5 } = await import("child_process");
|
|
47368
|
+
const { promisify: promisify8 } = await import("util");
|
|
47369
|
+
const execFileAsync4 = promisify8(execFile5);
|
|
47370
|
+
await execFileAsync4("git", ["worktree", "prune"], {
|
|
47371
|
+
cwd: repoRoot,
|
|
47372
|
+
encoding: "utf8",
|
|
47373
|
+
timeout: 3e4,
|
|
47374
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
47375
|
+
windowsHide: true
|
|
47376
|
+
});
|
|
47377
|
+
} catch {
|
|
47378
|
+
}
|
|
47379
|
+
const rm = await this.bestEffortRemoveWorktreeDir(workspace);
|
|
47081
47380
|
return {
|
|
47082
|
-
success:
|
|
47083
|
-
|
|
47084
|
-
|
|
47085
|
-
|
|
47381
|
+
success: true,
|
|
47382
|
+
removedPath: workspace,
|
|
47383
|
+
repoRoot,
|
|
47384
|
+
reason: "worktree_unregistered_residue_recovered",
|
|
47385
|
+
recovered: true,
|
|
47386
|
+
...rm.residue ? {
|
|
47387
|
+
residue: true,
|
|
47388
|
+
residueWarning: `Worktree was already de-registered from git but the directory could not be fully removed (leftover residue at '${workspace}'): ${rm.error || "unknown error"}. The node will be dropped from the mesh; remove the directory manually if needed.`,
|
|
47389
|
+
residueError: rm.error
|
|
47390
|
+
} : {}
|
|
47086
47391
|
};
|
|
47087
47392
|
}
|
|
47088
47393
|
if (managedEntry.branch && managedEntry.branch !== args.node.worktreeBranch) {
|
|
@@ -47145,8 +47450,8 @@ var DaemonCommandRouter = class {
|
|
|
47145
47450
|
convergence: forceFallbackConvergence
|
|
47146
47451
|
};
|
|
47147
47452
|
} catch (deinitError) {
|
|
47453
|
+
const rm = await this.bestEffortRemoveWorktreeDir(workspace);
|
|
47148
47454
|
try {
|
|
47149
|
-
fs26.rmSync(workspace, { recursive: true, force: true });
|
|
47150
47455
|
await execFileAsync4("git", ["worktree", "prune"], {
|
|
47151
47456
|
cwd: repoRoot,
|
|
47152
47457
|
encoding: "utf8",
|
|
@@ -47154,23 +47459,22 @@ var DaemonCommandRouter = class {
|
|
|
47154
47459
|
maxBuffer: GIT_MAX_BUFFER_CLEANUP,
|
|
47155
47460
|
windowsHide: true
|
|
47156
47461
|
});
|
|
47157
|
-
|
|
47158
|
-
success: true,
|
|
47159
|
-
removedPath: workspace,
|
|
47160
|
-
repoRoot,
|
|
47161
|
-
fallback: "fs_rm_worktree_prune",
|
|
47162
|
-
forced: true,
|
|
47163
|
-
reason: "working_trees_containing_submodules",
|
|
47164
|
-
convergence: forceFallbackConvergence
|
|
47165
|
-
};
|
|
47166
|
-
} catch (rmError) {
|
|
47167
|
-
return {
|
|
47168
|
-
success: false,
|
|
47169
|
-
code: "mesh_worktree_cleanup_failed",
|
|
47170
|
-
error: `All removal fallbacks exhausted. deinit+remove: ${deinitError?.message || deinitError}; rmSync+prune: ${rmError?.message || rmError}`,
|
|
47171
|
-
recoveryHint: "Manually remove the worktree directory and run git worktree prune from the source repo."
|
|
47172
|
-
};
|
|
47462
|
+
} catch {
|
|
47173
47463
|
}
|
|
47464
|
+
return {
|
|
47465
|
+
success: true,
|
|
47466
|
+
removedPath: workspace,
|
|
47467
|
+
repoRoot,
|
|
47468
|
+
fallback: "fs_rm_worktree_prune",
|
|
47469
|
+
forced: true,
|
|
47470
|
+
reason: "working_trees_containing_submodules",
|
|
47471
|
+
convergence: forceFallbackConvergence,
|
|
47472
|
+
...rm.residue ? {
|
|
47473
|
+
residue: true,
|
|
47474
|
+
residueWarning: `Worktree was de-registered from git but the directory could not be fully removed (leftover residue at '${workspace}'): ${rm.error || "unknown error"}; deinit+remove first failed with: ${deinitError?.message || deinitError}. The node will be dropped from the mesh; remove the directory manually if needed.`,
|
|
47475
|
+
residueError: rm.error
|
|
47476
|
+
} : {}
|
|
47477
|
+
};
|
|
47174
47478
|
}
|
|
47175
47479
|
}
|
|
47176
47480
|
return {
|
|
@@ -50569,7 +50873,14 @@ ${hintLines.join("\n")}` : "",
|
|
|
50569
50873
|
} catch {
|
|
50570
50874
|
}
|
|
50571
50875
|
}
|
|
50572
|
-
|
|
50876
|
+
const residueWarning = worktreeCleanup?.residue === true && typeof worktreeCleanup?.residueWarning === "string" ? worktreeCleanup.residueWarning : void 0;
|
|
50877
|
+
return {
|
|
50878
|
+
success: true,
|
|
50879
|
+
removed,
|
|
50880
|
+
...residueWarning ? { residueWarning } : {},
|
|
50881
|
+
...sessionCleanup ? { sessionCleanup } : {},
|
|
50882
|
+
...worktreeCleanup ? { worktreeCleanup } : {}
|
|
50883
|
+
};
|
|
50573
50884
|
} catch (e) {
|
|
50574
50885
|
return { success: false, error: e.message };
|
|
50575
50886
|
}
|
|
@@ -53015,6 +53326,7 @@ var DaemonAgentStreamManager = class {
|
|
|
53015
53326
|
|
|
53016
53327
|
// src/agent-stream/poller.ts
|
|
53017
53328
|
init_logger();
|
|
53329
|
+
init_approval_utils();
|
|
53018
53330
|
init_chat_message_normalization();
|
|
53019
53331
|
var AgentStreamPoller = class {
|
|
53020
53332
|
deps;
|
|
@@ -60562,6 +60874,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
60562
60874
|
createNativeHistoryDispatcher,
|
|
60563
60875
|
createSessionDelivery,
|
|
60564
60876
|
createWorktree,
|
|
60877
|
+
daemonIdsEquivalent,
|
|
60565
60878
|
deleteDirectDispatchesByTaskId,
|
|
60566
60879
|
deleteMesh,
|
|
60567
60880
|
deriveMeshReviewInboxItems,
|
|
@@ -60575,6 +60888,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
60575
60888
|
ensureSessionHostReady,
|
|
60576
60889
|
evaluateFsm,
|
|
60577
60890
|
execNpmCommandSync,
|
|
60891
|
+
expandDaemonIdForms,
|
|
60578
60892
|
fastForwardMeshNode,
|
|
60579
60893
|
filterActivityChatMessages,
|
|
60580
60894
|
filterChatMessagesByVisibility,
|
|
@@ -60665,6 +60979,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
60665
60979
|
loadMeshWorktreeBootstrapConfig,
|
|
60666
60980
|
loadState,
|
|
60667
60981
|
logCommand,
|
|
60982
|
+
machineCoreFromDaemonId,
|
|
60668
60983
|
markSessionDeliveriesTerminal,
|
|
60669
60984
|
markSetupComplete,
|
|
60670
60985
|
markStaleDirectDispatches,
|