@adhdev/daemon-standalone 1.0.58-rc.1 → 1.0.58-rc.3

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
@@ -3591,14 +3591,77 @@ var require_dist = __commonJS({
3591
3591
  }
3592
3592
  };
3593
3593
  }
3594
+ var establishedSockets2 = /* @__PURE__ */ new WeakSet();
3594
3595
  var SessionHostClient2 = class {
3595
3596
  endpoint;
3596
3597
  socket = null;
3597
3598
  requestWaiters = /* @__PURE__ */ new Map();
3598
3599
  eventListeners = /* @__PURE__ */ new Set();
3600
+ disconnectListeners = /* @__PURE__ */ new Set();
3601
+ /** Guards against emitting both an 'error'-path and a 'close'-path disconnect for one socket. */
3602
+ disconnectedSockets = /* @__PURE__ */ new WeakSet();
3599
3603
  constructor(options = {}) {
3600
3604
  this.endpoint = options.endpoint || getDefaultSessionHostEndpoint2(options.appName || "adhdev");
3601
3605
  }
3606
+ /**
3607
+ * Fires when an established connection to the session host goes away.
3608
+ *
3609
+ * Before this existed the client registered only 'data' and 'error' handlers,
3610
+ * so a *clean* FIN — the host process exiting normally, or dying to an
3611
+ * uncaught exception that took the socket down without an error event on our
3612
+ * end — ran nothing at all: `this.socket` stayed non-null pointing at a dead
3613
+ * socket, in-flight waiters hung to their 30s timeout, and no caller was told.
3614
+ * That silence is what let a session-host death present downstream as an
3615
+ * unrelated application-level fault (a missing completion marker) instead of
3616
+ * "the host is gone".
3617
+ */
3618
+ onDisconnect(listener) {
3619
+ this.disconnectListeners.add(listener);
3620
+ return () => {
3621
+ this.disconnectListeners.delete(listener);
3622
+ };
3623
+ }
3624
+ handleDisconnect(socket, reason, error48) {
3625
+ if (this.disconnectedSockets.has(socket)) return;
3626
+ this.disconnectedSockets.add(socket);
3627
+ const wasEstablished = establishedSockets2.has(socket);
3628
+ if (!wasEstablished) {
3629
+ if (this.socket === socket) this.socket = null;
3630
+ try {
3631
+ socket.destroy();
3632
+ } catch {
3633
+ }
3634
+ const failure2 = error48 || new Error(`Session host connect failed (${this.endpoint.path})`);
3635
+ for (const waiter of this.requestWaiters.values()) waiter.reject(failure2);
3636
+ this.requestWaiters.clear();
3637
+ return;
3638
+ }
3639
+ const pendingRequests = this.requestWaiters.size;
3640
+ const failure = error48 || new Error(`Session host connection ${reason} (${this.endpoint.path})`);
3641
+ for (const waiter of this.requestWaiters.values()) {
3642
+ waiter.reject(failure);
3643
+ }
3644
+ this.requestWaiters.clear();
3645
+ if (this.socket === socket) {
3646
+ this.socket = null;
3647
+ }
3648
+ try {
3649
+ socket.destroy();
3650
+ } catch {
3651
+ }
3652
+ const info = {
3653
+ reason,
3654
+ endpointPath: this.endpoint.path,
3655
+ pendingRequests,
3656
+ error: error48
3657
+ };
3658
+ for (const listener of this.disconnectListeners) {
3659
+ try {
3660
+ listener(info);
3661
+ } catch {
3662
+ }
3663
+ }
3664
+ }
3602
3665
  async connect() {
3603
3666
  if (this.socket && !this.socket.destroyed) return;
3604
3667
  if (this.socket) {
@@ -3624,20 +3687,19 @@ var require_dist = __commonJS({
3624
3687
  }
3625
3688
  }));
3626
3689
  socket.on("error", (error48) => {
3627
- for (const waiter of this.requestWaiters.values()) {
3628
- waiter.reject(error48);
3629
- }
3630
- this.requestWaiters.clear();
3631
- if (this.socket === socket) {
3632
- this.socket = null;
3633
- }
3634
- try {
3635
- socket.destroy();
3636
- } catch {
3637
- }
3690
+ this.handleDisconnect(socket, "error", error48);
3691
+ });
3692
+ socket.on("close", () => {
3693
+ this.handleDisconnect(socket, "closed");
3694
+ });
3695
+ socket.on("end", () => {
3696
+ this.handleDisconnect(socket, "ended");
3638
3697
  });
3639
3698
  await new Promise((resolve3, reject) => {
3640
- socket.once("connect", () => resolve3());
3699
+ socket.once("connect", () => {
3700
+ establishedSockets2.add(socket);
3701
+ resolve3();
3702
+ });
3641
3703
  socket.once("error", reject);
3642
3704
  });
3643
3705
  }
@@ -3679,6 +3741,7 @@ var require_dist = __commonJS({
3679
3741
  if (!this.socket) return;
3680
3742
  const socket = this.socket;
3681
3743
  this.socket = null;
3744
+ this.disconnectedSockets.add(socket);
3682
3745
  for (const waiter of this.requestWaiters.values()) {
3683
3746
  waiter.reject(new Error("Session host client closed"));
3684
3747
  }
@@ -36768,10 +36831,10 @@ var require_dist3 = __commonJS({
36768
36831
  }
36769
36832
  function getDaemonBuildInfo() {
36770
36833
  if (cached2) return cached2;
36771
- const commit = readInjected(true ? "e38506ee9da3e916fb4e3c99c19b636f20e5a35c" : void 0) ?? "unknown";
36772
- const commitShort = readInjected(true ? "e38506ee" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
36773
- const version2 = readInjected(true ? "1.0.58-rc.1" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
36774
- const builtAt = readInjected(true ? "2026-08-22T12:35:42.535Z" : void 0);
36834
+ const commit = readInjected(true ? "789e0aa08f214c5b059b3d12eff74e412488db3b" : void 0) ?? "unknown";
36835
+ const commitShort = readInjected(true ? "789e0aa0" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
36836
+ const version2 = readInjected(true ? "1.0.58-rc.3" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
36837
+ const builtAt = readInjected(true ? "2026-08-23T01:04:20.549Z" : void 0);
36775
36838
  cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
36776
36839
  return cached2;
36777
36840
  }
@@ -38186,7 +38249,9 @@ var require_dist3 = __commonJS({
38186
38249
  }
38187
38250
  }
38188
38251
  function sizeRotationPath(logFile, generation) {
38189
- return logFile.replace(/\.log$/, `.${generation}.log`);
38252
+ const match = logFile.match(/^(.*)(\.[^./\\]+)$/);
38253
+ if (!match) return `${logFile}.${generation}`;
38254
+ return `${match[1]}.${generation}${match[2]}`;
38190
38255
  }
38191
38256
  function rotateSizeGenerations(logFile, maxGenerations = MAX_SIZE_ROTATION_GENERATIONS) {
38192
38257
  if (maxGenerations < 1) return;
@@ -38205,6 +38270,20 @@ var require_dist3 = __commonJS({
38205
38270
  }
38206
38271
  fs22.renameSync(logFile, sizeRotationPath(logFile, 1));
38207
38272
  }
38273
+ function rotateCaptureLogIfNeeded(logPath, maxSize = MAX_CAPTURE_LOG_SIZE, maxGenerations = MAX_CAPTURE_LOG_GENERATIONS) {
38274
+ try {
38275
+ const stat2 = fs22.statSync(logPath);
38276
+ if (stat2.size <= maxSize) return false;
38277
+ } catch {
38278
+ return false;
38279
+ }
38280
+ try {
38281
+ rotateSizeGenerations(logPath, maxGenerations);
38282
+ return true;
38283
+ } catch {
38284
+ return false;
38285
+ }
38286
+ }
38208
38287
  function rotateSizeIfNeeded() {
38209
38288
  try {
38210
38289
  const stat2 = fs22.statSync(currentLogFile);
@@ -38343,6 +38422,8 @@ var require_dist3 = __commonJS({
38343
38422
  var currentDate;
38344
38423
  var currentLogDir;
38345
38424
  var currentLogFile;
38425
+ var MAX_CAPTURE_LOG_SIZE;
38426
+ var MAX_CAPTURE_LOG_GENERATIONS;
38346
38427
  var preparedLogDirs;
38347
38428
  var writeCount;
38348
38429
  var currentLogDirEnv;
@@ -38371,6 +38452,8 @@ var require_dist3 = __commonJS({
38371
38452
  currentDate = getDateStr();
38372
38453
  currentLogDir = resolveLogDir();
38373
38454
  currentLogFile = path32.join(currentLogDir, daemonLogFileName(currentDate));
38455
+ MAX_CAPTURE_LOG_SIZE = 10 * 1024 * 1024;
38456
+ MAX_CAPTURE_LOG_GENERATIONS = 2;
38374
38457
  preparedLogDirs = /* @__PURE__ */ new Set();
38375
38458
  writeCount = 0;
38376
38459
  currentLogDirEnv = process.env.ADHDEV_CONFIG_DIR;
@@ -44084,6 +44167,7 @@ ${error48.message || ""}`;
44084
44167
  __export2(mesh_config_exports, {
44085
44168
  addNode: () => addNode,
44086
44169
  applyMeshHostJoinRequest: () => applyMeshHostJoinRequest,
44170
+ collectIgnoredMagiSlotFields: () => collectIgnoredMagiSlotFields,
44087
44171
  configureMeshHostPairing: () => configureMeshHostPairing,
44088
44172
  createMesh: () => createMesh,
44089
44173
  createMeshHostPairingToken: () => createMeshHostPairingToken,
@@ -44116,25 +44200,75 @@ ${error48.message || ""}`;
44116
44200
  function getMeshConfigPath() {
44117
44201
  return (0, import_path5.join)(getConfigDir2(), "meshes.json");
44118
44202
  }
44119
- function loadMeshConfig(options = {}) {
44203
+ function sleepBlockingMs(ms) {
44204
+ if (ms <= 0) return;
44205
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
44206
+ }
44207
+ function acquireMeshConfigLock() {
44208
+ const lockPath = `${getMeshConfigPath()}.lock`;
44209
+ const deadline = Date.now() + MESH_CONFIG_LOCK_WAIT_MS;
44210
+ while (Date.now() <= deadline) {
44211
+ try {
44212
+ (0, import_fs5.mkdirSync)(lockPath);
44213
+ return () => {
44214
+ try {
44215
+ (0, import_fs5.rmSync)(lockPath, { recursive: true, force: true });
44216
+ } catch {
44217
+ }
44218
+ };
44219
+ } catch (error48) {
44220
+ if (error48?.code !== "EEXIST") return null;
44221
+ try {
44222
+ const stat2 = (0, import_fs5.statSync)(lockPath);
44223
+ if (Date.now() - stat2.mtimeMs > MESH_CONFIG_LOCK_STALE_MS) {
44224
+ (0, import_fs5.rmSync)(lockPath, { recursive: true, force: true });
44225
+ continue;
44226
+ }
44227
+ } catch {
44228
+ continue;
44229
+ }
44230
+ sleepBlockingMs(MESH_CONFIG_LOCK_POLL_MS);
44231
+ }
44232
+ }
44233
+ return null;
44234
+ }
44235
+ function withMeshConfigWriteLock(fn) {
44236
+ if (meshConfigLockHeldInProcess) return fn();
44237
+ const release2 = acquireMeshConfigLock();
44238
+ if (!release2) return fn();
44239
+ meshConfigLockHeldInProcess = true;
44240
+ try {
44241
+ return fn();
44242
+ } finally {
44243
+ meshConfigLockHeldInProcess = false;
44244
+ release2();
44245
+ }
44246
+ }
44247
+ function readMeshConfigFile() {
44120
44248
  const path60 = getMeshConfigPath();
44121
44249
  if (!(0, import_fs5.existsSync)(path60)) return { meshes: [] };
44122
44250
  try {
44123
44251
  const raw = JSON.parse((0, import_fs5.readFileSync)(path60, "utf-8"));
44124
44252
  if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
44125
- const config2 = raw;
44126
- const migrated = migrateLoadedMeshConfig(config2);
44127
- if (migrated && options.persistMigrations !== false) {
44128
- try {
44129
- saveMeshConfig(config2);
44130
- } catch {
44131
- }
44132
- }
44133
- return config2;
44253
+ return raw;
44134
44254
  } catch {
44135
44255
  return { meshes: [] };
44136
44256
  }
44137
44257
  }
44258
+ function loadMeshConfig(options = {}) {
44259
+ const config2 = readMeshConfigFile();
44260
+ const migrated = migrateLoadedMeshConfig(config2);
44261
+ if (migrated && options.persistMigrations !== false) {
44262
+ try {
44263
+ withMeshConfigWriteLock(() => {
44264
+ const fresh = readMeshConfigFile();
44265
+ if (migrateLoadedMeshConfig(fresh)) saveMeshConfig(fresh);
44266
+ });
44267
+ } catch {
44268
+ }
44269
+ }
44270
+ return config2;
44271
+ }
44138
44272
  function migrateLoadedMeshConfig(config2) {
44139
44273
  let changed = false;
44140
44274
  if (foldLegacyTopLevelMeshSetting(config2, "magiKindPanels", "mesh_magi_kind_panel_set({ meshId, task_kind, slots })")) changed = true;
@@ -44219,7 +44353,9 @@ ${error48.message || ""}`;
44219
44353
  }
44220
44354
  function saveMeshConfig(config2) {
44221
44355
  const path60 = getMeshConfigPath();
44222
- (0, import_fs5.writeFileSync)(path60, JSON.stringify(config2, null, 2), { encoding: "utf-8", mode: 384 });
44356
+ const tmpPath = `${path60}.tmp-${process.pid}`;
44357
+ (0, import_fs5.writeFileSync)(tmpPath, JSON.stringify(config2, null, 2), { encoding: "utf-8", mode: 384 });
44358
+ (0, import_fs5.renameSync)(tmpPath, path60);
44223
44359
  }
44224
44360
  function normalizeRepoIdentity(remoteUrl) {
44225
44361
  let identity = remoteUrl.trim().replace(/[?#].*$/, "").replace(/\/+$/, "");
@@ -44259,7 +44395,10 @@ ${error48.message || ""}`;
44259
44395
  const normalized = normalizeRepoIdentity(repoIdentity);
44260
44396
  return loadMeshConfig().meshes.find((m) => normalizeRepoIdentity(m.repoIdentity) === normalized);
44261
44397
  }
44262
- function createMesh(opts) {
44398
+ function createMesh(...args) {
44399
+ return withMeshConfigWriteLock(() => createMeshUnlocked(...args));
44400
+ }
44401
+ function createMeshUnlocked(opts) {
44263
44402
  const config2 = loadMeshConfig();
44264
44403
  if (config2.meshes.length >= 20) {
44265
44404
  throw new Error("Maximum 20 meshes allowed");
@@ -44288,7 +44427,10 @@ ${error48.message || ""}`;
44288
44427
  saveMeshConfig(config2);
44289
44428
  return mesh;
44290
44429
  }
44291
- function updateMesh(meshId, opts) {
44430
+ function updateMesh(...args) {
44431
+ return withMeshConfigWriteLock(() => updateMeshUnlocked(...args));
44432
+ }
44433
+ function updateMeshUnlocked(meshId, opts) {
44292
44434
  const config2 = loadMeshConfig();
44293
44435
  const mesh = config2.meshes.find((m) => m.id === meshId);
44294
44436
  if (!mesh) return void 0;
@@ -44301,7 +44443,10 @@ ${error48.message || ""}`;
44301
44443
  saveMeshConfig(config2);
44302
44444
  return mesh;
44303
44445
  }
44304
- function deleteMesh(meshId) {
44446
+ function deleteMesh(...args) {
44447
+ return withMeshConfigWriteLock(() => deleteMeshUnlocked(...args));
44448
+ }
44449
+ function deleteMeshUnlocked(meshId) {
44305
44450
  const config2 = loadMeshConfig();
44306
44451
  const idx = config2.meshes.findIndex((m) => m.id === meshId);
44307
44452
  if (idx === -1) return false;
@@ -44348,7 +44493,10 @@ ${error48.message || ""}`;
44348
44493
  }
44349
44494
  return { ok: true, tokenId: presentedTokenId };
44350
44495
  }
44351
- function configureMeshHostPairing(meshId, opts) {
44496
+ function configureMeshHostPairing(...args) {
44497
+ return withMeshConfigWriteLock(() => configureMeshHostPairingUnlocked(...args));
44498
+ }
44499
+ function configureMeshHostPairingUnlocked(meshId, opts) {
44352
44500
  const hostAddress = normalizeManualHostAddress(opts.hostAddress);
44353
44501
  const token = opts.token.trim();
44354
44502
  if (!token) throw new Error("token required");
@@ -44372,7 +44520,10 @@ ${error48.message || ""}`;
44372
44520
  saveMeshConfig(config2);
44373
44521
  return { mesh, meshHost, hostAddress };
44374
44522
  }
44375
- function createMeshHostPairingToken(meshId, opts = {}) {
44523
+ function createMeshHostPairingToken(...args) {
44524
+ return withMeshConfigWriteLock(() => createMeshHostPairingTokenUnlocked(...args));
44525
+ }
44526
+ function createMeshHostPairingTokenUnlocked(meshId, opts = {}) {
44376
44527
  const config2 = loadMeshConfig();
44377
44528
  const mesh = config2.meshes.find((m) => m.id === meshId);
44378
44529
  if (!mesh) return void 0;
@@ -44400,7 +44551,10 @@ ${error48.message || ""}`;
44400
44551
  saveMeshConfig(config2);
44401
44552
  return { mesh, meshHost, token, tokenId, ...expiresAt ? { expiresAt } : {} };
44402
44553
  }
44403
- function applyMeshHostJoinRequest(meshId, opts) {
44554
+ function applyMeshHostJoinRequest(...args) {
44555
+ return withMeshConfigWriteLock(() => applyMeshHostJoinRequestUnlocked(...args));
44556
+ }
44557
+ function applyMeshHostJoinRequestUnlocked(meshId, opts) {
44404
44558
  const config2 = loadMeshConfig();
44405
44559
  const mesh = config2.meshes.find((m) => m.id === meshId);
44406
44560
  if (!mesh) return void 0;
@@ -44465,7 +44619,10 @@ ${error48.message || ""}`;
44465
44619
  saveMeshConfig(config2);
44466
44620
  return { accepted: true, mesh, meshHost: mesh.meshHost, node, tokenId: validation.tokenId };
44467
44621
  }
44468
- function setMeshHostPin(meshId, opts) {
44622
+ function setMeshHostPin(...args) {
44623
+ return withMeshConfigWriteLock(() => setMeshHostPinUnlocked(...args));
44624
+ }
44625
+ function setMeshHostPinUnlocked(meshId, opts) {
44469
44626
  const config2 = loadMeshConfig();
44470
44627
  const mesh = config2.meshes.find((m) => m.id === meshId);
44471
44628
  if (!mesh) return void 0;
@@ -44545,7 +44702,10 @@ ${error48.message || ""}`;
44545
44702
  ...mesh.meshHost.hostNodeId ? { hostNodeId: mesh.meshHost.hostNodeId } : {}
44546
44703
  };
44547
44704
  }
44548
- function markMeshHostPairingJoined(meshId, opts) {
44705
+ function markMeshHostPairingJoined(...args) {
44706
+ return withMeshConfigWriteLock(() => markMeshHostPairingJoinedUnlocked(...args));
44707
+ }
44708
+ function markMeshHostPairingJoinedUnlocked(meshId, opts) {
44549
44709
  const config2 = loadMeshConfig();
44550
44710
  const mesh = config2.meshes.find((m) => m.id === meshId);
44551
44711
  if (!mesh) return void 0;
@@ -44569,7 +44729,10 @@ ${error48.message || ""}`;
44569
44729
  saveMeshConfig(config2);
44570
44730
  return { mesh, meshHost: mesh.meshHost };
44571
44731
  }
44572
- function addNode(meshId, opts) {
44732
+ function addNode(...args) {
44733
+ return withMeshConfigWriteLock(() => addNodeUnlocked(...args));
44734
+ }
44735
+ function addNodeUnlocked(meshId, opts) {
44573
44736
  const config2 = loadMeshConfig();
44574
44737
  const mesh = config2.meshes.find((m) => m.id === meshId);
44575
44738
  if (!mesh) return void 0;
@@ -44616,7 +44779,10 @@ ${error48.message || ""}`;
44616
44779
  saveMeshConfig(config2);
44617
44780
  return node;
44618
44781
  }
44619
- function removeNode(meshId, nodeId) {
44782
+ function removeNode(...args) {
44783
+ return withMeshConfigWriteLock(() => removeNodeUnlocked(...args));
44784
+ }
44785
+ function removeNodeUnlocked(meshId, nodeId) {
44620
44786
  const config2 = loadMeshConfig();
44621
44787
  const mesh = config2.meshes.find((m) => m.id === meshId);
44622
44788
  if (!mesh) return false;
@@ -44628,7 +44794,10 @@ ${error48.message || ""}`;
44628
44794
  saveMeshConfig(config2);
44629
44795
  return true;
44630
44796
  }
44631
- function updateNode(meshId, nodeId, opts) {
44797
+ function updateNode(...args) {
44798
+ return withMeshConfigWriteLock(() => updateNodeUnlocked(...args));
44799
+ }
44800
+ function updateNodeUnlocked(meshId, nodeId, opts) {
44632
44801
  const config2 = loadMeshConfig();
44633
44802
  const mesh = config2.meshes.find((m) => m.id === meshId);
44634
44803
  if (!mesh) return void 0;
@@ -44680,6 +44849,22 @@ ${error48.message || ""}`;
44680
44849
  }
44681
44850
  return s2;
44682
44851
  }
44852
+ function collectIgnoredMagiSlotFields(slots) {
44853
+ if (!Array.isArray(slots)) return [];
44854
+ const out = [];
44855
+ slots.forEach((entry, idx) => {
44856
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) return;
44857
+ for (const key2 of Object.keys(entry)) {
44858
+ if (MAGI_SLOT_KNOWN_KEYS.includes(key2)) continue;
44859
+ out.push({
44860
+ slot: idx,
44861
+ field: key2,
44862
+ reason: MAGI_SLOT_IGNORED_FIELD_REASONS[key2] ?? `not a recognized MAGI slot key (accepted: ${MAGI_SLOT_KNOWN_KEYS.join(", ")}); it was dropped and has no effect.`
44863
+ });
44864
+ }
44865
+ });
44866
+ return out;
44867
+ }
44683
44868
  function normalizeMagiSlots(slots, knownNodeIds) {
44684
44869
  const allowed = knownNodeIds ? new Set(knownNodeIds) : void 0;
44685
44870
  if (!Array.isArray(slots) || slots.length === 0) {
@@ -44742,7 +44927,10 @@ ${error48.message || ""}`;
44742
44927
  const config2 = loadMeshConfig();
44743
44928
  return resolveScopedMesh(config2, meshId)?.magiKindPanels?.[key2];
44744
44929
  }
44745
- function setMagiKindPanel(kind, slots, meshId) {
44930
+ function setMagiKindPanel(...args) {
44931
+ return withMeshConfigWriteLock(() => setMagiKindPanelUnlocked(...args));
44932
+ }
44933
+ function setMagiKindPanelUnlocked(kind, slots, meshId) {
44746
44934
  const key2 = normalizeMagiTaskKindKey(kind);
44747
44935
  const stored = loadMeshConfig();
44748
44936
  const mesh = resolveScopedMesh(stored, meshId);
@@ -44759,7 +44947,10 @@ ${error48.message || ""}`;
44759
44947
  saveMeshConfig(stored);
44760
44948
  return normalized;
44761
44949
  }
44762
- function removeMagiKindPanel(kind, meshId) {
44950
+ function removeMagiKindPanel(...args) {
44951
+ return withMeshConfigWriteLock(() => removeMagiKindPanelUnlocked(...args));
44952
+ }
44953
+ function removeMagiKindPanelUnlocked(kind, meshId) {
44763
44954
  let key2;
44764
44955
  try {
44765
44956
  key2 = normalizeMagiTaskKindKey(kind);
@@ -44796,7 +44987,10 @@ ${error48.message || ""}`;
44796
44987
  const normalized = normalizeDifficultyBrainMap(stored);
44797
44988
  return Object.keys(normalized).length > 0 ? normalized : { ...DEFAULT_DIFFICULTY_BRAINS };
44798
44989
  }
44799
- function setDifficultyBrains(map3, meshId) {
44990
+ function setDifficultyBrains(...args) {
44991
+ return withMeshConfigWriteLock(() => setDifficultyBrainsUnlocked(...args));
44992
+ }
44993
+ function setDifficultyBrainsUnlocked(map3, meshId) {
44800
44994
  const normalized = normalizeDifficultyBrainMap(map3);
44801
44995
  const stored = loadMeshConfig();
44802
44996
  const mesh = resolveScopedMesh(stored, meshId);
@@ -44842,7 +45036,10 @@ ${error48.message || ""}`;
44842
45036
  const stored = resolveScopedMesh(config2, meshId)?.policy?.quotaRouting;
44843
45037
  return normalizeQuotaRoutingPolicy(stored) ?? {};
44844
45038
  }
44845
- function setMeshQuotaRouting(input, meshId) {
45039
+ function setMeshQuotaRouting(...args) {
45040
+ return withMeshConfigWriteLock(() => setMeshQuotaRoutingUnlocked(...args));
45041
+ }
45042
+ function setMeshQuotaRoutingUnlocked(input, meshId) {
44846
45043
  const overrides = validateQuotaRoutingOverrides(input);
44847
45044
  const stored = loadMeshConfig();
44848
45045
  const mesh = resolveScopedMesh(stored, meshId);
@@ -44859,9 +45056,15 @@ ${error48.message || ""}`;
44859
45056
  var import_fs5;
44860
45057
  var import_path5;
44861
45058
  var import_crypto3;
45059
+ var MESH_CONFIG_LOCK_WAIT_MS;
45060
+ var MESH_CONFIG_LOCK_STALE_MS;
45061
+ var MESH_CONFIG_LOCK_POLL_MS;
45062
+ var meshConfigLockHeldInProcess;
44862
45063
  var mergeMeshPolicy;
44863
45064
  var MAGI_KIND_PANEL_KINDS;
44864
45065
  var MAX_MAGI_KIND_SLOTS;
45066
+ var MAGI_SLOT_KNOWN_KEYS;
45067
+ var MAGI_SLOT_IGNORED_FIELD_REASONS;
44865
45068
  var QUOTA_ROUTING_PERCENT_FIELDS;
44866
45069
  var QUOTA_ROUTING_NONNEGATIVE_FIELDS;
44867
45070
  var init_mesh_config = __esm2({
@@ -44875,9 +45078,20 @@ ${error48.message || ""}`;
44875
45078
  init_dist();
44876
45079
  init_repo_mesh_types();
44877
45080
  init_mesh_host_ownership();
45081
+ MESH_CONFIG_LOCK_WAIT_MS = 2e3;
45082
+ MESH_CONFIG_LOCK_STALE_MS = 15e3;
45083
+ MESH_CONFIG_LOCK_POLL_MS = 25;
45084
+ meshConfigLockHeldInProcess = false;
44878
45085
  mergeMeshPolicy = mergeAndNormalizePolicy;
44879
45086
  MAGI_KIND_PANEL_KINDS = ["claim_audit", "rca", "design", "freeform"];
44880
45087
  MAX_MAGI_KIND_SLOTS = 24;
45088
+ MAGI_SLOT_KNOWN_KEYS = ["provider", "nodeId", "model", "capabilityTags", "n"];
45089
+ MAGI_SLOT_IGNORED_FIELD_REASONS = Object.freeze({
45090
+ thinkingLevel: "not part of a MAGI slot \u2014 a panel selects WHO answers independently, not how hard each replica thinks. Set thinkingLevel on the node's capability slots (mesh_node_slots_set), which is the routing axis.",
45091
+ difficulty: "not part of a MAGI slot \u2014 MAGI always enqueues its replicas with the fixed 'freeform' difficulty sentinel because the panel has already chosen the (node, provider) target. Set difficulty on the node's capability slots instead.",
45092
+ maxParallel: "not part of a MAGI slot \u2014 per-slot concurrency is a node capability-slot axis. Use the per-slot `n` replica count to control MAGI fan-out width.",
45093
+ capability: "not a MAGI slot key \u2014 did you mean `capabilityTags`?"
45094
+ });
44881
45095
  QUOTA_ROUTING_PERCENT_FIELDS = /* @__PURE__ */ new Set(["sessionMinRemainingPercent", "weeklyMinRemainingPercent"]);
44882
45096
  QUOTA_ROUTING_NONNEGATIVE_FIELDS = /* @__PURE__ */ new Set(["staleAfterMs", "sessionResetImminentMs", "spreadBonusMax"]);
44883
45097
  }
@@ -48569,6 +48783,36 @@ ${blocks.join("\n\n")}`;
48569
48783
  divergenceLogOnce = /* @__PURE__ */ new Set();
48570
48784
  }
48571
48785
  });
48786
+ function s(v) {
48787
+ return typeof v === "string" && v.trim() ? v.trim() : "";
48788
+ }
48789
+ function meshEventTraceKey(ctx) {
48790
+ const segs = [`task=${s(ctx.taskId) || "-"}`];
48791
+ const eventId = s(ctx.eventId);
48792
+ if (eventId) segs.push(`evt=${eventId}`);
48793
+ segs.push(`sess=${s(ctx.sessionId) || "-"}`);
48794
+ const nodeId = s(ctx.nodeId);
48795
+ if (nodeId) segs.push(`node=${nodeId}`);
48796
+ const meshId = s(ctx.meshId);
48797
+ if (meshId) segs.push(`mesh=${meshId}`);
48798
+ const event = s(ctx.event);
48799
+ if (event) segs.push(`event=${event}`);
48800
+ return segs.join(" ");
48801
+ }
48802
+ function traceMeshEventStage(stage, ctx, detail) {
48803
+ LOG2.info(CAT, `[stage:${stage}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
48804
+ }
48805
+ function traceMeshEventDrop(reason, ctx, detail) {
48806
+ LOG2.warn(CAT, `[drop:${reason}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
48807
+ }
48808
+ var CAT;
48809
+ var init_mesh_event_trace = __esm2({
48810
+ "src/mesh/mesh-event-trace.ts"() {
48811
+ "use strict";
48812
+ init_logger();
48813
+ CAT = "EvtTrace";
48814
+ }
48815
+ });
48572
48816
  function isSupportedMeshProtocolVersion(value) {
48573
48817
  return typeof value === "string" && SUPPORTED_MESH_PROTOCOL_VERSIONS.includes(value);
48574
48818
  }
@@ -49039,13 +49283,55 @@ ${blocks.join("\n\n")}`;
49039
49283
  }
49040
49284
  return backfilled.reverse();
49041
49285
  }
49286
+ function readPendingEventTaskId(event) {
49287
+ const metadataEvent = readRecord2(event.metadataEvent);
49288
+ return readNonEmptyString(metadataEvent?.taskId);
49289
+ }
49290
+ function dropStaleTerminalTaskEvents(meshId, events) {
49291
+ if (!events.some((event) => STALE_TASK_DROPPABLE_EVENTS.has(event.event))) return events;
49292
+ let store;
49293
+ try {
49294
+ store = MeshRuntimeStore.getInstance();
49295
+ } catch {
49296
+ return events;
49297
+ }
49298
+ const terminalByTaskId = /* @__PURE__ */ new Map();
49299
+ const isTaskTerminal = (taskId) => {
49300
+ const cached5 = terminalByTaskId.get(taskId);
49301
+ if (cached5 !== void 0) return cached5;
49302
+ let terminal = false;
49303
+ try {
49304
+ const entry = store.findQueueEntryById(meshId, taskId);
49305
+ terminal = !!entry && STALE_TASK_TERMINAL_STATUSES.has(entry.status);
49306
+ } catch {
49307
+ terminal = false;
49308
+ }
49309
+ terminalByTaskId.set(taskId, terminal);
49310
+ return terminal;
49311
+ };
49312
+ return events.filter((event) => {
49313
+ if (!STALE_TASK_DROPPABLE_EVENTS.has(event.event)) return true;
49314
+ const taskId = readPendingEventTaskId(event);
49315
+ if (!taskId) return true;
49316
+ if (!isTaskTerminal(taskId)) return true;
49317
+ traceMeshEventDrop("stale_task_terminal", {
49318
+ taskId,
49319
+ sessionId: resolveEventSessionId(event.metadataEvent) ?? event.targetCoordinatorSessionId,
49320
+ nodeId: event.nodeId,
49321
+ meshId,
49322
+ event: event.event
49323
+ }, "task row is already terminal (completed/failed/cancelled) \u2014 non-terminal alert is stale");
49324
+ return false;
49325
+ });
49326
+ }
49042
49327
  function reconcilePendingMeshCoordinatorEvents(meshId, events) {
49043
49328
  const backfilled = refineTerminalEventFromLedger(meshId, events);
49044
49329
  const terminalJobIds = new Set(
49045
49330
  [...events.filter((event) => REFINE_TERMINAL_EVENTS.has(event.event)), ...backfilled].map((event) => readRefineJobId2(event)).filter(Boolean)
49046
49331
  );
49047
49332
  const reconciled = terminalJobIds.size === 0 ? events : events.filter((event) => !(event.event === "refine:accepted" && terminalJobIds.has(readRefineJobId2(event))));
49048
- return backfilled.length === 0 ? reconciled : [...reconciled, ...backfilled];
49333
+ const fresh = dropStaleTerminalTaskEvents(meshId, reconciled);
49334
+ return backfilled.length === 0 ? fresh : [...fresh, ...backfilled];
49049
49335
  }
49050
49336
  function getPendingRetentionCounters() {
49051
49337
  return { ...pendingRetentionCounters };
@@ -49430,6 +49716,8 @@ ${blocks.join("\n\n")}`;
49430
49716
  var TERMINAL_COMPLETION_EVENTS;
49431
49717
  var COORDINATOR_ALERT_EVENTS_WITH_REASON_FINGERPRINT;
49432
49718
  var TERMINAL_COMPLETION_DEDUP_TTL_MS;
49719
+ var STALE_TASK_DROPPABLE_EVENTS;
49720
+ var STALE_TASK_TERMINAL_STATUSES;
49433
49721
  var PENDING_EVENTS_DRAINED_RETENTION_MS;
49434
49722
  var PENDING_EVENTS_UNDRAINED_RETENTION_MS;
49435
49723
  var PENDING_RETENTION_EXPIRED_HOLD_REASON;
@@ -49444,6 +49732,7 @@ ${blocks.join("\n\n")}`;
49444
49732
  init_mesh_runtime_store();
49445
49733
  init_mesh_turn_presentation();
49446
49734
  init_mesh_events_utils();
49735
+ init_mesh_event_trace();
49447
49736
  init_dist();
49448
49737
  init_contracts();
49449
49738
  REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
@@ -49484,6 +49773,15 @@ ${blocks.join("\n\n")}`;
49484
49773
  "mesh:dispatch_blocked"
49485
49774
  ]);
49486
49775
  TERMINAL_COMPLETION_DEDUP_TTL_MS = 60 * 60 * 1e3;
49776
+ STALE_TASK_DROPPABLE_EVENTS = /* @__PURE__ */ new Set([
49777
+ // Actionable dispatch-skip page ("this task will NOT dispatch on its own"). Meaningless
49778
+ // once the task is terminal — the measured 081317f3 case.
49779
+ "mesh:dispatch_blocked",
49780
+ // Stall watchdog ("no progress observed"). A terminal task cannot make progress; the
49781
+ // alert only invites the coordinator to re-drive already-finished work.
49782
+ "monitor:no_progress"
49783
+ ]);
49784
+ STALE_TASK_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
49487
49785
  PENDING_EVENTS_DRAINED_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
49488
49786
  PENDING_EVENTS_UNDRAINED_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
49489
49787
  PENDING_RETENTION_EXPIRED_HOLD_REASON = "pending_retention_expired";
@@ -49504,36 +49802,6 @@ ${blocks.join("\n\n")}`;
49504
49802
  };
49505
49803
  }
49506
49804
  });
49507
- function s(v) {
49508
- return typeof v === "string" && v.trim() ? v.trim() : "";
49509
- }
49510
- function meshEventTraceKey(ctx) {
49511
- const segs = [`task=${s(ctx.taskId) || "-"}`];
49512
- const eventId = s(ctx.eventId);
49513
- if (eventId) segs.push(`evt=${eventId}`);
49514
- segs.push(`sess=${s(ctx.sessionId) || "-"}`);
49515
- const nodeId = s(ctx.nodeId);
49516
- if (nodeId) segs.push(`node=${nodeId}`);
49517
- const meshId = s(ctx.meshId);
49518
- if (meshId) segs.push(`mesh=${meshId}`);
49519
- const event = s(ctx.event);
49520
- if (event) segs.push(`event=${event}`);
49521
- return segs.join(" ");
49522
- }
49523
- function traceMeshEventStage(stage, ctx, detail) {
49524
- LOG2.info(CAT, `[stage:${stage}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
49525
- }
49526
- function traceMeshEventDrop(reason, ctx, detail) {
49527
- LOG2.warn(CAT, `[drop:${reason}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
49528
- }
49529
- var CAT;
49530
- var init_mesh_event_trace = __esm2({
49531
- "src/mesh/mesh-event-trace.ts"() {
49532
- "use strict";
49533
- init_logger();
49534
- CAT = "EvtTrace";
49535
- }
49536
- });
49537
49805
  function taskIsParked(task) {
49538
49806
  return !!readNonEmptyString(task?.parked?.reason);
49539
49807
  }
@@ -49641,6 +49909,176 @@ The instruction it carried was never delivered to anyone. If it still matters, r
49641
49909
  PARK_RETENTION_EXPIRED_REASON = "parked_task_retention_expired";
49642
49910
  }
49643
49911
  });
49912
+ function isWorkerAbsenceDispatchFailure(reason) {
49913
+ const text = readNonEmptyString(reason);
49914
+ if (!text) return false;
49915
+ const normalized = text.toLowerCase();
49916
+ return normalized.includes("cli agent not running") || normalized.includes("no provider instance for session") || normalized.includes("no mesh worker session bound to node");
49917
+ }
49918
+ function resolveTunedReconcileMs(envName, def, min, max) {
49919
+ const raw = readNonEmptyString(process.env[envName]);
49920
+ if (raw) {
49921
+ const parsed = Number.parseInt(raw, 10);
49922
+ if (Number.isFinite(parsed) && parsed >= min && parsed <= max) return parsed;
49923
+ }
49924
+ return def;
49925
+ }
49926
+ function resolveAckedDeathDeadlineMs() {
49927
+ return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
49928
+ }
49929
+ function resolveAckedTranscriptFastTrackGraceMs() {
49930
+ return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
49931
+ }
49932
+ function resolveAckedHoldHardCeilingMs() {
49933
+ return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_HOLD_HARD_CEILING_MS", 90 * 6e4, 0, 24 * 60 * 6e4);
49934
+ }
49935
+ function inFlightSynthKey(meshId, taskId) {
49936
+ return `${meshId}::${taskId}`;
49937
+ }
49938
+ function taskIdFromSynthKey(meshId, synthKey) {
49939
+ const prefix = `${meshId}::`;
49940
+ return synthKey.startsWith(prefix) ? synthKey.slice(prefix.length) : synthKey;
49941
+ }
49942
+ function holdStore() {
49943
+ try {
49944
+ return MeshRuntimeStore.getInstance();
49945
+ } catch {
49946
+ return void 0;
49947
+ }
49948
+ }
49949
+ function getHoldState(synthKey, meshId) {
49950
+ const cached5 = inFlightAckedHoldState.get(synthKey);
49951
+ if (cached5) return cached5;
49952
+ const store = holdStore();
49953
+ if (!store) return void 0;
49954
+ let row;
49955
+ try {
49956
+ row = store.getInflightHold(taskIdFromSynthKey(meshId, synthKey));
49957
+ } catch {
49958
+ return void 0;
49959
+ }
49960
+ if (!row) return void 0;
49961
+ const state = {
49962
+ liveConfirmedSinceAck: row.holdReason === "live",
49963
+ consecutiveReadFailures: row.readFailureCount ?? 0,
49964
+ ...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {},
49965
+ ...row.heldAt !== null && row.heldAt !== void 0 ? { heldSinceMs: row.heldAt } : {}
49966
+ };
49967
+ inFlightAckedHoldState.set(synthKey, state);
49968
+ return state;
49969
+ }
49970
+ function setHoldState(synthKey, meshId, state) {
49971
+ const store = holdStore();
49972
+ let priorHeldSinceMs = state.heldSinceMs ?? inFlightAckedHoldState.get(synthKey)?.heldSinceMs;
49973
+ if (priorHeldSinceMs === void 0 && store) {
49974
+ try {
49975
+ priorHeldSinceMs = store.getInflightHold(taskIdFromSynthKey(meshId, synthKey))?.heldAt ?? void 0;
49976
+ } catch {
49977
+ }
49978
+ }
49979
+ const heldSinceMs = priorHeldSinceMs ?? Date.now();
49980
+ inFlightAckedHoldState.set(synthKey, { ...state, heldSinceMs });
49981
+ if (!store) return;
49982
+ try {
49983
+ store.upsertInflightHold({
49984
+ taskId: taskIdFromSynthKey(meshId, synthKey),
49985
+ meshId,
49986
+ holdReason: state.liveConfirmedSinceAck ? "live" : "unconfirmed",
49987
+ // Only meaningful when the row is NEW — upsertInflightHold deliberately
49988
+ // preserves held_at on conflict, so an existing row keeps its original anchor.
49989
+ heldAt: heldSinceMs,
49990
+ firstIdleSinceAck: state.transcriptIdleSinceMs ?? null,
49991
+ readFailureCount: state.consecutiveReadFailures
49992
+ });
49993
+ } catch {
49994
+ }
49995
+ }
49996
+ function deleteHoldState(synthKey, meshId) {
49997
+ inFlightAckedHoldState.delete(synthKey);
49998
+ const store = holdStore();
49999
+ if (!store) return;
50000
+ try {
50001
+ store.deleteInflightHold(taskIdFromSynthKey(meshId, synthKey));
50002
+ } catch {
50003
+ }
50004
+ }
50005
+ function recordAckedHoldDispatchOutcome(meshId, taskId, outcome) {
50006
+ const key2 = inFlightSynthKey(meshId, taskId);
50007
+ if (outcome.ok || !isWorkerAbsenceDispatchFailure(outcome.reason)) {
50008
+ ackedHoldDispatchFailureStreak.delete(key2);
50009
+ return;
50010
+ }
50011
+ const prior = ackedHoldDispatchFailureStreak.get(key2)?.count ?? 0;
50012
+ ackedHoldDispatchFailureStreak.set(key2, {
50013
+ count: prior + 1,
50014
+ lastReason: readNonEmptyString(outcome.reason) || "worker_absent"
50015
+ });
50016
+ }
50017
+ function getAckedHoldDispatchFailureStreak(meshId, taskId) {
50018
+ return ackedHoldDispatchFailureStreak.get(inFlightSynthKey(meshId, taskId));
50019
+ }
50020
+ function clearAckedHoldDispatchFailureStreak(synthKey) {
50021
+ ackedHoldDispatchFailureStreak.delete(synthKey);
50022
+ }
50023
+ function rehydrateAckedHoldsForMesh(meshId) {
50024
+ if (rehydratedHoldMeshes.has(meshId)) return;
50025
+ rehydratedHoldMeshes.add(meshId);
50026
+ const store = holdStore();
50027
+ if (!store) return;
50028
+ let rows;
50029
+ try {
50030
+ rows = store.listInflightHoldsByMesh(meshId);
50031
+ } catch {
50032
+ return;
50033
+ }
50034
+ for (const row of rows) {
50035
+ const synthKey = inFlightSynthKey(meshId, row.taskId);
50036
+ if (inFlightAckedHoldState.has(synthKey)) continue;
50037
+ inFlightAckedHoldState.set(synthKey, {
50038
+ liveConfirmedSinceAck: row.holdReason === "live",
50039
+ consecutiveReadFailures: row.readFailureCount ?? 0,
50040
+ ...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {},
50041
+ ...row.heldAt !== null && row.heldAt !== void 0 ? { heldSinceMs: row.heldAt } : {}
50042
+ });
50043
+ }
50044
+ if (rows.length > 0) {
50045
+ LOG2.info("MeshReconcile", `Rehydrated ${rows.length} persisted acked-hold row(s) for mesh ${meshId} after (re)start`);
50046
+ }
50047
+ }
50048
+ function collectHeldSynthKeysForMesh(meshId) {
50049
+ const heldKeys = /* @__PURE__ */ new Set();
50050
+ for (const key2 of inFlightAckedHoldState.keys()) {
50051
+ if (key2.startsWith(`${meshId}::`)) heldKeys.add(key2);
50052
+ }
50053
+ const store = holdStore();
50054
+ if (store) {
50055
+ try {
50056
+ for (const row of store.listInflightHoldsByMesh(meshId)) {
50057
+ heldKeys.add(inFlightSynthKey(meshId, row.taskId));
50058
+ }
50059
+ } catch {
50060
+ }
50061
+ }
50062
+ return heldKeys;
50063
+ }
50064
+ var ACKED_DEATH_CONSECUTIVE_READ_FAILURES;
50065
+ var ACKED_DEATH_CONSECUTIVE_DISPATCH_FAILURES;
50066
+ var inFlightAckedHoldState;
50067
+ var rehydratedHoldMeshes;
50068
+ var ackedHoldDispatchFailureStreak;
50069
+ var init_mesh_reconcile_acked_hold = __esm2({
50070
+ "src/mesh/mesh-reconcile-acked-hold.ts"() {
50071
+ "use strict";
50072
+ init_logger();
50073
+ init_mesh_runtime_store();
50074
+ init_mesh_events_utils();
50075
+ ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
50076
+ ACKED_DEATH_CONSECUTIVE_DISPATCH_FAILURES = 3;
50077
+ inFlightAckedHoldState = /* @__PURE__ */ new Map();
50078
+ rehydratedHoldMeshes = /* @__PURE__ */ new Set();
50079
+ ackedHoldDispatchFailureStreak = /* @__PURE__ */ new Map();
50080
+ }
50081
+ });
49644
50082
  function readPayloadTaskId(entry) {
49645
50083
  const value = entry.payload?.taskId;
49646
50084
  return typeof value === "string" && value.trim() ? value.trim() : "";
@@ -50147,6 +50585,7 @@ The instruction it carried was never delivered to anyone. If it still matters, r
50147
50585
  normalizeMeshTaskPriority: () => normalizeMeshTaskPriority,
50148
50586
  parkTaskTargetPin: () => parkTaskTargetPin,
50149
50587
  reclaimStrandedAssignedTask: () => reclaimStrandedAssignedTask,
50588
+ recordAckedHoldDispatchOutcome: () => recordAckedHoldDispatchOutcome,
50150
50589
  recordDirectDispatchTask: () => recordDirectDispatchTask,
50151
50590
  recordMeshToolCall: () => recordMeshToolCall,
50152
50591
  recordTaskAutoLaunch: () => recordTaskAutoLaunch,
@@ -51045,6 +51484,7 @@ The instruction it carried was never delivered to anyone. If it still matters, r
51045
51484
  init_mesh_task_mode_guardrail();
51046
51485
  init_mesh_task_parking();
51047
51486
  init_mesh_task_mode_guardrail();
51487
+ init_mesh_reconcile_acked_hold();
51048
51488
  ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
51049
51489
  HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
51050
51490
  MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
@@ -58370,6 +58810,7 @@ ${rules.join("\n")}`;
58370
58810
  - **Classify task difficulty honestly.** Judge each task's real difficulty (\`easy\`/\`medium\`/\`difficult\`/\`freeform\`) per the Task difficulty section above \u2014 it is a routing hint, and the matched slot's own model/thinking is what launches. Never bend difficulty to chase a model; retune slots instead (\`mesh_node_slots_set\`).
58371
58811
  - **Retune node profiles when routing is a poor fit \u2014 but only with approval.** A node's capability slots (its provider/model/thinking + difficulty range + capability tags, seen via \`mesh_node_slots_list\`) are what task\u2192node fitness routing matches against. If you notice a persistent mismatch \u2014 e.g. every \`difficult\` task lands on a node whose only slot is a cheap model, or a capability a node clearly has isn't declared \u2014 you MAY propose a slot change with \`mesh_node_slots_set\` (write=false). That returns current-vs-proposed; present that diff to the user with a one-line reason and apply (write=true) ONLY after they approve. It is a WHOLESALE replacement of the node's slots, so include the slots you want to keep. Never rewrite a node's profile silently or without a clear routing reason.
58372
58812
  - **Bootstrap a node's slots from what's actually installed.** When a node has NO slots configured (routing then falls back to "first available provider"), or CLI agents were newly installed on it, call \`mesh_node_slots_propose({ node_id })\` instead of hand-writing a profile. It detects the node's installed CLI agents and drafts a slot list from them \u2014 read-only, it never writes. Present its \`proposedSlots\` with the \`droppedSlots\` / \`destructive\` fields it reports (a wholesale write would delete any existing hand-tuned slot the draft doesn't reproduce, including providers not currently on PATH), then apply with \`mesh_node_slots_set({ slots: proposedSlots, write: true })\` after approval. It flags \`unknownProvider\` / \`provisional\` slots whose placement is a conservative guess rather than an attested one \u2014 call those out rather than presenting them as settled.
58813
+ - **When a MAGI panel is unconfigured, bootstrap it from the same detection.** \`mesh_magi_review({ task_kind })\` resolves its panel SOLELY from the configured kind-panel binding, so a task_kind with no slots fails outright with \`magi_kind_not_configured\` \u2014 MAGI is simply unavailable until someone binds it, and the usual reason nobody has is that this path is easy to miss. Pass \`mesh_node_slots_propose({ node_id, include_magi: true })\` to also get a \`magiPanel\` draft: one slot per DISTINCT detected provider, with no model pinned, because a panel's value is cross-provider independence rather than picking the best provider. It is read-only like the rest of the tool. Apply it per kind with \`mesh_magi_kind_panel_set({ task_kind, slots, write: true })\` after approval \u2014 and note that write is a WHOLESALE replacement of that kind's binding, so present the dry-run's \`currentSlots\` first. Do NOT reach for \`include_magi\` on every slot proposal; it is for when the panels are actually empty or a newly installed provider should join them.
58373
58814
  - **Respect explicit provider requests.** Map: Hermes \u2192 \`hermes-cli\`, Claude/Claude Code \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`, Antigravity \u2192 \`antigravity-cli\`. Never substitute the coordinator's own runtime.
58374
58815
  - **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
58375
58816
  - **Match concurrency to task kind.** Independent read-only tasks (\`live_debug_readonly\`) dispatch all at once up to the read-only cap \u2014 no worktree, no free node needed. Each write task needs its OWN branch workspace (Workflow 3.b0); spreading writes across base nodes is NOT a substitute: a mesh with four base nodes still has zero branch isolation. Ramp up cautiously only when tasks share a base branch or submodule pointer (landing order matters). Never launch a second session onto in-flight work for the same issue, even when \`mesh_read_chat\` shows no final message yet \u2014 successive stages of one investigation stay in their session (see Workflow 3f).
@@ -58530,6 +58971,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
58530
58971
  e. For a continuation of the same issue in an existing session, send a concise **delta instruction**: current verified state, the exact failed/blocked step, the newly approved action, and final reporting requirements. Do not resend the full original task or open a new chat solely to continue the same work; that wastes coordinator and worker context.
58531
58972
  f. **Let the investigator apply the fix when the findings settle it \u2014 otherwise split deliberately.** An investigator that has read the source and named the file:line and the fix already holds context a fresh worker must rebuild from scratch, and you would have to restate its findings in the new task message to get there. Task mode is **per task, not per session**: the read-only guardrail is evaluated on each dispatch from that task's own \`readonly\`/\`task_mode\`, so you hand off by sending a follow-up \`mesh_send_task\` to the SAME session WITHOUT the read-only flag (use \`task_mode: "code_change"\`). You do not need a new session or a fresh worktree for the mode to change. **Hand off in-session when** the findings match your hypothesis, the fix stays inside the files just investigated, and no user decision is pending. **Split to a separate task when** the investigation needs a user decision (it surfaced design options, or a cost/risk tradeoff), when it OVERTURNED your hypothesis so the direction itself needs rethinking, or when the fix touches files another in-flight worker owns. **Never convert an investigation whose own conclusion was "do not change this"** \u2014 a correct no-op finding is a completed task, and pushing it into a fix produces an unverified change nobody asked for. Dispatching the investigation as an ordinary report-first task skips the handoff, but drops the guardrail against premature fixes \u2014 keep \`live_debug_readonly\` whenever the point is to find out whether anything is wrong at all.
58532
58973
  4. **Monitor** \u2014 Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly. Do **not** repeatedly call \`mesh_status\` or \`mesh_view_queue\` just to wait for assigned/generating work. After dispatching a direct or queued task, send one progress update with the task/session handle, then stop. Wait for \`pendingCoordinatorEvents\` or another completion/approval/status signal, an explicit user status request, or a real timeout/stall signal before reading status/chat/queue again. Use at most one compact \`mesh_read_chat\` check after a terminal signal. Handle approvals via \`mesh_approve\`. **Proactively parallelize new work.** When the user reports a new bug or asks for new work, start it immediately if it is independent of in-flight tasks and there is headroom under \`maxParallelTasks\` \u2014 do not wait for a current task to finish or for the user to prompt you to parallelize. Read-only diagnosis (\`live_debug_readonly\`) has no isolation or merge cost, so dispatch it in parallel right away. The no-polling / concurrency-limit rules constrain *re-checking or duplicating already-dispatched work*; they are **not** a reason to defer starting a new, independent task.
58974
+ - **Arrival order is not occurrence order \u2014 identify every notification by its \`taskId\`/\`sessionId\`.** While you are generating, worker notifications are held in the queue and injected together on the tick after you go idle. This is intended (a raw write into a generating session is not consumed as a turn), and the delay is normally well under a minute \u2014 measured median ~1 minute, worst case ~10 minutes. The consequence is that a notification arriving now is **not necessarily about the task you most recently dispatched**. Never infer a notification's subject from timing or from what you just sent: read the \`taskId\`/\`sessionId\` in the notification itself and match it to your own record of what you dispatched. Also note that your own coordinator session id appears in these traces, so a session id in a notification is not automatically a worker's. If a notification refers to a task you have already cancelled or completed, treat it as stale \u2014 do not act on it, and say so rather than silently reinterpreting it as being about current work.
58533
58975
  5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
58534
58976
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
58535
58977
  7. **Converge branches** \u2014 Before marking any task complete, classify every touched node/branch into exactly one final state: \`merged_to_main\`, \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\`. Use \`mesh_status\` branchConvergenceSummary. For obvious clean branch catch-up (ahead 0, behind > 0, upstream fresh, no dirty/stash/submodule issues), use \`mesh_fast_forward_node\` dry-run first and execute only when explicitly safe/approved; this avoids consuming an agent session. Use \`mesh_refine_node\` for clean worktree branches when safe \u2014 but when 2+ sibling worktrees share a base, converge them with \`mesh_refine_batch\` rather than repeated single-node calls (see the sequencing rule in Rules). Before/refine merging root commits that contain submodule gitlink changes, require each submodule commit to be reachable from the configured submodule remote main branch, not merely present on a feature ref or local checkout. If \`mesh_refine_node\` returns \`submodule_reachability_failed\` or publish-required evidence, keep the public convergence bucket as \`blocked_review\`; unless \`allowAutoPublishSubmoduleMainCommits\` is explicitly enabled and Refinery reports successful non-force publish plus post-publish verification, ask the user for explicit approval to push/publish the unreachable submodule commit(s) to submodule main, then rerun \`mesh_refine_node\`. Do not merge the root branch until the submodule commit(s) are reachable from submodule origin/main. A task that remains on a non-main branch is not fully complete unless the final report names the follow-up state and next step.
@@ -61360,6 +61802,10 @@ ${rendered}`, "utf-8");
61360
61802
  if (cachedInline && registry2?.updateInlineMeshNode) {
61361
61803
  registry2.updateInlineMeshNode(req.meshId, cachedInline, node);
61362
61804
  published = true;
61805
+ } else if (!cachedInline && !mesh && registry2?.updateInlineMeshNode) {
61806
+ const shell = { id: req.meshId, nodes: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
61807
+ registry2.updateInlineMeshNode(req.meshId, shell, node);
61808
+ published = true;
61363
61809
  }
61364
61810
  } catch {
61365
61811
  }
@@ -61719,7 +62165,7 @@ ${rendered}`, "utf-8");
61719
62165
  }
61720
62166
  async function registerWorkspaceNodeBestEffort(intent, created, ports, bootstrapStatus) {
61721
62167
  try {
61722
- await ports.registerNode({
62168
+ const published = await ports.registerNode({
61723
62169
  meshId: intent.meshId,
61724
62170
  nodeId: created.nodeId,
61725
62171
  worktreePath: created.worktreePath,
@@ -61727,6 +62173,9 @@ ${rendered}`, "utf-8");
61727
62173
  sourceNodeId: intent.sourceNodeId,
61728
62174
  bootstrapStatus
61729
62175
  });
62176
+ if (!published) {
62177
+ LOG2.warn("MeshGraphWorkspace", `node registration (${bootstrapStatus}) published NOTHING for ${intent.graphId}/${intent.workspaceRef}: node ${created.nodeId} exists on disk at ${created.worktreePath} but is in no membership view (mesh ${intent.meshId} has no config twin on this daemon and no inline-cache seam accepted it) \u2014 mesh_list_nodes will not show it`);
62178
+ }
61730
62179
  } catch (e) {
61731
62180
  LOG2.warn("MeshGraphWorkspace", `node registration (${bootstrapStatus}) failed for ${intent.graphId}/${intent.workspaceRef}: ${e?.message || e}`);
61732
62181
  }
@@ -67937,7 +68386,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
67937
68386
  const base = 1;
67938
68387
  let difficulty = 0;
67939
68388
  const diff = isMeshTaskDifficulty(task.difficulty) ? task.difficulty : void 0;
67940
- if (diff) {
68389
+ if (diff && diff !== "freeform") {
67941
68390
  if (slot.difficulty?.length) {
67942
68391
  difficulty = slot.difficulty.includes(diff) ? 100 : 0;
67943
68392
  } else {
@@ -68804,6 +69253,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
68804
69253
  if (timer) clearTimeout(timer);
68805
69254
  const isQueued = res && typeof res === "object" && res.status === "queued";
68806
69255
  updateSessionDeliveryStatus(delivery.id, isQueued ? "queued" : "delivered");
69256
+ recordAckedHoldDispatchOutcome(ctx.meshId, ctx.task.id, { ok: true });
68807
69257
  if (ctx.task.attemptId) {
68808
69258
  try {
68809
69259
  recordTurnAck({
@@ -68852,6 +69302,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
68852
69302
  }
68853
69303
  LOG2.error("MeshQueue", `Failed to dispatch task via ${ctx.transport} to node ${ctx.nodeId}: ${e?.message}`);
68854
69304
  updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
69305
+ recordAckedHoldDispatchOutcome(ctx.meshId, ctx.task.id, { ok: false, reason: e?.message });
68855
69306
  endTaskDispatchInFlight(ctx.meshId, ctx.task.id);
68856
69307
  try {
68857
69308
  closeAttemptForReassignment({ meshId: ctx.meshId, taskId: ctx.task.id, reason: "dispatch_failed" });
@@ -74491,148 +74942,6 @@ ${cleanBody}`;
74491
74942
  init_mesh_events_utils();
74492
74943
  }
74493
74944
  });
74494
- function resolveTunedReconcileMs(envName, def, min, max) {
74495
- const raw = readNonEmptyString(process.env[envName]);
74496
- if (raw) {
74497
- const parsed = Number.parseInt(raw, 10);
74498
- if (Number.isFinite(parsed) && parsed >= min && parsed <= max) return parsed;
74499
- }
74500
- return def;
74501
- }
74502
- function resolveAckedDeathDeadlineMs() {
74503
- return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
74504
- }
74505
- function resolveAckedTranscriptFastTrackGraceMs() {
74506
- return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
74507
- }
74508
- function resolveAckedHoldHardCeilingMs() {
74509
- return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_HOLD_HARD_CEILING_MS", 90 * 6e4, 0, 24 * 60 * 6e4);
74510
- }
74511
- function inFlightSynthKey(meshId, taskId) {
74512
- return `${meshId}::${taskId}`;
74513
- }
74514
- function taskIdFromSynthKey(meshId, synthKey) {
74515
- const prefix = `${meshId}::`;
74516
- return synthKey.startsWith(prefix) ? synthKey.slice(prefix.length) : synthKey;
74517
- }
74518
- function holdStore() {
74519
- try {
74520
- return MeshRuntimeStore.getInstance();
74521
- } catch {
74522
- return void 0;
74523
- }
74524
- }
74525
- function getHoldState(synthKey, meshId) {
74526
- const cached5 = inFlightAckedHoldState.get(synthKey);
74527
- if (cached5) return cached5;
74528
- const store = holdStore();
74529
- if (!store) return void 0;
74530
- let row;
74531
- try {
74532
- row = store.getInflightHold(taskIdFromSynthKey(meshId, synthKey));
74533
- } catch {
74534
- return void 0;
74535
- }
74536
- if (!row) return void 0;
74537
- const state = {
74538
- liveConfirmedSinceAck: row.holdReason === "live",
74539
- consecutiveReadFailures: row.readFailureCount ?? 0,
74540
- ...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {},
74541
- ...row.heldAt !== null && row.heldAt !== void 0 ? { heldSinceMs: row.heldAt } : {}
74542
- };
74543
- inFlightAckedHoldState.set(synthKey, state);
74544
- return state;
74545
- }
74546
- function setHoldState(synthKey, meshId, state) {
74547
- const store = holdStore();
74548
- let priorHeldSinceMs = state.heldSinceMs ?? inFlightAckedHoldState.get(synthKey)?.heldSinceMs;
74549
- if (priorHeldSinceMs === void 0 && store) {
74550
- try {
74551
- priorHeldSinceMs = store.getInflightHold(taskIdFromSynthKey(meshId, synthKey))?.heldAt ?? void 0;
74552
- } catch {
74553
- }
74554
- }
74555
- const heldSinceMs = priorHeldSinceMs ?? Date.now();
74556
- inFlightAckedHoldState.set(synthKey, { ...state, heldSinceMs });
74557
- if (!store) return;
74558
- try {
74559
- store.upsertInflightHold({
74560
- taskId: taskIdFromSynthKey(meshId, synthKey),
74561
- meshId,
74562
- holdReason: state.liveConfirmedSinceAck ? "live" : "unconfirmed",
74563
- // Only meaningful when the row is NEW — upsertInflightHold deliberately
74564
- // preserves held_at on conflict, so an existing row keeps its original anchor.
74565
- heldAt: heldSinceMs,
74566
- firstIdleSinceAck: state.transcriptIdleSinceMs ?? null,
74567
- readFailureCount: state.consecutiveReadFailures
74568
- });
74569
- } catch {
74570
- }
74571
- }
74572
- function deleteHoldState(synthKey, meshId) {
74573
- inFlightAckedHoldState.delete(synthKey);
74574
- const store = holdStore();
74575
- if (!store) return;
74576
- try {
74577
- store.deleteInflightHold(taskIdFromSynthKey(meshId, synthKey));
74578
- } catch {
74579
- }
74580
- }
74581
- function rehydrateAckedHoldsForMesh(meshId) {
74582
- if (rehydratedHoldMeshes.has(meshId)) return;
74583
- rehydratedHoldMeshes.add(meshId);
74584
- const store = holdStore();
74585
- if (!store) return;
74586
- let rows;
74587
- try {
74588
- rows = store.listInflightHoldsByMesh(meshId);
74589
- } catch {
74590
- return;
74591
- }
74592
- for (const row of rows) {
74593
- const synthKey = inFlightSynthKey(meshId, row.taskId);
74594
- if (inFlightAckedHoldState.has(synthKey)) continue;
74595
- inFlightAckedHoldState.set(synthKey, {
74596
- liveConfirmedSinceAck: row.holdReason === "live",
74597
- consecutiveReadFailures: row.readFailureCount ?? 0,
74598
- ...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {},
74599
- ...row.heldAt !== null && row.heldAt !== void 0 ? { heldSinceMs: row.heldAt } : {}
74600
- });
74601
- }
74602
- if (rows.length > 0) {
74603
- LOG2.info("MeshReconcile", `Rehydrated ${rows.length} persisted acked-hold row(s) for mesh ${meshId} after (re)start`);
74604
- }
74605
- }
74606
- function collectHeldSynthKeysForMesh(meshId) {
74607
- const heldKeys = /* @__PURE__ */ new Set();
74608
- for (const key2 of inFlightAckedHoldState.keys()) {
74609
- if (key2.startsWith(`${meshId}::`)) heldKeys.add(key2);
74610
- }
74611
- const store = holdStore();
74612
- if (store) {
74613
- try {
74614
- for (const row of store.listInflightHoldsByMesh(meshId)) {
74615
- heldKeys.add(inFlightSynthKey(meshId, row.taskId));
74616
- }
74617
- } catch {
74618
- }
74619
- }
74620
- return heldKeys;
74621
- }
74622
- var ACKED_DEATH_CONSECUTIVE_READ_FAILURES;
74623
- var inFlightAckedHoldState;
74624
- var rehydratedHoldMeshes;
74625
- var init_mesh_reconcile_acked_hold = __esm2({
74626
- "src/mesh/mesh-reconcile-acked-hold.ts"() {
74627
- "use strict";
74628
- init_logger();
74629
- init_mesh_runtime_store();
74630
- init_mesh_events_utils();
74631
- ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
74632
- inFlightAckedHoldState = /* @__PURE__ */ new Map();
74633
- rehydratedHoldMeshes = /* @__PURE__ */ new Set();
74634
- }
74635
- });
74636
74945
  function resolveAutoPruneMinAgeMs() {
74637
74946
  const raw = readNonEmptyString(process.env.MESH_AUTO_PRUNE_MIN_AGE_MS);
74638
74947
  if (raw) {
@@ -74864,6 +75173,109 @@ ${cleanBody}`;
74864
75173
  init_mesh_reconcile_identity();
74865
75174
  }
74866
75175
  });
75176
+ function formatBytes(bytes) {
75177
+ if (!Number.isFinite(bytes) || bytes < 0) return "unknown";
75178
+ const units = ["B", "KiB", "MiB", "GiB", "TiB"];
75179
+ let value = bytes;
75180
+ let unit = 0;
75181
+ while (value >= 1024 && unit < units.length - 1) {
75182
+ value /= 1024;
75183
+ unit += 1;
75184
+ }
75185
+ return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)}${units[unit]}`;
75186
+ }
75187
+ function classifyDiskSpace(stats) {
75188
+ if (!Number.isFinite(stats.totalBytes) || stats.totalBytes <= 0) return "ok";
75189
+ const { percentFree, freeBytes } = stats;
75190
+ if (percentFree < DISK_CRITICAL_PERCENT_FREE && freeBytes < DISK_CRITICAL_FREE_BYTES) {
75191
+ return "critical";
75192
+ }
75193
+ if (percentFree < DISK_WARNING_PERCENT_FREE && freeBytes < DISK_WARNING_FREE_BYTES) {
75194
+ return "warning";
75195
+ }
75196
+ return "ok";
75197
+ }
75198
+ function describeDiskSpace(stats, level, path60) {
75199
+ const pct = Number.isFinite(stats.percentFree) ? stats.percentFree.toFixed(1) : "?";
75200
+ const used = Number.isFinite(stats.percentFree) ? (100 - stats.percentFree).toFixed(1) : "?";
75201
+ return `disk ${level.toUpperCase()} at ${path60}: ${formatBytes(stats.freeBytes)} free of ${formatBytes(stats.totalBytes)} (${pct}% free / ${used}% used)`;
75202
+ }
75203
+ function readDiskSpace(path60) {
75204
+ try {
75205
+ const stats = (0, import_fs16.statfsSync)(path60);
75206
+ const blockSize = Number(stats.bsize);
75207
+ const freeBytes = Number(stats.bavail) * blockSize;
75208
+ const totalBytes = Number(stats.blocks) * blockSize;
75209
+ if (!Number.isFinite(freeBytes) || !Number.isFinite(totalBytes) || totalBytes <= 0) {
75210
+ return null;
75211
+ }
75212
+ return {
75213
+ freeBytes,
75214
+ totalBytes,
75215
+ percentFree: freeBytes / totalBytes * 100
75216
+ };
75217
+ } catch {
75218
+ return null;
75219
+ }
75220
+ }
75221
+ function checkDiskSpace(path60) {
75222
+ const stats = readDiskSpace(path60);
75223
+ if (!stats) return null;
75224
+ const level = classifyDiskSpace(stats);
75225
+ return { ...stats, level, path: path60, summary: describeDiskSpace(stats, level, path60) };
75226
+ }
75227
+ function logDiskSpaceStatus(status, context) {
75228
+ if (!status) {
75229
+ LOG2.debug("DiskSpace", `${context}: volume not measurable (statfs unavailable)`);
75230
+ return;
75231
+ }
75232
+ switch (status.level) {
75233
+ case "critical":
75234
+ LOG2.error("DiskSpace", `${context}: ${status.summary} \u2014 writes are expected to fail with ENOSPC`);
75235
+ break;
75236
+ case "warning":
75237
+ LOG2.warn("DiskSpace", `${context}: ${status.summary}`);
75238
+ break;
75239
+ default:
75240
+ LOG2.debug("DiskSpace", `${context}: ${status.summary}`);
75241
+ break;
75242
+ }
75243
+ }
75244
+ function preflightDiskSpace(path60, operation, options = {}) {
75245
+ const status = checkDiskSpace(path60);
75246
+ logDiskSpaceStatus(status, `preflight before ${operation}`);
75247
+ if (status?.level === "critical" && options.throwOnCritical !== false) {
75248
+ throw new LowDiskSpaceError(status, operation);
75249
+ }
75250
+ return status;
75251
+ }
75252
+ var import_fs16;
75253
+ var DISK_CRITICAL_PERCENT_FREE;
75254
+ var DISK_CRITICAL_FREE_BYTES;
75255
+ var DISK_WARNING_PERCENT_FREE;
75256
+ var DISK_WARNING_FREE_BYTES;
75257
+ var LowDiskSpaceError;
75258
+ var init_disk_space_preflight = __esm2({
75259
+ "src/diagnostics/disk-space-preflight.ts"() {
75260
+ "use strict";
75261
+ import_fs16 = require("fs");
75262
+ init_logger();
75263
+ DISK_CRITICAL_PERCENT_FREE = 2;
75264
+ DISK_CRITICAL_FREE_BYTES = 1 * 1024 * 1024 * 1024;
75265
+ DISK_WARNING_PERCENT_FREE = 5;
75266
+ DISK_WARNING_FREE_BYTES = 5 * 1024 * 1024 * 1024;
75267
+ LowDiskSpaceError = class extends Error {
75268
+ status;
75269
+ constructor(status, operation) {
75270
+ super(
75271
+ `Refusing to ${operation}: ${status.summary}. Writes would fail with ENOSPC mid-operation. Free space and retry (see \`adhdev doctor\` for the largest reclaimable paths).`
75272
+ );
75273
+ this.name = "LowDiskSpaceError";
75274
+ this.status = status;
75275
+ }
75276
+ };
75277
+ }
75278
+ });
74867
75279
  function selectExpiredLedgerJsonl(files, now, maxAgeMs = LEDGER_JSONL_MAX_AGE_MS) {
74868
75280
  return files.filter((f) => now - f.mtimeMs > maxAgeMs);
74869
75281
  }
@@ -74898,7 +75310,7 @@ ${cleanBody}`;
74898
75310
  }
74899
75311
  function safeUnlink(path60) {
74900
75312
  try {
74901
- (0, import_fs16.unlinkSync)(path60);
75313
+ (0, import_fs17.unlinkSync)(path60);
74902
75314
  return true;
74903
75315
  } catch (e) {
74904
75316
  LOG2.warn("DiskRetention", `Failed to delete ${path60}: ${e?.message || e}`);
@@ -74906,18 +75318,18 @@ ${cleanBody}`;
74906
75318
  }
74907
75319
  }
74908
75320
  function listDirFiles(dir) {
74909
- if (!(0, import_fs16.existsSync)(dir)) return [];
75321
+ if (!(0, import_fs17.existsSync)(dir)) return [];
74910
75322
  const out = [];
74911
75323
  let names;
74912
75324
  try {
74913
- names = (0, import_fs16.readdirSync)(dir);
75325
+ names = (0, import_fs17.readdirSync)(dir);
74914
75326
  } catch {
74915
75327
  return [];
74916
75328
  }
74917
75329
  for (const name of names) {
74918
75330
  const path60 = (0, import_path14.join)(dir, name);
74919
75331
  try {
74920
- const st = (0, import_fs16.statSync)(path60);
75332
+ const st = (0, import_fs17.statSync)(path60);
74921
75333
  if (st.isFile()) out.push({ path: path60, mtimeMs: st.mtimeMs });
74922
75334
  } catch {
74923
75335
  }
@@ -74944,22 +75356,22 @@ ${cleanBody}`;
74944
75356
  }
74945
75357
  function pruneExpiredSessionHostRuntimes(now = Date.now()) {
74946
75358
  const root = (0, import_path14.join)(getConfigDir2(), "session-host");
74947
- if (!(0, import_fs16.existsSync)(root)) return 0;
75359
+ if (!(0, import_fs17.existsSync)(root)) return 0;
74948
75360
  let apps;
74949
75361
  try {
74950
- apps = (0, import_fs16.readdirSync)(root);
75362
+ apps = (0, import_fs17.readdirSync)(root);
74951
75363
  } catch {
74952
75364
  return 0;
74953
75365
  }
74954
75366
  const candidates = [];
74955
75367
  for (const app of apps) {
74956
75368
  const runtimesDir = (0, import_path14.join)(root, app, "runtimes");
74957
- if (!(0, import_fs16.existsSync)(runtimesDir)) continue;
75369
+ if (!(0, import_fs17.existsSync)(runtimesDir)) continue;
74958
75370
  for (const f of listDirFiles(runtimesDir)) {
74959
75371
  if (!f.path.endsWith(".json")) continue;
74960
75372
  let record2 = null;
74961
75373
  try {
74962
- const parsed = JSON.parse((0, import_fs16.readFileSync)(f.path, "utf-8"));
75374
+ const parsed = JSON.parse((0, import_fs17.readFileSync)(f.path, "utf-8"));
74963
75375
  const rec = parsed && typeof parsed === "object" ? parsed.record : null;
74964
75376
  record2 = rec && typeof rec === "object" ? rec : null;
74965
75377
  } catch {
@@ -75005,7 +75417,15 @@ ${cleanBody}`;
75005
75417
  } catch (e) {
75006
75418
  LOG2.warn("DiskRetention", `Ledger rotation cap sweep failed: ${e?.message || e}`);
75007
75419
  }
75008
- return { ledgerJsonl, dbBackups, sessionHostRuntimes, rotationEvicted, rotationEvictedBytes };
75420
+ let diskLevel = "ok";
75421
+ try {
75422
+ const status = checkDiskSpace(getConfigDir2());
75423
+ logDiskSpaceStatus(status, "disk retention sweep");
75424
+ if (status) diskLevel = status.level;
75425
+ } catch (e) {
75426
+ LOG2.warn("DiskRetention", `Disk space check failed: ${e?.message || e}`);
75427
+ }
75428
+ return { ledgerJsonl, dbBackups, sessionHostRuntimes, rotationEvicted, rotationEvictedBytes, diskLevel };
75009
75429
  }
75010
75430
  async function detectAndSignalOrphanWorktrees(mesh, now = Date.now()) {
75011
75431
  const nodes = Array.isArray(mesh.nodes) ? mesh.nodes : [];
@@ -75056,7 +75476,7 @@ ${cleanBody}`;
75056
75476
  }
75057
75477
  return signalled;
75058
75478
  }
75059
- var import_fs16;
75479
+ var import_fs17;
75060
75480
  var import_path14;
75061
75481
  var DAY_MS2;
75062
75482
  var LEDGER_JSONL_MAX_AGE_MS;
@@ -75066,13 +75486,14 @@ ${cleanBody}`;
75066
75486
  var init_mesh_disk_retention = __esm2({
75067
75487
  "src/mesh/mesh-disk-retention.ts"() {
75068
75488
  "use strict";
75069
- import_fs16 = require("fs");
75489
+ import_fs17 = require("fs");
75070
75490
  import_path14 = require("path");
75071
75491
  init_config();
75072
75492
  init_mesh_ledger();
75073
75493
  init_runtime_surface();
75074
75494
  init_git_worktree();
75075
75495
  init_logger();
75496
+ init_disk_space_preflight();
75076
75497
  DAY_MS2 = 24 * 60 * 60 * 1e3;
75077
75498
  LEDGER_JSONL_MAX_AGE_MS = 30 * DAY_MS2;
75078
75499
  SESSION_HOST_RUNTIME_MAX_AGE_MS = 14 * DAY_MS2;
@@ -76085,6 +76506,7 @@ ${cleanBody}`;
76085
76506
  const { meshId, taskId, sessionId, nodeId, providerType, synthKey, reason, detail } = args;
76086
76507
  updateDirectDispatchStatus(meshId, sessionId, "stale", taskId);
76087
76508
  deleteHoldState(synthKey, meshId);
76509
+ clearAckedHoldDispatchFailureStreak(synthKey);
76088
76510
  try {
76089
76511
  appendLedgerEntry(meshId, {
76090
76512
  kind: "acked_hold_terminalized",
@@ -76140,6 +76562,27 @@ ${cleanBody}`;
76140
76562
  };
76141
76563
  const synthKey = inFlightSynthKey(mesh.id, taskId);
76142
76564
  const isAcked = dispatch.status === "acked";
76565
+ if (isAcked) {
76566
+ const dispatchStreak = getAckedHoldDispatchFailureStreak(mesh.id, taskId);
76567
+ if (dispatchStreak && dispatchStreak.count >= ACKED_DEATH_CONSECUTIVE_DISPATCH_FAILURES) {
76568
+ LOG2.warn("MeshReconcile", `Acked-hold dispatch-failure death signal: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) failed dispatch ${dispatchStreak.count}x consecutively with a worker-absence reason ("${dispatchStreak.lastReason}") \u2014 the target adapter does not exist, so the worker cannot be holding this turn; marking the dispatch row STALE and deleting the synth hold (no completion is asserted \u2014 the transcript never showed one).`);
76569
+ terminalizeAckedHold({
76570
+ meshId: mesh.id,
76571
+ taskId,
76572
+ sessionId,
76573
+ nodeId,
76574
+ ...providerType ? { providerType } : {},
76575
+ synthKey,
76576
+ reason: "acked_dispatch_failure_death",
76577
+ detail: {
76578
+ consecutiveDispatchFailures: dispatchStreak.count,
76579
+ threshold: ACKED_DEATH_CONSECUTIVE_DISPATCH_FAILURES,
76580
+ lastReason: dispatchStreak.lastReason
76581
+ }
76582
+ });
76583
+ continue;
76584
+ }
76585
+ }
76143
76586
  if (isAcked) {
76144
76587
  const ceilingMs = resolveAckedHoldHardCeilingMs();
76145
76588
  const heldSinceMs = getHoldState(synthKey, mesh.id)?.heldSinceMs;
@@ -81093,6 +81536,69 @@ ${cleanBody}`;
81093
81536
  return void 0;
81094
81537
  }
81095
81538
  }
81539
+ function gitRefsResolvable(cwd, refs) {
81540
+ for (const ref of refs) {
81541
+ if (!ref) return false;
81542
+ try {
81543
+ (0, import_node_child_process11.execFileSync)(GIT4, ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], { cwd, stdio: "ignore", windowsHide: true });
81544
+ } catch {
81545
+ return false;
81546
+ }
81547
+ }
81548
+ return true;
81549
+ }
81550
+ function probeGitAncestry(cwd, ancestor, descendant) {
81551
+ try {
81552
+ if (!fs51.existsSync(cwd)) return "undeterminable";
81553
+ } catch {
81554
+ return "undeterminable";
81555
+ }
81556
+ if (!gitRefsResolvable(cwd, [ancestor, descendant])) return "undeterminable";
81557
+ try {
81558
+ (0, import_node_child_process11.execFileSync)(GIT4, ["merge-base", "--is-ancestor", ancestor, descendant], { cwd, stdio: "ignore", windowsHide: true });
81559
+ return true;
81560
+ } catch (e) {
81561
+ return e?.status === 1 ? false : "undeterminable";
81562
+ }
81563
+ }
81564
+ function probeSubmoduleGitlinkReachability(input) {
81565
+ const { path: path60, baseCommit, branchCommit, probeRoot, baseRepoRoot } = input;
81566
+ const submoduleRepo = (0, import_path17.resolve)(probeRoot, path60);
81567
+ const baseSubmoduleRepo = (0, import_path17.resolve)(baseRepoRoot, path60);
81568
+ if (baseCommit) ensureSubmoduleCommitLocal(submoduleRepo, baseSubmoduleRepo, baseCommit);
81569
+ if (branchCommit) ensureSubmoduleCommitLocal(submoduleRepo, baseSubmoduleRepo, branchCommit);
81570
+ let fastForward;
81571
+ let reachableFromOriginMain;
81572
+ const undeterminable = [];
81573
+ if (branchCommit) {
81574
+ if (baseCommit) {
81575
+ const ff = probeGitAncestry(submoduleRepo, baseCommit, branchCommit);
81576
+ if (ff === "undeterminable") undeterminable.push("fastForward");
81577
+ else fastForward = ff;
81578
+ }
81579
+ const reach = probeGitAncestry(submoduleRepo, branchCommit, "refs/remotes/origin/main");
81580
+ if (reach === "undeterminable") undeterminable.push("reachableFromOriginMain");
81581
+ else reachableFromOriginMain = reach;
81582
+ }
81583
+ return {
81584
+ path: path60,
81585
+ baseCommit,
81586
+ branchCommit,
81587
+ fastForward,
81588
+ reachableFromOriginMain,
81589
+ ...undeterminable.length ? { undeterminable } : {},
81590
+ probedRepo: submoduleRepo
81591
+ };
81592
+ }
81593
+ function buildSubmoduleReachabilityUndeterminableWarning(nodeId, evidence) {
81594
+ if (!evidence.submoduleReachabilityUndeterminable) return void 0;
81595
+ const entries = (evidence.submoduleGitlinks || []).filter((g) => (g.undeterminable || []).includes("reachableFromOriginMain")).map((g) => `${g.path}@${(g.branchCommit || "?").slice(0, 12)} (probed: ${g.probedRepo || "unknown"})`).join(", ");
81596
+ return `[Refinery] Could NOT determine submodule gitlink reachability from submodule origin/main for node ${nodeId} \u2014 probe had NO ANSWER (missing commit object and/or missing refs/remotes/origin/main in the probed repo). "undeterminable", NOT "unpublished" and NOT "nothing to converge": ${entries}`;
81597
+ }
81598
+ function warnRefineSubmoduleUndeterminable(nodeId, evidence) {
81599
+ const message = buildSubmoduleReachabilityUndeterminableWarning(nodeId, evidence);
81600
+ if (message) LOG2.warn("Mesh", message);
81601
+ }
81096
81602
  function submoduleCommitPresent(submoduleRepoPath, commit) {
81097
81603
  if (!commit) return false;
81098
81604
  try {
@@ -81140,6 +81646,7 @@ ${cleanBody}`;
81140
81646
  }
81141
81647
  var fs51;
81142
81648
  var import_node_child_process11;
81649
+ var import_path17;
81143
81650
  var GIT4;
81144
81651
  var REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES;
81145
81652
  var init_mesh_refine_gitlink_utils = __esm2({
@@ -81147,6 +81654,8 @@ ${cleanBody}`;
81147
81654
  "use strict";
81148
81655
  fs51 = __toESM2(require("fs"));
81149
81656
  import_node_child_process11 = require("child_process");
81657
+ import_path17 = require("path");
81658
+ init_logger();
81150
81659
  init_resolve_executable();
81151
81660
  GIT4 = process.platform === "win32" ? resolveWin32Executable("git") : "git";
81152
81661
  REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
@@ -81232,9 +81741,9 @@ ${cleanBody}`;
81232
81741
  for (const path60 of changed) {
81233
81742
  const baseCommit = readTreeObject(baseRepoRoot, baseHead, path60);
81234
81743
  const branchCommit = readTreeObject(worktreeRoot, branchHead, path60);
81235
- const submoduleRepoPath = (0, import_path17.resolve)(worktreeRoot, path60);
81744
+ const submoduleRepoPath = (0, import_path18.resolve)(worktreeRoot, path60);
81236
81745
  if (baseCommit) {
81237
- ensureSubmoduleCommitLocal(submoduleRepoPath, (0, import_path17.resolve)(baseRepoRoot, path60), baseCommit);
81746
+ ensureSubmoduleCommitLocal(submoduleRepoPath, (0, import_path18.resolve)(baseRepoRoot, path60), baseCommit);
81238
81747
  }
81239
81748
  const markUndeterminable = () => {
81240
81749
  const unavailable = [];
@@ -81380,7 +81889,7 @@ ${cleanBody}`;
81380
81889
  for (const p of conflicts) {
81381
81890
  const commit = resolveByPath.get(p);
81382
81891
  try {
81383
- (0, import_node_child_process12.execFileSync)(GIT4, ["checkout", "-q", "--detach", commit], { cwd: (0, import_path17.resolve)(worktreeRoot, p), stdio: "ignore" });
81892
+ (0, import_node_child_process12.execFileSync)(GIT4, ["checkout", "-q", "--detach", commit], { cwd: (0, import_path18.resolve)(worktreeRoot, p), stdio: "ignore" });
81384
81893
  } catch {
81385
81894
  }
81386
81895
  try {
@@ -81399,13 +81908,13 @@ ${cleanBody}`;
81399
81908
  return { ok: true, branchHead };
81400
81909
  }
81401
81910
  var fs52;
81402
- var import_path17;
81911
+ var import_path18;
81403
81912
  var import_node_child_process12;
81404
81913
  var init_mesh_refine_submodule_converge = __esm2({
81405
81914
  "src/mesh/mesh-refine-submodule-converge.ts"() {
81406
81915
  "use strict";
81407
81916
  fs52 = __toESM2(require("fs"));
81408
- import_path17 = require("path");
81917
+ import_path18 = require("path");
81409
81918
  import_node_child_process12 = require("child_process");
81410
81919
  init_mesh_refine_gitlink_utils();
81411
81920
  }
@@ -81427,10 +81936,10 @@ ${tail}`;
81427
81936
  }
81428
81937
  function writeValidationFailureLog(workspace, index, candidate, streams, now = () => /* @__PURE__ */ new Date()) {
81429
81938
  try {
81430
- const dir = (0, import_path18.join)(workspace, REFINE_VALIDATION_LOG_DIR);
81939
+ const dir = (0, import_path19.join)(workspace, REFINE_VALIDATION_LOG_DIR);
81431
81940
  fs53.mkdirSync(dir, { recursive: true });
81432
81941
  const stamp = now().toISOString().replace(/[:.]/g, "-");
81433
- const file2 = (0, import_path18.join)(dir, `refine-${stamp}-${index}.log`);
81942
+ const file2 = (0, import_path19.join)(dir, `refine-${stamp}-${index}.log`);
81434
81943
  const asText = (v) => typeof v === "string" ? v : v == null ? "" : String(v);
81435
81944
  const shown = candidate.displayCommand || [candidate.command, ...candidate.args || []].join(" ");
81436
81945
  fs53.writeFileSync(
@@ -81618,9 +82127,15 @@ ${e?.stderr || ""}`
81618
82127
  };
81619
82128
  }
81620
82129
  }
82130
+ async function classifyAndWarnPatchEquivalenceFailure(nodeId, repoRoot, baseHead, branchHead, summary, options = {}) {
82131
+ const classification = await classifyPatchEquivalenceFailure(repoRoot, baseHead, branchHead, summary, options);
82132
+ warnRefineSubmoduleUndeterminable(nodeId, classification.evidence);
82133
+ return classification;
82134
+ }
81621
82135
  async function classifyPatchEquivalenceFailure(repoRoot, baseHead, branchHead, summary, options = {}) {
81622
82136
  const targetBaseRef = options.targetBaseRef || baseHead;
81623
82137
  const autoPublish = options.autoPublishSubmoduleMainCommits;
82138
+ const submoduleProbeRoot = options.worktreeRoot || repoRoot;
81624
82139
  const evidence = {
81625
82140
  baseHead,
81626
82141
  branchHead,
@@ -81685,20 +82200,19 @@ ${e?.stderr || ""}`
81685
82200
  } catch {
81686
82201
  continue;
81687
82202
  }
81688
- const submoduleRepo = (0, import_path18.join)(repoRoot, p);
81689
- let fastForward;
81690
- let reachableFromOriginMain;
81691
- if (branchCommit) {
81692
- if (baseCommit) {
81693
- fastForward = execGitOk(submoduleRepo, ["merge-base", "--is-ancestor", baseCommit, branchCommit]);
81694
- }
81695
- reachableFromOriginMain = execGitOk(submoduleRepo, ["merge-base", "--is-ancestor", branchCommit, "refs/remotes/origin/main"]);
81696
- }
81697
- submoduleGitlinks.push({ path: p, baseCommit, branchCommit, fastForward, reachableFromOriginMain });
82203
+ submoduleGitlinks.push(probeSubmoduleGitlinkReachability({
82204
+ path: p,
82205
+ baseCommit,
82206
+ branchCommit,
82207
+ probeRoot: submoduleProbeRoot,
82208
+ baseRepoRoot: repoRoot
82209
+ }));
81698
82210
  }
81699
82211
  } catch {
81700
82212
  }
81701
82213
  if (submoduleGitlinks.length) evidence.submoduleGitlinks = submoduleGitlinks;
82214
+ const undeterminableGitlinks = submoduleGitlinks.filter((g) => (g.undeterminable || []).includes("reachableFromOriginMain"));
82215
+ if (undeterminableGitlinks.length > 0) evidence.submoduleReachabilityUndeterminable = true;
81702
82216
  const gitlinkFf = summary.gitlinkTrivialFastForward;
81703
82217
  const noResidualDiff = !evidence.diffStat && (!summary.actualPatchId || summary.actualPatchId === "");
81704
82218
  if (ahead === 0 && behind === 0 && noResidualDiff) {
@@ -81719,6 +82233,15 @@ ${e?.stderr || ""}`
81719
82233
  evidence
81720
82234
  };
81721
82235
  }
82236
+ if (undeterminableGitlinks.length > 0) {
82237
+ const refs = undeterminableGitlinks.map((g) => `${g.path}@${(g.branchCommit || "?").slice(0, 12)} (probed: ${g.probedRepo || "unknown"})`).join(", ");
82238
+ return {
82239
+ detailedReason: "submodule_reachability_undeterminable",
82240
+ detailedReasonDescription: `Could NOT determine whether submodule gitlink commit(s) are reachable from submodule origin/main \u2014 the probe had no answer (missing commit object and/or missing refs/remotes/origin/main in the probed repo): ${refs}. This is "undeterminable", NOT "unpublished".`,
82241
+ recommendedAction: "Make the probe answerable, then rerun mesh_refine_node: fetch the submodule remote in the probed checkout (`git -C <probedRepo> fetch origin main`) so both the gitlink commit object and refs/remotes/origin/main exist locally. Do NOT publish/push the submodule commit on the strength of this result \u2014 reachability was never established either way.",
82242
+ evidence
82243
+ };
82244
+ }
81722
82245
  const changedGitlinks = submoduleGitlinks.length > 0;
81723
82246
  const allGitlinksFf = changedGitlinks && submoduleGitlinks.every((g) => g.fastForward === true);
81724
82247
  const gateSawUnresolvedGitlinkFf = gitlinkFf?.resolved === false && Array.isArray(gitlinkFf.gitlinks) && gitlinkFf.gitlinks.some((g) => g.fastForward);
@@ -81754,14 +82277,6 @@ ${e?.stderr || ""}`
81754
82277
  };
81755
82278
  }
81756
82279
  }
81757
- function execGitOk(cwd, args) {
81758
- try {
81759
- (0, import_node_child_process13.execFileSync)(GIT4, args, { cwd, encoding: "utf8", maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES, windowsHide: true });
81760
- return true;
81761
- } catch {
81762
- return false;
81763
- }
81764
- }
81765
82280
  async function checkWorktreeChangesPatchEquivalentInRef(repoRoot, ref, worktreeHead) {
81766
82281
  const startedAt = Date.now();
81767
82282
  try {
@@ -81955,7 +82470,7 @@ ${mergeTreeErr?.stderr || ""}`;
81955
82470
  const baseCommit = readTreeObject(repoRoot, baseHead, path60);
81956
82471
  const branchCommit = readTreeObject(repoRoot, branchHead, path60);
81957
82472
  if (!baseCommit || !branchCommit) return false;
81958
- return isSubmoduleFastForward((0, import_path18.resolve)(repoRoot, path60), baseCommit, branchCommit);
82473
+ return isSubmoduleFastForward((0, import_path19.resolve)(repoRoot, path60), baseCommit, branchCommit);
81959
82474
  });
81960
82475
  }
81961
82476
  function collectTrivialFastForwardGitlinkResolutions(worktreeRoot, baseRepoRoot, baseHead, branchHead) {
@@ -81964,8 +82479,8 @@ ${mergeTreeErr?.stderr || ""}`;
81964
82479
  const baseCommit = readTreeObject(baseRepoRoot, baseHead, path60);
81965
82480
  const branchCommit = readTreeObject(worktreeRoot, branchHead, path60);
81966
82481
  if (!baseCommit || !branchCommit) continue;
81967
- const submoduleRepoPath = (0, import_path18.resolve)(worktreeRoot, path60);
81968
- ensureSubmoduleCommitLocal(submoduleRepoPath, (0, import_path18.resolve)(baseRepoRoot, path60), baseCommit);
82482
+ const submoduleRepoPath = (0, import_path19.resolve)(worktreeRoot, path60);
82483
+ ensureSubmoduleCommitLocal(submoduleRepoPath, (0, import_path19.resolve)(baseRepoRoot, path60), baseCommit);
81969
82484
  if (baseCommit === branchCommit) {
81970
82485
  continue;
81971
82486
  }
@@ -81981,7 +82496,7 @@ ${mergeTreeErr?.stderr || ""}`;
81981
82496
  const changedGitlinks = readChangedGitlinkPaths(repoRoot, baseHead, branchHead).map((path60) => {
81982
82497
  const baseCommit = readTreeObject(repoRoot, baseHead, path60);
81983
82498
  const branchCommit = readTreeObject(repoRoot, branchHead, path60);
81984
- const submoduleRepoPath = (0, import_path18.resolve)(repoRoot, path60);
82499
+ const submoduleRepoPath = (0, import_path19.resolve)(repoRoot, path60);
81985
82500
  const fastForward = !!baseCommit && !!branchCommit && isSubmoduleFastForward(submoduleRepoPath, baseCommit, branchCommit);
81986
82501
  return { path: path60, baseCommit, branchCommit, fastForward };
81987
82502
  });
@@ -82036,7 +82551,7 @@ ${mergeTreeErr?.stderr || ""}`;
82036
82551
  if (!tree) return void 0;
82037
82552
  const updates = paths.map((path60) => `160000 commit ${placeholderCommit} ${path60}`).join("\n");
82038
82553
  if (!updates) return tree;
82039
- const tmpIndex = (0, import_path18.join)(resolveGitDir(repoRoot), `adhdev-refine-eq-${commitish.slice(0, 12)}.index`);
82554
+ const tmpIndex = (0, import_path19.join)(resolveGitDir(repoRoot), `adhdev-refine-eq-${commitish.slice(0, 12)}.index`);
82040
82555
  const env2 = { ...process.env, GIT_INDEX_FILE: tmpIndex };
82041
82556
  try {
82042
82557
  (0, import_node_child_process13.execFileSync)(GIT4, ["read-tree", tree], { cwd: repoRoot, env: env2, stdio: "ignore" });
@@ -82111,7 +82626,7 @@ ${mergeTreeErr?.stderr || ""}`;
82111
82626
  if (!contentTree) return void 0;
82112
82627
  const updates = branchGitlinks.map((entry) => `160000 commit ${entry.branchCommit} ${entry.path}`).join("\n");
82113
82628
  if (!updates) return contentTree;
82114
- const tmpIndex = (0, import_path18.join)(resolveGitDir(repoRoot), `adhdev-refine-ff-${baseHead.slice(0, 12)}-${branchHead.slice(0, 12)}.index`);
82629
+ const tmpIndex = (0, import_path19.join)(resolveGitDir(repoRoot), `adhdev-refine-ff-${baseHead.slice(0, 12)}-${branchHead.slice(0, 12)}.index`);
82115
82630
  const env2 = { ...process.env, GIT_INDEX_FILE: tmpIndex };
82116
82631
  try {
82117
82632
  (0, import_node_child_process13.execFileSync)(GIT4, ["read-tree", contentTree], { cwd: repoRoot, env: env2, stdio: "ignore" });
@@ -82268,7 +82783,7 @@ ${mergeTreeErr?.stderr || ""}`;
82268
82783
  return match ? { commit: match[1], path: match[2] } : null;
82269
82784
  }).filter((entry) => !!entry);
82270
82785
  for (const gitlink of gitlinks) {
82271
- const submodulePath = (0, import_path18.resolve)(repoRoot, gitlink.path);
82786
+ const submodulePath = (0, import_path19.resolve)(repoRoot, gitlink.path);
82272
82787
  const entry = {
82273
82788
  path: gitlink.path,
82274
82789
  commit: gitlink.commit,
@@ -82295,7 +82810,7 @@ ${mergeTreeErr?.stderr || ""}`;
82295
82810
  entry.localReachable = false;
82296
82811
  if (options.allowAutoPublishSubmoduleMainCommits === true && options.worktreeRoot) {
82297
82812
  try {
82298
- const imported = await importCommitFromWorktreeSubmodule(submodulePath, (0, import_path18.resolve)(options.worktreeRoot, gitlink.path), gitlink.commit);
82813
+ const imported = await importCommitFromWorktreeSubmodule(submodulePath, (0, import_path19.resolve)(options.worktreeRoot, gitlink.path), gitlink.commit);
82299
82814
  if (imported) {
82300
82815
  entry.localReachable = true;
82301
82816
  entry.importedFromWorktree = true;
@@ -82525,13 +83040,13 @@ ${mergeTreeErr?.stderr || ""}`;
82525
83040
  ...extras
82526
83041
  });
82527
83042
  const isPackageManagerValidation = (candidate) => {
82528
- const command = (0, import_path18.basename)(candidate.command).replace(/\.(?:cmd|exe)$/i, "");
83043
+ const command = (0, import_path19.basename)(candidate.command).replace(/\.(?:cmd|exe)$/i, "");
82529
83044
  return ["npm", "pnpm", "yarn", "bun"].includes(command) && candidate.args.some((arg) => arg === "run" || arg === "test" || arg === "exec");
82530
83045
  };
82531
83046
  const dependenciesLikelyMissing = (cwd) => {
82532
- if (!fs53.existsSync((0, import_path18.join)(cwd, "package.json"))) return false;
82533
- if (fs53.existsSync((0, import_path18.join)(cwd, "node_modules"))) return false;
82534
- return ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"].some((lock) => fs53.existsSync((0, import_path18.join)(cwd, lock)));
83047
+ if (!fs53.existsSync((0, import_path19.join)(cwd, "package.json"))) return false;
83048
+ if (fs53.existsSync((0, import_path19.join)(cwd, "node_modules"))) return false;
83049
+ return ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"].some((lock) => fs53.existsSync((0, import_path19.join)(cwd, lock)));
82535
83050
  };
82536
83051
  const needsNodeModules = (candidate, cwd) => isPackageManagerValidation(candidate) && dependenciesLikelyMissing(cwd);
82537
83052
  const isDaemonScopedCommand = (candidate) => {
@@ -82598,7 +83113,7 @@ ${mergeTreeErr?.stderr || ""}`;
82598
83113
  summary.bootstrap = { stage: "legacy" };
82599
83114
  for (const candidate of selection.bootstrapCommands) {
82600
83115
  const startedAt = Date.now();
82601
- const cwd = candidate.cwd ? (0, import_path18.resolve)(workspace, candidate.cwd) : workspace;
83116
+ const cwd = candidate.cwd ? (0, import_path19.resolve)(workspace, candidate.cwd) : workspace;
82602
83117
  const timeout = candidate.timeoutMs || REFINE_VALIDATION_TIMEOUT_MS;
82603
83118
  const resolvedCommand = resolveWin32Executable(candidate.command);
82604
83119
  const spawn7 = buildWin32ExecFileSpawn(resolvedCommand, candidate.args);
@@ -82631,7 +83146,7 @@ ${mergeTreeErr?.stderr || ""}`;
82631
83146
  let missingDepsBlocked = false;
82632
83147
  for (const candidate of commandsToRun) {
82633
83148
  const startedAt = Date.now();
82634
- const cwd = candidate.cwd ? (0, import_path18.resolve)(workspace, candidate.cwd) : workspace;
83149
+ const cwd = candidate.cwd ? (0, import_path19.resolve)(workspace, candidate.cwd) : workspace;
82635
83150
  const timeout = candidate.timeoutMs || REFINE_VALIDATION_TIMEOUT_MS;
82636
83151
  const bootstrapProvidedDependencies = summary.bootstrap?.stage === "cached" || summary.bootstrap?.stage === "ran" || summary.bootstrap?.stage === "legacy";
82637
83152
  if (!bootstrapProvidedDependencies && needsNodeModules(candidate, cwd)) {
@@ -82698,7 +83213,7 @@ ${mergeTreeErr?.stderr || ""}`;
82698
83213
  summary.status = "passed";
82699
83214
  return summary;
82700
83215
  }
82701
- var import_path18;
83216
+ var import_path19;
82702
83217
  var fs53;
82703
83218
  var import_node_child_process13;
82704
83219
  var REFINE_VALIDATION_TIMEOUT_MS;
@@ -82713,7 +83228,7 @@ ${mergeTreeErr?.stderr || ""}`;
82713
83228
  init_git_status();
82714
83229
  init_refine_config();
82715
83230
  init_worktree_bootstrap_config();
82716
- import_path18 = require("path");
83231
+ import_path19 = require("path");
82717
83232
  fs53 = __toESM2(require("fs"));
82718
83233
  import_node_child_process13 = require("child_process");
82719
83234
  init_resolve_executable();
@@ -82725,7 +83240,7 @@ ${mergeTreeErr?.stderr || ""}`;
82725
83240
  REFINE_VALIDATION_SUMMARY_HEAD_CHARS = 2e3;
82726
83241
  REFINE_VALIDATION_SUMMARY_TAIL_CHARS = 6e3;
82727
83242
  REFINE_VALIDATION_SUMMARY_CHARS = REFINE_VALIDATION_SUMMARY_HEAD_CHARS + REFINE_VALIDATION_SUMMARY_TAIL_CHARS;
82728
- REFINE_VALIDATION_LOG_DIR = (0, import_path18.join)(".adhdev", "logs");
83243
+ REFINE_VALIDATION_LOG_DIR = (0, import_path19.join)(".adhdev", "logs");
82729
83244
  }
82730
83245
  });
82731
83246
  function findOpenRefineDispatchForNode(args) {
@@ -83807,16 +84322,11 @@ ${excerpt}` : "\n--- git output ---\n(none captured)");
83807
84322
  error: submoduleHintPatchEquivalence.error,
83808
84323
  actionableHint: submoduleHintPatchEquivalence.actionableHint
83809
84324
  });
83810
- const classification = await classifyPatchEquivalenceFailure(
83811
- repoRoot,
83812
- baseHead,
83813
- ctx.branchHead,
83814
- submoduleHintPatchEquivalence,
83815
- {
83816
- targetBaseRef: baseHead,
83817
- autoPublishSubmoduleMainCommits: resolveRefineryAutoPublishSubmoduleMainCommits(ctx.mesh, node.workspace).enabled
83818
- }
83819
- );
84325
+ const classification = await classifyAndWarnPatchEquivalenceFailure(node.id, repoRoot, baseHead, ctx.branchHead, submoduleHintPatchEquivalence, {
84326
+ targetBaseRef: baseHead,
84327
+ worktreeRoot: node.workspace,
84328
+ autoPublishSubmoduleMainCommits: resolveRefineryAutoPublishSubmoduleMainCommits(ctx.mesh, node.workspace).enabled
84329
+ });
83820
84330
  return { kind: "terminal", result: {
83821
84331
  success: false,
83822
84332
  code: "patch_equivalence_failed",
@@ -84000,19 +84510,15 @@ ${tail}` : ""
84000
84510
  if (!patchEquivalence.equivalent) {
84001
84511
  const alreadyMergedViaOtherPath = !patchEquivalence.actualPatchId && !!patchEquivalence.expectedPatchId;
84002
84512
  if (!alreadyMergedViaOtherPath) {
84003
- const classification = await classifyPatchEquivalenceFailure(
84004
- repoRoot,
84005
- baseHead,
84006
- branchHead,
84007
- patchEquivalence,
84008
- {
84009
- targetBaseRef: baseHead,
84010
- autoPublishSubmoduleMainCommits: resolveRefineryAutoPublishSubmoduleMainCommits(mesh, node.workspace).enabled
84011
- }
84012
- );
84513
+ const classification = await classifyAndWarnPatchEquivalenceFailure(node.id, repoRoot, baseHead, branchHead, patchEquivalence, {
84514
+ targetBaseRef: baseHead,
84515
+ worktreeRoot: node.workspace,
84516
+ autoPublishSubmoduleMainCommits: resolveRefineryAutoPublishSubmoduleMainCommits(mesh, node.workspace).enabled
84517
+ });
84013
84518
  recordMeshRefineStage(refineStages, "patch_equivalence_classification", "failed", patchEquivalenceStarted, {
84014
84519
  detailedReason: classification.detailedReason,
84015
- recommendedAction: classification.recommendedAction
84520
+ recommendedAction: classification.recommendedAction,
84521
+ ...classification.evidence.submoduleReachabilityUndeterminable ? { submoduleReachabilityUndeterminable: true } : {}
84016
84522
  });
84017
84523
  return { kind: "terminal", result: {
84018
84524
  success: false,
@@ -85391,6 +85897,10 @@ ${e?.stderr || ""}`;
85391
85897
  DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS: () => DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS,
85392
85898
  DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS: () => DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS,
85393
85899
  DEV_SERVER_PORT: () => DEV_SERVER_PORT,
85900
+ DISK_CRITICAL_FREE_BYTES: () => DISK_CRITICAL_FREE_BYTES,
85901
+ DISK_CRITICAL_PERCENT_FREE: () => DISK_CRITICAL_PERCENT_FREE,
85902
+ DISK_WARNING_FREE_BYTES: () => DISK_WARNING_FREE_BYTES,
85903
+ DISK_WARNING_PERCENT_FREE: () => DISK_WARNING_PERCENT_FREE,
85394
85904
  DUPLICATE_MESH_DISPATCH_CODE: () => DUPLICATE_MESH_DISPATCH_CODE,
85395
85905
  DaemonAgentStreamManager: () => DaemonAgentStreamManager,
85396
85906
  DaemonCdpInitializer: () => DaemonCdpInitializer,
@@ -85415,8 +85925,11 @@ ${e?.stderr || ""}`;
85415
85925
  KNOWN_DIGEST_ALGORITHMS: () => KNOWN_DIGEST_ALGORITHMS,
85416
85926
  LEGACY_UNVERIFIED_ALGORITHM: () => LEGACY_UNVERIFIED_ALGORITHM,
85417
85927
  LOG: () => LOG2,
85928
+ LowDiskSpaceError: () => LowDiskSpaceError,
85418
85929
  MAGI_NEEDS_VERIFICATION_PREVIEW_CAP: () => MAGI_NEEDS_VERIFICATION_PREVIEW_CAP,
85419
85930
  MAGI_RAW_ANSWER_CAP: () => MAGI_RAW_ANSWER_CAP,
85931
+ MAX_CAPTURE_LOG_GENERATIONS: () => MAX_CAPTURE_LOG_GENERATIONS,
85932
+ MAX_CAPTURE_LOG_SIZE: () => MAX_CAPTURE_LOG_SIZE,
85420
85933
  MAX_LEDGER_SLICE_LIMIT: () => MAX_LEDGER_SLICE_LIMIT,
85421
85934
  MAX_SESSIONS_PER_MESH: () => MAX_SESSIONS_PER_MESH,
85422
85935
  MAX_SIZE_ROTATION_GENERATIONS: () => MAX_SIZE_ROTATION_GENERATIONS,
@@ -85546,9 +86059,11 @@ ${e?.stderr || ""}`;
85546
86059
  buildUserChatMessage: () => buildUserChatMessage,
85547
86060
  cancelTask: () => cancelTask,
85548
86061
  canonicalDaemonId: () => canonicalDaemonId,
86062
+ checkDiskSpace: () => checkDiskSpace,
85549
86063
  claimMeshGraphGate: () => claimMeshGraphGate,
85550
86064
  claimNextTask: () => claimNextTask,
85551
86065
  classifyChatMessageVisibility: () => classifyChatMessageVisibility,
86066
+ classifyDiskSpace: () => classifyDiskSpace,
85552
86067
  classifyDuplicateMeshDispatch: () => classifyDuplicateMeshDispatch,
85553
86068
  classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush2,
85554
86069
  classifyP2pRelayFailure: () => classifyP2pRelayFailure,
@@ -85561,6 +86076,7 @@ ${e?.stderr || ""}`;
85561
86076
  clearDebugTrace: () => clearDebugTrace,
85562
86077
  clearPendingMeshCoordinatorEvents: () => clearPendingMeshCoordinatorEvents,
85563
86078
  codexSessionsDir: () => codexSessionsDir,
86079
+ collectIgnoredMagiSlotFields: () => collectIgnoredMagiSlotFields,
85564
86080
  collectPendingApprovals: () => collectPendingApprovals,
85565
86081
  collectSyncTargetTypes: () => collectSyncTargetTypes,
85566
86082
  commitMeshGraphPlan: () => commitMeshGraphPlan,
@@ -85599,6 +86115,7 @@ ${e?.stderr || ""}`;
85599
86115
  deriveMeshReviewInboxItems: () => deriveMeshReviewInboxItems,
85600
86116
  deriveWorkspaceBranchIdentity: () => deriveWorkspaceBranchIdentity,
85601
86117
  deriveWorkspaceOwnerTag: () => deriveWorkspaceOwnerTag,
86118
+ describeDiskSpace: () => describeDiskSpace,
85602
86119
  describeTaskDependencyState: () => describeTaskDependencyState,
85603
86120
  detectAllVersions: () => detectAllVersions,
85604
86121
  detectCLI: () => detectCLI,
@@ -85634,6 +86151,7 @@ ${e?.stderr || ""}`;
85634
86151
  flattenMessageParts: () => flattenMessageParts,
85635
86152
  foldUsageRecords: () => foldUsageRecords,
85636
86153
  forceRefreshQuota: () => forceRefreshQuota2,
86154
+ formatBytes: () => formatBytes,
85637
86155
  formatManifestValidationIssues: () => formatManifestValidationIssues,
85638
86156
  formatMeshTaskModeViolations: () => formatMeshTaskModeViolations,
85639
86157
  forwardAgentStreamsToIdeInstance: () => forwardAgentStreamsToIdeInstance2,
@@ -85751,6 +86269,7 @@ ${e?.stderr || ""}`;
85751
86269
  loadRepoSettings: () => loadRepoSettings,
85752
86270
  loadState: () => loadState,
85753
86271
  logCommand: () => logCommand,
86272
+ logDiskSpaceStatus: () => logDiskSpaceStatus,
85754
86273
  machineCoreFromDaemonId: () => machineCoreFromDaemonId,
85755
86274
  magiAutoLaunchedSessionCleanupDecision: () => magiAutoLaunchedSessionCleanupDecision,
85756
86275
  makeUsage: () => makeUsage,
@@ -85807,6 +86326,7 @@ ${e?.stderr || ""}`;
85807
86326
  partitionSessionHostDiagnosticsSessions: () => import_session_host_core32.partitionSessionHostDiagnosticsSessions,
85808
86327
  partitionSessionHostRecords: () => import_session_host_core32.partitionSessionHostRecords,
85809
86328
  planMeshOnboarding: () => planMeshOnboarding,
86329
+ preflightDiskSpace: () => preflightDiskSpace,
85810
86330
  prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate2,
85811
86331
  prepareSessionModalUpdate: () => prepareSessionModalUpdate2,
85812
86332
  presentationFromAttemptRow: () => presentationFromAttemptRow,
@@ -85828,6 +86348,7 @@ ${e?.stderr || ""}`;
85828
86348
  readChatHistory: () => readChatHistory,
85829
86349
  readClaudeCliSession: () => readSession,
85830
86350
  readCodexCliSession: () => readSession2,
86351
+ readDiskSpace: () => readDiskSpace,
85831
86352
  readHermesCliSession: () => readSession4,
85832
86353
  readLatestCodexRateLimits: () => readLatestCodexRateLimits,
85833
86354
  readLedgerEntries: () => readLedgerEntries,
@@ -85909,6 +86430,7 @@ ${e?.stderr || ""}`;
85909
86430
  resolveTurnAttemptRow: () => resolveTurnAttemptRow,
85910
86431
  resolveWorktreeBaseDir: () => resolveWorktreeBaseDir,
85911
86432
  resolveWorktreePath: () => resolveWorktreePath,
86433
+ rotateCaptureLogIfNeeded: () => rotateCaptureLogIfNeeded,
85912
86434
  runAsyncBatch: () => runAsyncBatch2,
85913
86435
  runGit: () => runGit,
85914
86436
  runMeshWorktreeBootstrap: () => runMeshWorktreeBootstrap,
@@ -89460,7 +89982,7 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89460
89982
  init_state_store();
89461
89983
  var import_child_process5 = require("child_process");
89462
89984
  var import_util22 = require("util");
89463
- var import_fs17 = require("fs");
89985
+ var import_fs18 = require("fs");
89464
89986
  var import_os3 = require("os");
89465
89987
  var path24 = __toESM2(require("path"));
89466
89988
  var fs16 = __toESM2(require("fs"));
@@ -89537,7 +90059,7 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89537
90059
  if (path24.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
89538
90060
  const candidate = trimmed.startsWith("~") ? path24.join((0, import_os3.homedir)(), trimmed.slice(1)) : trimmed;
89539
90061
  const resolved = path24.isAbsolute(candidate) ? candidate : path24.resolve(candidate);
89540
- return (0, import_fs17.existsSync)(resolved) ? resolved : null;
90062
+ return (0, import_fs18.existsSync)(resolved) ? resolved : null;
89541
90063
  }
89542
90064
  const isWin = (0, import_os3.platform)() === "win32";
89543
90065
  const paths = (process.env.PATH || "").split(isWin ? ";" : ":");
@@ -89547,8 +90069,8 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89547
90069
  for (const ext of exes) {
89548
90070
  const fullPath = path24.join(p, trimmed + ext);
89549
90071
  try {
89550
- if ((0, import_fs17.existsSync)(fullPath)) {
89551
- const stat2 = (0, import_fs17.statSync)(fullPath);
90072
+ if ((0, import_fs18.existsSync)(fullPath)) {
90073
+ const stat2 = (0, import_fs18.statSync)(fullPath);
89552
90074
  if (stat2.isFile() && (isWin || stat2.mode & 73)) {
89553
90075
  return fullPath;
89554
90076
  }
@@ -89566,9 +90088,9 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89566
90088
  if (normalized.includes("*")) {
89567
90089
  const username = home.split(/[\\/]/).pop() || "";
89568
90090
  const resolved = normalized.replace("*", username);
89569
- if ((0, import_fs17.existsSync)(resolved)) return resolved;
90091
+ if ((0, import_fs18.existsSync)(resolved)) return resolved;
89570
90092
  } else {
89571
- if ((0, import_fs17.existsSync)(normalized)) return normalized;
90093
+ if ((0, import_fs18.existsSync)(normalized)) return normalized;
89572
90094
  }
89573
90095
  }
89574
90096
  return null;
@@ -89582,7 +90104,7 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89582
90104
  let resolvedCli = cliPath;
89583
90105
  if (!resolvedCli && appPath && os33 === "darwin") {
89584
90106
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
89585
- if ((0, import_fs17.existsSync)(bundledCli)) resolvedCli = bundledCli;
90107
+ if ((0, import_fs18.existsSync)(bundledCli)) resolvedCli = bundledCli;
89586
90108
  }
89587
90109
  if (!resolvedCli && appPath && os33 === "win32") {
89588
90110
  const { dirname: dirname24 } = await import("path");
@@ -89595,7 +90117,7 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89595
90117
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
89596
90118
  ];
89597
90119
  for (const c of candidates) {
89598
- if ((0, import_fs17.existsSync)(c)) {
90120
+ if ((0, import_fs18.existsSync)(c)) {
89599
90121
  resolvedCli = c;
89600
90122
  break;
89601
90123
  }
@@ -101233,7 +101755,7 @@ ${marker}`,
101233
101755
  var os24 = __toESM2(require("os"));
101234
101756
  var path40 = __toESM2(require("path"));
101235
101757
  var crypto6 = __toESM2(require("crypto"));
101236
- var import_fs18 = require("fs");
101758
+ var import_fs19 = require("fs");
101237
101759
  var import_child_process11 = require("child_process");
101238
101760
  var import_chalk = __toESM2((init_source(), __toCommonJS(source_exports)));
101239
101761
  var fs322 = __toESM2(require("fs"));
@@ -112557,7 +113079,7 @@ ${rawInput}` : rawInput;
112557
113079
  const trimmed = command.trim();
112558
113080
  if (!trimmed) return false;
112559
113081
  if (isExplicitCommand(trimmed)) {
112560
- return (0, import_fs18.existsSync)(expandExecutable(trimmed));
113082
+ return (0, import_fs19.existsSync)(expandExecutable(trimmed));
112561
113083
  }
112562
113084
  try {
112563
113085
  (0, import_child_process11.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -112703,10 +113225,10 @@ ${rawInput}` : rawInput;
112703
113225
  }
112704
113226
  function ensureEmptyDelegatedMcpConfig(workspace) {
112705
113227
  const baseDir = path40.join(os24.tmpdir(), "adhdev-delegated-agent-empty-mcp");
112706
- (0, import_fs18.mkdirSync)(baseDir, { recursive: true });
113228
+ (0, import_fs19.mkdirSync)(baseDir, { recursive: true });
112707
113229
  const workspaceHash = shortHash(path40.resolve(workspace || os24.tmpdir()));
112708
113230
  const filePath = path40.join(baseDir, `${workspaceHash}.json`);
112709
- (0, import_fs18.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
113231
+ (0, import_fs19.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
112710
113232
  return filePath;
112711
113233
  }
112712
113234
  function buildCoordinatorDelegatedCliLaunchOptions(input) {
@@ -120458,7 +120980,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
120458
120980
  normalizeRepoMeshDeclarativeConfig: normalizeRepoMeshDeclarativeConfig2,
120459
120981
  MESH_JSON_CONFIG_LOCATIONS: MESH_JSON_CONFIG_LOCATIONS2
120460
120982
  } = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
120461
- const { mkdirSync: mkdirSync31, writeFileSync: writeFileSync31 } = await import("fs");
120983
+ const { mkdirSync: mkdirSync32, writeFileSync: writeFileSync31 } = await import("fs");
120462
120984
  const { dirname: dirname24, join: join68 } = await import("path");
120463
120985
  const scaffold = buildMeshJsonConfigScaffold2(mesh);
120464
120986
  const scaffoldJson = serializeMeshJsonConfigScaffold2(scaffold);
@@ -120499,7 +121021,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
120499
121021
  note: "Dry-run: nothing written. Re-run with write=true to persist to the repo (commit target). meshes.json is untouched."
120500
121022
  };
120501
121023
  }
120502
- mkdirSync31(dirname24(absolutePath), { recursive: true });
121024
+ mkdirSync32(dirname24(absolutePath), { recursive: true });
120503
121025
  writeFileSync31(absolutePath, `${scaffoldJson}
120504
121026
  `, "utf-8");
120505
121027
  return {
@@ -120569,7 +121091,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
120569
121091
  normalizeRepoMeshDeclarativeConfig: normalizeRepoMeshDeclarativeConfig2,
120570
121092
  MESH_JSON_CONFIG_LOCATIONS: MESH_JSON_CONFIG_LOCATIONS2
120571
121093
  } = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
120572
- const { existsSync: existsSync70, readFileSync: readFileSync55, mkdirSync: mkdirSync31, writeFileSync: writeFileSync31 } = await import("fs");
121094
+ const { existsSync: existsSync70, readFileSync: readFileSync55, mkdirSync: mkdirSync32, writeFileSync: writeFileSync31 } = await import("fs");
120573
121095
  const { dirname: dirname24, join: join68 } = await import("path");
120574
121096
  const yaml6 = await Promise.resolve().then(() => (init_js_yaml(), js_yaml_exports));
120575
121097
  const relativePath = MESH_JSON_CONFIG_LOCATIONS2[0];
@@ -120634,7 +121156,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
120634
121156
  note: "Dry-run: nothing written. Re-run with write=true to persist. Only the providerDefaults zone is merged; other repo zones are preserved."
120635
121157
  };
120636
121158
  }
120637
- mkdirSync31(dirname24(absolutePath), { recursive: true });
121159
+ mkdirSync32(dirname24(absolutePath), { recursive: true });
120638
121160
  writeFileSync31(absolutePath, serialized, "utf-8");
120639
121161
  return {
120640
121162
  success: true,
@@ -120702,10 +121224,17 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
120702
121224
  if (!kind) return { success: false, error: "invalid_magi_kind_panel: task_kind is required" };
120703
121225
  const requestedMeshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
120704
121226
  try {
120705
- const { setMagiKindPanel: setMagiKindPanel2, resolveScopedMeshId: resolveScopedMeshId2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
121227
+ const { setMagiKindPanel: setMagiKindPanel2, resolveScopedMeshId: resolveScopedMeshId2, collectIgnoredMagiSlotFields: collectIgnoredMagiSlotFields2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
121228
+ const ignoredFields = collectIgnoredMagiSlotFields2(args?.slots);
120706
121229
  const slots = setMagiKindPanel2(kind, args?.slots, requestedMeshId || void 0);
120707
121230
  const meshId = requestedMeshId || resolveScopedMeshId2();
120708
- return { success: true, kind, slots, meshId: meshId ?? null };
121231
+ return {
121232
+ success: true,
121233
+ kind,
121234
+ slots,
121235
+ meshId: meshId ?? null,
121236
+ ...ignoredFields.length ? { ignoredFields } : {}
121237
+ };
120709
121238
  } catch (e) {
120710
121239
  return { success: false, error: e.message };
120711
121240
  }
@@ -121584,7 +122113,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
121584
122113
  error: applied.reason
121585
122114
  };
121586
122115
  }
121587
- ctx.inlineMeshCache.set(meshId, applied.mesh);
122116
+ ctx.getCachedInlineMesh(meshId, applied.mesh);
121588
122117
  ctx.invalidateAggregateMeshStatus(meshId);
121589
122118
  try {
121590
122119
  const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
@@ -122936,7 +123465,7 @@ ${ptyResult.output.slice(-2e3)}`);
122936
123465
  workspace
122937
123466
  };
122938
123467
  }
122939
- const { existsSync: existsSync70, readFileSync: readFileSync55, writeFileSync: writeFileSync31, copyFileSync: copyFileSync3, mkdirSync: mkdirSync31 } = await import("fs");
123468
+ const { existsSync: existsSync70, readFileSync: readFileSync55, writeFileSync: writeFileSync31, copyFileSync: copyFileSync3, mkdirSync: mkdirSync32 } = await import("fs");
122940
123469
  const { dirname: dirname24 } = await import("path");
122941
123470
  const mcpConfigPath = coordinatorSetup.configPath;
122942
123471
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
@@ -122974,7 +123503,7 @@ ${ptyResult.output.slice(-2e3)}`);
122974
123503
  ...mcpServerEnv ? { env: mcpServerEnv } : {}
122975
123504
  });
122976
123505
  try {
122977
- mkdirSync31(dirname24(mcpConfigPath), { recursive: true });
123506
+ mkdirSync32(dirname24(mcpConfigPath), { recursive: true });
122978
123507
  } catch (error48) {
122979
123508
  const message = `Could not prepare MCP config path for automatic setup: ${error48?.message || error48}`;
122980
123509
  LOG2.error("MeshCoordinator", message);
@@ -124002,7 +124531,7 @@ ${ptyResult.output.slice(-2e3)}`);
124002
124531
  init_router_refine();
124003
124532
  var fs54 = __toESM2(require("fs"));
124004
124533
  var import_node_os22 = require("os");
124005
- var import_path19 = require("path");
124534
+ var import_path20 = require("path");
124006
124535
  init_logger();
124007
124536
  init_git_locale();
124008
124537
  init_dist();
@@ -124014,7 +124543,7 @@ ${ptyResult.output.slice(-2e3)}`);
124014
124543
  function acceptableManagedWorktreePaths(resolveWorktreePath2, normalizePath2, repoRoot, meshName, branch, worktreeBaseDir) {
124015
124544
  const safeBranch = branch.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
124016
124545
  const safeMeshName = meshName.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
124017
- const legacyPath = (0, import_path19.join)((0, import_path19.dirname)(repoRoot), LEGACY_WORKTREE_DIR_NAME, safeMeshName, safeBranch);
124546
+ const legacyPath = (0, import_path20.join)((0, import_path20.dirname)(repoRoot), LEGACY_WORKTREE_DIR_NAME, safeMeshName, safeBranch);
124018
124547
  const candidates = [
124019
124548
  resolveWorktreePath2(repoRoot, meshName, branch, worktreeBaseDir),
124020
124549
  legacyPath
@@ -124041,8 +124570,8 @@ ${ptyResult.output.slice(-2e3)}`);
124041
124570
  function looksLikeCrossTrackWorktreePath(actualPath, normalizePath2) {
124042
124571
  const home = normalizePath2((0, import_node_os22.homedir)());
124043
124572
  return TRACK_CONFIG_DIR_NAMES.some((trackDirName) => {
124044
- const trackWorktreesDir = (0, import_path19.join)(home, trackDirName, "worktrees");
124045
- return actualPath === normalizePath2(trackWorktreesDir) || actualPath.startsWith(normalizePath2(trackWorktreesDir) + import_path19.sep);
124573
+ const trackWorktreesDir = (0, import_path20.join)(home, trackDirName, "worktrees");
124574
+ return actualPath === normalizePath2(trackWorktreesDir) || actualPath.startsWith(normalizePath2(trackWorktreesDir) + import_path20.sep);
124046
124575
  });
124047
124576
  }
124048
124577
  function unexpectedPathRecoveryHint(actualPath, normalizePath2, suffix) {
@@ -124152,7 +124681,7 @@ ${ptyResult.output.slice(-2e3)}`);
124152
124681
  }
124153
124682
  const { resolveWorktreePath: resolveWorktreePath2, listWorktrees: listWorktrees2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
124154
124683
  const normalizePath2 = (value) => {
124155
- const resolved = (0, import_path19.resolve)(value);
124684
+ const resolved = (0, import_path20.resolve)(value);
124156
124685
  try {
124157
124686
  return fs54.realpathSync(resolved);
124158
124687
  } catch {
@@ -124279,7 +124808,7 @@ ${ptyResult.output.slice(-2e3)}`);
124279
124808
  }
124280
124809
  const { resolveWorktreePath: resolveWorktreePath2, listWorktrees: listWorktrees2, removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
124281
124810
  const normalizePath2 = (value) => {
124282
- const resolved = (0, import_path19.resolve)(value);
124811
+ const resolved = (0, import_path20.resolve)(value);
124283
124812
  try {
124284
124813
  return fs54.realpathSync(resolved);
124285
124814
  } catch {
@@ -124947,7 +125476,7 @@ ${ptyResult.output.slice(-2e3)}`);
124947
125476
  init_logger();
124948
125477
  var yaml5 = __toESM2(require_js_yaml());
124949
125478
  var import_os5 = require("os");
124950
- var import_path20 = require("path");
125479
+ var import_path21 = require("path");
124951
125480
  var fs55 = __toESM2(require("fs"));
124952
125481
  var MESH_COORDINATOR_AUTO_IMPORT_FORMATS = ["claude_mcp_json", "hermes_config_yaml", "opencode_json"];
124953
125482
  function isSupportedMeshCoordinatorConfigFormat(format) {
@@ -124988,13 +125517,13 @@ ${ptyResult.output.slice(-2e3)}`);
124988
125517
  }
124989
125518
  function resolveHermesUserHome() {
124990
125519
  const explicitHome = process.env.HERMES_HOME?.trim();
124991
- return explicitHome || (0, import_path20.join)((0, import_os5.homedir)(), ".hermes");
125520
+ return explicitHome || (0, import_path21.join)((0, import_os5.homedir)(), ".hermes");
124992
125521
  }
124993
125522
  function loadHermesCoordinatorBaseConfig(targetConfigPath) {
124994
125523
  const sourceHome = resolveHermesUserHome();
124995
- const sourceConfigPath = (0, import_path20.join)(sourceHome, "config.yaml");
125524
+ const sourceConfigPath = (0, import_path21.join)(sourceHome, "config.yaml");
124996
125525
  if (!fs55.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
124997
- if ((0, import_path20.resolve)(sourceConfigPath) === (0, import_path20.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
125526
+ if ((0, import_path21.resolve)(sourceConfigPath) === (0, import_path21.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
124998
125527
  const parsed = parseMeshCoordinatorMcpConfig(fs55.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
124999
125528
  const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
125000
125529
  return { config: baseConfig, sourceHome, sourceConfigPath };
@@ -125028,10 +125557,10 @@ ${ptyResult.output.slice(-2e3)}`);
125028
125557
  return sanitized;
125029
125558
  }
125030
125559
  function copyHermesCoordinatorCredentialFiles(sourceHome, targetHome) {
125031
- if ((0, import_path20.resolve)(sourceHome) === (0, import_path20.resolve)(targetHome)) return;
125560
+ if ((0, import_path21.resolve)(sourceHome) === (0, import_path21.resolve)(targetHome)) return;
125032
125561
  for (const fileName of [".env", "auth.json"]) {
125033
- const sourcePath = (0, import_path20.join)(sourceHome, fileName);
125034
- const targetPath = (0, import_path20.join)(targetHome, fileName);
125562
+ const sourcePath = (0, import_path21.join)(sourceHome, fileName);
125563
+ const targetPath = (0, import_path21.join)(targetHome, fileName);
125035
125564
  if (!fs55.existsSync(sourcePath)) continue;
125036
125565
  try {
125037
125566
  fs55.copyFileSync(sourcePath, targetPath);
@@ -126168,6 +126697,7 @@ ${ptyResult.output.slice(-2e3)}`);
126168
126697
  init_track_identity();
126169
126698
  init_normalize();
126170
126699
  init_logger();
126700
+ init_disk_space_preflight();
126171
126701
  var UNICODE_SYMBOLS = {
126172
126702
  ok: "\u2713",
126173
126703
  fail: "\u2717",
@@ -133236,6 +133766,7 @@ data: ${JSON.stringify(msg.data)}
133236
133766
  var path59 = __toESM2(require("path"));
133237
133767
  var import_session_host_core14 = require_dist();
133238
133768
  init_logger();
133769
+ init_disk_space_preflight();
133239
133770
  init_runtime_defaults();
133240
133771
  function createManagedSessionHost2(options) {
133241
133772
  const appName = options.appName;
@@ -133339,6 +133870,7 @@ data: ${JSON.stringify(msg.data)}
133339
133870
  function spawnHost() {
133340
133871
  const entry = resolveEntry();
133341
133872
  verifyConptyPrebuildBeforeSpawn(entry);
133873
+ preflightDiskSpace(instance().configDir, "spawn the session host");
133342
133874
  const nodeExecutable = resolveSessionHostNode();
133343
133875
  let stdio = "ignore";
133344
133876
  let logFd = null;
@@ -133354,7 +133886,20 @@ data: ${JSON.stringify(msg.data)}
133354
133886
  windowsHide: true,
133355
133887
  env: buildEnv(process.env)
133356
133888
  });
133357
- child.unref();
133889
+ if (typeof child?.on === "function") {
133890
+ child.on("error", (error48) => {
133891
+ LOG2.error("SessionHost", `Failed to spawn session-host process: ${error48?.message || error48}`);
133892
+ });
133893
+ child.on("exit", (code, signal) => {
133894
+ const how = signal ? `signal ${signal}` : `code ${code}`;
133895
+ const detail = options.spawnStdio === "logfile" ? ` \u2014 see ${path59.join(instance().configDir, "logs", "session-host.log")} for its stderr` : "";
133896
+ LOG2.error(
133897
+ "SessionHost",
133898
+ `Session-host process (pid ${child.pid ?? "unknown"}) exited with ${how}${detail}`
133899
+ );
133900
+ });
133901
+ }
133902
+ if (typeof child?.unref === "function") child.unref();
133358
133903
  if (logFd !== null) {
133359
133904
  try {
133360
133905
  fs62.closeSync(logFd);
@@ -133805,8 +134350,8 @@ data: ${JSON.stringify(msg.data)}
133805
134350
  init_config_dir();
133806
134351
  init_mesh_events();
133807
134352
  init_mesh_reconcile_loop();
133808
- var import_fs19 = require("fs");
133809
- var import_path21 = require("path");
134353
+ var import_fs20 = require("fs");
134354
+ var import_path222 = require("path");
133810
134355
  var import_crypto18 = require("crypto");
133811
134356
  init_logger();
133812
134357
  init_mesh_ledger();
@@ -133874,31 +134419,31 @@ data: ${JSON.stringify(msg.data)}
133874
134419
  } catch {
133875
134420
  return result;
133876
134421
  }
133877
- if (!(0, import_fs19.existsSync)(dir)) return result;
134422
+ if (!(0, import_fs20.existsSync)(dir)) return result;
133878
134423
  let names;
133879
134424
  try {
133880
- names = (0, import_fs19.readdirSync)(dir);
134425
+ names = (0, import_fs20.readdirSync)(dir);
133881
134426
  } catch (e) {
133882
134427
  LOG2.warn("MeshEvents", `Pending-events migration: cannot read ledger dir: ${e?.message || e}`);
133883
134428
  return result;
133884
134429
  }
133885
134430
  for (const name of names) {
133886
134431
  if (!isPendingEventsFile(name)) continue;
133887
- const path60 = (0, import_path21.join)(dir, name);
134432
+ const path60 = (0, import_path222.join)(dir, name);
133888
134433
  result.filesScanned++;
133889
134434
  const claimed = `${path60}.migrating`;
133890
134435
  try {
133891
- (0, import_fs19.renameSync)(path60, claimed);
134436
+ (0, import_fs20.renameSync)(path60, claimed);
133892
134437
  } catch {
133893
134438
  continue;
133894
134439
  }
133895
134440
  let content;
133896
134441
  try {
133897
- content = (0, import_fs19.readFileSync)(claimed, "utf-8");
134442
+ content = (0, import_fs20.readFileSync)(claimed, "utf-8");
133898
134443
  } catch (e) {
133899
134444
  LOG2.warn("MeshEvents", `Pending-events migration: cannot read ${name}; leaving it for the next boot: ${e?.message || e}`);
133900
134445
  try {
133901
- (0, import_fs19.renameSync)(claimed, path60);
134446
+ (0, import_fs20.renameSync)(claimed, path60);
133902
134447
  } catch {
133903
134448
  }
133904
134449
  result.filesRetained++;
@@ -133913,14 +134458,14 @@ data: ${JSON.stringify(msg.data)}
133913
134458
  }
133914
134459
  if (!allImported) {
133915
134460
  try {
133916
- (0, import_fs19.renameSync)(claimed, path60);
134461
+ (0, import_fs20.renameSync)(claimed, path60);
133917
134462
  } catch {
133918
134463
  }
133919
134464
  result.filesRetained++;
133920
134465
  continue;
133921
134466
  }
133922
134467
  try {
133923
- (0, import_fs19.unlinkSync)(claimed);
134468
+ (0, import_fs20.unlinkSync)(claimed);
133924
134469
  result.filesRemoved++;
133925
134470
  } catch (e) {
133926
134471
  LOG2.warn("MeshEvents", `Pending-events migration: imported ${name} but could not unlink it: ${e?.message || e}`);
@@ -135339,14 +135884,77 @@ function createLineParser(onEnvelope) {
135339
135884
  }
135340
135885
  };
135341
135886
  }
135887
+ var establishedSockets = /* @__PURE__ */ new WeakSet();
135342
135888
  var SessionHostClient = class {
135343
135889
  endpoint;
135344
135890
  socket = null;
135345
135891
  requestWaiters = /* @__PURE__ */ new Map();
135346
135892
  eventListeners = /* @__PURE__ */ new Set();
135893
+ disconnectListeners = /* @__PURE__ */ new Set();
135894
+ /** Guards against emitting both an 'error'-path and a 'close'-path disconnect for one socket. */
135895
+ disconnectedSockets = /* @__PURE__ */ new WeakSet();
135347
135896
  constructor(options = {}) {
135348
135897
  this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || "adhdev");
135349
135898
  }
135899
+ /**
135900
+ * Fires when an established connection to the session host goes away.
135901
+ *
135902
+ * Before this existed the client registered only 'data' and 'error' handlers,
135903
+ * so a *clean* FIN — the host process exiting normally, or dying to an
135904
+ * uncaught exception that took the socket down without an error event on our
135905
+ * end — ran nothing at all: `this.socket` stayed non-null pointing at a dead
135906
+ * socket, in-flight waiters hung to their 30s timeout, and no caller was told.
135907
+ * That silence is what let a session-host death present downstream as an
135908
+ * unrelated application-level fault (a missing completion marker) instead of
135909
+ * "the host is gone".
135910
+ */
135911
+ onDisconnect(listener) {
135912
+ this.disconnectListeners.add(listener);
135913
+ return () => {
135914
+ this.disconnectListeners.delete(listener);
135915
+ };
135916
+ }
135917
+ handleDisconnect(socket, reason, error48) {
135918
+ if (this.disconnectedSockets.has(socket)) return;
135919
+ this.disconnectedSockets.add(socket);
135920
+ const wasEstablished = establishedSockets.has(socket);
135921
+ if (!wasEstablished) {
135922
+ if (this.socket === socket) this.socket = null;
135923
+ try {
135924
+ socket.destroy();
135925
+ } catch {
135926
+ }
135927
+ const failure2 = error48 || new Error(`Session host connect failed (${this.endpoint.path})`);
135928
+ for (const waiter of this.requestWaiters.values()) waiter.reject(failure2);
135929
+ this.requestWaiters.clear();
135930
+ return;
135931
+ }
135932
+ const pendingRequests = this.requestWaiters.size;
135933
+ const failure = error48 || new Error(`Session host connection ${reason} (${this.endpoint.path})`);
135934
+ for (const waiter of this.requestWaiters.values()) {
135935
+ waiter.reject(failure);
135936
+ }
135937
+ this.requestWaiters.clear();
135938
+ if (this.socket === socket) {
135939
+ this.socket = null;
135940
+ }
135941
+ try {
135942
+ socket.destroy();
135943
+ } catch {
135944
+ }
135945
+ const info = {
135946
+ reason,
135947
+ endpointPath: this.endpoint.path,
135948
+ pendingRequests,
135949
+ error: error48
135950
+ };
135951
+ for (const listener of this.disconnectListeners) {
135952
+ try {
135953
+ listener(info);
135954
+ } catch {
135955
+ }
135956
+ }
135957
+ }
135350
135958
  async connect() {
135351
135959
  if (this.socket && !this.socket.destroyed) return;
135352
135960
  if (this.socket) {
@@ -135372,20 +135980,19 @@ var SessionHostClient = class {
135372
135980
  }
135373
135981
  }));
135374
135982
  socket.on("error", (error48) => {
135375
- for (const waiter of this.requestWaiters.values()) {
135376
- waiter.reject(error48);
135377
- }
135378
- this.requestWaiters.clear();
135379
- if (this.socket === socket) {
135380
- this.socket = null;
135381
- }
135382
- try {
135383
- socket.destroy();
135384
- } catch {
135385
- }
135983
+ this.handleDisconnect(socket, "error", error48);
135984
+ });
135985
+ socket.on("close", () => {
135986
+ this.handleDisconnect(socket, "closed");
135987
+ });
135988
+ socket.on("end", () => {
135989
+ this.handleDisconnect(socket, "ended");
135386
135990
  });
135387
135991
  await new Promise((resolve3, reject) => {
135388
- socket.once("connect", () => resolve3());
135992
+ socket.once("connect", () => {
135993
+ establishedSockets.add(socket);
135994
+ resolve3();
135995
+ });
135389
135996
  socket.once("error", reject);
135390
135997
  });
135391
135998
  }
@@ -135427,6 +136034,7 @@ var SessionHostClient = class {
135427
136034
  if (!this.socket) return;
135428
136035
  const socket = this.socket;
135429
136036
  this.socket = null;
136037
+ this.disconnectedSockets.add(socket);
135430
136038
  for (const waiter of this.requestWaiters.values()) {
135431
136039
  waiter.reject(new Error("Session host client closed"));
135432
136040
  }