@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.mjs
CHANGED
|
@@ -311,10 +311,10 @@ function readInjected(value) {
|
|
|
311
311
|
}
|
|
312
312
|
function getDaemonBuildInfo() {
|
|
313
313
|
if (cached) return cached;
|
|
314
|
-
const commit = readInjected(true ? "
|
|
315
|
-
const commitShort = readInjected(true ? "
|
|
316
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
317
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
314
|
+
const commit = readInjected(true ? "a680b74d9b940b82f691ebb85a725a1a72445bfc" : void 0) ?? "unknown";
|
|
315
|
+
const commitShort = readInjected(true ? "a680b74d" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
316
|
+
const version = readInjected(true ? "0.9.82-rc.353" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
317
|
+
const builtAt = readInjected(true ? "2026-06-22T09:11:13.499Z" : void 0);
|
|
318
318
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
319
319
|
return cached;
|
|
320
320
|
}
|
|
@@ -2703,6 +2703,257 @@ var init_mesh_config = __esm({
|
|
|
2703
2703
|
}
|
|
2704
2704
|
});
|
|
2705
2705
|
|
|
2706
|
+
// ../mesh-shared/dist/index.mjs
|
|
2707
|
+
function readRecord(value) {
|
|
2708
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2709
|
+
}
|
|
2710
|
+
function readString3(...values) {
|
|
2711
|
+
for (const value of values) {
|
|
2712
|
+
if (typeof value !== "string") continue;
|
|
2713
|
+
const trimmed = value.trim();
|
|
2714
|
+
if (trimmed) return trimmed;
|
|
2715
|
+
}
|
|
2716
|
+
return void 0;
|
|
2717
|
+
}
|
|
2718
|
+
function readNumber(...values) {
|
|
2719
|
+
for (const value of values) {
|
|
2720
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2721
|
+
}
|
|
2722
|
+
return void 0;
|
|
2723
|
+
}
|
|
2724
|
+
function readBoolean(...values) {
|
|
2725
|
+
for (const value of values) {
|
|
2726
|
+
if (typeof value === "boolean") return value;
|
|
2727
|
+
}
|
|
2728
|
+
return void 0;
|
|
2729
|
+
}
|
|
2730
|
+
function joinRepoPath(root, relativePath) {
|
|
2731
|
+
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
2732
|
+
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
2733
|
+
if (!normalizedPath) return void 0;
|
|
2734
|
+
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
2735
|
+
if (!normalizedRoot) return void 0;
|
|
2736
|
+
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
2737
|
+
}
|
|
2738
|
+
function scoreGitUpstreamFreshness(status) {
|
|
2739
|
+
switch (status) {
|
|
2740
|
+
case "fresh":
|
|
2741
|
+
return 30;
|
|
2742
|
+
case "no_upstream":
|
|
2743
|
+
return 4;
|
|
2744
|
+
case "unchecked":
|
|
2745
|
+
case void 0:
|
|
2746
|
+
return 0;
|
|
2747
|
+
case "stale":
|
|
2748
|
+
return -10;
|
|
2749
|
+
case "unavailable":
|
|
2750
|
+
return -15;
|
|
2751
|
+
default:
|
|
2752
|
+
return 0;
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
function readGitSubmodules(value, parentRepoRoot) {
|
|
2756
|
+
if (!Array.isArray(value)) return void 0;
|
|
2757
|
+
const submodules = value.map((entry) => {
|
|
2758
|
+
const submodule = readRecord(entry);
|
|
2759
|
+
const path42 = readString3(submodule.path);
|
|
2760
|
+
const commit = readString3(submodule.commit);
|
|
2761
|
+
const repoPath = readString3(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path42);
|
|
2762
|
+
if (!path42 || !commit) return null;
|
|
2763
|
+
const result = {
|
|
2764
|
+
path: path42,
|
|
2765
|
+
commit,
|
|
2766
|
+
dirty: readBoolean(submodule.dirty) ?? false,
|
|
2767
|
+
outOfSync: readBoolean(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
2768
|
+
lastCheckedAt: readNumber(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now()
|
|
2769
|
+
};
|
|
2770
|
+
if (repoPath) result.repoPath = repoPath;
|
|
2771
|
+
const error = readString3(submodule.error);
|
|
2772
|
+
if (error) result.error = error;
|
|
2773
|
+
return result;
|
|
2774
|
+
}).filter((entry) => entry !== null);
|
|
2775
|
+
return submodules.length > 0 ? submodules : void 0;
|
|
2776
|
+
}
|
|
2777
|
+
function hasGitStatusEvidence(status) {
|
|
2778
|
+
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(
|
|
2779
|
+
status.ahead,
|
|
2780
|
+
status.behind,
|
|
2781
|
+
status.staged,
|
|
2782
|
+
status.modified,
|
|
2783
|
+
status.untracked,
|
|
2784
|
+
status.deleted,
|
|
2785
|
+
status.renamed,
|
|
2786
|
+
status.lastCheckedAt,
|
|
2787
|
+
status.last_checked_at
|
|
2788
|
+
) !== void 0 || Array.isArray(status.submodules) && status.submodules.length > 0;
|
|
2789
|
+
}
|
|
2790
|
+
function normalizeGitStatus(status, node, options) {
|
|
2791
|
+
const explicitIsGitRepo = readBoolean(status.isGitRepo);
|
|
2792
|
+
if (!Object.keys(status).length || !hasGitStatusEvidence(status)) return void 0;
|
|
2793
|
+
const isGitRepo = explicitIsGitRepo ?? true;
|
|
2794
|
+
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((entry) => typeof entry === "string") : [];
|
|
2795
|
+
const conflictCount = readNumber(status.conflicts) ?? conflictFiles.length;
|
|
2796
|
+
const hasConflicts = readBoolean(status.hasConflicts) ?? conflictCount > 0;
|
|
2797
|
+
const repoRoot = readString3(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
|
|
2798
|
+
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
2799
|
+
const upstreamStatus = readString3(status.upstreamStatus, status.upstream_status);
|
|
2800
|
+
const upstreamFetchedAt = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
|
|
2801
|
+
const upstreamFetchError = readString3(status.upstreamFetchError, status.upstream_fetch_error);
|
|
2802
|
+
const error = readString3(status.error);
|
|
2803
|
+
const staged = readNumber(status.staged) ?? 0;
|
|
2804
|
+
const modified = readNumber(status.modified) ?? 0;
|
|
2805
|
+
const untracked = readNumber(status.untracked) ?? 0;
|
|
2806
|
+
const deleted = readNumber(status.deleted) ?? 0;
|
|
2807
|
+
const renamed = readNumber(status.renamed) ?? 0;
|
|
2808
|
+
return {
|
|
2809
|
+
workspace: readString3(status.workspace, node.workspace) || "",
|
|
2810
|
+
repoRoot: repoRoot ?? null,
|
|
2811
|
+
isGitRepo,
|
|
2812
|
+
branch: readString3(status.branch) ?? null,
|
|
2813
|
+
headCommit: readString3(status.headCommit) ?? null,
|
|
2814
|
+
headMessage: readString3(status.headMessage) ?? null,
|
|
2815
|
+
upstream: readString3(status.upstream) ?? null,
|
|
2816
|
+
upstreamStatus: upstreamStatus ?? "unchecked",
|
|
2817
|
+
...upstreamFetchedAt !== void 0 ? { upstreamFetchedAt } : {},
|
|
2818
|
+
...upstreamFetchError ? { upstreamFetchError } : {},
|
|
2819
|
+
ahead: readNumber(status.ahead) ?? 0,
|
|
2820
|
+
behind: readNumber(status.behind) ?? 0,
|
|
2821
|
+
staged,
|
|
2822
|
+
modified,
|
|
2823
|
+
untracked,
|
|
2824
|
+
deleted,
|
|
2825
|
+
renamed,
|
|
2826
|
+
dirty: readBoolean(status.dirty, status.isDirty, status.is_dirty) ?? (staged + modified + untracked + deleted + renamed > 0 || hasConflicts),
|
|
2827
|
+
hasConflicts,
|
|
2828
|
+
conflictFiles,
|
|
2829
|
+
stashCount: readNumber(status.stashCount, status.stash_count) ?? 0,
|
|
2830
|
+
lastCheckedAt: options?.lastCheckedAt ?? readNumber(status.lastCheckedAt, status.last_checked_at) ?? Date.now(),
|
|
2831
|
+
...submodules ? { submodules } : {},
|
|
2832
|
+
...error ? { error } : {}
|
|
2833
|
+
};
|
|
2834
|
+
}
|
|
2835
|
+
function scoreGitStatusCandidate(git) {
|
|
2836
|
+
if (!git) return Number.NEGATIVE_INFINITY;
|
|
2837
|
+
let score = 0;
|
|
2838
|
+
if (git.isGitRepo === true) score += 50;
|
|
2839
|
+
if (git.isGitRepo === false) score -= 10;
|
|
2840
|
+
if (git.branch) score += 20;
|
|
2841
|
+
if (git.headCommit) score += 20;
|
|
2842
|
+
if (git.upstream) score += 10;
|
|
2843
|
+
score += scoreGitUpstreamFreshness(git.upstreamStatus);
|
|
2844
|
+
if (typeof git.ahead === "number") score += 2;
|
|
2845
|
+
if (typeof git.behind === "number") score += 2;
|
|
2846
|
+
if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
|
|
2847
|
+
if (git.error) score -= 20;
|
|
2848
|
+
return score;
|
|
2849
|
+
}
|
|
2850
|
+
function pickBestTransitGitStatus(node, options) {
|
|
2851
|
+
const rawGit = readRecord(node.lastGit ?? node.last_git);
|
|
2852
|
+
const gitResult = readRecord(rawGit.result);
|
|
2853
|
+
const directStatus = readRecord(rawGit.status);
|
|
2854
|
+
const nestedStatus = readRecord(gitResult.status);
|
|
2855
|
+
const rawProbe = readRecord(node.lastProbe ?? node.last_probe);
|
|
2856
|
+
const probeGit = readRecord(rawProbe.git);
|
|
2857
|
+
const probeGitResult = readRecord(probeGit.result);
|
|
2858
|
+
const probeDirectStatus = readRecord(probeGit.status);
|
|
2859
|
+
const probeNestedStatus = readRecord(probeGitResult.status);
|
|
2860
|
+
const lastCheckedAt = options?.lastCheckedAt;
|
|
2861
|
+
let best = null;
|
|
2862
|
+
for (const status of [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus]) {
|
|
2863
|
+
const normalized = normalizeGitStatus(status, node, { lastCheckedAt: lastCheckedAt ?? Date.now() });
|
|
2864
|
+
if (!normalized) continue;
|
|
2865
|
+
const score = scoreGitStatusCandidate(normalized);
|
|
2866
|
+
if (!best || score > best.score) best = { git: normalized, score };
|
|
2867
|
+
}
|
|
2868
|
+
return best?.git;
|
|
2869
|
+
}
|
|
2870
|
+
function normalizeMeshNodeId(node) {
|
|
2871
|
+
const record = node && typeof node === "object" ? node : {};
|
|
2872
|
+
return readString3(record.id, record.nodeId, record.node_id);
|
|
2873
|
+
}
|
|
2874
|
+
function meshNodeIdMatches(node, candidateId) {
|
|
2875
|
+
if (!candidateId) return false;
|
|
2876
|
+
const trimmed = candidateId.trim();
|
|
2877
|
+
if (!trimmed) return false;
|
|
2878
|
+
return normalizeMeshNodeId(node) === trimmed;
|
|
2879
|
+
}
|
|
2880
|
+
function machineCoreFromDaemonId(id) {
|
|
2881
|
+
const trimmed = readString3(id);
|
|
2882
|
+
if (!trimmed) return void 0;
|
|
2883
|
+
for (const prefix of DAEMON_ID_PREFIXES) {
|
|
2884
|
+
if (trimmed.startsWith(prefix)) {
|
|
2885
|
+
const core = trimmed.slice(prefix.length).trim();
|
|
2886
|
+
return core || void 0;
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
return trimmed;
|
|
2890
|
+
}
|
|
2891
|
+
function daemonIdsEquivalent(a, b) {
|
|
2892
|
+
const coreA = machineCoreFromDaemonId(a);
|
|
2893
|
+
const coreB = machineCoreFromDaemonId(b);
|
|
2894
|
+
if (!coreA || !coreB) return false;
|
|
2895
|
+
return coreA === coreB;
|
|
2896
|
+
}
|
|
2897
|
+
function expandDaemonIdForms(ids) {
|
|
2898
|
+
const list = Array.isArray(ids) ? ids : ids != null ? [ids] : [];
|
|
2899
|
+
const out = [];
|
|
2900
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2901
|
+
const add = (value) => {
|
|
2902
|
+
if (!value || seen.has(value)) return;
|
|
2903
|
+
seen.add(value);
|
|
2904
|
+
out.push(value);
|
|
2905
|
+
};
|
|
2906
|
+
for (const raw of list) add(readString3(raw));
|
|
2907
|
+
for (const raw of list) {
|
|
2908
|
+
const core = machineCoreFromDaemonId(readString3(raw));
|
|
2909
|
+
if (!core || !core.startsWith("mach_")) continue;
|
|
2910
|
+
add(core);
|
|
2911
|
+
for (const prefix of DAEMON_ID_PREFIXES) add(`${prefix}${core}`);
|
|
2912
|
+
}
|
|
2913
|
+
return out;
|
|
2914
|
+
}
|
|
2915
|
+
function summarizeGitShape(status) {
|
|
2916
|
+
const record = readRecord(status);
|
|
2917
|
+
if (!Object.keys(record).length) return null;
|
|
2918
|
+
const submodules = Array.isArray(record.submodules) ? record.submodules.map((entry) => {
|
|
2919
|
+
const sub = readRecord(entry);
|
|
2920
|
+
return {
|
|
2921
|
+
path: readString3(sub.path) ?? null,
|
|
2922
|
+
commit: readString3(sub.commit)?.slice(0, 12) ?? null,
|
|
2923
|
+
dirty: readBoolean(sub.dirty) ?? false,
|
|
2924
|
+
outOfSync: readBoolean(sub.outOfSync, sub.out_of_sync) ?? false
|
|
2925
|
+
};
|
|
2926
|
+
}) : [];
|
|
2927
|
+
return {
|
|
2928
|
+
isGitRepo: readBoolean(record.isGitRepo),
|
|
2929
|
+
workspace: readString3(record.workspace) ?? null,
|
|
2930
|
+
repoRoot: readString3(record.repoRoot, record.repo_root) ?? null,
|
|
2931
|
+
branch: readString3(record.branch) ?? null,
|
|
2932
|
+
upstream: readString3(record.upstream) ?? null,
|
|
2933
|
+
upstreamStatus: readString3(record.upstreamStatus, record.upstream_status) ?? null,
|
|
2934
|
+
headCommit: readString3(record.headCommit, record.head_commit)?.slice(0, 12) ?? null,
|
|
2935
|
+
ahead: readNumber(record.ahead) ?? null,
|
|
2936
|
+
behind: readNumber(record.behind) ?? null,
|
|
2937
|
+
dirtyCounts: {
|
|
2938
|
+
staged: readNumber(record.staged) ?? 0,
|
|
2939
|
+
modified: readNumber(record.modified) ?? 0,
|
|
2940
|
+
untracked: readNumber(record.untracked) ?? 0,
|
|
2941
|
+
deleted: readNumber(record.deleted) ?? 0,
|
|
2942
|
+
renamed: readNumber(record.renamed) ?? 0
|
|
2943
|
+
},
|
|
2944
|
+
lastCheckedAt: readNumber(record.lastCheckedAt, record.last_checked_at) ?? null,
|
|
2945
|
+
submoduleCount: submodules.length,
|
|
2946
|
+
submodules
|
|
2947
|
+
};
|
|
2948
|
+
}
|
|
2949
|
+
var DAEMON_ID_PREFIXES;
|
|
2950
|
+
var init_dist = __esm({
|
|
2951
|
+
"../mesh-shared/dist/index.mjs"() {
|
|
2952
|
+
"use strict";
|
|
2953
|
+
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
2954
|
+
}
|
|
2955
|
+
});
|
|
2956
|
+
|
|
2706
2957
|
// src/mesh/coordinator-prompt.ts
|
|
2707
2958
|
var coordinator_prompt_exports = {};
|
|
2708
2959
|
__export(coordinator_prompt_exports, {
|
|
@@ -3193,7 +3444,7 @@ function installGlobalInterceptor() {
|
|
|
3193
3444
|
function getLogPath() {
|
|
3194
3445
|
return currentLogFile;
|
|
3195
3446
|
}
|
|
3196
|
-
var 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;
|
|
3447
|
+
var 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;
|
|
3197
3448
|
var init_logger = __esm({
|
|
3198
3449
|
"src/logging/logger.ts"() {
|
|
3199
3450
|
"use strict";
|
|
@@ -3201,7 +3452,8 @@ var init_logger = __esm({
|
|
|
3201
3452
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
3202
3453
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
3203
3454
|
currentLevel = "info";
|
|
3204
|
-
|
|
3455
|
+
ADHDEV_HOME = process.env.ADHDEV_CONFIG_DIR && process.env.ADHDEV_CONFIG_DIR.trim() ? process.env.ADHDEV_CONFIG_DIR.trim() : path9.join(os3.homedir(), ".adhdev");
|
|
3456
|
+
LOG_DIR = path9.join(ADHDEV_HOME, "logs");
|
|
3205
3457
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
3206
3458
|
MAX_LOG_DAYS = 7;
|
|
3207
3459
|
try {
|
|
@@ -4001,6 +4253,7 @@ __export(mesh_work_queue_exports, {
|
|
|
4001
4253
|
nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
|
|
4002
4254
|
normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
|
|
4003
4255
|
normalizeMeshTaskMode: () => normalizeMeshTaskMode,
|
|
4256
|
+
reclaimStrandedAssignedTask: () => reclaimStrandedAssignedTask,
|
|
4004
4257
|
recordDirectDispatchTask: () => recordDirectDispatchTask,
|
|
4005
4258
|
recordMeshToolCall: () => recordMeshToolCall,
|
|
4006
4259
|
recordTaskAutoLaunch: () => recordTaskAutoLaunch,
|
|
@@ -4437,6 +4690,52 @@ function requeueTask(meshId, taskId, opts) {
|
|
|
4437
4690
|
return entry;
|
|
4438
4691
|
});
|
|
4439
4692
|
}
|
|
4693
|
+
function reclaimStrandedAssignedTask(meshId, taskId, opts) {
|
|
4694
|
+
requireMeshHostQueueOwner(opts);
|
|
4695
|
+
return withQueueLock(meshId, () => {
|
|
4696
|
+
const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
|
|
4697
|
+
if (!entry) return null;
|
|
4698
|
+
if (entry.status !== "assigned") return null;
|
|
4699
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4700
|
+
const reason = opts?.reason || "assigned_stranded_dispatch_unconfirmed";
|
|
4701
|
+
const reclaims = (entry.strandedReclaimCount || 0) + 1;
|
|
4702
|
+
const prevNode = entry.assignedNodeId;
|
|
4703
|
+
const prevSession = entry.assignedSessionId;
|
|
4704
|
+
delete entry.assignedNodeId;
|
|
4705
|
+
delete entry.assignedSessionId;
|
|
4706
|
+
delete entry.assignedProviderType;
|
|
4707
|
+
delete entry.dispatchTimestamp;
|
|
4708
|
+
entry.strandedReclaimCount = reclaims;
|
|
4709
|
+
entry.updatedAt = now;
|
|
4710
|
+
if (reclaims > MAX_STRANDED_RECLAIMS) {
|
|
4711
|
+
entry.status = "failed";
|
|
4712
|
+
entry.cancelReason = `stranded_dispatch_unrecovered: reclaimed ${reclaims - 1} time(s) without a confirmed dispatch`;
|
|
4713
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
4714
|
+
propagateDependencyFailure(meshId, taskId);
|
|
4715
|
+
} else {
|
|
4716
|
+
entry.status = "pending";
|
|
4717
|
+
entry.requeuedAt = now;
|
|
4718
|
+
entry.requeueReason = reason;
|
|
4719
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
4720
|
+
}
|
|
4721
|
+
try {
|
|
4722
|
+
appendLedgerEntry(meshId, {
|
|
4723
|
+
kind: "task_reclaimed",
|
|
4724
|
+
nodeId: prevNode,
|
|
4725
|
+
sessionId: prevSession,
|
|
4726
|
+
payload: {
|
|
4727
|
+
taskId,
|
|
4728
|
+
reason,
|
|
4729
|
+
...typeof opts?.ageMs === "number" ? { ageMs: opts.ageMs } : {},
|
|
4730
|
+
reclaimCount: reclaims,
|
|
4731
|
+
outcome: entry.status
|
|
4732
|
+
}
|
|
4733
|
+
});
|
|
4734
|
+
} catch {
|
|
4735
|
+
}
|
|
4736
|
+
return entry;
|
|
4737
|
+
});
|
|
4738
|
+
}
|
|
4440
4739
|
function updateSessionTaskStatus(meshId, sessionId, status, opts) {
|
|
4441
4740
|
return withQueueLock(meshId, () => {
|
|
4442
4741
|
const store = MeshRuntimeStore.getInstance();
|
|
@@ -4550,7 +4849,7 @@ function recordMeshToolCall(opts) {
|
|
|
4550
4849
|
return { rateLimitExceeded: false, callsInWindow: 0, advisory: null };
|
|
4551
4850
|
}
|
|
4552
4851
|
}
|
|
4553
|
-
var ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES, MESH_TASK_MODES, LIVE_DEBUG_READONLY_FORBIDDEN, NEGATION_CUES, NEGATION_WINDOW_TOKENS, GIT_MUTATION_SUBCOMMANDS, GIT_STASH_READONLY_SUBCOMMANDS, DEPENDENCY_FAILURE_TERMINALS;
|
|
4852
|
+
var ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES, MESH_TASK_MODES, LIVE_DEBUG_READONLY_FORBIDDEN, NEGATION_CUES, NEGATION_WINDOW_TOKENS, GIT_MUTATION_SUBCOMMANDS, GIT_STASH_READONLY_SUBCOMMANDS, DEPENDENCY_FAILURE_TERMINALS, MAX_STRANDED_RECLAIMS;
|
|
4554
4853
|
var init_mesh_work_queue = __esm({
|
|
4555
4854
|
"src/mesh/mesh-work-queue.ts"() {
|
|
4556
4855
|
"use strict";
|
|
@@ -4559,6 +4858,7 @@ var init_mesh_work_queue = __esm({
|
|
|
4559
4858
|
init_mesh_runtime_store();
|
|
4560
4859
|
init_mesh_config();
|
|
4561
4860
|
init_logger();
|
|
4861
|
+
init_mesh_ledger();
|
|
4562
4862
|
ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
|
|
4563
4863
|
HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
|
|
4564
4864
|
MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
|
|
@@ -4611,6 +4911,7 @@ var init_mesh_work_queue = __esm({
|
|
|
4611
4911
|
]);
|
|
4612
4912
|
GIT_STASH_READONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["list", "show"]);
|
|
4613
4913
|
DEPENDENCY_FAILURE_TERMINALS = /* @__PURE__ */ new Set(["failed", "cancelled"]);
|
|
4914
|
+
MAX_STRANDED_RECLAIMS = 3;
|
|
4614
4915
|
}
|
|
4615
4916
|
});
|
|
4616
4917
|
|
|
@@ -5496,6 +5797,22 @@ var init_mesh_runtime_store = __esm({
|
|
|
5496
5797
|
updatedAt: r.updated_at
|
|
5497
5798
|
}));
|
|
5498
5799
|
}
|
|
5800
|
+
/**
|
|
5801
|
+
* Bug B watchdog support: true when at least one delivery record for the task has
|
|
5802
|
+
* reached a confirmed-handed-off status (delivered / acked / completed). The
|
|
5803
|
+
* assigned-stranded watchdog uses this to distinguish a dispatch that was never
|
|
5804
|
+
* confirmed (reclaimable) from one that WAS handed to the worker (a genuinely
|
|
5805
|
+
* in-flight or completion-lost task, which is PHASE 4's responsibility, not this
|
|
5806
|
+
* watchdog's). Indexed by (mesh_id, task_id).
|
|
5807
|
+
*/
|
|
5808
|
+
taskHasConfirmedDelivery(meshId, taskId) {
|
|
5809
|
+
const row = this.db.prepare(`
|
|
5810
|
+
SELECT 1 FROM mesh_session_delivery
|
|
5811
|
+
WHERE mesh_id = ? AND task_id = ? AND status IN ('delivered','acked','completed')
|
|
5812
|
+
LIMIT 1
|
|
5813
|
+
`).get(meshId, taskId);
|
|
5814
|
+
return !!row;
|
|
5815
|
+
}
|
|
5499
5816
|
expireStaleSessionDeliveries(meshId) {
|
|
5500
5817
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5501
5818
|
this.db.prepare(`
|
|
@@ -6244,10 +6561,10 @@ var init_mesh_missions = __esm({
|
|
|
6244
6561
|
});
|
|
6245
6562
|
|
|
6246
6563
|
// src/mesh/mesh-refine-status.ts
|
|
6247
|
-
function
|
|
6564
|
+
function readString4(value) {
|
|
6248
6565
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
6249
6566
|
}
|
|
6250
|
-
function
|
|
6567
|
+
function readRecord2(value) {
|
|
6251
6568
|
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
6252
6569
|
}
|
|
6253
6570
|
function eventStatus(event, fallback) {
|
|
@@ -6270,7 +6587,7 @@ function instructionForStatus(status) {
|
|
|
6270
6587
|
return "Refine job failed; inspect result/finalBranchConvergenceState in mesh_task_history, fix the blocker, then rerun mesh_refine_node when ready.";
|
|
6271
6588
|
}
|
|
6272
6589
|
function mergeJob(jobs, patch) {
|
|
6273
|
-
const jobId =
|
|
6590
|
+
const jobId = readString4(patch.jobId);
|
|
6274
6591
|
if (!jobId) return;
|
|
6275
6592
|
const previous = jobs.get(jobId);
|
|
6276
6593
|
const status = patch.status || previous?.status || "running";
|
|
@@ -6288,54 +6605,54 @@ function mergeJob(jobs, patch) {
|
|
|
6288
6605
|
function buildMeshAsyncRefineJobs(args) {
|
|
6289
6606
|
const jobs = /* @__PURE__ */ new Map();
|
|
6290
6607
|
for (const entry of args.ledgerEntries || []) {
|
|
6291
|
-
const payload =
|
|
6608
|
+
const payload = readRecord2(entry.payload);
|
|
6292
6609
|
if (payload?.source !== "refine_mesh_node_async_job") continue;
|
|
6293
|
-
const refineJob =
|
|
6294
|
-
const result =
|
|
6295
|
-
const finalState =
|
|
6296
|
-
const jobId =
|
|
6610
|
+
const refineJob = readRecord2(payload.refineJob);
|
|
6611
|
+
const result = readRecord2(payload.result);
|
|
6612
|
+
const finalState = readRecord2(payload.finalBranchConvergenceState) || readRecord2(result?.finalBranchConvergenceState);
|
|
6613
|
+
const jobId = readString4(refineJob?.jobId);
|
|
6297
6614
|
if (!jobId) continue;
|
|
6298
|
-
const status = ledgerStatus(entry.kind,
|
|
6615
|
+
const status = ledgerStatus(entry.kind, readString4(refineJob?.status));
|
|
6299
6616
|
mergeJob(jobs, {
|
|
6300
6617
|
jobId,
|
|
6301
|
-
interactionId:
|
|
6618
|
+
interactionId: readString4(refineJob?.interactionId),
|
|
6302
6619
|
status,
|
|
6303
|
-
meshId:
|
|
6304
|
-
nodeId:
|
|
6305
|
-
targetNodeId:
|
|
6306
|
-
targetDaemonId:
|
|
6307
|
-
workspace:
|
|
6308
|
-
branch:
|
|
6309
|
-
into:
|
|
6310
|
-
startedAt:
|
|
6311
|
-
completedAt:
|
|
6312
|
-
retryOfJobId:
|
|
6620
|
+
meshId: readString4(refineJob?.meshId) || args.meshId,
|
|
6621
|
+
nodeId: readString4(refineJob?.nodeId) || entry.nodeId,
|
|
6622
|
+
targetNodeId: readString4(refineJob?.nodeId) || entry.nodeId,
|
|
6623
|
+
targetDaemonId: readString4(refineJob?.targetDaemonId),
|
|
6624
|
+
workspace: readString4(refineJob?.workspace),
|
|
6625
|
+
branch: readString4(result?.branch) || readString4(finalState?.branch),
|
|
6626
|
+
into: readString4(result?.into) || readString4(finalState?.baseBranch),
|
|
6627
|
+
startedAt: readString4(refineJob?.startedAt),
|
|
6628
|
+
completedAt: readString4(refineJob?.completedAt),
|
|
6629
|
+
retryOfJobId: readString4(refineJob?.retryOfJobId) || readString4(payload.retryOfJobId),
|
|
6313
6630
|
lastLedgerKind: entry.kind,
|
|
6314
6631
|
lastUpdatedAt: entry.timestamp
|
|
6315
6632
|
});
|
|
6316
6633
|
}
|
|
6317
6634
|
for (const event of args.pendingEvents || []) {
|
|
6318
|
-
const metadata =
|
|
6635
|
+
const metadata = readRecord2(event.metadataEvent);
|
|
6319
6636
|
if (metadata?.source !== "refine_mesh_node_async_job") continue;
|
|
6320
|
-
const result =
|
|
6321
|
-
const finalState =
|
|
6322
|
-
const jobId =
|
|
6637
|
+
const result = readRecord2(metadata.result);
|
|
6638
|
+
const finalState = readRecord2(result?.finalBranchConvergenceState);
|
|
6639
|
+
const jobId = readString4(metadata.jobId);
|
|
6323
6640
|
if (!jobId) continue;
|
|
6324
|
-
const status = eventStatus(event.event,
|
|
6641
|
+
const status = eventStatus(event.event, readString4(metadata.status));
|
|
6325
6642
|
mergeJob(jobs, {
|
|
6326
6643
|
jobId,
|
|
6327
|
-
interactionId:
|
|
6644
|
+
interactionId: readString4(metadata.interactionId),
|
|
6328
6645
|
...status ? { status } : {},
|
|
6329
|
-
meshId:
|
|
6330
|
-
nodeId:
|
|
6331
|
-
targetNodeId:
|
|
6332
|
-
targetDaemonId:
|
|
6333
|
-
workspace:
|
|
6334
|
-
branch:
|
|
6335
|
-
into:
|
|
6336
|
-
startedAt:
|
|
6337
|
-
completedAt:
|
|
6338
|
-
retryOfJobId:
|
|
6646
|
+
meshId: readString4(metadata.meshId) || event.meshId || args.meshId,
|
|
6647
|
+
nodeId: readString4(metadata.nodeId) || event.nodeId,
|
|
6648
|
+
targetNodeId: readString4(metadata.nodeId) || event.nodeId,
|
|
6649
|
+
targetDaemonId: readString4(metadata.targetDaemonId),
|
|
6650
|
+
workspace: readString4(metadata.workspace) || event.workspace,
|
|
6651
|
+
branch: readString4(result?.branch) || readString4(finalState?.branch),
|
|
6652
|
+
into: readString4(result?.into) || readString4(finalState?.baseBranch),
|
|
6653
|
+
startedAt: readString4(metadata.startedAt),
|
|
6654
|
+
completedAt: readString4(metadata.completedAt),
|
|
6655
|
+
retryOfJobId: readString4(metadata.retryOfJobId),
|
|
6339
6656
|
lastEvent: event.event,
|
|
6340
6657
|
lastUpdatedAt: new Date(event.queuedAt).toISOString()
|
|
6341
6658
|
});
|
|
@@ -6396,10 +6713,10 @@ var mesh_review_inbox_exports = {};
|
|
|
6396
6713
|
__export(mesh_review_inbox_exports, {
|
|
6397
6714
|
deriveMeshReviewInboxItems: () => deriveMeshReviewInboxItems
|
|
6398
6715
|
});
|
|
6399
|
-
function
|
|
6716
|
+
function readString5(value) {
|
|
6400
6717
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
6401
6718
|
}
|
|
6402
|
-
function
|
|
6719
|
+
function readRecord3(value) {
|
|
6403
6720
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
6404
6721
|
}
|
|
6405
6722
|
function readStringArray3(value, max) {
|
|
@@ -6409,20 +6726,20 @@ function readStringArray3(value, max) {
|
|
|
6409
6726
|
}
|
|
6410
6727
|
function isLocalNodeStatus(node) {
|
|
6411
6728
|
if (node.isLocalWorktree === true) return true;
|
|
6412
|
-
const connection =
|
|
6413
|
-
return
|
|
6729
|
+
const connection = readRecord3(node.connection);
|
|
6730
|
+
return readString5(connection?.state) === "self";
|
|
6414
6731
|
}
|
|
6415
6732
|
function readNodeConvergence(node) {
|
|
6416
|
-
const convergence =
|
|
6417
|
-
const status =
|
|
6733
|
+
const convergence = readRecord3(node.branchConvergence);
|
|
6734
|
+
const status = readString5(convergence?.status);
|
|
6418
6735
|
if (!convergence || !status) return null;
|
|
6419
6736
|
return {
|
|
6420
6737
|
status,
|
|
6421
|
-
reason:
|
|
6422
|
-
nextStep:
|
|
6738
|
+
reason: readString5(convergence.reason),
|
|
6739
|
+
nextStep: readString5(convergence.nextStep),
|
|
6423
6740
|
needsConvergence: convergence.needsConvergence === true,
|
|
6424
|
-
branch:
|
|
6425
|
-
defaultBranch:
|
|
6741
|
+
branch: readString5(convergence.branch),
|
|
6742
|
+
defaultBranch: readString5(convergence.defaultBranch)
|
|
6426
6743
|
};
|
|
6427
6744
|
}
|
|
6428
6745
|
function isMergeCandidate(convergence) {
|
|
@@ -6430,15 +6747,15 @@ function isMergeCandidate(convergence) {
|
|
|
6430
6747
|
return convergence.status === "cleanup_candidate" && convergence.reason === "clean_non_default_worktree_branch";
|
|
6431
6748
|
}
|
|
6432
6749
|
function readWorkerArtifact(value) {
|
|
6433
|
-
const worker =
|
|
6750
|
+
const worker = readRecord3(value);
|
|
6434
6751
|
if (!worker) return null;
|
|
6435
6752
|
const changed = readStringArray3(worker.changedFiles, MAX_CHANGED_FILES);
|
|
6436
6753
|
return {
|
|
6437
|
-
status:
|
|
6438
|
-
...
|
|
6754
|
+
status: readString5(worker.status) ?? "unknown",
|
|
6755
|
+
...readString5(worker.classification) ? { classification: readString5(worker.classification) } : {},
|
|
6439
6756
|
changedFiles: changed.values,
|
|
6440
6757
|
...changed.truncated ? { changedFilesTruncated: true } : {},
|
|
6441
|
-
validationResults: Array.isArray(worker.validationResults) ? worker.validationResults.map((item) =>
|
|
6758
|
+
validationResults: Array.isArray(worker.validationResults) ? worker.validationResults.map((item) => readRecord3(item)).filter((item) => item !== null) : [],
|
|
6442
6759
|
errors: readStringArray3(worker.errors, 20).values,
|
|
6443
6760
|
requiresUserAction: worker.requiresUserAction === true
|
|
6444
6761
|
};
|
|
@@ -6452,43 +6769,43 @@ function resolveNodeEvidence(nodeId, ledgerEntries) {
|
|
|
6452
6769
|
for (let i = ledgerEntries.length - 1; i >= 0; i--) {
|
|
6453
6770
|
const entry = ledgerEntries[i];
|
|
6454
6771
|
if (entry.nodeId !== nodeId || !isTerminalLedgerKind(entry.kind)) continue;
|
|
6455
|
-
const payload =
|
|
6772
|
+
const payload = readRecord3(entry.payload) ?? {};
|
|
6456
6773
|
if (!evidence.available) {
|
|
6457
6774
|
if (payload.source === "refine_mesh_node_async_job") {
|
|
6458
|
-
const result =
|
|
6459
|
-
const validationSummary =
|
|
6775
|
+
const result = readRecord3(payload.result);
|
|
6776
|
+
const validationSummary = readRecord3(result?.validationSummary);
|
|
6460
6777
|
evidence = {
|
|
6461
6778
|
available: true,
|
|
6462
6779
|
kind: entry.kind,
|
|
6463
6780
|
source: "refine_job",
|
|
6464
6781
|
timestamp: entry.timestamp,
|
|
6465
6782
|
...entry.sessionId ? { sessionId: entry.sessionId } : {},
|
|
6466
|
-
bootstrap:
|
|
6783
|
+
bootstrap: readRecord3(validationSummary?.bootstrap),
|
|
6467
6784
|
validation: validationSummary ? Object.fromEntries(Object.entries(validationSummary).filter(([key]) => key !== "bootstrap")) : null,
|
|
6468
|
-
checkpoint:
|
|
6785
|
+
checkpoint: readRecord3(result?.checkpoint),
|
|
6469
6786
|
worker: null,
|
|
6470
|
-
...
|
|
6471
|
-
...
|
|
6787
|
+
...readRecord3(payload.finalBranchConvergenceState) ?? readRecord3(result?.finalBranchConvergenceState) ? { finalBranchConvergenceState: readRecord3(payload.finalBranchConvergenceState) ?? readRecord3(result?.finalBranchConvergenceState) } : {},
|
|
6788
|
+
...readRecord3(payload.refineJob) ? { refineJob: readRecord3(payload.refineJob) } : {}
|
|
6472
6789
|
};
|
|
6473
6790
|
} else {
|
|
6474
|
-
const envelope =
|
|
6791
|
+
const envelope = readRecord3(payload.evidence);
|
|
6475
6792
|
evidence = {
|
|
6476
6793
|
available: true,
|
|
6477
6794
|
kind: entry.kind,
|
|
6478
6795
|
source: "task_completion",
|
|
6479
6796
|
timestamp: entry.timestamp,
|
|
6480
|
-
...
|
|
6797
|
+
...readString5(payload.taskId) ? { taskId: readString5(payload.taskId) } : {},
|
|
6481
6798
|
...entry.sessionId ? { sessionId: entry.sessionId } : {},
|
|
6482
6799
|
bootstrap: null,
|
|
6483
|
-
validation:
|
|
6484
|
-
checkpoint:
|
|
6800
|
+
validation: readRecord3(envelope?.validation),
|
|
6801
|
+
checkpoint: readRecord3(envelope?.checkpoint),
|
|
6485
6802
|
worker: readWorkerArtifact(envelope?.workerResult ?? payload.workerResult)
|
|
6486
6803
|
};
|
|
6487
6804
|
}
|
|
6488
6805
|
}
|
|
6489
6806
|
if (!transcriptHandle) {
|
|
6490
|
-
const envelope =
|
|
6491
|
-
transcriptHandle =
|
|
6807
|
+
const envelope = readRecord3(payload.evidence);
|
|
6808
|
+
transcriptHandle = readRecord3(envelope?.transcriptHandle);
|
|
6492
6809
|
}
|
|
6493
6810
|
if (evidence.available && transcriptHandle) break;
|
|
6494
6811
|
}
|
|
@@ -6498,11 +6815,11 @@ function hasBlockedReviewRefineResult(nodeId, ledgerEntries) {
|
|
|
6498
6815
|
for (let i = ledgerEntries.length - 1; i >= 0; i--) {
|
|
6499
6816
|
const entry = ledgerEntries[i];
|
|
6500
6817
|
if (entry.nodeId !== nodeId || !isTerminalLedgerKind(entry.kind)) continue;
|
|
6501
|
-
const payload =
|
|
6818
|
+
const payload = readRecord3(entry.payload) ?? {};
|
|
6502
6819
|
if (payload.source !== "refine_mesh_node_async_job") continue;
|
|
6503
|
-
const result =
|
|
6504
|
-
const finalState =
|
|
6505
|
-
return
|
|
6820
|
+
const result = readRecord3(payload.result);
|
|
6821
|
+
const finalState = readRecord3(payload.finalBranchConvergenceState) ?? readRecord3(result?.finalBranchConvergenceState);
|
|
6822
|
+
return readString5(finalState?.status) === "blocked_review" || readString5(result?.code) === "blocked_review";
|
|
6506
6823
|
}
|
|
6507
6824
|
return false;
|
|
6508
6825
|
}
|
|
@@ -6511,7 +6828,7 @@ function deriveMeshReviewInboxItems(args) {
|
|
|
6511
6828
|
const excludedRemoteNodeIds = [];
|
|
6512
6829
|
const refineJobs = buildMeshAsyncRefineJobs({ ledgerEntries: args.ledgerEntries });
|
|
6513
6830
|
for (const node of args.nodes) {
|
|
6514
|
-
const nodeId =
|
|
6831
|
+
const nodeId = readString5(node.nodeId) ?? readString5(node.id);
|
|
6515
6832
|
if (!nodeId) continue;
|
|
6516
6833
|
if (!isLocalNodeStatus(node)) {
|
|
6517
6834
|
excludedRemoteNodeIds.push(nodeId);
|
|
@@ -6533,8 +6850,8 @@ function deriveMeshReviewInboxItems(args) {
|
|
|
6533
6850
|
) ?? null;
|
|
6534
6851
|
items.push({
|
|
6535
6852
|
nodeId,
|
|
6536
|
-
workspace:
|
|
6537
|
-
branch: convergence.branch ??
|
|
6853
|
+
workspace: readString5(node.workspace),
|
|
6854
|
+
branch: convergence.branch ?? readString5(node.worktreeBranch),
|
|
6538
6855
|
defaultBranch: convergence.defaultBranch,
|
|
6539
6856
|
isLocalWorktree: node.isLocalWorktree === true,
|
|
6540
6857
|
reviewReason,
|
|
@@ -7745,220 +8062,6 @@ var init_mesh_fast_forward = __esm({
|
|
|
7745
8062
|
}
|
|
7746
8063
|
});
|
|
7747
8064
|
|
|
7748
|
-
// ../mesh-shared/dist/index.mjs
|
|
7749
|
-
function readRecord3(value) {
|
|
7750
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
7751
|
-
}
|
|
7752
|
-
function readString5(...values) {
|
|
7753
|
-
for (const value of values) {
|
|
7754
|
-
if (typeof value !== "string") continue;
|
|
7755
|
-
const trimmed = value.trim();
|
|
7756
|
-
if (trimmed) return trimmed;
|
|
7757
|
-
}
|
|
7758
|
-
return void 0;
|
|
7759
|
-
}
|
|
7760
|
-
function readNumber(...values) {
|
|
7761
|
-
for (const value of values) {
|
|
7762
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
7763
|
-
}
|
|
7764
|
-
return void 0;
|
|
7765
|
-
}
|
|
7766
|
-
function readBoolean(...values) {
|
|
7767
|
-
for (const value of values) {
|
|
7768
|
-
if (typeof value === "boolean") return value;
|
|
7769
|
-
}
|
|
7770
|
-
return void 0;
|
|
7771
|
-
}
|
|
7772
|
-
function joinRepoPath(root, relativePath) {
|
|
7773
|
-
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
7774
|
-
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
7775
|
-
if (!normalizedPath) return void 0;
|
|
7776
|
-
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
7777
|
-
if (!normalizedRoot) return void 0;
|
|
7778
|
-
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
7779
|
-
}
|
|
7780
|
-
function scoreGitUpstreamFreshness(status) {
|
|
7781
|
-
switch (status) {
|
|
7782
|
-
case "fresh":
|
|
7783
|
-
return 30;
|
|
7784
|
-
case "no_upstream":
|
|
7785
|
-
return 4;
|
|
7786
|
-
case "unchecked":
|
|
7787
|
-
case void 0:
|
|
7788
|
-
return 0;
|
|
7789
|
-
case "stale":
|
|
7790
|
-
return -10;
|
|
7791
|
-
case "unavailable":
|
|
7792
|
-
return -15;
|
|
7793
|
-
default:
|
|
7794
|
-
return 0;
|
|
7795
|
-
}
|
|
7796
|
-
}
|
|
7797
|
-
function readGitSubmodules(value, parentRepoRoot) {
|
|
7798
|
-
if (!Array.isArray(value)) return void 0;
|
|
7799
|
-
const submodules = value.map((entry) => {
|
|
7800
|
-
const submodule = readRecord3(entry);
|
|
7801
|
-
const path42 = readString5(submodule.path);
|
|
7802
|
-
const commit = readString5(submodule.commit);
|
|
7803
|
-
const repoPath = readString5(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path42);
|
|
7804
|
-
if (!path42 || !commit) return null;
|
|
7805
|
-
const result = {
|
|
7806
|
-
path: path42,
|
|
7807
|
-
commit,
|
|
7808
|
-
dirty: readBoolean(submodule.dirty) ?? false,
|
|
7809
|
-
outOfSync: readBoolean(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
7810
|
-
lastCheckedAt: readNumber(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now()
|
|
7811
|
-
};
|
|
7812
|
-
if (repoPath) result.repoPath = repoPath;
|
|
7813
|
-
const error = readString5(submodule.error);
|
|
7814
|
-
if (error) result.error = error;
|
|
7815
|
-
return result;
|
|
7816
|
-
}).filter((entry) => entry !== null);
|
|
7817
|
-
return submodules.length > 0 ? submodules : void 0;
|
|
7818
|
-
}
|
|
7819
|
-
function hasGitStatusEvidence(status) {
|
|
7820
|
-
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(
|
|
7821
|
-
status.ahead,
|
|
7822
|
-
status.behind,
|
|
7823
|
-
status.staged,
|
|
7824
|
-
status.modified,
|
|
7825
|
-
status.untracked,
|
|
7826
|
-
status.deleted,
|
|
7827
|
-
status.renamed,
|
|
7828
|
-
status.lastCheckedAt,
|
|
7829
|
-
status.last_checked_at
|
|
7830
|
-
) !== void 0 || Array.isArray(status.submodules) && status.submodules.length > 0;
|
|
7831
|
-
}
|
|
7832
|
-
function normalizeGitStatus(status, node, options) {
|
|
7833
|
-
const explicitIsGitRepo = readBoolean(status.isGitRepo);
|
|
7834
|
-
if (!Object.keys(status).length || !hasGitStatusEvidence(status)) return void 0;
|
|
7835
|
-
const isGitRepo = explicitIsGitRepo ?? true;
|
|
7836
|
-
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((entry) => typeof entry === "string") : [];
|
|
7837
|
-
const conflictCount = readNumber(status.conflicts) ?? conflictFiles.length;
|
|
7838
|
-
const hasConflicts = readBoolean(status.hasConflicts) ?? conflictCount > 0;
|
|
7839
|
-
const repoRoot = readString5(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
|
|
7840
|
-
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
7841
|
-
const upstreamStatus = readString5(status.upstreamStatus, status.upstream_status);
|
|
7842
|
-
const upstreamFetchedAt = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
|
|
7843
|
-
const upstreamFetchError = readString5(status.upstreamFetchError, status.upstream_fetch_error);
|
|
7844
|
-
const error = readString5(status.error);
|
|
7845
|
-
const staged = readNumber(status.staged) ?? 0;
|
|
7846
|
-
const modified = readNumber(status.modified) ?? 0;
|
|
7847
|
-
const untracked = readNumber(status.untracked) ?? 0;
|
|
7848
|
-
const deleted = readNumber(status.deleted) ?? 0;
|
|
7849
|
-
const renamed = readNumber(status.renamed) ?? 0;
|
|
7850
|
-
return {
|
|
7851
|
-
workspace: readString5(status.workspace, node.workspace) || "",
|
|
7852
|
-
repoRoot: repoRoot ?? null,
|
|
7853
|
-
isGitRepo,
|
|
7854
|
-
branch: readString5(status.branch) ?? null,
|
|
7855
|
-
headCommit: readString5(status.headCommit) ?? null,
|
|
7856
|
-
headMessage: readString5(status.headMessage) ?? null,
|
|
7857
|
-
upstream: readString5(status.upstream) ?? null,
|
|
7858
|
-
upstreamStatus: upstreamStatus ?? "unchecked",
|
|
7859
|
-
...upstreamFetchedAt !== void 0 ? { upstreamFetchedAt } : {},
|
|
7860
|
-
...upstreamFetchError ? { upstreamFetchError } : {},
|
|
7861
|
-
ahead: readNumber(status.ahead) ?? 0,
|
|
7862
|
-
behind: readNumber(status.behind) ?? 0,
|
|
7863
|
-
staged,
|
|
7864
|
-
modified,
|
|
7865
|
-
untracked,
|
|
7866
|
-
deleted,
|
|
7867
|
-
renamed,
|
|
7868
|
-
dirty: readBoolean(status.dirty, status.isDirty, status.is_dirty) ?? (staged + modified + untracked + deleted + renamed > 0 || hasConflicts),
|
|
7869
|
-
hasConflicts,
|
|
7870
|
-
conflictFiles,
|
|
7871
|
-
stashCount: readNumber(status.stashCount, status.stash_count) ?? 0,
|
|
7872
|
-
lastCheckedAt: options?.lastCheckedAt ?? readNumber(status.lastCheckedAt, status.last_checked_at) ?? Date.now(),
|
|
7873
|
-
...submodules ? { submodules } : {},
|
|
7874
|
-
...error ? { error } : {}
|
|
7875
|
-
};
|
|
7876
|
-
}
|
|
7877
|
-
function scoreGitStatusCandidate(git) {
|
|
7878
|
-
if (!git) return Number.NEGATIVE_INFINITY;
|
|
7879
|
-
let score = 0;
|
|
7880
|
-
if (git.isGitRepo === true) score += 50;
|
|
7881
|
-
if (git.isGitRepo === false) score -= 10;
|
|
7882
|
-
if (git.branch) score += 20;
|
|
7883
|
-
if (git.headCommit) score += 20;
|
|
7884
|
-
if (git.upstream) score += 10;
|
|
7885
|
-
score += scoreGitUpstreamFreshness(git.upstreamStatus);
|
|
7886
|
-
if (typeof git.ahead === "number") score += 2;
|
|
7887
|
-
if (typeof git.behind === "number") score += 2;
|
|
7888
|
-
if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
|
|
7889
|
-
if (git.error) score -= 20;
|
|
7890
|
-
return score;
|
|
7891
|
-
}
|
|
7892
|
-
function pickBestTransitGitStatus(node, options) {
|
|
7893
|
-
const rawGit = readRecord3(node.lastGit ?? node.last_git);
|
|
7894
|
-
const gitResult = readRecord3(rawGit.result);
|
|
7895
|
-
const directStatus = readRecord3(rawGit.status);
|
|
7896
|
-
const nestedStatus = readRecord3(gitResult.status);
|
|
7897
|
-
const rawProbe = readRecord3(node.lastProbe ?? node.last_probe);
|
|
7898
|
-
const probeGit = readRecord3(rawProbe.git);
|
|
7899
|
-
const probeGitResult = readRecord3(probeGit.result);
|
|
7900
|
-
const probeDirectStatus = readRecord3(probeGit.status);
|
|
7901
|
-
const probeNestedStatus = readRecord3(probeGitResult.status);
|
|
7902
|
-
const lastCheckedAt = options?.lastCheckedAt;
|
|
7903
|
-
let best = null;
|
|
7904
|
-
for (const status of [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus]) {
|
|
7905
|
-
const normalized = normalizeGitStatus(status, node, { lastCheckedAt: lastCheckedAt ?? Date.now() });
|
|
7906
|
-
if (!normalized) continue;
|
|
7907
|
-
const score = scoreGitStatusCandidate(normalized);
|
|
7908
|
-
if (!best || score > best.score) best = { git: normalized, score };
|
|
7909
|
-
}
|
|
7910
|
-
return best?.git;
|
|
7911
|
-
}
|
|
7912
|
-
function normalizeMeshNodeId(node) {
|
|
7913
|
-
const record = node && typeof node === "object" ? node : {};
|
|
7914
|
-
return readString5(record.id, record.nodeId, record.node_id);
|
|
7915
|
-
}
|
|
7916
|
-
function meshNodeIdMatches(node, candidateId) {
|
|
7917
|
-
if (!candidateId) return false;
|
|
7918
|
-
const trimmed = candidateId.trim();
|
|
7919
|
-
if (!trimmed) return false;
|
|
7920
|
-
return normalizeMeshNodeId(node) === trimmed;
|
|
7921
|
-
}
|
|
7922
|
-
function summarizeGitShape(status) {
|
|
7923
|
-
const record = readRecord3(status);
|
|
7924
|
-
if (!Object.keys(record).length) return null;
|
|
7925
|
-
const submodules = Array.isArray(record.submodules) ? record.submodules.map((entry) => {
|
|
7926
|
-
const sub = readRecord3(entry);
|
|
7927
|
-
return {
|
|
7928
|
-
path: readString5(sub.path) ?? null,
|
|
7929
|
-
commit: readString5(sub.commit)?.slice(0, 12) ?? null,
|
|
7930
|
-
dirty: readBoolean(sub.dirty) ?? false,
|
|
7931
|
-
outOfSync: readBoolean(sub.outOfSync, sub.out_of_sync) ?? false
|
|
7932
|
-
};
|
|
7933
|
-
}) : [];
|
|
7934
|
-
return {
|
|
7935
|
-
isGitRepo: readBoolean(record.isGitRepo),
|
|
7936
|
-
workspace: readString5(record.workspace) ?? null,
|
|
7937
|
-
repoRoot: readString5(record.repoRoot, record.repo_root) ?? null,
|
|
7938
|
-
branch: readString5(record.branch) ?? null,
|
|
7939
|
-
upstream: readString5(record.upstream) ?? null,
|
|
7940
|
-
upstreamStatus: readString5(record.upstreamStatus, record.upstream_status) ?? null,
|
|
7941
|
-
headCommit: readString5(record.headCommit, record.head_commit)?.slice(0, 12) ?? null,
|
|
7942
|
-
ahead: readNumber(record.ahead) ?? null,
|
|
7943
|
-
behind: readNumber(record.behind) ?? null,
|
|
7944
|
-
dirtyCounts: {
|
|
7945
|
-
staged: readNumber(record.staged) ?? 0,
|
|
7946
|
-
modified: readNumber(record.modified) ?? 0,
|
|
7947
|
-
untracked: readNumber(record.untracked) ?? 0,
|
|
7948
|
-
deleted: readNumber(record.deleted) ?? 0,
|
|
7949
|
-
renamed: readNumber(record.renamed) ?? 0
|
|
7950
|
-
},
|
|
7951
|
-
lastCheckedAt: readNumber(record.lastCheckedAt, record.last_checked_at) ?? null,
|
|
7952
|
-
submoduleCount: submodules.length,
|
|
7953
|
-
submodules
|
|
7954
|
-
};
|
|
7955
|
-
}
|
|
7956
|
-
var init_dist = __esm({
|
|
7957
|
-
"../mesh-shared/dist/index.mjs"() {
|
|
7958
|
-
"use strict";
|
|
7959
|
-
}
|
|
7960
|
-
});
|
|
7961
|
-
|
|
7962
8065
|
// src/mesh/mesh-active-work.ts
|
|
7963
8066
|
function readString6(value) {
|
|
7964
8067
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
@@ -8615,17 +8718,7 @@ import { appendFileSync as appendFileSync2, existsSync as existsSync14, readFile
|
|
|
8615
8718
|
import { join as join15 } from "path";
|
|
8616
8719
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
8617
8720
|
function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
|
|
8618
|
-
|
|
8619
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8620
|
-
const out = [];
|
|
8621
|
-
for (const id of raw) {
|
|
8622
|
-
if (typeof id !== "string") continue;
|
|
8623
|
-
const trimmed = id.trim();
|
|
8624
|
-
if (!trimmed || seen.has(trimmed)) continue;
|
|
8625
|
-
seen.add(trimmed);
|
|
8626
|
-
out.push(trimmed);
|
|
8627
|
-
}
|
|
8628
|
-
return out;
|
|
8721
|
+
return expandDaemonIdForms(coordinatorDaemonId);
|
|
8629
8722
|
}
|
|
8630
8723
|
function readRefineJobId2(event) {
|
|
8631
8724
|
const metadata = readRecord4(event.metadataEvent) || event;
|
|
@@ -9012,6 +9105,7 @@ var init_mesh_events_pending = __esm({
|
|
|
9012
9105
|
init_mesh_ledger();
|
|
9013
9106
|
init_mesh_runtime_store();
|
|
9014
9107
|
init_mesh_events_utils();
|
|
9108
|
+
init_dist();
|
|
9015
9109
|
REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
|
|
9016
9110
|
MAX_PENDING_EVENTS_BYTES = 100 * 1024;
|
|
9017
9111
|
MAX_PENDING_EVENTS_KEEP = 50;
|
|
@@ -12466,12 +12560,9 @@ var init_snapshot = __esm({
|
|
|
12466
12560
|
// src/mesh/mesh-events-coordinator.ts
|
|
12467
12561
|
import { existsSync as existsSync17 } from "fs";
|
|
12468
12562
|
function resolveCoordinatorDrainDaemonIds(components) {
|
|
12469
|
-
const ids = /* @__PURE__ */ new Set();
|
|
12470
12563
|
const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
|
|
12471
|
-
if (statusInstanceId) ids.add(statusInstanceId);
|
|
12472
12564
|
const machineId = readNonEmptyString2(loadConfig().machineId);
|
|
12473
|
-
|
|
12474
|
-
return [...ids];
|
|
12565
|
+
return expandDaemonIdForms([statusInstanceId, machineId]);
|
|
12475
12566
|
}
|
|
12476
12567
|
function getCachedMeshByWorkspace(workspace) {
|
|
12477
12568
|
const now = Date.now();
|
|
@@ -12622,6 +12713,55 @@ function resolveActiveDirectDispatchTaskId(meshId, sessionId) {
|
|
|
12622
12713
|
return void 0;
|
|
12623
12714
|
}
|
|
12624
12715
|
}
|
|
12716
|
+
function deliverTaskToSession(dispatchThunk, ctx) {
|
|
12717
|
+
const delivery = createSessionDelivery({
|
|
12718
|
+
meshId: ctx.meshId,
|
|
12719
|
+
nodeId: ctx.nodeId,
|
|
12720
|
+
sessionId: ctx.sessionId,
|
|
12721
|
+
providerType: ctx.providerType,
|
|
12722
|
+
taskId: ctx.task.id,
|
|
12723
|
+
kind: "task",
|
|
12724
|
+
message: ctx.task.message,
|
|
12725
|
+
status: "delivering",
|
|
12726
|
+
...ctx.sourceCoordinatorSessionId ? { sourceCoordinatorSessionId: ctx.sourceCoordinatorSessionId } : {},
|
|
12727
|
+
...ctx.sourceCoordinatorDaemonId ? { sourceCoordinatorDaemonId: ctx.sourceCoordinatorDaemonId } : {}
|
|
12728
|
+
});
|
|
12729
|
+
let dispatchPromise;
|
|
12730
|
+
try {
|
|
12731
|
+
dispatchPromise = Promise.resolve(dispatchThunk());
|
|
12732
|
+
} catch (e) {
|
|
12733
|
+
dispatchPromise = Promise.reject(e);
|
|
12734
|
+
}
|
|
12735
|
+
let timer;
|
|
12736
|
+
const guarded = Promise.race([
|
|
12737
|
+
dispatchPromise,
|
|
12738
|
+
new Promise((_, reject) => {
|
|
12739
|
+
timer = setTimeout(
|
|
12740
|
+
() => reject(new Error(`dispatch_confirm_timeout after ${DISPATCH_CONFIRM_TIMEOUT_MS}ms`)),
|
|
12741
|
+
DISPATCH_CONFIRM_TIMEOUT_MS
|
|
12742
|
+
);
|
|
12743
|
+
if (typeof timer?.unref === "function") timer.unref();
|
|
12744
|
+
})
|
|
12745
|
+
]);
|
|
12746
|
+
guarded.then(() => {
|
|
12747
|
+
if (timer) clearTimeout(timer);
|
|
12748
|
+
updateSessionDeliveryStatus(delivery.id, "delivered");
|
|
12749
|
+
}).catch((e) => {
|
|
12750
|
+
if (timer) clearTimeout(timer);
|
|
12751
|
+
LOG.error("MeshQueue", `Failed to dispatch task via ${ctx.transport} to node ${ctx.nodeId}: ${e?.message}`);
|
|
12752
|
+
updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
12753
|
+
updateTaskStatus(ctx.meshId, ctx.task.id, "pending");
|
|
12754
|
+
try {
|
|
12755
|
+
appendLedgerEntry(ctx.meshId, {
|
|
12756
|
+
kind: "dispatch_failed",
|
|
12757
|
+
nodeId: ctx.nodeId,
|
|
12758
|
+
sessionId: ctx.sessionId,
|
|
12759
|
+
payload: { taskId: ctx.task.id, deliveryId: delivery.id, error: e?.message, retryable: true, transport: ctx.transport }
|
|
12760
|
+
});
|
|
12761
|
+
} catch {
|
|
12762
|
+
}
|
|
12763
|
+
});
|
|
12764
|
+
}
|
|
12625
12765
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
12626
12766
|
const mesh = getMeshWithCache(components, meshId);
|
|
12627
12767
|
const node = mesh?.nodes.find((n) => readMeshNodeId(n) === nodeId);
|
|
@@ -12640,46 +12780,33 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
12640
12780
|
if (!isLocalNode) {
|
|
12641
12781
|
const localDaemonIdForDispatch = readNonEmptyString2(loadConfig().machineId) || void 0;
|
|
12642
12782
|
const sourceCoordinatorSessionId = readNonEmptyString2(task.sourceCoordinatorSessionId) || void 0;
|
|
12643
|
-
const
|
|
12644
|
-
|
|
12645
|
-
|
|
12646
|
-
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
meshContext: {
|
|
12783
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
12784
|
+
const remoteDaemonId = node.daemonId;
|
|
12785
|
+
deliverTaskToSession(
|
|
12786
|
+
() => dispatchMeshCommand(remoteDaemonId, "agent_command", {
|
|
12787
|
+
targetSessionId: sessionId,
|
|
12788
|
+
cliType: providerType,
|
|
12789
|
+
action: "send_chat",
|
|
12790
|
+
message: task.message,
|
|
12791
|
+
meshContext: {
|
|
12792
|
+
meshId,
|
|
12793
|
+
nodeId,
|
|
12794
|
+
taskId: task.id,
|
|
12795
|
+
...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {},
|
|
12796
|
+
...sourceCoordinatorSessionId ? { coordinatorSessionId: sourceCoordinatorSessionId } : {}
|
|
12797
|
+
}
|
|
12798
|
+
}),
|
|
12799
|
+
{
|
|
12661
12800
|
meshId,
|
|
12662
12801
|
nodeId,
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
}).catch((e) => {
|
|
12670
|
-
LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
|
|
12671
|
-
updateSessionDeliveryStatus(delivery2.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
12672
|
-
updateTaskStatus(meshId, task.id, "pending");
|
|
12673
|
-
try {
|
|
12674
|
-
appendLedgerEntry(meshId, {
|
|
12675
|
-
kind: "dispatch_failed",
|
|
12676
|
-
nodeId,
|
|
12677
|
-
sessionId,
|
|
12678
|
-
payload: { taskId: task.id, deliveryId: delivery2.id, error: e?.message, retryable: true }
|
|
12679
|
-
});
|
|
12680
|
-
} catch {
|
|
12802
|
+
sessionId,
|
|
12803
|
+
providerType,
|
|
12804
|
+
task,
|
|
12805
|
+
transport: "remote",
|
|
12806
|
+
...sourceCoordinatorSessionId ? { sourceCoordinatorSessionId } : {},
|
|
12807
|
+
...localDaemonIdForDispatch ? { sourceCoordinatorDaemonId: localDaemonIdForDispatch } : {}
|
|
12681
12808
|
}
|
|
12682
|
-
|
|
12809
|
+
);
|
|
12683
12810
|
return true;
|
|
12684
12811
|
}
|
|
12685
12812
|
}
|
|
@@ -12701,39 +12828,24 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
12701
12828
|
}
|
|
12702
12829
|
} catch {
|
|
12703
12830
|
}
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
|
|
12707
|
-
|
|
12708
|
-
|
|
12709
|
-
|
|
12710
|
-
|
|
12711
|
-
|
|
12712
|
-
|
|
12713
|
-
|
|
12714
|
-
|
|
12715
|
-
|
|
12716
|
-
|
|
12717
|
-
|
|
12718
|
-
|
|
12719
|
-
|
|
12720
|
-
message: task.message
|
|
12721
|
-
}).then(() => {
|
|
12722
|
-
updateSessionDeliveryStatus(delivery.id, "delivered");
|
|
12723
|
-
}).catch((e) => {
|
|
12724
|
-
LOG.error("MeshQueue", `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
|
|
12725
|
-
updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
12726
|
-
updateTaskStatus(meshId, task.id, "pending");
|
|
12727
|
-
try {
|
|
12728
|
-
appendLedgerEntry(meshId, {
|
|
12729
|
-
kind: "dispatch_failed",
|
|
12730
|
-
nodeId,
|
|
12731
|
-
sessionId,
|
|
12732
|
-
payload: { taskId: task.id, deliveryId: delivery.id, error: e?.message, retryable: true }
|
|
12733
|
-
});
|
|
12734
|
-
} catch {
|
|
12831
|
+
deliverTaskToSession(
|
|
12832
|
+
() => components.cliManager.handleCliCommand("agent_command", {
|
|
12833
|
+
targetSessionId: sessionId,
|
|
12834
|
+
cliType: providerType,
|
|
12835
|
+
action: "send_chat",
|
|
12836
|
+
message: task.message
|
|
12837
|
+
}),
|
|
12838
|
+
{
|
|
12839
|
+
meshId,
|
|
12840
|
+
nodeId,
|
|
12841
|
+
sessionId,
|
|
12842
|
+
providerType,
|
|
12843
|
+
task,
|
|
12844
|
+
transport: "local",
|
|
12845
|
+
...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { sourceCoordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {},
|
|
12846
|
+
...readNonEmptyString2(loadConfig().machineId) ? { sourceCoordinatorDaemonId: readNonEmptyString2(loadConfig().machineId) } : {}
|
|
12735
12847
|
}
|
|
12736
|
-
|
|
12848
|
+
);
|
|
12737
12849
|
return true;
|
|
12738
12850
|
}
|
|
12739
12851
|
function sweepExpiredCooldowns() {
|
|
@@ -12998,7 +13110,7 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
12998
13110
|
}
|
|
12999
13111
|
}
|
|
13000
13112
|
const candidateNodes = Array.isArray(mesh?.nodes) ? mesh.nodes.filter((node) => {
|
|
13001
|
-
if (task.targetNodeId &&
|
|
13113
|
+
if (task.targetNodeId && !meshNodeIdMatches(node, task.targetNodeId)) return false;
|
|
13002
13114
|
if (task.requiredTags?.length) {
|
|
13003
13115
|
const priorities = normalizeProviderPriority(node?.policy);
|
|
13004
13116
|
const providerCandidates = priorities.length ? priorities : [void 0];
|
|
@@ -13009,7 +13121,12 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
13009
13121
|
return true;
|
|
13010
13122
|
}) : [];
|
|
13011
13123
|
if (!candidateNodes.length) {
|
|
13012
|
-
|
|
13124
|
+
const targetPinUnmatched = !!task.targetNodeId && !(Array.isArray(mesh?.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, task.targetNodeId)));
|
|
13125
|
+
markAutoLaunch(meshId, task.id, {
|
|
13126
|
+
status: "skipped",
|
|
13127
|
+
reason: targetPinUnmatched ? "target_node_id_unmatched" : "no_node_satisfies_required_tags",
|
|
13128
|
+
nodeId: task.targetNodeId
|
|
13129
|
+
});
|
|
13013
13130
|
continue;
|
|
13014
13131
|
}
|
|
13015
13132
|
const strategy = resolveSchedulingStrategy(mesh);
|
|
@@ -13960,7 +14077,7 @@ function setupMeshEventForwarding(components) {
|
|
|
13960
14077
|
});
|
|
13961
14078
|
});
|
|
13962
14079
|
}
|
|
13963
|
-
var 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;
|
|
14080
|
+
var 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;
|
|
13964
14081
|
var init_mesh_events_coordinator = __esm({
|
|
13965
14082
|
"src/mesh/mesh-events-coordinator.ts"() {
|
|
13966
14083
|
"use strict";
|
|
@@ -13988,6 +14105,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
13988
14105
|
idleAutoFastForwardLastAttempt = /* @__PURE__ */ new Map();
|
|
13989
14106
|
INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
|
|
13990
14107
|
RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
|
|
14108
|
+
DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
|
|
13991
14109
|
autoLaunchInProgress = /* @__PURE__ */ new Set();
|
|
13992
14110
|
autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
|
|
13993
14111
|
AUTO_LAUNCH_COOLDOWN_MS = 5e3;
|
|
@@ -14043,12 +14161,9 @@ function resolveReconcileIntervalMs() {
|
|
|
14043
14161
|
return DEFAULT_RECONCILE_INTERVAL_MS;
|
|
14044
14162
|
}
|
|
14045
14163
|
function resolveCoordinatorDaemonIds(components) {
|
|
14046
|
-
const ids = /* @__PURE__ */ new Set();
|
|
14047
14164
|
const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
|
|
14048
|
-
if (statusInstanceId) ids.add(statusInstanceId);
|
|
14049
14165
|
const machineId = readNonEmptyString2(loadConfig().machineId);
|
|
14050
|
-
|
|
14051
|
-
return [...ids];
|
|
14166
|
+
return expandDaemonIdForms([statusInstanceId, machineId]);
|
|
14052
14167
|
}
|
|
14053
14168
|
function daemonHostsMesh(mesh, daemonIds) {
|
|
14054
14169
|
const host = mesh.meshHost;
|
|
@@ -14132,6 +14247,24 @@ function recordHeldTerminalEventsToLedger(meshId, drainDaemonIds, reason, heldFo
|
|
|
14132
14247
|
}
|
|
14133
14248
|
}
|
|
14134
14249
|
}
|
|
14250
|
+
function recoverStrandedAssignedDispatches(meshId, store) {
|
|
14251
|
+
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
14252
|
+
if (!assigned.length) return;
|
|
14253
|
+
const nowMs = Date.now();
|
|
14254
|
+
for (const row of assigned) {
|
|
14255
|
+
const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
|
|
14256
|
+
if (!Number.isFinite(dispatchedAtMs)) continue;
|
|
14257
|
+
if (nowMs - dispatchedAtMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
|
|
14258
|
+
if (store.taskHasConfirmedDelivery(meshId, row.id)) continue;
|
|
14259
|
+
const reclaimed = reclaimStrandedAssignedTask(meshId, row.id, {
|
|
14260
|
+
reason: "assigned_stranded_dispatch_unconfirmed",
|
|
14261
|
+
ageMs: nowMs - dispatchedAtMs
|
|
14262
|
+
});
|
|
14263
|
+
if (reclaimed) {
|
|
14264
|
+
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})`);
|
|
14265
|
+
}
|
|
14266
|
+
}
|
|
14267
|
+
}
|
|
14135
14268
|
async function runMeshReconcileTick(components) {
|
|
14136
14269
|
const localDaemonId = readNonEmptyString2(loadConfig().machineId) || void 0;
|
|
14137
14270
|
const drainDaemonIds = resolveCoordinatorDaemonIds(components);
|
|
@@ -14161,6 +14294,17 @@ async function runMeshReconcileTick(components) {
|
|
|
14161
14294
|
}
|
|
14162
14295
|
}
|
|
14163
14296
|
}
|
|
14297
|
+
if (store) {
|
|
14298
|
+
for (const mesh of listMeshes()) {
|
|
14299
|
+
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
14300
|
+
if (!daemonHostsMesh(mesh, selfIds)) continue;
|
|
14301
|
+
try {
|
|
14302
|
+
recoverStrandedAssignedDispatches(mesh.id, store);
|
|
14303
|
+
} catch (e) {
|
|
14304
|
+
LOG.warn("MeshReconcile", `Assigned-stranded watchdog failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
14305
|
+
}
|
|
14306
|
+
}
|
|
14307
|
+
}
|
|
14164
14308
|
for (const mesh of listMeshes()) {
|
|
14165
14309
|
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
14166
14310
|
if (!daemonHostsMesh(mesh, selfIds)) continue;
|
|
@@ -14548,7 +14692,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
14548
14692
|
}
|
|
14549
14693
|
};
|
|
14550
14694
|
}
|
|
14551
|
-
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, heldEventLedgerRecorded, STRICT_SESSION_MATCH_TTL_MS;
|
|
14695
|
+
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS;
|
|
14552
14696
|
var init_mesh_reconcile_loop = __esm({
|
|
14553
14697
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
14554
14698
|
"use strict";
|
|
@@ -14561,6 +14705,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
14561
14705
|
init_mesh_events_coordinator();
|
|
14562
14706
|
init_mesh_unresolved_forward_outbox();
|
|
14563
14707
|
init_mesh_events_utils();
|
|
14708
|
+
init_dist();
|
|
14564
14709
|
init_mesh_work_queue();
|
|
14565
14710
|
init_mesh_ledger();
|
|
14566
14711
|
init_mesh_active_work();
|
|
@@ -14569,6 +14714,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
14569
14714
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
14570
14715
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
14571
14716
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
14717
|
+
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
14572
14718
|
STRICT_SESSION_MATCH_TTL_MS = 6e4;
|
|
14573
14719
|
}
|
|
14574
14720
|
});
|
|
@@ -14601,6 +14747,84 @@ var init_mesh_events = __esm({
|
|
|
14601
14747
|
}
|
|
14602
14748
|
});
|
|
14603
14749
|
|
|
14750
|
+
// src/providers/approval-utils.ts
|
|
14751
|
+
function normalizeApprovalLabel(value) {
|
|
14752
|
+
return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
|
|
14753
|
+
}
|
|
14754
|
+
function isNegativeApprovalLabel(value) {
|
|
14755
|
+
const label = normalizeApprovalLabel(value);
|
|
14756
|
+
return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
|
|
14757
|
+
}
|
|
14758
|
+
function hasNegativeApprovalOption(buttons) {
|
|
14759
|
+
return (buttons || []).some((button) => isNegativeApprovalLabel(String(button || "")));
|
|
14760
|
+
}
|
|
14761
|
+
function getApprovalPositiveHints(provider) {
|
|
14762
|
+
const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
|
|
14763
|
+
return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
|
|
14764
|
+
}
|
|
14765
|
+
function pickApprovalButton(buttons, provider) {
|
|
14766
|
+
const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
|
|
14767
|
+
if (labels.length === 0) {
|
|
14768
|
+
return { index: -1, label: "" };
|
|
14769
|
+
}
|
|
14770
|
+
const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
|
|
14771
|
+
const hints = getApprovalPositiveHints(provider);
|
|
14772
|
+
for (const hint of hints) {
|
|
14773
|
+
const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
|
|
14774
|
+
if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
|
|
14775
|
+
const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
|
|
14776
|
+
if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
|
|
14777
|
+
const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
|
|
14778
|
+
if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
|
|
14779
|
+
}
|
|
14780
|
+
return { index: -1, label: "" };
|
|
14781
|
+
}
|
|
14782
|
+
function pickAutoApprovalButton(buttons) {
|
|
14783
|
+
const labels = (buttons || []).map((button) => String(button || "").trim());
|
|
14784
|
+
const index = labels.findIndex(Boolean);
|
|
14785
|
+
return index >= 0 ? { index, label: labels[index] } : { index: -1, label: "" };
|
|
14786
|
+
}
|
|
14787
|
+
function formatAutoApprovalMessage(modalMessage, buttonLabel) {
|
|
14788
|
+
const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
|
|
14789
|
+
const cleanMessage = String(modalMessage || "").trim();
|
|
14790
|
+
if (cleanMessage) lines.push(cleanMessage);
|
|
14791
|
+
return lines.join("\n");
|
|
14792
|
+
}
|
|
14793
|
+
function looksLikeActiveApprovalPromptText(content) {
|
|
14794
|
+
const text = content.trim();
|
|
14795
|
+
if (!text || text.length > 2e3) return false;
|
|
14796
|
+
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);
|
|
14797
|
+
const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text) || /^\s*1[.)]\s+yes\b/im.test(text);
|
|
14798
|
+
if (hasApprovalQuestion && hasNumberedChoices) return true;
|
|
14799
|
+
const lastLines = text.split(/\r?\n/).slice(-12).join("\n");
|
|
14800
|
+
const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines) || /yes.*always allow/i.test(lastLines);
|
|
14801
|
+
const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
|
|
14802
|
+
if (hasDontAskAgain && hasNoOption) return true;
|
|
14803
|
+
if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
|
|
14804
|
+
return false;
|
|
14805
|
+
}
|
|
14806
|
+
var DEFAULT_APPROVAL_POSITIVE_HINTS;
|
|
14807
|
+
var init_approval_utils = __esm({
|
|
14808
|
+
"src/providers/approval-utils.ts"() {
|
|
14809
|
+
"use strict";
|
|
14810
|
+
DEFAULT_APPROVAL_POSITIVE_HINTS = [
|
|
14811
|
+
"yes",
|
|
14812
|
+
"allow once",
|
|
14813
|
+
"approve",
|
|
14814
|
+
"accept",
|
|
14815
|
+
"continue",
|
|
14816
|
+
"run",
|
|
14817
|
+
"proceed",
|
|
14818
|
+
"confirm",
|
|
14819
|
+
"save",
|
|
14820
|
+
"ok",
|
|
14821
|
+
"trust",
|
|
14822
|
+
"allow",
|
|
14823
|
+
"always allow"
|
|
14824
|
+
];
|
|
14825
|
+
}
|
|
14826
|
+
});
|
|
14827
|
+
|
|
14604
14828
|
// src/logging/debug-config.ts
|
|
14605
14829
|
function normalizeCategories(categories) {
|
|
14606
14830
|
if (!Array.isArray(categories)) return [];
|
|
@@ -15587,6 +15811,27 @@ function compileSettledPromptMatchers(spec) {
|
|
|
15587
15811
|
});
|
|
15588
15812
|
return { prompt, footers };
|
|
15589
15813
|
}
|
|
15814
|
+
function extractButtonLabels(spec, text) {
|
|
15815
|
+
if (!text) return [];
|
|
15816
|
+
const flags = spec.buttonFlags && spec.buttonFlags.includes("m") ? spec.buttonFlags : `${spec.buttonFlags ?? ""}m`;
|
|
15817
|
+
const buttonRe = compile2(spec.buttonPattern, flags);
|
|
15818
|
+
const labelGroup = Number.isInteger(spec.buttonLabelGroup) && (spec.buttonLabelGroup ?? 0) > 0 ? spec.buttonLabelGroup : 1;
|
|
15819
|
+
const out = [];
|
|
15820
|
+
for (const line of text.split("\n")) {
|
|
15821
|
+
buttonRe.lastIndex = 0;
|
|
15822
|
+
const m = buttonRe.exec(line);
|
|
15823
|
+
if (!m) continue;
|
|
15824
|
+
const captured = m[labelGroup] ?? (labelGroup === 1 && m.length > 2 ? m[m.length - 1] : void 0);
|
|
15825
|
+
if (captured && captured.trim()) out.push(captured.trim());
|
|
15826
|
+
}
|
|
15827
|
+
return out;
|
|
15828
|
+
}
|
|
15829
|
+
function buttonBlockApprovalCue(spec, text) {
|
|
15830
|
+
const labels = extractButtonLabels(spec, text);
|
|
15831
|
+
if (labels.length < 2) return false;
|
|
15832
|
+
if (pickApprovalButton(labels).index < 0) return false;
|
|
15833
|
+
return hasNegativeApprovalOption(labels);
|
|
15834
|
+
}
|
|
15590
15835
|
function modalMatches(spec, input) {
|
|
15591
15836
|
const text = input.screenText ?? "";
|
|
15592
15837
|
const question = compile2(spec.questionPattern, spec.questionFlags ?? "i");
|
|
@@ -15595,6 +15840,7 @@ function modalMatches(spec, input) {
|
|
|
15595
15840
|
const re = compile2(variant.regex, variant.flags ?? "i");
|
|
15596
15841
|
if (re.test(text)) return true;
|
|
15597
15842
|
}
|
|
15843
|
+
if (buttonBlockApprovalCue(spec, text)) return true;
|
|
15598
15844
|
return false;
|
|
15599
15845
|
}
|
|
15600
15846
|
function evaluateGroup(group, spec, input, compiled) {
|
|
@@ -15649,6 +15895,7 @@ var init_detect_status = __esm({
|
|
|
15649
15895
|
"src/providers/sdk/v1/builders/cli/detect-status.ts"() {
|
|
15650
15896
|
"use strict";
|
|
15651
15897
|
init_visible_region();
|
|
15898
|
+
init_approval_utils();
|
|
15652
15899
|
DEFAULT_ORDER = ["spinner", "modal", "settled-prompt"];
|
|
15653
15900
|
}
|
|
15654
15901
|
});
|
|
@@ -21194,6 +21441,7 @@ function getSavedProviderSessions(state, filters) {
|
|
|
21194
21441
|
|
|
21195
21442
|
// src/index.ts
|
|
21196
21443
|
init_mesh_config();
|
|
21444
|
+
init_dist();
|
|
21197
21445
|
init_coordinator_prompt();
|
|
21198
21446
|
init_mesh_missions();
|
|
21199
21447
|
init_mesh_task_stats();
|
|
@@ -25746,76 +25994,8 @@ function validateReadChatResultPayload(raw, source = "read_chat") {
|
|
|
25746
25994
|
return normalized;
|
|
25747
25995
|
}
|
|
25748
25996
|
|
|
25749
|
-
// src/providers/approval-utils.ts
|
|
25750
|
-
var DEFAULT_APPROVAL_POSITIVE_HINTS = [
|
|
25751
|
-
"yes",
|
|
25752
|
-
"allow once",
|
|
25753
|
-
"approve",
|
|
25754
|
-
"accept",
|
|
25755
|
-
"continue",
|
|
25756
|
-
"run",
|
|
25757
|
-
"proceed",
|
|
25758
|
-
"confirm",
|
|
25759
|
-
"save",
|
|
25760
|
-
"ok",
|
|
25761
|
-
"trust",
|
|
25762
|
-
"allow",
|
|
25763
|
-
"always allow"
|
|
25764
|
-
];
|
|
25765
|
-
function normalizeApprovalLabel(value) {
|
|
25766
|
-
return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
|
|
25767
|
-
}
|
|
25768
|
-
function isNegativeApprovalLabel(value) {
|
|
25769
|
-
const label = normalizeApprovalLabel(value);
|
|
25770
|
-
return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
|
|
25771
|
-
}
|
|
25772
|
-
function getApprovalPositiveHints(provider) {
|
|
25773
|
-
const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
|
|
25774
|
-
return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
|
|
25775
|
-
}
|
|
25776
|
-
function pickApprovalButton(buttons, provider) {
|
|
25777
|
-
const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
|
|
25778
|
-
if (labels.length === 0) {
|
|
25779
|
-
return { index: -1, label: "" };
|
|
25780
|
-
}
|
|
25781
|
-
const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
|
|
25782
|
-
const hints = getApprovalPositiveHints(provider);
|
|
25783
|
-
for (const hint of hints) {
|
|
25784
|
-
const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
|
|
25785
|
-
if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
|
|
25786
|
-
const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
|
|
25787
|
-
if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
|
|
25788
|
-
const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
|
|
25789
|
-
if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
|
|
25790
|
-
}
|
|
25791
|
-
return { index: -1, label: "" };
|
|
25792
|
-
}
|
|
25793
|
-
function pickAutoApprovalButton(buttons) {
|
|
25794
|
-
const labels = (buttons || []).map((button) => String(button || "").trim());
|
|
25795
|
-
const index = labels.findIndex(Boolean);
|
|
25796
|
-
return index >= 0 ? { index, label: labels[index] } : { index: -1, label: "" };
|
|
25797
|
-
}
|
|
25798
|
-
function formatAutoApprovalMessage(modalMessage, buttonLabel) {
|
|
25799
|
-
const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
|
|
25800
|
-
const cleanMessage = String(modalMessage || "").trim();
|
|
25801
|
-
if (cleanMessage) lines.push(cleanMessage);
|
|
25802
|
-
return lines.join("\n");
|
|
25803
|
-
}
|
|
25804
|
-
function looksLikeActiveApprovalPromptText(content) {
|
|
25805
|
-
const text = content.trim();
|
|
25806
|
-
if (!text || text.length > 2e3) return false;
|
|
25807
|
-
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);
|
|
25808
|
-
const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text) || /^\s*1[.)]\s+yes\b/im.test(text);
|
|
25809
|
-
if (hasApprovalQuestion && hasNumberedChoices) return true;
|
|
25810
|
-
const lastLines = text.split(/\r?\n/).slice(-12).join("\n");
|
|
25811
|
-
const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines) || /yes.*always allow/i.test(lastLines);
|
|
25812
|
-
const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
|
|
25813
|
-
if (hasDontAskAgain && hasNoOption) return true;
|
|
25814
|
-
if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
|
|
25815
|
-
return false;
|
|
25816
|
-
}
|
|
25817
|
-
|
|
25818
25997
|
// src/providers/ide-provider-instance.ts
|
|
25998
|
+
init_approval_utils();
|
|
25819
25999
|
init_provider_patch_state();
|
|
25820
26000
|
init_chat_message_normalization();
|
|
25821
26001
|
init_open_panel_support();
|
|
@@ -26899,6 +27079,7 @@ import * as fs7 from "fs";
|
|
|
26899
27079
|
import * as os10 from "os";
|
|
26900
27080
|
import * as path16 from "path";
|
|
26901
27081
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
27082
|
+
init_approval_utils();
|
|
26902
27083
|
init_coordinator_registry();
|
|
26903
27084
|
init_logger();
|
|
26904
27085
|
|
|
@@ -34887,6 +35068,7 @@ function createCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFact
|
|
|
34887
35068
|
// src/providers/cli-provider-instance.ts
|
|
34888
35069
|
init_logger();
|
|
34889
35070
|
init_control_effects();
|
|
35071
|
+
init_approval_utils();
|
|
34890
35072
|
init_provider_patch_state();
|
|
34891
35073
|
|
|
34892
35074
|
// src/providers/provider-session-id.ts
|
|
@@ -35148,6 +35330,20 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
35148
35330
|
* keystroke until the modal *content* has settled.
|
|
35149
35331
|
*/
|
|
35150
35332
|
static AUTO_APPROVE_SETTLE_MS = 600;
|
|
35333
|
+
/**
|
|
35334
|
+
* Busy-side hysteresis for the settle gate. A momentary `generating` flip
|
|
35335
|
+
* while the SAME approval modal's button block is still on screen (its
|
|
35336
|
+
* question line scrolled out of the captured frame, only the buttons + a
|
|
35337
|
+
* residual `esc to interrupt` spinner remain) briefly reports
|
|
35338
|
+
* status!=waiting_approval. Without hysteresis that flip wipes the settle
|
|
35339
|
+
* clock, and the modal→generating→modal flap restarts the 600ms window
|
|
35340
|
+
* every time so auto-approve never fires. We keep the in-progress settle
|
|
35341
|
+
* gate warm across an inactive blip up to this bound; only once the modal
|
|
35342
|
+
* has genuinely stayed gone this long (a real resolution → idle) is the
|
|
35343
|
+
* gate cleared. Bounded so a genuinely new, later approval still re-settles
|
|
35344
|
+
* from scratch rather than firing on a stale timestamp.
|
|
35345
|
+
*/
|
|
35346
|
+
static AUTO_APPROVE_GATE_HYSTERESIS_MS = 1500;
|
|
35151
35347
|
adapter;
|
|
35152
35348
|
context = null;
|
|
35153
35349
|
events = [];
|
|
@@ -35169,6 +35365,10 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
35169
35365
|
pendingAutoApprovalSignature = "";
|
|
35170
35366
|
pendingAutoApprovalSince = 0;
|
|
35171
35367
|
autoApproveSettleTimer = null;
|
|
35368
|
+
// Wall-clock when auto-approve first observed status!=waiting_approval while
|
|
35369
|
+
// a settle gate was in progress. Drives AUTO_APPROVE_GATE_HYSTERESIS_MS so a
|
|
35370
|
+
// brief generating flip does not immediately wipe the settle clock.
|
|
35371
|
+
autoApproveInactiveSince = 0;
|
|
35172
35372
|
controlValues = {};
|
|
35173
35373
|
summaryMetadata = void 0;
|
|
35174
35374
|
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
@@ -35989,14 +36189,28 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
35989
36189
|
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
|
|
35990
36190
|
if (!autoApproveActive) {
|
|
35991
36191
|
this.lastAutoApprovalSignature = "";
|
|
36192
|
+
if (this.pendingAutoApprovalSince) {
|
|
36193
|
+
if (!this.autoApproveInactiveSince) this.autoApproveInactiveSince = now;
|
|
36194
|
+
const goneForMs = now - this.autoApproveInactiveSince;
|
|
36195
|
+
if (goneForMs < _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS) {
|
|
36196
|
+
if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
|
|
36197
|
+
this.autoApproveSettleTimer = setTimeout(() => {
|
|
36198
|
+
this.autoApproveSettleTimer = null;
|
|
36199
|
+
this.recheckAutoApproveSettled();
|
|
36200
|
+
}, _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS - goneForMs + 20);
|
|
36201
|
+
return autoApproveActive;
|
|
36202
|
+
}
|
|
36203
|
+
}
|
|
35992
36204
|
this.pendingAutoApprovalSignature = "";
|
|
35993
36205
|
this.pendingAutoApprovalSince = 0;
|
|
36206
|
+
this.autoApproveInactiveSince = 0;
|
|
35994
36207
|
if (this.autoApproveSettleTimer) {
|
|
35995
36208
|
clearTimeout(this.autoApproveSettleTimer);
|
|
35996
36209
|
this.autoApproveSettleTimer = null;
|
|
35997
36210
|
}
|
|
35998
36211
|
return autoApproveActive;
|
|
35999
36212
|
}
|
|
36213
|
+
this.autoApproveInactiveSince = 0;
|
|
36000
36214
|
const modal = adapterStatus.activeModal;
|
|
36001
36215
|
const buttons = Array.isArray(modal?.buttons) ? modal.buttons.map((b) => String(b || "").trim()).filter(Boolean) : [];
|
|
36002
36216
|
if (!modal || buttons.length === 0) {
|
|
@@ -36006,18 +36220,18 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36006
36220
|
if (buttonIndex < 0) {
|
|
36007
36221
|
return autoApproveActive;
|
|
36008
36222
|
}
|
|
36009
|
-
const
|
|
36010
|
-
const signature = [
|
|
36011
|
-
approvalEntrySeq,
|
|
36223
|
+
const modalSignature = [
|
|
36012
36224
|
typeof modal?.message === "string" ? modal.message.trim() : "",
|
|
36013
36225
|
buttons.join("|"),
|
|
36014
36226
|
buttonIndex
|
|
36015
36227
|
].join("::");
|
|
36016
|
-
|
|
36228
|
+
const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
|
|
36229
|
+
const busySignature = `${approvalEntrySeq}::${modalSignature}`;
|
|
36230
|
+
if (this.autoApproveBusy && busySignature === this.lastAutoApprovalSignature) {
|
|
36017
36231
|
return autoApproveActive;
|
|
36018
36232
|
}
|
|
36019
|
-
if (
|
|
36020
|
-
this.pendingAutoApprovalSignature =
|
|
36233
|
+
if (modalSignature !== this.pendingAutoApprovalSignature) {
|
|
36234
|
+
this.pendingAutoApprovalSignature = modalSignature;
|
|
36021
36235
|
this.pendingAutoApprovalSince = now;
|
|
36022
36236
|
}
|
|
36023
36237
|
const settledForMs = now - this.pendingAutoApprovalSince;
|
|
@@ -36034,9 +36248,10 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36034
36248
|
this.autoApproveSettleTimer = null;
|
|
36035
36249
|
}
|
|
36036
36250
|
this.autoApproveBusy = true;
|
|
36037
|
-
this.lastAutoApprovalSignature =
|
|
36251
|
+
this.lastAutoApprovalSignature = busySignature;
|
|
36038
36252
|
this.pendingAutoApprovalSignature = "";
|
|
36039
36253
|
this.pendingAutoApprovalSince = 0;
|
|
36254
|
+
this.autoApproveInactiveSince = 0;
|
|
36040
36255
|
if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
|
|
36041
36256
|
this.autoApproveBusyTimer = setTimeout(() => {
|
|
36042
36257
|
this.autoApproveBusy = false;
|
|
@@ -38823,9 +39038,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
38823
39038
|
}
|
|
38824
39039
|
}
|
|
38825
39040
|
}
|
|
38826
|
-
|
|
38827
|
-
|
|
38828
|
-
|
|
39041
|
+
if (!opts?.instanceKey) {
|
|
39042
|
+
for (const [k, a] of this.adapters) {
|
|
39043
|
+
if (a.cliType === agentType) {
|
|
39044
|
+
return { adapter: a, key: k };
|
|
39045
|
+
}
|
|
38829
39046
|
}
|
|
38830
39047
|
}
|
|
38831
39048
|
return null;
|
|
@@ -42928,7 +43145,8 @@ init_logger();
|
|
|
42928
43145
|
import * as fs23 from "fs";
|
|
42929
43146
|
import * as path35 from "path";
|
|
42930
43147
|
import * as os26 from "os";
|
|
42931
|
-
var
|
|
43148
|
+
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");
|
|
43149
|
+
var LOG_DIR2 = path35.join(ADHDEV_HOME2, "logs");
|
|
42932
43150
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
42933
43151
|
var MAX_DAYS = 7;
|
|
42934
43152
|
try {
|
|
@@ -43783,13 +44001,14 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
43783
44001
|
}
|
|
43784
44002
|
}
|
|
43785
44003
|
}
|
|
43786
|
-
function stopSessionHostProcesses(appName) {
|
|
44004
|
+
async function stopSessionHostProcesses(appName) {
|
|
43787
44005
|
const pidFile = path36.join(os27.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
44006
|
+
let killedPid = null;
|
|
43788
44007
|
try {
|
|
43789
44008
|
if (fs25.existsSync(pidFile)) {
|
|
43790
44009
|
const pid = Number.parseInt(fs25.readFileSync(pidFile, "utf8").trim(), 10);
|
|
43791
44010
|
if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
|
|
43792
|
-
killPid(pid);
|
|
44011
|
+
if (killPid(pid)) killedPid = pid;
|
|
43793
44012
|
}
|
|
43794
44013
|
}
|
|
43795
44014
|
} catch {
|
|
@@ -43799,6 +44018,15 @@ function stopSessionHostProcesses(appName) {
|
|
|
43799
44018
|
} catch {
|
|
43800
44019
|
}
|
|
43801
44020
|
}
|
|
44021
|
+
if (killedPid !== null) {
|
|
44022
|
+
await waitForPidExit(killedPid, 15e3);
|
|
44023
|
+
}
|
|
44024
|
+
}
|
|
44025
|
+
function isRetriableInstallLockError(error) {
|
|
44026
|
+
const code = error?.code;
|
|
44027
|
+
if (code === "EBUSY" || code === "EPERM") return true;
|
|
44028
|
+
const text = `${error?.message || ""} ${error?.stderr || ""}`;
|
|
44029
|
+
return /\bEBUSY\b|\bEPERM\b|resource busy or locked/i.test(text);
|
|
43802
44030
|
}
|
|
43803
44031
|
function removeDaemonPidFile() {
|
|
43804
44032
|
const pidFile = path36.join(os27.homedir(), ".adhdev", "daemon.pid");
|
|
@@ -43878,22 +44106,37 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
43878
44106
|
appendUpgradeLog(`Waiting for parent pid ${payload.parentPid} to exit`);
|
|
43879
44107
|
await waitForPidExit(payload.parentPid, 15e3);
|
|
43880
44108
|
}
|
|
43881
|
-
stopSessionHostProcesses(sessionHostAppName);
|
|
44109
|
+
await stopSessionHostProcesses(sessionHostAppName);
|
|
43882
44110
|
removeDaemonPidFile();
|
|
43883
44111
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
43884
44112
|
const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
|
|
43885
44113
|
appendUpgradeLog(`Installing ${spec}`);
|
|
43886
|
-
const
|
|
43887
|
-
|
|
43888
|
-
|
|
43889
|
-
{
|
|
43890
|
-
|
|
43891
|
-
|
|
43892
|
-
|
|
43893
|
-
|
|
43894
|
-
|
|
44114
|
+
const maxInstallAttempts = process.platform === "win32" ? 3 : 1;
|
|
44115
|
+
let installOutput = "";
|
|
44116
|
+
for (let attempt = 1; attempt <= maxInstallAttempts; attempt++) {
|
|
44117
|
+
try {
|
|
44118
|
+
installOutput = String(execFileSync5(
|
|
44119
|
+
installCommand.command,
|
|
44120
|
+
installCommand.args,
|
|
44121
|
+
{
|
|
44122
|
+
encoding: "utf8",
|
|
44123
|
+
stdio: "pipe",
|
|
44124
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
44125
|
+
env: buildInstallEnvWithNodeOnPath(),
|
|
44126
|
+
...installCommand.execOptions
|
|
44127
|
+
}
|
|
44128
|
+
));
|
|
44129
|
+
break;
|
|
44130
|
+
} catch (error) {
|
|
44131
|
+
if (attempt < maxInstallAttempts && isRetriableInstallLockError(error)) {
|
|
44132
|
+
appendUpgradeLog(`Install attempt ${attempt} hit a file lock (${error?.code || "lock"}); cleaning staging and retrying after backoff`);
|
|
44133
|
+
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
44134
|
+
await new Promise((resolve24) => setTimeout(resolve24, attempt * 1500));
|
|
44135
|
+
continue;
|
|
44136
|
+
}
|
|
44137
|
+
throw error;
|
|
43895
44138
|
}
|
|
43896
|
-
|
|
44139
|
+
}
|
|
43897
44140
|
if (installOutput.trim()) {
|
|
43898
44141
|
appendUpgradeLog(installOutput.trim());
|
|
43899
44142
|
}
|
|
@@ -46156,7 +46399,14 @@ var MESH_FORWARDABLE_SESSION_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
46156
46399
|
"resolve_action",
|
|
46157
46400
|
"set_mode",
|
|
46158
46401
|
"change_model",
|
|
46159
|
-
"set_thought_level"
|
|
46402
|
+
"set_thought_level",
|
|
46403
|
+
// agent_command (send_chat / clear_history / stop) is session-scoped too: a command
|
|
46404
|
+
// explicitly naming a targetSessionId MUST reach that session wherever it lives, never a
|
|
46405
|
+
// different local session. Without forwarding, a misrouted/relayed send_chat for a REMOTE
|
|
46406
|
+
// worker session that reaches the wrong daemon used to fuzzy-inject the task body into that
|
|
46407
|
+
// daemon's own CLI session (TASKECHO coordinator self-echo). Forwarding to the owning daemon
|
|
46408
|
+
// delivers it to the real worker instead. (findAdapter is also fail-closed as the backstop.)
|
|
46409
|
+
"agent_command"
|
|
46160
46410
|
]);
|
|
46161
46411
|
var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
|
|
46162
46412
|
function normalizeCommandSource(source) {
|
|
@@ -46509,7 +46759,7 @@ var DaemonCommandRouter = class {
|
|
|
46509
46759
|
if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
|
|
46510
46760
|
const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
|
|
46511
46761
|
if (!nodeDaemonId) continue;
|
|
46512
|
-
if (selfDaemonId && nodeDaemonId
|
|
46762
|
+
if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
|
|
46513
46763
|
return nodeDaemonId;
|
|
46514
46764
|
}
|
|
46515
46765
|
return void 0;
|
|
@@ -46664,6 +46914,38 @@ var DaemonCommandRouter = class {
|
|
|
46664
46914
|
if (record?.meta?.meshNodeId === nodeId) return true;
|
|
46665
46915
|
return false;
|
|
46666
46916
|
}
|
|
46917
|
+
/**
|
|
46918
|
+
* Best-effort recursive removal of a managed worktree directory.
|
|
46919
|
+
*
|
|
46920
|
+
* The git-registry de-registration is the safety-critical step of worktree
|
|
46921
|
+
* teardown; a leftover directory must never gate dropping the node from the
|
|
46922
|
+
* mesh. On Windows, `fs.rmSync` can throw EINVAL/EPERM/EBUSY on submodule
|
|
46923
|
+
* gitlink (`.git`) files, long paths, junctions, or while a just-stopped
|
|
46924
|
+
* delegate session is still releasing a handle/cwd on the directory. This
|
|
46925
|
+
* helper absorbs those errors (never throws), with bounded retries + backoff
|
|
46926
|
+
* to give handles time to release, and reports whether residue remains.
|
|
46927
|
+
*/
|
|
46928
|
+
async bestEffortRemoveWorktreeDir(dir) {
|
|
46929
|
+
if (!dir || !fs26.existsSync(dir)) return { removed: true, residue: false };
|
|
46930
|
+
const sleep3 = (ms) => new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
46931
|
+
const ABSORB = /* @__PURE__ */ new Set(["EINVAL", "EPERM", "EBUSY", "ENOTEMPTY", "EACCES", "EMFILE", "ENFILE"]);
|
|
46932
|
+
let lastErr;
|
|
46933
|
+
for (let attempt = 0; attempt < 4; attempt++) {
|
|
46934
|
+
try {
|
|
46935
|
+
fs26.rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
46936
|
+
if (!fs26.existsSync(dir)) return { removed: true, residue: false };
|
|
46937
|
+
lastErr = new Error("directory still present after rmSync");
|
|
46938
|
+
} catch (e) {
|
|
46939
|
+
lastErr = e;
|
|
46940
|
+
const code = typeof e?.code === "string" ? e.code : "";
|
|
46941
|
+
if (code && !ABSORB.has(code)) {
|
|
46942
|
+
break;
|
|
46943
|
+
}
|
|
46944
|
+
}
|
|
46945
|
+
await sleep3(150 * (attempt + 1));
|
|
46946
|
+
}
|
|
46947
|
+
return fs26.existsSync(dir) ? { removed: false, residue: true, error: String(lastErr?.message || lastErr || "unknown rm error") } : { removed: true, residue: false };
|
|
46948
|
+
}
|
|
46667
46949
|
async cleanupLocalWorktreeNode(args) {
|
|
46668
46950
|
const workspace = typeof args.node?.workspace === "string" ? args.node.workspace.trim() : "";
|
|
46669
46951
|
if (!workspace) {
|
|
@@ -46718,11 +47000,31 @@ var DaemonCommandRouter = class {
|
|
|
46718
47000
|
const entries = await listWorktrees2(repoRoot);
|
|
46719
47001
|
const managedEntry = entries.find((entry) => normalizePath(entry.path) === actualPath);
|
|
46720
47002
|
if (!managedEntry) {
|
|
47003
|
+
try {
|
|
47004
|
+
const { execFile: execFile5 } = await import("child_process");
|
|
47005
|
+
const { promisify: promisify8 } = await import("util");
|
|
47006
|
+
const execFileAsync4 = promisify8(execFile5);
|
|
47007
|
+
await execFileAsync4("git", ["worktree", "prune"], {
|
|
47008
|
+
cwd: repoRoot,
|
|
47009
|
+
encoding: "utf8",
|
|
47010
|
+
timeout: 3e4,
|
|
47011
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
47012
|
+
windowsHide: true
|
|
47013
|
+
});
|
|
47014
|
+
} catch {
|
|
47015
|
+
}
|
|
47016
|
+
const rm = await this.bestEffortRemoveWorktreeDir(workspace);
|
|
46721
47017
|
return {
|
|
46722
|
-
success:
|
|
46723
|
-
|
|
46724
|
-
|
|
46725
|
-
|
|
47018
|
+
success: true,
|
|
47019
|
+
removedPath: workspace,
|
|
47020
|
+
repoRoot,
|
|
47021
|
+
reason: "worktree_unregistered_residue_recovered",
|
|
47022
|
+
recovered: true,
|
|
47023
|
+
...rm.residue ? {
|
|
47024
|
+
residue: true,
|
|
47025
|
+
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.`,
|
|
47026
|
+
residueError: rm.error
|
|
47027
|
+
} : {}
|
|
46726
47028
|
};
|
|
46727
47029
|
}
|
|
46728
47030
|
if (managedEntry.branch && managedEntry.branch !== args.node.worktreeBranch) {
|
|
@@ -46785,8 +47087,8 @@ var DaemonCommandRouter = class {
|
|
|
46785
47087
|
convergence: forceFallbackConvergence
|
|
46786
47088
|
};
|
|
46787
47089
|
} catch (deinitError) {
|
|
47090
|
+
const rm = await this.bestEffortRemoveWorktreeDir(workspace);
|
|
46788
47091
|
try {
|
|
46789
|
-
fs26.rmSync(workspace, { recursive: true, force: true });
|
|
46790
47092
|
await execFileAsync4("git", ["worktree", "prune"], {
|
|
46791
47093
|
cwd: repoRoot,
|
|
46792
47094
|
encoding: "utf8",
|
|
@@ -46794,23 +47096,22 @@ var DaemonCommandRouter = class {
|
|
|
46794
47096
|
maxBuffer: GIT_MAX_BUFFER_CLEANUP,
|
|
46795
47097
|
windowsHide: true
|
|
46796
47098
|
});
|
|
46797
|
-
|
|
46798
|
-
success: true,
|
|
46799
|
-
removedPath: workspace,
|
|
46800
|
-
repoRoot,
|
|
46801
|
-
fallback: "fs_rm_worktree_prune",
|
|
46802
|
-
forced: true,
|
|
46803
|
-
reason: "working_trees_containing_submodules",
|
|
46804
|
-
convergence: forceFallbackConvergence
|
|
46805
|
-
};
|
|
46806
|
-
} catch (rmError) {
|
|
46807
|
-
return {
|
|
46808
|
-
success: false,
|
|
46809
|
-
code: "mesh_worktree_cleanup_failed",
|
|
46810
|
-
error: `All removal fallbacks exhausted. deinit+remove: ${deinitError?.message || deinitError}; rmSync+prune: ${rmError?.message || rmError}`,
|
|
46811
|
-
recoveryHint: "Manually remove the worktree directory and run git worktree prune from the source repo."
|
|
46812
|
-
};
|
|
47099
|
+
} catch {
|
|
46813
47100
|
}
|
|
47101
|
+
return {
|
|
47102
|
+
success: true,
|
|
47103
|
+
removedPath: workspace,
|
|
47104
|
+
repoRoot,
|
|
47105
|
+
fallback: "fs_rm_worktree_prune",
|
|
47106
|
+
forced: true,
|
|
47107
|
+
reason: "working_trees_containing_submodules",
|
|
47108
|
+
convergence: forceFallbackConvergence,
|
|
47109
|
+
...rm.residue ? {
|
|
47110
|
+
residue: true,
|
|
47111
|
+
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.`,
|
|
47112
|
+
residueError: rm.error
|
|
47113
|
+
} : {}
|
|
47114
|
+
};
|
|
46814
47115
|
}
|
|
46815
47116
|
}
|
|
46816
47117
|
return {
|
|
@@ -50209,7 +50510,14 @@ ${hintLines.join("\n")}` : "",
|
|
|
50209
50510
|
} catch {
|
|
50210
50511
|
}
|
|
50211
50512
|
}
|
|
50212
|
-
|
|
50513
|
+
const residueWarning = worktreeCleanup?.residue === true && typeof worktreeCleanup?.residueWarning === "string" ? worktreeCleanup.residueWarning : void 0;
|
|
50514
|
+
return {
|
|
50515
|
+
success: true,
|
|
50516
|
+
removed,
|
|
50517
|
+
...residueWarning ? { residueWarning } : {},
|
|
50518
|
+
...sessionCleanup ? { sessionCleanup } : {},
|
|
50519
|
+
...worktreeCleanup ? { worktreeCleanup } : {}
|
|
50520
|
+
};
|
|
50213
50521
|
} catch (e) {
|
|
50214
50522
|
return { success: false, error: e.message };
|
|
50215
50523
|
}
|
|
@@ -52655,6 +52963,7 @@ var DaemonAgentStreamManager = class {
|
|
|
52655
52963
|
|
|
52656
52964
|
// src/agent-stream/poller.ts
|
|
52657
52965
|
init_logger();
|
|
52966
|
+
init_approval_utils();
|
|
52658
52967
|
init_chat_message_normalization();
|
|
52659
52968
|
var AgentStreamPoller = class {
|
|
52660
52969
|
deps;
|
|
@@ -60208,6 +60517,7 @@ export {
|
|
|
60208
60517
|
createNativeHistoryDispatcher,
|
|
60209
60518
|
createSessionDelivery,
|
|
60210
60519
|
createWorktree,
|
|
60520
|
+
daemonIdsEquivalent,
|
|
60211
60521
|
deleteDirectDispatchesByTaskId,
|
|
60212
60522
|
deleteMesh,
|
|
60213
60523
|
deriveMeshReviewInboxItems,
|
|
@@ -60221,6 +60531,7 @@ export {
|
|
|
60221
60531
|
ensureSessionHostReady,
|
|
60222
60532
|
evaluateFsm,
|
|
60223
60533
|
execNpmCommandSync,
|
|
60534
|
+
expandDaemonIdForms,
|
|
60224
60535
|
fastForwardMeshNode,
|
|
60225
60536
|
filterActivityChatMessages,
|
|
60226
60537
|
filterChatMessagesByVisibility,
|
|
@@ -60311,6 +60622,7 @@ export {
|
|
|
60311
60622
|
loadMeshWorktreeBootstrapConfig,
|
|
60312
60623
|
loadState,
|
|
60313
60624
|
logCommand,
|
|
60625
|
+
machineCoreFromDaemonId,
|
|
60314
60626
|
markSessionDeliveriesTerminal,
|
|
60315
60627
|
markSetupComplete,
|
|
60316
60628
|
markStaleDirectDispatches,
|