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