@adhdev/daemon-standalone 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
@@ -30036,10 +30036,10 @@ var require_dist3 = __commonJS({
30036
30036
  }
30037
30037
  function getDaemonBuildInfo() {
30038
30038
  if (cached2) return cached2;
30039
- const commit = readInjected(true ? "dad22ef2758130d10a3d55e3c419f0095d5e44b7" : void 0) ?? "unknown";
30040
- const commitShort = readInjected(true ? "dad22ef2" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
30041
- const version2 = readInjected(true ? "0.9.82-rc.351" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
30042
- const builtAt = readInjected(true ? "2026-06-22T04:05:27.792Z" : void 0);
30039
+ const commit = readInjected(true ? "a680b74d9b940b82f691ebb85a725a1a72445bfc" : void 0) ?? "unknown";
30040
+ const commitShort = readInjected(true ? "a680b74d" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
30041
+ const version2 = readInjected(true ? "0.9.82-rc.353" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
30042
+ const builtAt = readInjected(true ? "2026-06-22T09:11:41.749Z" : void 0);
30043
30043
  cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
30044
30044
  return cached2;
30045
30045
  }
@@ -32442,6 +32442,255 @@ ${error48.message || ""}`;
32442
32442
  SPAWNED_SESSION_VISIBILITY_MODES = /* @__PURE__ */ new Set(["visible", "hidden"]);
32443
32443
  }
32444
32444
  });
32445
+ function readRecord(value) {
32446
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
32447
+ }
32448
+ function readString3(...values) {
32449
+ for (const value of values) {
32450
+ if (typeof value !== "string") continue;
32451
+ const trimmed = value.trim();
32452
+ if (trimmed) return trimmed;
32453
+ }
32454
+ return void 0;
32455
+ }
32456
+ function readNumber(...values) {
32457
+ for (const value of values) {
32458
+ if (typeof value === "number" && Number.isFinite(value)) return value;
32459
+ }
32460
+ return void 0;
32461
+ }
32462
+ function readBoolean(...values) {
32463
+ for (const value of values) {
32464
+ if (typeof value === "boolean") return value;
32465
+ }
32466
+ return void 0;
32467
+ }
32468
+ function joinRepoPath(root, relativePath) {
32469
+ const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
32470
+ const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
32471
+ if (!normalizedPath) return void 0;
32472
+ if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
32473
+ if (!normalizedRoot) return void 0;
32474
+ return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
32475
+ }
32476
+ function scoreGitUpstreamFreshness(status) {
32477
+ switch (status) {
32478
+ case "fresh":
32479
+ return 30;
32480
+ case "no_upstream":
32481
+ return 4;
32482
+ case "unchecked":
32483
+ case void 0:
32484
+ return 0;
32485
+ case "stale":
32486
+ return -10;
32487
+ case "unavailable":
32488
+ return -15;
32489
+ default:
32490
+ return 0;
32491
+ }
32492
+ }
32493
+ function readGitSubmodules(value, parentRepoRoot) {
32494
+ if (!Array.isArray(value)) return void 0;
32495
+ const submodules = value.map((entry) => {
32496
+ const submodule = readRecord(entry);
32497
+ const path422 = readString3(submodule.path);
32498
+ const commit = readString3(submodule.commit);
32499
+ const repoPath = readString3(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path422);
32500
+ if (!path422 || !commit) return null;
32501
+ const result = {
32502
+ path: path422,
32503
+ commit,
32504
+ dirty: readBoolean(submodule.dirty) ?? false,
32505
+ outOfSync: readBoolean(submodule.outOfSync, submodule.out_of_sync) ?? false,
32506
+ lastCheckedAt: readNumber(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now()
32507
+ };
32508
+ if (repoPath) result.repoPath = repoPath;
32509
+ const error48 = readString3(submodule.error);
32510
+ if (error48) result.error = error48;
32511
+ return result;
32512
+ }).filter((entry) => entry !== null);
32513
+ return submodules.length > 0 ? submodules : void 0;
32514
+ }
32515
+ function hasGitStatusEvidence(status) {
32516
+ 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(
32517
+ status.ahead,
32518
+ status.behind,
32519
+ status.staged,
32520
+ status.modified,
32521
+ status.untracked,
32522
+ status.deleted,
32523
+ status.renamed,
32524
+ status.lastCheckedAt,
32525
+ status.last_checked_at
32526
+ ) !== void 0 || Array.isArray(status.submodules) && status.submodules.length > 0;
32527
+ }
32528
+ function normalizeGitStatus(status, node, options) {
32529
+ const explicitIsGitRepo = readBoolean(status.isGitRepo);
32530
+ if (!Object.keys(status).length || !hasGitStatusEvidence(status)) return void 0;
32531
+ const isGitRepo = explicitIsGitRepo ?? true;
32532
+ const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((entry) => typeof entry === "string") : [];
32533
+ const conflictCount = readNumber(status.conflicts) ?? conflictFiles.length;
32534
+ const hasConflicts = readBoolean(status.hasConflicts) ?? conflictCount > 0;
32535
+ const repoRoot = readString3(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
32536
+ const submodules = readGitSubmodules(status.submodules, repoRoot);
32537
+ const upstreamStatus = readString3(status.upstreamStatus, status.upstream_status);
32538
+ const upstreamFetchedAt = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
32539
+ const upstreamFetchError = readString3(status.upstreamFetchError, status.upstream_fetch_error);
32540
+ const error48 = readString3(status.error);
32541
+ const staged = readNumber(status.staged) ?? 0;
32542
+ const modified = readNumber(status.modified) ?? 0;
32543
+ const untracked = readNumber(status.untracked) ?? 0;
32544
+ const deleted = readNumber(status.deleted) ?? 0;
32545
+ const renamed = readNumber(status.renamed) ?? 0;
32546
+ return {
32547
+ workspace: readString3(status.workspace, node.workspace) || "",
32548
+ repoRoot: repoRoot ?? null,
32549
+ isGitRepo,
32550
+ branch: readString3(status.branch) ?? null,
32551
+ headCommit: readString3(status.headCommit) ?? null,
32552
+ headMessage: readString3(status.headMessage) ?? null,
32553
+ upstream: readString3(status.upstream) ?? null,
32554
+ upstreamStatus: upstreamStatus ?? "unchecked",
32555
+ ...upstreamFetchedAt !== void 0 ? { upstreamFetchedAt } : {},
32556
+ ...upstreamFetchError ? { upstreamFetchError } : {},
32557
+ ahead: readNumber(status.ahead) ?? 0,
32558
+ behind: readNumber(status.behind) ?? 0,
32559
+ staged,
32560
+ modified,
32561
+ untracked,
32562
+ deleted,
32563
+ renamed,
32564
+ dirty: readBoolean(status.dirty, status.isDirty, status.is_dirty) ?? (staged + modified + untracked + deleted + renamed > 0 || hasConflicts),
32565
+ hasConflicts,
32566
+ conflictFiles,
32567
+ stashCount: readNumber(status.stashCount, status.stash_count) ?? 0,
32568
+ lastCheckedAt: options?.lastCheckedAt ?? readNumber(status.lastCheckedAt, status.last_checked_at) ?? Date.now(),
32569
+ ...submodules ? { submodules } : {},
32570
+ ...error48 ? { error: error48 } : {}
32571
+ };
32572
+ }
32573
+ function scoreGitStatusCandidate(git) {
32574
+ if (!git) return Number.NEGATIVE_INFINITY;
32575
+ let score = 0;
32576
+ if (git.isGitRepo === true) score += 50;
32577
+ if (git.isGitRepo === false) score -= 10;
32578
+ if (git.branch) score += 20;
32579
+ if (git.headCommit) score += 20;
32580
+ if (git.upstream) score += 10;
32581
+ score += scoreGitUpstreamFreshness(git.upstreamStatus);
32582
+ if (typeof git.ahead === "number") score += 2;
32583
+ if (typeof git.behind === "number") score += 2;
32584
+ if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
32585
+ if (git.error) score -= 20;
32586
+ return score;
32587
+ }
32588
+ function pickBestTransitGitStatus(node, options) {
32589
+ const rawGit = readRecord(node.lastGit ?? node.last_git);
32590
+ const gitResult = readRecord(rawGit.result);
32591
+ const directStatus = readRecord(rawGit.status);
32592
+ const nestedStatus = readRecord(gitResult.status);
32593
+ const rawProbe = readRecord(node.lastProbe ?? node.last_probe);
32594
+ const probeGit = readRecord(rawProbe.git);
32595
+ const probeGitResult = readRecord(probeGit.result);
32596
+ const probeDirectStatus = readRecord(probeGit.status);
32597
+ const probeNestedStatus = readRecord(probeGitResult.status);
32598
+ const lastCheckedAt = options?.lastCheckedAt;
32599
+ let best = null;
32600
+ for (const status of [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus]) {
32601
+ const normalized = normalizeGitStatus(status, node, { lastCheckedAt: lastCheckedAt ?? Date.now() });
32602
+ if (!normalized) continue;
32603
+ const score = scoreGitStatusCandidate(normalized);
32604
+ if (!best || score > best.score) best = { git: normalized, score };
32605
+ }
32606
+ return best?.git;
32607
+ }
32608
+ function normalizeMeshNodeId(node) {
32609
+ const record2 = node && typeof node === "object" ? node : {};
32610
+ return readString3(record2.id, record2.nodeId, record2.node_id);
32611
+ }
32612
+ function meshNodeIdMatches(node, candidateId) {
32613
+ if (!candidateId) return false;
32614
+ const trimmed = candidateId.trim();
32615
+ if (!trimmed) return false;
32616
+ return normalizeMeshNodeId(node) === trimmed;
32617
+ }
32618
+ function machineCoreFromDaemonId(id) {
32619
+ const trimmed = readString3(id);
32620
+ if (!trimmed) return void 0;
32621
+ for (const prefix of DAEMON_ID_PREFIXES) {
32622
+ if (trimmed.startsWith(prefix)) {
32623
+ const core = trimmed.slice(prefix.length).trim();
32624
+ return core || void 0;
32625
+ }
32626
+ }
32627
+ return trimmed;
32628
+ }
32629
+ function daemonIdsEquivalent(a, b) {
32630
+ const coreA = machineCoreFromDaemonId(a);
32631
+ const coreB = machineCoreFromDaemonId(b);
32632
+ if (!coreA || !coreB) return false;
32633
+ return coreA === coreB;
32634
+ }
32635
+ function expandDaemonIdForms(ids) {
32636
+ const list = Array.isArray(ids) ? ids : ids != null ? [ids] : [];
32637
+ const out = [];
32638
+ const seen = /* @__PURE__ */ new Set();
32639
+ const add = (value) => {
32640
+ if (!value || seen.has(value)) return;
32641
+ seen.add(value);
32642
+ out.push(value);
32643
+ };
32644
+ for (const raw of list) add(readString3(raw));
32645
+ for (const raw of list) {
32646
+ const core = machineCoreFromDaemonId(readString3(raw));
32647
+ if (!core || !core.startsWith("mach_")) continue;
32648
+ add(core);
32649
+ for (const prefix of DAEMON_ID_PREFIXES) add(`${prefix}${core}`);
32650
+ }
32651
+ return out;
32652
+ }
32653
+ function summarizeGitShape(status) {
32654
+ const record2 = readRecord(status);
32655
+ if (!Object.keys(record2).length) return null;
32656
+ const submodules = Array.isArray(record2.submodules) ? record2.submodules.map((entry) => {
32657
+ const sub = readRecord(entry);
32658
+ return {
32659
+ path: readString3(sub.path) ?? null,
32660
+ commit: readString3(sub.commit)?.slice(0, 12) ?? null,
32661
+ dirty: readBoolean(sub.dirty) ?? false,
32662
+ outOfSync: readBoolean(sub.outOfSync, sub.out_of_sync) ?? false
32663
+ };
32664
+ }) : [];
32665
+ return {
32666
+ isGitRepo: readBoolean(record2.isGitRepo),
32667
+ workspace: readString3(record2.workspace) ?? null,
32668
+ repoRoot: readString3(record2.repoRoot, record2.repo_root) ?? null,
32669
+ branch: readString3(record2.branch) ?? null,
32670
+ upstream: readString3(record2.upstream) ?? null,
32671
+ upstreamStatus: readString3(record2.upstreamStatus, record2.upstream_status) ?? null,
32672
+ headCommit: readString3(record2.headCommit, record2.head_commit)?.slice(0, 12) ?? null,
32673
+ ahead: readNumber(record2.ahead) ?? null,
32674
+ behind: readNumber(record2.behind) ?? null,
32675
+ dirtyCounts: {
32676
+ staged: readNumber(record2.staged) ?? 0,
32677
+ modified: readNumber(record2.modified) ?? 0,
32678
+ untracked: readNumber(record2.untracked) ?? 0,
32679
+ deleted: readNumber(record2.deleted) ?? 0,
32680
+ renamed: readNumber(record2.renamed) ?? 0
32681
+ },
32682
+ lastCheckedAt: readNumber(record2.lastCheckedAt, record2.last_checked_at) ?? null,
32683
+ submoduleCount: submodules.length,
32684
+ submodules
32685
+ };
32686
+ }
32687
+ var DAEMON_ID_PREFIXES;
32688
+ var init_dist = __esm2({
32689
+ "../mesh-shared/dist/index.mjs"() {
32690
+ "use strict";
32691
+ DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
32692
+ }
32693
+ });
32445
32694
  var coordinator_prompt_exports = {};
32446
32695
  __export2(coordinator_prompt_exports, {
32447
32696
  buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
@@ -32936,6 +33185,7 @@ Follow these recovery rules:
32936
33185
  var LEVEL_NUM;
32937
33186
  var LEVEL_LABEL;
32938
33187
  var currentLevel;
33188
+ var ADHDEV_HOME;
32939
33189
  var LOG_DIR;
32940
33190
  var MAX_LOG_SIZE;
32941
33191
  var MAX_LOG_DAYS;
@@ -32961,7 +33211,8 @@ Follow these recovery rules:
32961
33211
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
32962
33212
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
32963
33213
  currentLevel = "info";
32964
- LOG_DIR = process.platform === "win32" ? path9.join(process.env.LOCALAPPDATA || process.env.APPDATA || path9.join(os32.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path9.join(os32.homedir(), "Library", "Logs", "adhdev") : path9.join(os32.homedir(), ".local", "share", "adhdev", "logs");
33214
+ ADHDEV_HOME = process.env.ADHDEV_CONFIG_DIR && process.env.ADHDEV_CONFIG_DIR.trim() ? process.env.ADHDEV_CONFIG_DIR.trim() : path9.join(os32.homedir(), ".adhdev");
33215
+ LOG_DIR = path9.join(ADHDEV_HOME, "logs");
32965
33216
  MAX_LOG_SIZE = 5 * 1024 * 1024;
32966
33217
  MAX_LOG_DAYS = 7;
32967
33218
  try {
@@ -33774,6 +34025,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
33774
34025
  nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
33775
34026
  normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
33776
34027
  normalizeMeshTaskMode: () => normalizeMeshTaskMode,
34028
+ reclaimStrandedAssignedTask: () => reclaimStrandedAssignedTask,
33777
34029
  recordDirectDispatchTask: () => recordDirectDispatchTask,
33778
34030
  recordMeshToolCall: () => recordMeshToolCall,
33779
34031
  recordTaskAutoLaunch: () => recordTaskAutoLaunch,
@@ -34209,6 +34461,52 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
34209
34461
  return entry;
34210
34462
  });
34211
34463
  }
34464
+ function reclaimStrandedAssignedTask(meshId, taskId, opts) {
34465
+ requireMeshHostQueueOwner(opts);
34466
+ return withQueueLock(meshId, () => {
34467
+ const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
34468
+ if (!entry) return null;
34469
+ if (entry.status !== "assigned") return null;
34470
+ const now = (/* @__PURE__ */ new Date()).toISOString();
34471
+ const reason = opts?.reason || "assigned_stranded_dispatch_unconfirmed";
34472
+ const reclaims = (entry.strandedReclaimCount || 0) + 1;
34473
+ const prevNode = entry.assignedNodeId;
34474
+ const prevSession = entry.assignedSessionId;
34475
+ delete entry.assignedNodeId;
34476
+ delete entry.assignedSessionId;
34477
+ delete entry.assignedProviderType;
34478
+ delete entry.dispatchTimestamp;
34479
+ entry.strandedReclaimCount = reclaims;
34480
+ entry.updatedAt = now;
34481
+ if (reclaims > MAX_STRANDED_RECLAIMS) {
34482
+ entry.status = "failed";
34483
+ entry.cancelReason = `stranded_dispatch_unrecovered: reclaimed ${reclaims - 1} time(s) without a confirmed dispatch`;
34484
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
34485
+ propagateDependencyFailure(meshId, taskId);
34486
+ } else {
34487
+ entry.status = "pending";
34488
+ entry.requeuedAt = now;
34489
+ entry.requeueReason = reason;
34490
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
34491
+ }
34492
+ try {
34493
+ appendLedgerEntry(meshId, {
34494
+ kind: "task_reclaimed",
34495
+ nodeId: prevNode,
34496
+ sessionId: prevSession,
34497
+ payload: {
34498
+ taskId,
34499
+ reason,
34500
+ ...typeof opts?.ageMs === "number" ? { ageMs: opts.ageMs } : {},
34501
+ reclaimCount: reclaims,
34502
+ outcome: entry.status
34503
+ }
34504
+ });
34505
+ } catch {
34506
+ }
34507
+ return entry;
34508
+ });
34509
+ }
34212
34510
  function updateSessionTaskStatus(meshId, sessionId, status, opts) {
34213
34511
  return withQueueLock(meshId, () => {
34214
34512
  const store = MeshRuntimeStore.getInstance();
@@ -34332,6 +34630,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
34332
34630
  var GIT_MUTATION_SUBCOMMANDS;
34333
34631
  var GIT_STASH_READONLY_SUBCOMMANDS;
34334
34632
  var DEPENDENCY_FAILURE_TERMINALS;
34633
+ var MAX_STRANDED_RECLAIMS;
34335
34634
  var init_mesh_work_queue = __esm2({
34336
34635
  "src/mesh/mesh-work-queue.ts"() {
34337
34636
  "use strict";
@@ -34341,6 +34640,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
34341
34640
  init_mesh_runtime_store();
34342
34641
  init_mesh_config();
34343
34642
  init_logger();
34643
+ init_mesh_ledger();
34344
34644
  ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
34345
34645
  HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
34346
34646
  MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
@@ -34393,6 +34693,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
34393
34693
  ]);
34394
34694
  GIT_STASH_READONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["list", "show"]);
34395
34695
  DEPENDENCY_FAILURE_TERMINALS = /* @__PURE__ */ new Set(["failed", "cancelled"]);
34696
+ MAX_STRANDED_RECLAIMS = 3;
34396
34697
  }
34397
34698
  });
34398
34699
  function loadDatabaseCtor() {
@@ -35280,6 +35581,22 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
35280
35581
  updatedAt: r.updated_at
35281
35582
  }));
35282
35583
  }
35584
+ /**
35585
+ * Bug B watchdog support: true when at least one delivery record for the task has
35586
+ * reached a confirmed-handed-off status (delivered / acked / completed). The
35587
+ * assigned-stranded watchdog uses this to distinguish a dispatch that was never
35588
+ * confirmed (reclaimable) from one that WAS handed to the worker (a genuinely
35589
+ * in-flight or completion-lost task, which is PHASE 4's responsibility, not this
35590
+ * watchdog's). Indexed by (mesh_id, task_id).
35591
+ */
35592
+ taskHasConfirmedDelivery(meshId, taskId) {
35593
+ const row = this.db.prepare(`
35594
+ SELECT 1 FROM mesh_session_delivery
35595
+ WHERE mesh_id = ? AND task_id = ? AND status IN ('delivered','acked','completed')
35596
+ LIMIT 1
35597
+ `).get(meshId, taskId);
35598
+ return !!row;
35599
+ }
35283
35600
  expireStaleSessionDeliveries(meshId) {
35284
35601
  const now = (/* @__PURE__ */ new Date()).toISOString();
35285
35602
  this.db.prepare(`
@@ -36025,10 +36342,10 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
36025
36342
  COMPACT_STATUS_GOAL_PREVIEW_MAX = 80;
36026
36343
  }
36027
36344
  });
36028
- function readString3(value) {
36345
+ function readString4(value) {
36029
36346
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
36030
36347
  }
36031
- function readRecord(value) {
36348
+ function readRecord2(value) {
36032
36349
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
36033
36350
  }
36034
36351
  function eventStatus(event, fallback) {
@@ -36051,7 +36368,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
36051
36368
  return "Refine job failed; inspect result/finalBranchConvergenceState in mesh_task_history, fix the blocker, then rerun mesh_refine_node when ready.";
36052
36369
  }
36053
36370
  function mergeJob(jobs, patch) {
36054
- const jobId = readString3(patch.jobId);
36371
+ const jobId = readString4(patch.jobId);
36055
36372
  if (!jobId) return;
36056
36373
  const previous = jobs.get(jobId);
36057
36374
  const status = patch.status || previous?.status || "running";
@@ -36069,54 +36386,54 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
36069
36386
  function buildMeshAsyncRefineJobs(args) {
36070
36387
  const jobs = /* @__PURE__ */ new Map();
36071
36388
  for (const entry of args.ledgerEntries || []) {
36072
- const payload = readRecord(entry.payload);
36389
+ const payload = readRecord2(entry.payload);
36073
36390
  if (payload?.source !== "refine_mesh_node_async_job") continue;
36074
- const refineJob = readRecord(payload.refineJob);
36075
- const result = readRecord(payload.result);
36076
- const finalState = readRecord(payload.finalBranchConvergenceState) || readRecord(result?.finalBranchConvergenceState);
36077
- const jobId = readString3(refineJob?.jobId);
36391
+ const refineJob = readRecord2(payload.refineJob);
36392
+ const result = readRecord2(payload.result);
36393
+ const finalState = readRecord2(payload.finalBranchConvergenceState) || readRecord2(result?.finalBranchConvergenceState);
36394
+ const jobId = readString4(refineJob?.jobId);
36078
36395
  if (!jobId) continue;
36079
- const status = ledgerStatus(entry.kind, readString3(refineJob?.status));
36396
+ const status = ledgerStatus(entry.kind, readString4(refineJob?.status));
36080
36397
  mergeJob(jobs, {
36081
36398
  jobId,
36082
- interactionId: readString3(refineJob?.interactionId),
36399
+ interactionId: readString4(refineJob?.interactionId),
36083
36400
  status,
36084
- meshId: readString3(refineJob?.meshId) || args.meshId,
36085
- nodeId: readString3(refineJob?.nodeId) || entry.nodeId,
36086
- targetNodeId: readString3(refineJob?.nodeId) || entry.nodeId,
36087
- targetDaemonId: readString3(refineJob?.targetDaemonId),
36088
- workspace: readString3(refineJob?.workspace),
36089
- branch: readString3(result?.branch) || readString3(finalState?.branch),
36090
- into: readString3(result?.into) || readString3(finalState?.baseBranch),
36091
- startedAt: readString3(refineJob?.startedAt),
36092
- completedAt: readString3(refineJob?.completedAt),
36093
- retryOfJobId: readString3(refineJob?.retryOfJobId) || readString3(payload.retryOfJobId),
36401
+ meshId: readString4(refineJob?.meshId) || args.meshId,
36402
+ nodeId: readString4(refineJob?.nodeId) || entry.nodeId,
36403
+ targetNodeId: readString4(refineJob?.nodeId) || entry.nodeId,
36404
+ targetDaemonId: readString4(refineJob?.targetDaemonId),
36405
+ workspace: readString4(refineJob?.workspace),
36406
+ branch: readString4(result?.branch) || readString4(finalState?.branch),
36407
+ into: readString4(result?.into) || readString4(finalState?.baseBranch),
36408
+ startedAt: readString4(refineJob?.startedAt),
36409
+ completedAt: readString4(refineJob?.completedAt),
36410
+ retryOfJobId: readString4(refineJob?.retryOfJobId) || readString4(payload.retryOfJobId),
36094
36411
  lastLedgerKind: entry.kind,
36095
36412
  lastUpdatedAt: entry.timestamp
36096
36413
  });
36097
36414
  }
36098
36415
  for (const event of args.pendingEvents || []) {
36099
- const metadata = readRecord(event.metadataEvent);
36416
+ const metadata = readRecord2(event.metadataEvent);
36100
36417
  if (metadata?.source !== "refine_mesh_node_async_job") continue;
36101
- const result = readRecord(metadata.result);
36102
- const finalState = readRecord(result?.finalBranchConvergenceState);
36103
- const jobId = readString3(metadata.jobId);
36418
+ const result = readRecord2(metadata.result);
36419
+ const finalState = readRecord2(result?.finalBranchConvergenceState);
36420
+ const jobId = readString4(metadata.jobId);
36104
36421
  if (!jobId) continue;
36105
- const status = eventStatus(event.event, readString3(metadata.status));
36422
+ const status = eventStatus(event.event, readString4(metadata.status));
36106
36423
  mergeJob(jobs, {
36107
36424
  jobId,
36108
- interactionId: readString3(metadata.interactionId),
36425
+ interactionId: readString4(metadata.interactionId),
36109
36426
  ...status ? { status } : {},
36110
- meshId: readString3(metadata.meshId) || event.meshId || args.meshId,
36111
- nodeId: readString3(metadata.nodeId) || event.nodeId,
36112
- targetNodeId: readString3(metadata.nodeId) || event.nodeId,
36113
- targetDaemonId: readString3(metadata.targetDaemonId),
36114
- workspace: readString3(metadata.workspace) || event.workspace,
36115
- branch: readString3(result?.branch) || readString3(finalState?.branch),
36116
- into: readString3(result?.into) || readString3(finalState?.baseBranch),
36117
- startedAt: readString3(metadata.startedAt),
36118
- completedAt: readString3(metadata.completedAt),
36119
- retryOfJobId: readString3(metadata.retryOfJobId),
36427
+ meshId: readString4(metadata.meshId) || event.meshId || args.meshId,
36428
+ nodeId: readString4(metadata.nodeId) || event.nodeId,
36429
+ targetNodeId: readString4(metadata.nodeId) || event.nodeId,
36430
+ targetDaemonId: readString4(metadata.targetDaemonId),
36431
+ workspace: readString4(metadata.workspace) || event.workspace,
36432
+ branch: readString4(result?.branch) || readString4(finalState?.branch),
36433
+ into: readString4(result?.into) || readString4(finalState?.baseBranch),
36434
+ startedAt: readString4(metadata.startedAt),
36435
+ completedAt: readString4(metadata.completedAt),
36436
+ retryOfJobId: readString4(metadata.retryOfJobId),
36120
36437
  lastEvent: event.event,
36121
36438
  lastUpdatedAt: new Date(event.queuedAt).toISOString()
36122
36439
  });
@@ -36177,10 +36494,10 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
36177
36494
  __export2(mesh_review_inbox_exports, {
36178
36495
  deriveMeshReviewInboxItems: () => deriveMeshReviewInboxItems
36179
36496
  });
36180
- function readString4(value) {
36497
+ function readString5(value) {
36181
36498
  return typeof value === "string" && value.trim() ? value.trim() : null;
36182
36499
  }
36183
- function readRecord2(value) {
36500
+ function readRecord3(value) {
36184
36501
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
36185
36502
  }
36186
36503
  function readStringArray3(value, max) {
@@ -36190,20 +36507,20 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
36190
36507
  }
36191
36508
  function isLocalNodeStatus(node) {
36192
36509
  if (node.isLocalWorktree === true) return true;
36193
- const connection = readRecord2(node.connection);
36194
- return readString4(connection?.state) === "self";
36510
+ const connection = readRecord3(node.connection);
36511
+ return readString5(connection?.state) === "self";
36195
36512
  }
36196
36513
  function readNodeConvergence(node) {
36197
- const convergence = readRecord2(node.branchConvergence);
36198
- const status = readString4(convergence?.status);
36514
+ const convergence = readRecord3(node.branchConvergence);
36515
+ const status = readString5(convergence?.status);
36199
36516
  if (!convergence || !status) return null;
36200
36517
  return {
36201
36518
  status,
36202
- reason: readString4(convergence.reason),
36203
- nextStep: readString4(convergence.nextStep),
36519
+ reason: readString5(convergence.reason),
36520
+ nextStep: readString5(convergence.nextStep),
36204
36521
  needsConvergence: convergence.needsConvergence === true,
36205
- branch: readString4(convergence.branch),
36206
- defaultBranch: readString4(convergence.defaultBranch)
36522
+ branch: readString5(convergence.branch),
36523
+ defaultBranch: readString5(convergence.defaultBranch)
36207
36524
  };
36208
36525
  }
36209
36526
  function isMergeCandidate(convergence) {
@@ -36211,15 +36528,15 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
36211
36528
  return convergence.status === "cleanup_candidate" && convergence.reason === "clean_non_default_worktree_branch";
36212
36529
  }
36213
36530
  function readWorkerArtifact(value) {
36214
- const worker = readRecord2(value);
36531
+ const worker = readRecord3(value);
36215
36532
  if (!worker) return null;
36216
36533
  const changed = readStringArray3(worker.changedFiles, MAX_CHANGED_FILES);
36217
36534
  return {
36218
- status: readString4(worker.status) ?? "unknown",
36219
- ...readString4(worker.classification) ? { classification: readString4(worker.classification) } : {},
36535
+ status: readString5(worker.status) ?? "unknown",
36536
+ ...readString5(worker.classification) ? { classification: readString5(worker.classification) } : {},
36220
36537
  changedFiles: changed.values,
36221
36538
  ...changed.truncated ? { changedFilesTruncated: true } : {},
36222
- validationResults: Array.isArray(worker.validationResults) ? worker.validationResults.map((item) => readRecord2(item)).filter((item) => item !== null) : [],
36539
+ validationResults: Array.isArray(worker.validationResults) ? worker.validationResults.map((item) => readRecord3(item)).filter((item) => item !== null) : [],
36223
36540
  errors: readStringArray3(worker.errors, 20).values,
36224
36541
  requiresUserAction: worker.requiresUserAction === true
36225
36542
  };
@@ -36233,43 +36550,43 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
36233
36550
  for (let i = ledgerEntries.length - 1; i >= 0; i--) {
36234
36551
  const entry = ledgerEntries[i];
36235
36552
  if (entry.nodeId !== nodeId || !isTerminalLedgerKind(entry.kind)) continue;
36236
- const payload = readRecord2(entry.payload) ?? {};
36553
+ const payload = readRecord3(entry.payload) ?? {};
36237
36554
  if (!evidence.available) {
36238
36555
  if (payload.source === "refine_mesh_node_async_job") {
36239
- const result = readRecord2(payload.result);
36240
- const validationSummary = readRecord2(result?.validationSummary);
36556
+ const result = readRecord3(payload.result);
36557
+ const validationSummary = readRecord3(result?.validationSummary);
36241
36558
  evidence = {
36242
36559
  available: true,
36243
36560
  kind: entry.kind,
36244
36561
  source: "refine_job",
36245
36562
  timestamp: entry.timestamp,
36246
36563
  ...entry.sessionId ? { sessionId: entry.sessionId } : {},
36247
- bootstrap: readRecord2(validationSummary?.bootstrap),
36564
+ bootstrap: readRecord3(validationSummary?.bootstrap),
36248
36565
  validation: validationSummary ? Object.fromEntries(Object.entries(validationSummary).filter(([key]) => key !== "bootstrap")) : null,
36249
- checkpoint: readRecord2(result?.checkpoint),
36566
+ checkpoint: readRecord3(result?.checkpoint),
36250
36567
  worker: null,
36251
- ...readRecord2(payload.finalBranchConvergenceState) ?? readRecord2(result?.finalBranchConvergenceState) ? { finalBranchConvergenceState: readRecord2(payload.finalBranchConvergenceState) ?? readRecord2(result?.finalBranchConvergenceState) } : {},
36252
- ...readRecord2(payload.refineJob) ? { refineJob: readRecord2(payload.refineJob) } : {}
36568
+ ...readRecord3(payload.finalBranchConvergenceState) ?? readRecord3(result?.finalBranchConvergenceState) ? { finalBranchConvergenceState: readRecord3(payload.finalBranchConvergenceState) ?? readRecord3(result?.finalBranchConvergenceState) } : {},
36569
+ ...readRecord3(payload.refineJob) ? { refineJob: readRecord3(payload.refineJob) } : {}
36253
36570
  };
36254
36571
  } else {
36255
- const envelope = readRecord2(payload.evidence);
36572
+ const envelope = readRecord3(payload.evidence);
36256
36573
  evidence = {
36257
36574
  available: true,
36258
36575
  kind: entry.kind,
36259
36576
  source: "task_completion",
36260
36577
  timestamp: entry.timestamp,
36261
- ...readString4(payload.taskId) ? { taskId: readString4(payload.taskId) } : {},
36578
+ ...readString5(payload.taskId) ? { taskId: readString5(payload.taskId) } : {},
36262
36579
  ...entry.sessionId ? { sessionId: entry.sessionId } : {},
36263
36580
  bootstrap: null,
36264
- validation: readRecord2(envelope?.validation),
36265
- checkpoint: readRecord2(envelope?.checkpoint),
36581
+ validation: readRecord3(envelope?.validation),
36582
+ checkpoint: readRecord3(envelope?.checkpoint),
36266
36583
  worker: readWorkerArtifact(envelope?.workerResult ?? payload.workerResult)
36267
36584
  };
36268
36585
  }
36269
36586
  }
36270
36587
  if (!transcriptHandle) {
36271
- const envelope = readRecord2(payload.evidence);
36272
- transcriptHandle = readRecord2(envelope?.transcriptHandle);
36588
+ const envelope = readRecord3(payload.evidence);
36589
+ transcriptHandle = readRecord3(envelope?.transcriptHandle);
36273
36590
  }
36274
36591
  if (evidence.available && transcriptHandle) break;
36275
36592
  }
@@ -36279,11 +36596,11 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
36279
36596
  for (let i = ledgerEntries.length - 1; i >= 0; i--) {
36280
36597
  const entry = ledgerEntries[i];
36281
36598
  if (entry.nodeId !== nodeId || !isTerminalLedgerKind(entry.kind)) continue;
36282
- const payload = readRecord2(entry.payload) ?? {};
36599
+ const payload = readRecord3(entry.payload) ?? {};
36283
36600
  if (payload.source !== "refine_mesh_node_async_job") continue;
36284
- const result = readRecord2(payload.result);
36285
- const finalState = readRecord2(payload.finalBranchConvergenceState) ?? readRecord2(result?.finalBranchConvergenceState);
36286
- return readString4(finalState?.status) === "blocked_review" || readString4(result?.code) === "blocked_review";
36601
+ const result = readRecord3(payload.result);
36602
+ const finalState = readRecord3(payload.finalBranchConvergenceState) ?? readRecord3(result?.finalBranchConvergenceState);
36603
+ return readString5(finalState?.status) === "blocked_review" || readString5(result?.code) === "blocked_review";
36287
36604
  }
36288
36605
  return false;
36289
36606
  }
@@ -36292,7 +36609,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
36292
36609
  const excludedRemoteNodeIds = [];
36293
36610
  const refineJobs = buildMeshAsyncRefineJobs({ ledgerEntries: args.ledgerEntries });
36294
36611
  for (const node of args.nodes) {
36295
- const nodeId = readString4(node.nodeId) ?? readString4(node.id);
36612
+ const nodeId = readString5(node.nodeId) ?? readString5(node.id);
36296
36613
  if (!nodeId) continue;
36297
36614
  if (!isLocalNodeStatus(node)) {
36298
36615
  excludedRemoteNodeIds.push(nodeId);
@@ -36314,8 +36631,8 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
36314
36631
  ) ?? null;
36315
36632
  items.push({
36316
36633
  nodeId,
36317
- workspace: readString4(node.workspace),
36318
- branch: convergence.branch ?? readString4(node.worktreeBranch),
36634
+ workspace: readString5(node.workspace),
36635
+ branch: convergence.branch ?? readString5(node.worktreeBranch),
36319
36636
  defaultBranch: convergence.defaultBranch,
36320
36637
  isLocalWorktree: node.isLocalWorktree === true,
36321
36638
  reviewReason,
@@ -37531,218 +37848,6 @@ ${rendered}`, "utf-8");
37531
37848
  STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15e3 };
37532
37849
  }
37533
37850
  });
37534
- function readRecord3(value) {
37535
- return value && typeof value === "object" && !Array.isArray(value) ? value : {};
37536
- }
37537
- function readString5(...values) {
37538
- for (const value of values) {
37539
- if (typeof value !== "string") continue;
37540
- const trimmed = value.trim();
37541
- if (trimmed) return trimmed;
37542
- }
37543
- return void 0;
37544
- }
37545
- function readNumber(...values) {
37546
- for (const value of values) {
37547
- if (typeof value === "number" && Number.isFinite(value)) return value;
37548
- }
37549
- return void 0;
37550
- }
37551
- function readBoolean(...values) {
37552
- for (const value of values) {
37553
- if (typeof value === "boolean") return value;
37554
- }
37555
- return void 0;
37556
- }
37557
- function joinRepoPath(root, relativePath) {
37558
- const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
37559
- const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
37560
- if (!normalizedPath) return void 0;
37561
- if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
37562
- if (!normalizedRoot) return void 0;
37563
- return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
37564
- }
37565
- function scoreGitUpstreamFreshness(status) {
37566
- switch (status) {
37567
- case "fresh":
37568
- return 30;
37569
- case "no_upstream":
37570
- return 4;
37571
- case "unchecked":
37572
- case void 0:
37573
- return 0;
37574
- case "stale":
37575
- return -10;
37576
- case "unavailable":
37577
- return -15;
37578
- default:
37579
- return 0;
37580
- }
37581
- }
37582
- function readGitSubmodules(value, parentRepoRoot) {
37583
- if (!Array.isArray(value)) return void 0;
37584
- const submodules = value.map((entry) => {
37585
- const submodule = readRecord3(entry);
37586
- const path422 = readString5(submodule.path);
37587
- const commit = readString5(submodule.commit);
37588
- const repoPath = readString5(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path422);
37589
- if (!path422 || !commit) return null;
37590
- const result = {
37591
- path: path422,
37592
- commit,
37593
- dirty: readBoolean(submodule.dirty) ?? false,
37594
- outOfSync: readBoolean(submodule.outOfSync, submodule.out_of_sync) ?? false,
37595
- lastCheckedAt: readNumber(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now()
37596
- };
37597
- if (repoPath) result.repoPath = repoPath;
37598
- const error48 = readString5(submodule.error);
37599
- if (error48) result.error = error48;
37600
- return result;
37601
- }).filter((entry) => entry !== null);
37602
- return submodules.length > 0 ? submodules : void 0;
37603
- }
37604
- function hasGitStatusEvidence(status) {
37605
- 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(
37606
- status.ahead,
37607
- status.behind,
37608
- status.staged,
37609
- status.modified,
37610
- status.untracked,
37611
- status.deleted,
37612
- status.renamed,
37613
- status.lastCheckedAt,
37614
- status.last_checked_at
37615
- ) !== void 0 || Array.isArray(status.submodules) && status.submodules.length > 0;
37616
- }
37617
- function normalizeGitStatus(status, node, options) {
37618
- const explicitIsGitRepo = readBoolean(status.isGitRepo);
37619
- if (!Object.keys(status).length || !hasGitStatusEvidence(status)) return void 0;
37620
- const isGitRepo = explicitIsGitRepo ?? true;
37621
- const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((entry) => typeof entry === "string") : [];
37622
- const conflictCount = readNumber(status.conflicts) ?? conflictFiles.length;
37623
- const hasConflicts = readBoolean(status.hasConflicts) ?? conflictCount > 0;
37624
- const repoRoot = readString5(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
37625
- const submodules = readGitSubmodules(status.submodules, repoRoot);
37626
- const upstreamStatus = readString5(status.upstreamStatus, status.upstream_status);
37627
- const upstreamFetchedAt = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
37628
- const upstreamFetchError = readString5(status.upstreamFetchError, status.upstream_fetch_error);
37629
- const error48 = readString5(status.error);
37630
- const staged = readNumber(status.staged) ?? 0;
37631
- const modified = readNumber(status.modified) ?? 0;
37632
- const untracked = readNumber(status.untracked) ?? 0;
37633
- const deleted = readNumber(status.deleted) ?? 0;
37634
- const renamed = readNumber(status.renamed) ?? 0;
37635
- return {
37636
- workspace: readString5(status.workspace, node.workspace) || "",
37637
- repoRoot: repoRoot ?? null,
37638
- isGitRepo,
37639
- branch: readString5(status.branch) ?? null,
37640
- headCommit: readString5(status.headCommit) ?? null,
37641
- headMessage: readString5(status.headMessage) ?? null,
37642
- upstream: readString5(status.upstream) ?? null,
37643
- upstreamStatus: upstreamStatus ?? "unchecked",
37644
- ...upstreamFetchedAt !== void 0 ? { upstreamFetchedAt } : {},
37645
- ...upstreamFetchError ? { upstreamFetchError } : {},
37646
- ahead: readNumber(status.ahead) ?? 0,
37647
- behind: readNumber(status.behind) ?? 0,
37648
- staged,
37649
- modified,
37650
- untracked,
37651
- deleted,
37652
- renamed,
37653
- dirty: readBoolean(status.dirty, status.isDirty, status.is_dirty) ?? (staged + modified + untracked + deleted + renamed > 0 || hasConflicts),
37654
- hasConflicts,
37655
- conflictFiles,
37656
- stashCount: readNumber(status.stashCount, status.stash_count) ?? 0,
37657
- lastCheckedAt: options?.lastCheckedAt ?? readNumber(status.lastCheckedAt, status.last_checked_at) ?? Date.now(),
37658
- ...submodules ? { submodules } : {},
37659
- ...error48 ? { error: error48 } : {}
37660
- };
37661
- }
37662
- function scoreGitStatusCandidate(git) {
37663
- if (!git) return Number.NEGATIVE_INFINITY;
37664
- let score = 0;
37665
- if (git.isGitRepo === true) score += 50;
37666
- if (git.isGitRepo === false) score -= 10;
37667
- if (git.branch) score += 20;
37668
- if (git.headCommit) score += 20;
37669
- if (git.upstream) score += 10;
37670
- score += scoreGitUpstreamFreshness(git.upstreamStatus);
37671
- if (typeof git.ahead === "number") score += 2;
37672
- if (typeof git.behind === "number") score += 2;
37673
- if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
37674
- if (git.error) score -= 20;
37675
- return score;
37676
- }
37677
- function pickBestTransitGitStatus(node, options) {
37678
- const rawGit = readRecord3(node.lastGit ?? node.last_git);
37679
- const gitResult = readRecord3(rawGit.result);
37680
- const directStatus = readRecord3(rawGit.status);
37681
- const nestedStatus = readRecord3(gitResult.status);
37682
- const rawProbe = readRecord3(node.lastProbe ?? node.last_probe);
37683
- const probeGit = readRecord3(rawProbe.git);
37684
- const probeGitResult = readRecord3(probeGit.result);
37685
- const probeDirectStatus = readRecord3(probeGit.status);
37686
- const probeNestedStatus = readRecord3(probeGitResult.status);
37687
- const lastCheckedAt = options?.lastCheckedAt;
37688
- let best = null;
37689
- for (const status of [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus]) {
37690
- const normalized = normalizeGitStatus(status, node, { lastCheckedAt: lastCheckedAt ?? Date.now() });
37691
- if (!normalized) continue;
37692
- const score = scoreGitStatusCandidate(normalized);
37693
- if (!best || score > best.score) best = { git: normalized, score };
37694
- }
37695
- return best?.git;
37696
- }
37697
- function normalizeMeshNodeId(node) {
37698
- const record2 = node && typeof node === "object" ? node : {};
37699
- return readString5(record2.id, record2.nodeId, record2.node_id);
37700
- }
37701
- function meshNodeIdMatches(node, candidateId) {
37702
- if (!candidateId) return false;
37703
- const trimmed = candidateId.trim();
37704
- if (!trimmed) return false;
37705
- return normalizeMeshNodeId(node) === trimmed;
37706
- }
37707
- function summarizeGitShape(status) {
37708
- const record2 = readRecord3(status);
37709
- if (!Object.keys(record2).length) return null;
37710
- const submodules = Array.isArray(record2.submodules) ? record2.submodules.map((entry) => {
37711
- const sub = readRecord3(entry);
37712
- return {
37713
- path: readString5(sub.path) ?? null,
37714
- commit: readString5(sub.commit)?.slice(0, 12) ?? null,
37715
- dirty: readBoolean(sub.dirty) ?? false,
37716
- outOfSync: readBoolean(sub.outOfSync, sub.out_of_sync) ?? false
37717
- };
37718
- }) : [];
37719
- return {
37720
- isGitRepo: readBoolean(record2.isGitRepo),
37721
- workspace: readString5(record2.workspace) ?? null,
37722
- repoRoot: readString5(record2.repoRoot, record2.repo_root) ?? null,
37723
- branch: readString5(record2.branch) ?? null,
37724
- upstream: readString5(record2.upstream) ?? null,
37725
- upstreamStatus: readString5(record2.upstreamStatus, record2.upstream_status) ?? null,
37726
- headCommit: readString5(record2.headCommit, record2.head_commit)?.slice(0, 12) ?? null,
37727
- ahead: readNumber(record2.ahead) ?? null,
37728
- behind: readNumber(record2.behind) ?? null,
37729
- dirtyCounts: {
37730
- staged: readNumber(record2.staged) ?? 0,
37731
- modified: readNumber(record2.modified) ?? 0,
37732
- untracked: readNumber(record2.untracked) ?? 0,
37733
- deleted: readNumber(record2.deleted) ?? 0,
37734
- renamed: readNumber(record2.renamed) ?? 0
37735
- },
37736
- lastCheckedAt: readNumber(record2.lastCheckedAt, record2.last_checked_at) ?? null,
37737
- submoduleCount: submodules.length,
37738
- submodules
37739
- };
37740
- }
37741
- var init_dist = __esm2({
37742
- "../mesh-shared/dist/index.mjs"() {
37743
- "use strict";
37744
- }
37745
- });
37746
37851
  function readString6(value) {
37747
37852
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
37748
37853
  }
@@ -38395,17 +38500,7 @@ Next step: ${nextStep}`;
38395
38500
  }
38396
38501
  });
38397
38502
  function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
38398
- const raw = Array.isArray(coordinatorDaemonId) ? coordinatorDaemonId : coordinatorDaemonId != null ? [coordinatorDaemonId] : [];
38399
- const seen = /* @__PURE__ */ new Set();
38400
- const out = [];
38401
- for (const id of raw) {
38402
- if (typeof id !== "string") continue;
38403
- const trimmed = id.trim();
38404
- if (!trimmed || seen.has(trimmed)) continue;
38405
- seen.add(trimmed);
38406
- out.push(trimmed);
38407
- }
38408
- return out;
38503
+ return expandDaemonIdForms(coordinatorDaemonId);
38409
38504
  }
38410
38505
  function readRefineJobId2(event) {
38411
38506
  const metadata = readRecord4(event.metadataEvent) || event;
@@ -38800,6 +38895,7 @@ Next step: ${nextStep}`;
38800
38895
  init_mesh_ledger();
38801
38896
  init_mesh_runtime_store();
38802
38897
  init_mesh_events_utils();
38898
+ init_dist();
38803
38899
  REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
38804
38900
  MAX_PENDING_EVENTS_BYTES = 100 * 1024;
38805
38901
  MAX_PENDING_EVENTS_KEEP = 50;
@@ -42257,12 +42353,9 @@ ${cleanBody}`;
42257
42353
  }
42258
42354
  });
42259
42355
  function resolveCoordinatorDrainDaemonIds(components) {
42260
- const ids = /* @__PURE__ */ new Set();
42261
42356
  const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
42262
- if (statusInstanceId) ids.add(statusInstanceId);
42263
42357
  const machineId = readNonEmptyString2(loadConfig2().machineId);
42264
- if (machineId) ids.add(machineId);
42265
- return [...ids];
42358
+ return expandDaemonIdForms([statusInstanceId, machineId]);
42266
42359
  }
42267
42360
  function getCachedMeshByWorkspace(workspace) {
42268
42361
  const now = Date.now();
@@ -42413,6 +42506,55 @@ ${cleanBody}`;
42413
42506
  return void 0;
42414
42507
  }
42415
42508
  }
42509
+ function deliverTaskToSession(dispatchThunk, ctx) {
42510
+ const delivery = createSessionDelivery({
42511
+ meshId: ctx.meshId,
42512
+ nodeId: ctx.nodeId,
42513
+ sessionId: ctx.sessionId,
42514
+ providerType: ctx.providerType,
42515
+ taskId: ctx.task.id,
42516
+ kind: "task",
42517
+ message: ctx.task.message,
42518
+ status: "delivering",
42519
+ ...ctx.sourceCoordinatorSessionId ? { sourceCoordinatorSessionId: ctx.sourceCoordinatorSessionId } : {},
42520
+ ...ctx.sourceCoordinatorDaemonId ? { sourceCoordinatorDaemonId: ctx.sourceCoordinatorDaemonId } : {}
42521
+ });
42522
+ let dispatchPromise;
42523
+ try {
42524
+ dispatchPromise = Promise.resolve(dispatchThunk());
42525
+ } catch (e) {
42526
+ dispatchPromise = Promise.reject(e);
42527
+ }
42528
+ let timer;
42529
+ const guarded = Promise.race([
42530
+ dispatchPromise,
42531
+ new Promise((_, reject) => {
42532
+ timer = setTimeout(
42533
+ () => reject(new Error(`dispatch_confirm_timeout after ${DISPATCH_CONFIRM_TIMEOUT_MS}ms`)),
42534
+ DISPATCH_CONFIRM_TIMEOUT_MS
42535
+ );
42536
+ if (typeof timer?.unref === "function") timer.unref();
42537
+ })
42538
+ ]);
42539
+ guarded.then(() => {
42540
+ if (timer) clearTimeout(timer);
42541
+ updateSessionDeliveryStatus(delivery.id, "delivered");
42542
+ }).catch((e) => {
42543
+ if (timer) clearTimeout(timer);
42544
+ LOG2.error("MeshQueue", `Failed to dispatch task via ${ctx.transport} to node ${ctx.nodeId}: ${e?.message}`);
42545
+ updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
42546
+ updateTaskStatus(ctx.meshId, ctx.task.id, "pending");
42547
+ try {
42548
+ appendLedgerEntry(ctx.meshId, {
42549
+ kind: "dispatch_failed",
42550
+ nodeId: ctx.nodeId,
42551
+ sessionId: ctx.sessionId,
42552
+ payload: { taskId: ctx.task.id, deliveryId: delivery.id, error: e?.message, retryable: true, transport: ctx.transport }
42553
+ });
42554
+ } catch {
42555
+ }
42556
+ });
42557
+ }
42416
42558
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
42417
42559
  const mesh = getMeshWithCache(components, meshId);
42418
42560
  const node = mesh?.nodes.find((n) => readMeshNodeId(n) === nodeId);
@@ -42431,46 +42573,33 @@ ${cleanBody}`;
42431
42573
  if (!isLocalNode) {
42432
42574
  const localDaemonIdForDispatch = readNonEmptyString2(loadConfig2().machineId) || void 0;
42433
42575
  const sourceCoordinatorSessionId = readNonEmptyString2(task.sourceCoordinatorSessionId) || void 0;
42434
- const delivery2 = createSessionDelivery({
42435
- meshId,
42436
- nodeId,
42437
- sessionId,
42438
- providerType,
42439
- taskId: task.id,
42440
- kind: "task",
42441
- message: task.message,
42442
- status: "delivering",
42443
- ...sourceCoordinatorSessionId ? { sourceCoordinatorSessionId } : {},
42444
- ...localDaemonIdForDispatch ? { sourceCoordinatorDaemonId: localDaemonIdForDispatch } : {}
42445
- });
42446
- components.dispatchMeshCommand(node.daemonId, "agent_command", {
42447
- targetSessionId: sessionId,
42448
- cliType: providerType,
42449
- action: "send_chat",
42450
- message: task.message,
42451
- meshContext: {
42576
+ const dispatchMeshCommand = components.dispatchMeshCommand;
42577
+ const remoteDaemonId = node.daemonId;
42578
+ deliverTaskToSession(
42579
+ () => dispatchMeshCommand(remoteDaemonId, "agent_command", {
42580
+ targetSessionId: sessionId,
42581
+ cliType: providerType,
42582
+ action: "send_chat",
42583
+ message: task.message,
42584
+ meshContext: {
42585
+ meshId,
42586
+ nodeId,
42587
+ taskId: task.id,
42588
+ ...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {},
42589
+ ...sourceCoordinatorSessionId ? { coordinatorSessionId: sourceCoordinatorSessionId } : {}
42590
+ }
42591
+ }),
42592
+ {
42452
42593
  meshId,
42453
42594
  nodeId,
42454
- taskId: task.id,
42455
- ...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {},
42456
- ...sourceCoordinatorSessionId ? { coordinatorSessionId: sourceCoordinatorSessionId } : {}
42457
- }
42458
- }).then(() => {
42459
- updateSessionDeliveryStatus(delivery2.id, "delivered");
42460
- }).catch((e) => {
42461
- LOG2.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
42462
- updateSessionDeliveryStatus(delivery2.id, "failed", { lastError: e?.message, incrementAttempt: true });
42463
- updateTaskStatus(meshId, task.id, "pending");
42464
- try {
42465
- appendLedgerEntry(meshId, {
42466
- kind: "dispatch_failed",
42467
- nodeId,
42468
- sessionId,
42469
- payload: { taskId: task.id, deliveryId: delivery2.id, error: e?.message, retryable: true }
42470
- });
42471
- } catch {
42595
+ sessionId,
42596
+ providerType,
42597
+ task,
42598
+ transport: "remote",
42599
+ ...sourceCoordinatorSessionId ? { sourceCoordinatorSessionId } : {},
42600
+ ...localDaemonIdForDispatch ? { sourceCoordinatorDaemonId: localDaemonIdForDispatch } : {}
42472
42601
  }
42473
- });
42602
+ );
42474
42603
  return true;
42475
42604
  }
42476
42605
  }
@@ -42492,39 +42621,24 @@ ${cleanBody}`;
42492
42621
  }
42493
42622
  } catch {
42494
42623
  }
42495
- const delivery = createSessionDelivery({
42496
- meshId,
42497
- nodeId,
42498
- sessionId,
42499
- providerType,
42500
- taskId: task.id,
42501
- kind: "task",
42502
- message: task.message,
42503
- status: "delivering",
42504
- ...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { sourceCoordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {},
42505
- ...readNonEmptyString2(loadConfig2().machineId) ? { sourceCoordinatorDaemonId: readNonEmptyString2(loadConfig2().machineId) } : {}
42506
- });
42507
- components.cliManager.handleCliCommand("agent_command", {
42508
- targetSessionId: sessionId,
42509
- cliType: providerType,
42510
- action: "send_chat",
42511
- message: task.message
42512
- }).then(() => {
42513
- updateSessionDeliveryStatus(delivery.id, "delivered");
42514
- }).catch((e) => {
42515
- LOG2.error("MeshQueue", `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
42516
- updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
42517
- updateTaskStatus(meshId, task.id, "pending");
42518
- try {
42519
- appendLedgerEntry(meshId, {
42520
- kind: "dispatch_failed",
42521
- nodeId,
42522
- sessionId,
42523
- payload: { taskId: task.id, deliveryId: delivery.id, error: e?.message, retryable: true }
42524
- });
42525
- } catch {
42624
+ deliverTaskToSession(
42625
+ () => components.cliManager.handleCliCommand("agent_command", {
42626
+ targetSessionId: sessionId,
42627
+ cliType: providerType,
42628
+ action: "send_chat",
42629
+ message: task.message
42630
+ }),
42631
+ {
42632
+ meshId,
42633
+ nodeId,
42634
+ sessionId,
42635
+ providerType,
42636
+ task,
42637
+ transport: "local",
42638
+ ...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { sourceCoordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {},
42639
+ ...readNonEmptyString2(loadConfig2().machineId) ? { sourceCoordinatorDaemonId: readNonEmptyString2(loadConfig2().machineId) } : {}
42526
42640
  }
42527
- });
42641
+ );
42528
42642
  return true;
42529
42643
  }
42530
42644
  function sweepExpiredCooldowns() {
@@ -42789,7 +42903,7 @@ ${cleanBody}`;
42789
42903
  }
42790
42904
  }
42791
42905
  const candidateNodes = Array.isArray(mesh?.nodes) ? mesh.nodes.filter((node) => {
42792
- if (task.targetNodeId && readMeshNodeId(node) !== task.targetNodeId) return false;
42906
+ if (task.targetNodeId && !meshNodeIdMatches(node, task.targetNodeId)) return false;
42793
42907
  if (task.requiredTags?.length) {
42794
42908
  const priorities = normalizeProviderPriority(node?.policy);
42795
42909
  const providerCandidates = priorities.length ? priorities : [void 0];
@@ -42800,7 +42914,12 @@ ${cleanBody}`;
42800
42914
  return true;
42801
42915
  }) : [];
42802
42916
  if (!candidateNodes.length) {
42803
- markAutoLaunch(meshId, task.id, { status: "skipped", reason: "no_node_satisfies_required_tags", nodeId: task.targetNodeId });
42917
+ const targetPinUnmatched = !!task.targetNodeId && !(Array.isArray(mesh?.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, task.targetNodeId)));
42918
+ markAutoLaunch(meshId, task.id, {
42919
+ status: "skipped",
42920
+ reason: targetPinUnmatched ? "target_node_id_unmatched" : "no_node_satisfies_required_tags",
42921
+ nodeId: task.targetNodeId
42922
+ });
42804
42923
  continue;
42805
42924
  }
42806
42925
  const strategy = resolveSchedulingStrategy(mesh);
@@ -43759,6 +43878,7 @@ ${cleanBody}`;
43759
43878
  var idleAutoFastForwardLastAttempt;
43760
43879
  var INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS;
43761
43880
  var RECENT_COMPLETION_FINGERPRINT_TTL_MS;
43881
+ var DISPATCH_CONFIRM_TIMEOUT_MS;
43762
43882
  var autoLaunchInProgress;
43763
43883
  var autoLaunchCooldownUntil;
43764
43884
  var AUTO_LAUNCH_COOLDOWN_MS;
@@ -43796,6 +43916,7 @@ ${cleanBody}`;
43796
43916
  idleAutoFastForwardLastAttempt = /* @__PURE__ */ new Map();
43797
43917
  INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
43798
43918
  RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
43919
+ DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
43799
43920
  autoLaunchInProgress = /* @__PURE__ */ new Set();
43800
43921
  autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
43801
43922
  AUTO_LAUNCH_COOLDOWN_MS = 5e3;
@@ -43849,12 +43970,9 @@ ${cleanBody}`;
43849
43970
  return DEFAULT_RECONCILE_INTERVAL_MS;
43850
43971
  }
43851
43972
  function resolveCoordinatorDaemonIds(components) {
43852
- const ids = /* @__PURE__ */ new Set();
43853
43973
  const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
43854
- if (statusInstanceId) ids.add(statusInstanceId);
43855
43974
  const machineId = readNonEmptyString2(loadConfig2().machineId);
43856
- if (machineId) ids.add(machineId);
43857
- return [...ids];
43975
+ return expandDaemonIdForms([statusInstanceId, machineId]);
43858
43976
  }
43859
43977
  function daemonHostsMesh(mesh, daemonIds) {
43860
43978
  const host = mesh.meshHost;
@@ -43938,6 +44056,24 @@ ${cleanBody}`;
43938
44056
  }
43939
44057
  }
43940
44058
  }
44059
+ function recoverStrandedAssignedDispatches(meshId, store) {
44060
+ const assigned = getQueue(meshId, { status: ["assigned"] });
44061
+ if (!assigned.length) return;
44062
+ const nowMs = Date.now();
44063
+ for (const row of assigned) {
44064
+ const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
44065
+ if (!Number.isFinite(dispatchedAtMs)) continue;
44066
+ if (nowMs - dispatchedAtMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
44067
+ if (store.taskHasConfirmedDelivery(meshId, row.id)) continue;
44068
+ const reclaimed = reclaimStrandedAssignedTask(meshId, row.id, {
44069
+ reason: "assigned_stranded_dispatch_unconfirmed",
44070
+ ageMs: nowMs - dispatchedAtMs
44071
+ });
44072
+ if (reclaimed) {
44073
+ LOG2.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})`);
44074
+ }
44075
+ }
44076
+ }
43941
44077
  async function runMeshReconcileTick(components) {
43942
44078
  const localDaemonId = readNonEmptyString2(loadConfig2().machineId) || void 0;
43943
44079
  const drainDaemonIds = resolveCoordinatorDaemonIds(components);
@@ -43967,6 +44103,17 @@ ${cleanBody}`;
43967
44103
  }
43968
44104
  }
43969
44105
  }
44106
+ if (store) {
44107
+ for (const mesh of listMeshes()) {
44108
+ const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
44109
+ if (!daemonHostsMesh(mesh, selfIds)) continue;
44110
+ try {
44111
+ recoverStrandedAssignedDispatches(mesh.id, store);
44112
+ } catch (e) {
44113
+ LOG2.warn("MeshReconcile", `Assigned-stranded watchdog failed for mesh ${mesh.id}: ${e?.message || e}`);
44114
+ }
44115
+ }
44116
+ }
43970
44117
  for (const mesh of listMeshes()) {
43971
44118
  const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
43972
44119
  if (!daemonHostsMesh(mesh, selfIds)) continue;
@@ -44357,6 +44504,7 @@ ${cleanBody}`;
44357
44504
  var DEFAULT_RECONCILE_INTERVAL_MS;
44358
44505
  var DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
44359
44506
  var heldEventLedgerRecorded;
44507
+ var ASSIGNED_STRANDED_DEADLINE_MS;
44360
44508
  var STRICT_SESSION_MATCH_TTL_MS;
44361
44509
  var init_mesh_reconcile_loop = __esm2({
44362
44510
  "src/mesh/mesh-reconcile-loop.ts"() {
@@ -44370,6 +44518,7 @@ ${cleanBody}`;
44370
44518
  init_mesh_events_coordinator();
44371
44519
  init_mesh_unresolved_forward_outbox();
44372
44520
  init_mesh_events_utils();
44521
+ init_dist();
44373
44522
  init_mesh_work_queue();
44374
44523
  init_mesh_ledger();
44375
44524
  init_mesh_active_work();
@@ -44378,6 +44527,7 @@ ${cleanBody}`;
44378
44527
  DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
44379
44528
  DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
44380
44529
  heldEventLedgerRecorded = /* @__PURE__ */ new Set();
44530
+ ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
44381
44531
  STRICT_SESSION_MATCH_TTL_MS = 6e4;
44382
44532
  }
44383
44533
  });
@@ -44407,6 +44557,82 @@ ${cleanBody}`;
44407
44557
  init_mesh_events_coordinator();
44408
44558
  }
44409
44559
  });
44560
+ function normalizeApprovalLabel(value) {
44561
+ return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
44562
+ }
44563
+ function isNegativeApprovalLabel(value) {
44564
+ const label = normalizeApprovalLabel(value);
44565
+ return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
44566
+ }
44567
+ function hasNegativeApprovalOption(buttons) {
44568
+ return (buttons || []).some((button) => isNegativeApprovalLabel(String(button || "")));
44569
+ }
44570
+ function getApprovalPositiveHints(provider) {
44571
+ const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
44572
+ return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
44573
+ }
44574
+ function pickApprovalButton(buttons, provider) {
44575
+ const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
44576
+ if (labels.length === 0) {
44577
+ return { index: -1, label: "" };
44578
+ }
44579
+ const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
44580
+ const hints = getApprovalPositiveHints(provider);
44581
+ for (const hint of hints) {
44582
+ const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
44583
+ if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
44584
+ const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
44585
+ if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
44586
+ const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
44587
+ if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
44588
+ }
44589
+ return { index: -1, label: "" };
44590
+ }
44591
+ function pickAutoApprovalButton(buttons) {
44592
+ const labels = (buttons || []).map((button) => String(button || "").trim());
44593
+ const index = labels.findIndex(Boolean);
44594
+ return index >= 0 ? { index, label: labels[index] } : { index: -1, label: "" };
44595
+ }
44596
+ function formatAutoApprovalMessage(modalMessage, buttonLabel) {
44597
+ const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
44598
+ const cleanMessage = String(modalMessage || "").trim();
44599
+ if (cleanMessage) lines.push(cleanMessage);
44600
+ return lines.join("\n");
44601
+ }
44602
+ function looksLikeActiveApprovalPromptText(content) {
44603
+ const text = content.trim();
44604
+ if (!text || text.length > 2e3) return false;
44605
+ 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);
44606
+ const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text) || /^\s*1[.)]\s+yes\b/im.test(text);
44607
+ if (hasApprovalQuestion && hasNumberedChoices) return true;
44608
+ const lastLines = text.split(/\r?\n/).slice(-12).join("\n");
44609
+ const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines) || /yes.*always allow/i.test(lastLines);
44610
+ const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
44611
+ if (hasDontAskAgain && hasNoOption) return true;
44612
+ if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
44613
+ return false;
44614
+ }
44615
+ var DEFAULT_APPROVAL_POSITIVE_HINTS;
44616
+ var init_approval_utils = __esm2({
44617
+ "src/providers/approval-utils.ts"() {
44618
+ "use strict";
44619
+ DEFAULT_APPROVAL_POSITIVE_HINTS = [
44620
+ "yes",
44621
+ "allow once",
44622
+ "approve",
44623
+ "accept",
44624
+ "continue",
44625
+ "run",
44626
+ "proceed",
44627
+ "confirm",
44628
+ "save",
44629
+ "ok",
44630
+ "trust",
44631
+ "allow",
44632
+ "always allow"
44633
+ ];
44634
+ }
44635
+ });
44410
44636
  function normalizeCategories(categories) {
44411
44637
  if (!Array.isArray(categories)) return [];
44412
44638
  return categories.map((category) => String(category || "").trim()).filter(Boolean);
@@ -45393,6 +45619,27 @@ ${cleanBody}`;
45393
45619
  });
45394
45620
  return { prompt, footers };
45395
45621
  }
45622
+ function extractButtonLabels(spec, text) {
45623
+ if (!text) return [];
45624
+ const flags = spec.buttonFlags && spec.buttonFlags.includes("m") ? spec.buttonFlags : `${spec.buttonFlags ?? ""}m`;
45625
+ const buttonRe = compile2(spec.buttonPattern, flags);
45626
+ const labelGroup = Number.isInteger(spec.buttonLabelGroup) && (spec.buttonLabelGroup ?? 0) > 0 ? spec.buttonLabelGroup : 1;
45627
+ const out = [];
45628
+ for (const line of text.split("\n")) {
45629
+ buttonRe.lastIndex = 0;
45630
+ const m = buttonRe.exec(line);
45631
+ if (!m) continue;
45632
+ const captured = m[labelGroup] ?? (labelGroup === 1 && m.length > 2 ? m[m.length - 1] : void 0);
45633
+ if (captured && captured.trim()) out.push(captured.trim());
45634
+ }
45635
+ return out;
45636
+ }
45637
+ function buttonBlockApprovalCue(spec, text) {
45638
+ const labels = extractButtonLabels(spec, text);
45639
+ if (labels.length < 2) return false;
45640
+ if (pickApprovalButton(labels).index < 0) return false;
45641
+ return hasNegativeApprovalOption(labels);
45642
+ }
45396
45643
  function modalMatches(spec, input) {
45397
45644
  const text = input.screenText ?? "";
45398
45645
  const question = compile2(spec.questionPattern, spec.questionFlags ?? "i");
@@ -45401,6 +45648,7 @@ ${cleanBody}`;
45401
45648
  const re = compile2(variant.regex, variant.flags ?? "i");
45402
45649
  if (re.test(text)) return true;
45403
45650
  }
45651
+ if (buttonBlockApprovalCue(spec, text)) return true;
45404
45652
  return false;
45405
45653
  }
45406
45654
  function evaluateGroup(group, spec, input, compiled) {
@@ -45455,6 +45703,7 @@ ${cleanBody}`;
45455
45703
  "src/providers/sdk/v1/builders/cli/detect-status.ts"() {
45456
45704
  "use strict";
45457
45705
  init_visible_region();
45706
+ init_approval_utils();
45458
45707
  DEFAULT_ORDER = ["spinner", "modal", "settled-prompt"];
45459
45708
  }
45460
45709
  });
@@ -49905,6 +50154,7 @@ ${lastSnapshot}`;
49905
50154
  createNativeHistoryDispatcher: () => createNativeHistoryDispatcher,
49906
50155
  createSessionDelivery: () => createSessionDelivery,
49907
50156
  createWorktree: () => createWorktree,
50157
+ daemonIdsEquivalent: () => daemonIdsEquivalent,
49908
50158
  deleteDirectDispatchesByTaskId: () => deleteDirectDispatchesByTaskId,
49909
50159
  deleteMesh: () => deleteMesh,
49910
50160
  deriveMeshReviewInboxItems: () => deriveMeshReviewInboxItems,
@@ -49918,6 +50168,7 @@ ${lastSnapshot}`;
49918
50168
  ensureSessionHostReady: () => ensureSessionHostReady2,
49919
50169
  evaluateFsm: () => evaluateFsm,
49920
50170
  execNpmCommandSync: () => execNpmCommandSync,
50171
+ expandDaemonIdForms: () => expandDaemonIdForms,
49921
50172
  fastForwardMeshNode: () => fastForwardMeshNode,
49922
50173
  filterActivityChatMessages: () => filterActivityChatMessages,
49923
50174
  filterChatMessagesByVisibility: () => filterChatMessagesByVisibility,
@@ -50008,6 +50259,7 @@ ${lastSnapshot}`;
50008
50259
  loadMeshWorktreeBootstrapConfig: () => loadMeshWorktreeBootstrapConfig,
50009
50260
  loadState: () => loadState,
50010
50261
  logCommand: () => logCommand,
50262
+ machineCoreFromDaemonId: () => machineCoreFromDaemonId,
50011
50263
  markSessionDeliveriesTerminal: () => markSessionDeliveriesTerminal,
50012
50264
  markSetupComplete: () => markSetupComplete,
50013
50265
  markStaleDirectDispatches: () => markStaleDirectDispatches,
@@ -51342,6 +51594,7 @@ ${lastSnapshot}`;
51342
51594
  })).sort((a, b) => b.lastUsedAt - a.lastUsedAt);
51343
51595
  }
51344
51596
  init_mesh_config();
51597
+ init_dist();
51345
51598
  init_coordinator_prompt();
51346
51599
  init_mesh_missions();
51347
51600
  init_mesh_task_stats();
@@ -55843,73 +56096,7 @@ ${effect.notification.body || ""}`.trim();
55843
56096
  if (raw.coverage === "full" || raw.coverage === "tail" || raw.coverage === "current-turn") normalized.coverage = raw.coverage;
55844
56097
  return normalized;
55845
56098
  }
55846
- var DEFAULT_APPROVAL_POSITIVE_HINTS = [
55847
- "yes",
55848
- "allow once",
55849
- "approve",
55850
- "accept",
55851
- "continue",
55852
- "run",
55853
- "proceed",
55854
- "confirm",
55855
- "save",
55856
- "ok",
55857
- "trust",
55858
- "allow",
55859
- "always allow"
55860
- ];
55861
- function normalizeApprovalLabel(value) {
55862
- return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
55863
- }
55864
- function isNegativeApprovalLabel(value) {
55865
- const label = normalizeApprovalLabel(value);
55866
- return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
55867
- }
55868
- function getApprovalPositiveHints(provider) {
55869
- const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
55870
- return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
55871
- }
55872
- function pickApprovalButton(buttons, provider) {
55873
- const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
55874
- if (labels.length === 0) {
55875
- return { index: -1, label: "" };
55876
- }
55877
- const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
55878
- const hints = getApprovalPositiveHints(provider);
55879
- for (const hint of hints) {
55880
- const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
55881
- if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
55882
- const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
55883
- if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
55884
- const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
55885
- if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
55886
- }
55887
- return { index: -1, label: "" };
55888
- }
55889
- function pickAutoApprovalButton(buttons) {
55890
- const labels = (buttons || []).map((button) => String(button || "").trim());
55891
- const index = labels.findIndex(Boolean);
55892
- return index >= 0 ? { index, label: labels[index] } : { index: -1, label: "" };
55893
- }
55894
- function formatAutoApprovalMessage(modalMessage, buttonLabel) {
55895
- const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
55896
- const cleanMessage = String(modalMessage || "").trim();
55897
- if (cleanMessage) lines.push(cleanMessage);
55898
- return lines.join("\n");
55899
- }
55900
- function looksLikeActiveApprovalPromptText(content) {
55901
- const text = content.trim();
55902
- if (!text || text.length > 2e3) return false;
55903
- 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);
55904
- const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text) || /^\s*1[.)]\s+yes\b/im.test(text);
55905
- if (hasApprovalQuestion && hasNumberedChoices) return true;
55906
- const lastLines = text.split(/\r?\n/).slice(-12).join("\n");
55907
- const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines) || /yes.*always allow/i.test(lastLines);
55908
- const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
55909
- if (hasDontAskAgain && hasNoOption) return true;
55910
- if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
55911
- return false;
55912
- }
56099
+ init_approval_utils();
55913
56100
  init_provider_patch_state();
55914
56101
  init_chat_message_normalization();
55915
56102
  init_open_panel_support();
@@ -56973,6 +57160,7 @@ ${effect.notification.body || ""}`.trim();
56973
57160
  var import_node_crypto3 = require("crypto");
56974
57161
  init_contracts();
56975
57162
  init_provider_input_support();
57163
+ init_approval_utils();
56976
57164
  init_coordinator_registry();
56977
57165
  init_logger();
56978
57166
  init_debug_config();
@@ -64913,6 +65101,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
64913
65101
  }
64914
65102
  init_logger();
64915
65103
  init_control_effects();
65104
+ init_approval_utils();
64916
65105
  init_provider_patch_state();
64917
65106
  function normalizeProviderSessionId(provider, providerSessionId) {
64918
65107
  const normalizedId = typeof providerSessionId === "string" ? providerSessionId.trim() : "";
@@ -65166,6 +65355,20 @@ ${formatManifestValidationIssues2(validation.issues)}`,
65166
65355
  * keystroke until the modal *content* has settled.
65167
65356
  */
65168
65357
  static AUTO_APPROVE_SETTLE_MS = 600;
65358
+ /**
65359
+ * Busy-side hysteresis for the settle gate. A momentary `generating` flip
65360
+ * while the SAME approval modal's button block is still on screen (its
65361
+ * question line scrolled out of the captured frame, only the buttons + a
65362
+ * residual `esc to interrupt` spinner remain) briefly reports
65363
+ * status!=waiting_approval. Without hysteresis that flip wipes the settle
65364
+ * clock, and the modal→generating→modal flap restarts the 600ms window
65365
+ * every time so auto-approve never fires. We keep the in-progress settle
65366
+ * gate warm across an inactive blip up to this bound; only once the modal
65367
+ * has genuinely stayed gone this long (a real resolution → idle) is the
65368
+ * gate cleared. Bounded so a genuinely new, later approval still re-settles
65369
+ * from scratch rather than firing on a stale timestamp.
65370
+ */
65371
+ static AUTO_APPROVE_GATE_HYSTERESIS_MS = 1500;
65169
65372
  adapter;
65170
65373
  context = null;
65171
65374
  events = [];
@@ -65187,6 +65390,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
65187
65390
  pendingAutoApprovalSignature = "";
65188
65391
  pendingAutoApprovalSince = 0;
65189
65392
  autoApproveSettleTimer = null;
65393
+ // Wall-clock when auto-approve first observed status!=waiting_approval while
65394
+ // a settle gate was in progress. Drives AUTO_APPROVE_GATE_HYSTERESIS_MS so a
65395
+ // brief generating flip does not immediately wipe the settle clock.
65396
+ autoApproveInactiveSince = 0;
65190
65397
  controlValues = {};
65191
65398
  summaryMetadata = void 0;
65192
65399
  appliedEffectKeys = /* @__PURE__ */ new Set();
@@ -66007,14 +66214,28 @@ ${formatManifestValidationIssues2(validation.issues)}`,
66007
66214
  const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
66008
66215
  if (!autoApproveActive) {
66009
66216
  this.lastAutoApprovalSignature = "";
66217
+ if (this.pendingAutoApprovalSince) {
66218
+ if (!this.autoApproveInactiveSince) this.autoApproveInactiveSince = now;
66219
+ const goneForMs = now - this.autoApproveInactiveSince;
66220
+ if (goneForMs < _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS) {
66221
+ if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
66222
+ this.autoApproveSettleTimer = setTimeout(() => {
66223
+ this.autoApproveSettleTimer = null;
66224
+ this.recheckAutoApproveSettled();
66225
+ }, _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS - goneForMs + 20);
66226
+ return autoApproveActive;
66227
+ }
66228
+ }
66010
66229
  this.pendingAutoApprovalSignature = "";
66011
66230
  this.pendingAutoApprovalSince = 0;
66231
+ this.autoApproveInactiveSince = 0;
66012
66232
  if (this.autoApproveSettleTimer) {
66013
66233
  clearTimeout(this.autoApproveSettleTimer);
66014
66234
  this.autoApproveSettleTimer = null;
66015
66235
  }
66016
66236
  return autoApproveActive;
66017
66237
  }
66238
+ this.autoApproveInactiveSince = 0;
66018
66239
  const modal = adapterStatus.activeModal;
66019
66240
  const buttons = Array.isArray(modal?.buttons) ? modal.buttons.map((b) => String(b || "").trim()).filter(Boolean) : [];
66020
66241
  if (!modal || buttons.length === 0) {
@@ -66024,18 +66245,18 @@ ${formatManifestValidationIssues2(validation.issues)}`,
66024
66245
  if (buttonIndex < 0) {
66025
66246
  return autoApproveActive;
66026
66247
  }
66027
- const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
66028
- const signature = [
66029
- approvalEntrySeq,
66248
+ const modalSignature = [
66030
66249
  typeof modal?.message === "string" ? modal.message.trim() : "",
66031
66250
  buttons.join("|"),
66032
66251
  buttonIndex
66033
66252
  ].join("::");
66034
- if (this.autoApproveBusy && signature === this.lastAutoApprovalSignature) {
66253
+ const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
66254
+ const busySignature = `${approvalEntrySeq}::${modalSignature}`;
66255
+ if (this.autoApproveBusy && busySignature === this.lastAutoApprovalSignature) {
66035
66256
  return autoApproveActive;
66036
66257
  }
66037
- if (signature !== this.pendingAutoApprovalSignature) {
66038
- this.pendingAutoApprovalSignature = signature;
66258
+ if (modalSignature !== this.pendingAutoApprovalSignature) {
66259
+ this.pendingAutoApprovalSignature = modalSignature;
66039
66260
  this.pendingAutoApprovalSince = now;
66040
66261
  }
66041
66262
  const settledForMs = now - this.pendingAutoApprovalSince;
@@ -66052,9 +66273,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
66052
66273
  this.autoApproveSettleTimer = null;
66053
66274
  }
66054
66275
  this.autoApproveBusy = true;
66055
- this.lastAutoApprovalSignature = signature;
66276
+ this.lastAutoApprovalSignature = busySignature;
66056
66277
  this.pendingAutoApprovalSignature = "";
66057
66278
  this.pendingAutoApprovalSince = 0;
66279
+ this.autoApproveInactiveSince = 0;
66058
66280
  if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
66059
66281
  this.autoApproveBusyTimer = setTimeout(() => {
66060
66282
  this.autoApproveBusy = false;
@@ -68828,9 +69050,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
68828
69050
  }
68829
69051
  }
68830
69052
  }
68831
- for (const [k, a] of this.adapters) {
68832
- if (a.cliType === agentType) {
68833
- return { adapter: a, key: k };
69053
+ if (!opts?.instanceKey) {
69054
+ for (const [k, a] of this.adapters) {
69055
+ if (a.cliType === agentType) {
69056
+ return { adapter: a, key: k };
69057
+ }
68834
69058
  }
68835
69059
  }
68836
69060
  return null;
@@ -72903,7 +73127,8 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
72903
73127
  var fs23 = __toESM2(require("fs"));
72904
73128
  var path35 = __toESM2(require("path"));
72905
73129
  var os26 = __toESM2(require("os"));
72906
- 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");
73130
+ 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");
73131
+ var LOG_DIR2 = path35.join(ADHDEV_HOME2, "logs");
72907
73132
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
72908
73133
  var MAX_DAYS = 7;
72909
73134
  try {
@@ -73738,13 +73963,14 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
73738
73963
  }
73739
73964
  }
73740
73965
  }
73741
- function stopSessionHostProcesses(appName) {
73966
+ async function stopSessionHostProcesses(appName) {
73742
73967
  const pidFile = path36.join(os27.homedir(), ".adhdev", `${appName}-session-host.pid`);
73968
+ let killedPid = null;
73743
73969
  try {
73744
73970
  if (fs25.existsSync(pidFile)) {
73745
73971
  const pid = Number.parseInt(fs25.readFileSync(pidFile, "utf8").trim(), 10);
73746
73972
  if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
73747
- killPid2(pid);
73973
+ if (killPid2(pid)) killedPid = pid;
73748
73974
  }
73749
73975
  }
73750
73976
  } catch {
@@ -73754,6 +73980,15 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
73754
73980
  } catch {
73755
73981
  }
73756
73982
  }
73983
+ if (killedPid !== null) {
73984
+ await waitForPidExit(killedPid, 15e3);
73985
+ }
73986
+ }
73987
+ function isRetriableInstallLockError(error48) {
73988
+ const code = error48?.code;
73989
+ if (code === "EBUSY" || code === "EPERM") return true;
73990
+ const text = `${error48?.message || ""} ${error48?.stderr || ""}`;
73991
+ return /\bEBUSY\b|\bEPERM\b|resource busy or locked/i.test(text);
73757
73992
  }
73758
73993
  function removeDaemonPidFile() {
73759
73994
  const pidFile = path36.join(os27.homedir(), ".adhdev", "daemon.pid");
@@ -73833,22 +74068,37 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
73833
74068
  appendUpgradeLog(`Waiting for parent pid ${payload.parentPid} to exit`);
73834
74069
  await waitForPidExit(payload.parentPid, 15e3);
73835
74070
  }
73836
- stopSessionHostProcesses(sessionHostAppName);
74071
+ await stopSessionHostProcesses(sessionHostAppName);
73837
74072
  removeDaemonPidFile();
73838
74073
  cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
73839
74074
  const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
73840
74075
  appendUpgradeLog(`Installing ${spec}`);
73841
- const installOutput = (0, import_child_process8.execFileSync)(
73842
- installCommand.command,
73843
- installCommand.args,
73844
- {
73845
- encoding: "utf8",
73846
- stdio: "pipe",
73847
- maxBuffer: 20 * 1024 * 1024,
73848
- env: buildInstallEnvWithNodeOnPath(),
73849
- ...installCommand.execOptions
74076
+ const maxInstallAttempts = process.platform === "win32" ? 3 : 1;
74077
+ let installOutput = "";
74078
+ for (let attempt = 1; attempt <= maxInstallAttempts; attempt++) {
74079
+ try {
74080
+ installOutput = String((0, import_child_process8.execFileSync)(
74081
+ installCommand.command,
74082
+ installCommand.args,
74083
+ {
74084
+ encoding: "utf8",
74085
+ stdio: "pipe",
74086
+ maxBuffer: 20 * 1024 * 1024,
74087
+ env: buildInstallEnvWithNodeOnPath(),
74088
+ ...installCommand.execOptions
74089
+ }
74090
+ ));
74091
+ break;
74092
+ } catch (error48) {
74093
+ if (attempt < maxInstallAttempts && isRetriableInstallLockError(error48)) {
74094
+ appendUpgradeLog(`Install attempt ${attempt} hit a file lock (${error48?.code || "lock"}); cleaning staging and retrying after backoff`);
74095
+ cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
74096
+ await new Promise((resolve24) => setTimeout(resolve24, attempt * 1500));
74097
+ continue;
74098
+ }
74099
+ throw error48;
73850
74100
  }
73851
- );
74101
+ }
73852
74102
  if (installOutput.trim()) {
73853
74103
  appendUpgradeLog(installOutput.trim());
73854
74104
  }
@@ -76109,7 +76359,14 @@ ${mergeTreeErr?.stderr || ""}`;
76109
76359
  "resolve_action",
76110
76360
  "set_mode",
76111
76361
  "change_model",
76112
- "set_thought_level"
76362
+ "set_thought_level",
76363
+ // agent_command (send_chat / clear_history / stop) is session-scoped too: a command
76364
+ // explicitly naming a targetSessionId MUST reach that session wherever it lives, never a
76365
+ // different local session. Without forwarding, a misrouted/relayed send_chat for a REMOTE
76366
+ // worker session that reaches the wrong daemon used to fuzzy-inject the task body into that
76367
+ // daemon's own CLI session (TASKECHO coordinator self-echo). Forwarding to the owning daemon
76368
+ // delivers it to the real worker instead. (findAdapter is also fail-closed as the backstop.)
76369
+ "agent_command"
76113
76370
  ]);
76114
76371
  var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
76115
76372
  function normalizeCommandSource(source) {
@@ -76462,7 +76719,7 @@ ${mergeTreeErr?.stderr || ""}`;
76462
76719
  if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
76463
76720
  const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
76464
76721
  if (!nodeDaemonId) continue;
76465
- if (selfDaemonId && nodeDaemonId === selfDaemonId) return void 0;
76722
+ if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
76466
76723
  return nodeDaemonId;
76467
76724
  }
76468
76725
  return void 0;
@@ -76617,6 +76874,38 @@ ${mergeTreeErr?.stderr || ""}`;
76617
76874
  if (record2?.meta?.meshNodeId === nodeId) return true;
76618
76875
  return false;
76619
76876
  }
76877
+ /**
76878
+ * Best-effort recursive removal of a managed worktree directory.
76879
+ *
76880
+ * The git-registry de-registration is the safety-critical step of worktree
76881
+ * teardown; a leftover directory must never gate dropping the node from the
76882
+ * mesh. On Windows, `fs.rmSync` can throw EINVAL/EPERM/EBUSY on submodule
76883
+ * gitlink (`.git`) files, long paths, junctions, or while a just-stopped
76884
+ * delegate session is still releasing a handle/cwd on the directory. This
76885
+ * helper absorbs those errors (never throws), with bounded retries + backoff
76886
+ * to give handles time to release, and reports whether residue remains.
76887
+ */
76888
+ async bestEffortRemoveWorktreeDir(dir) {
76889
+ if (!dir || !fs26.existsSync(dir)) return { removed: true, residue: false };
76890
+ const sleep3 = (ms) => new Promise((resolve24) => setTimeout(resolve24, ms));
76891
+ const ABSORB = /* @__PURE__ */ new Set(["EINVAL", "EPERM", "EBUSY", "ENOTEMPTY", "EACCES", "EMFILE", "ENFILE"]);
76892
+ let lastErr;
76893
+ for (let attempt = 0; attempt < 4; attempt++) {
76894
+ try {
76895
+ fs26.rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
76896
+ if (!fs26.existsSync(dir)) return { removed: true, residue: false };
76897
+ lastErr = new Error("directory still present after rmSync");
76898
+ } catch (e) {
76899
+ lastErr = e;
76900
+ const code = typeof e?.code === "string" ? e.code : "";
76901
+ if (code && !ABSORB.has(code)) {
76902
+ break;
76903
+ }
76904
+ }
76905
+ await sleep3(150 * (attempt + 1));
76906
+ }
76907
+ return fs26.existsSync(dir) ? { removed: false, residue: true, error: String(lastErr?.message || lastErr || "unknown rm error") } : { removed: true, residue: false };
76908
+ }
76620
76909
  async cleanupLocalWorktreeNode(args) {
76621
76910
  const workspace = typeof args.node?.workspace === "string" ? args.node.workspace.trim() : "";
76622
76911
  if (!workspace) {
@@ -76671,11 +76960,31 @@ ${mergeTreeErr?.stderr || ""}`;
76671
76960
  const entries = await listWorktrees2(repoRoot);
76672
76961
  const managedEntry = entries.find((entry) => normalizePath(entry.path) === actualPath);
76673
76962
  if (!managedEntry) {
76963
+ try {
76964
+ const { execFile: execFile5 } = await import("child_process");
76965
+ const { promisify: promisify8 } = await import("util");
76966
+ const execFileAsync4 = promisify8(execFile5);
76967
+ await execFileAsync4("git", ["worktree", "prune"], {
76968
+ cwd: repoRoot,
76969
+ encoding: "utf8",
76970
+ timeout: 3e4,
76971
+ maxBuffer: 4 * 1024 * 1024,
76972
+ windowsHide: true
76973
+ });
76974
+ } catch {
76975
+ }
76976
+ const rm = await this.bestEffortRemoveWorktreeDir(workspace);
76674
76977
  return {
76675
- success: false,
76676
- code: "mesh_worktree_cleanup_not_registered",
76677
- error: `Refusing to remove '${workspace}' because it is not registered in git worktree list for '${repoRoot}'`,
76678
- recoveryHint: "Inspect git worktree list --porcelain from the source repo. If the path was already removed, prune git worktrees before retrying."
76978
+ success: true,
76979
+ removedPath: workspace,
76980
+ repoRoot,
76981
+ reason: "worktree_unregistered_residue_recovered",
76982
+ recovered: true,
76983
+ ...rm.residue ? {
76984
+ residue: true,
76985
+ 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.`,
76986
+ residueError: rm.error
76987
+ } : {}
76679
76988
  };
76680
76989
  }
76681
76990
  if (managedEntry.branch && managedEntry.branch !== args.node.worktreeBranch) {
@@ -76738,8 +77047,8 @@ ${mergeTreeErr?.stderr || ""}`;
76738
77047
  convergence: forceFallbackConvergence
76739
77048
  };
76740
77049
  } catch (deinitError) {
77050
+ const rm = await this.bestEffortRemoveWorktreeDir(workspace);
76741
77051
  try {
76742
- fs26.rmSync(workspace, { recursive: true, force: true });
76743
77052
  await execFileAsync4("git", ["worktree", "prune"], {
76744
77053
  cwd: repoRoot,
76745
77054
  encoding: "utf8",
@@ -76747,23 +77056,22 @@ ${mergeTreeErr?.stderr || ""}`;
76747
77056
  maxBuffer: GIT_MAX_BUFFER_CLEANUP,
76748
77057
  windowsHide: true
76749
77058
  });
76750
- return {
76751
- success: true,
76752
- removedPath: workspace,
76753
- repoRoot,
76754
- fallback: "fs_rm_worktree_prune",
76755
- forced: true,
76756
- reason: "working_trees_containing_submodules",
76757
- convergence: forceFallbackConvergence
76758
- };
76759
- } catch (rmError) {
76760
- return {
76761
- success: false,
76762
- code: "mesh_worktree_cleanup_failed",
76763
- error: `All removal fallbacks exhausted. deinit+remove: ${deinitError?.message || deinitError}; rmSync+prune: ${rmError?.message || rmError}`,
76764
- recoveryHint: "Manually remove the worktree directory and run git worktree prune from the source repo."
76765
- };
77059
+ } catch {
76766
77060
  }
77061
+ return {
77062
+ success: true,
77063
+ removedPath: workspace,
77064
+ repoRoot,
77065
+ fallback: "fs_rm_worktree_prune",
77066
+ forced: true,
77067
+ reason: "working_trees_containing_submodules",
77068
+ convergence: forceFallbackConvergence,
77069
+ ...rm.residue ? {
77070
+ residue: true,
77071
+ 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.`,
77072
+ residueError: rm.error
77073
+ } : {}
77074
+ };
76767
77075
  }
76768
77076
  }
76769
77077
  return {
@@ -80162,7 +80470,14 @@ ${hintLines.join("\n")}` : "",
80162
80470
  } catch {
80163
80471
  }
80164
80472
  }
80165
- return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {}, ...worktreeCleanup ? { worktreeCleanup } : {} };
80473
+ const residueWarning = worktreeCleanup?.residue === true && typeof worktreeCleanup?.residueWarning === "string" ? worktreeCleanup.residueWarning : void 0;
80474
+ return {
80475
+ success: true,
80476
+ removed,
80477
+ ...residueWarning ? { residueWarning } : {},
80478
+ ...sessionCleanup ? { sessionCleanup } : {},
80479
+ ...worktreeCleanup ? { worktreeCleanup } : {}
80480
+ };
80166
80481
  } catch (e) {
80167
80482
  return { success: false, error: e.message };
80168
80483
  }
@@ -82592,6 +82907,7 @@ ${ptyResult.output.slice(-2e3)}`);
82592
82907
  }
82593
82908
  };
82594
82909
  init_logger();
82910
+ init_approval_utils();
82595
82911
  init_chat_message_normalization();
82596
82912
  var AgentStreamPoller = class {
82597
82913
  deps;