@adhdev/daemon-standalone 1.0.58-rc.2 → 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 ? "8e051f2dacc04bd04da37212168709c3ade00877" : void 0) ?? "unknown";
36772
- const commitShort = readInjected(true ? "8e051f2d" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
36773
- const version2 = readInjected(true ? "1.0.58-rc.2" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
36774
- const builtAt = readInjected(true ? "2026-08-22T14:13:56.874Z" : 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;
@@ -44117,25 +44200,75 @@ ${error48.message || ""}`;
44117
44200
  function getMeshConfigPath() {
44118
44201
  return (0, import_path5.join)(getConfigDir2(), "meshes.json");
44119
44202
  }
44120
- 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() {
44121
44248
  const path60 = getMeshConfigPath();
44122
44249
  if (!(0, import_fs5.existsSync)(path60)) return { meshes: [] };
44123
44250
  try {
44124
44251
  const raw = JSON.parse((0, import_fs5.readFileSync)(path60, "utf-8"));
44125
44252
  if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
44126
- const config2 = raw;
44127
- const migrated = migrateLoadedMeshConfig(config2);
44128
- if (migrated && options.persistMigrations !== false) {
44129
- try {
44130
- saveMeshConfig(config2);
44131
- } catch {
44132
- }
44133
- }
44134
- return config2;
44253
+ return raw;
44135
44254
  } catch {
44136
44255
  return { meshes: [] };
44137
44256
  }
44138
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
+ }
44139
44272
  function migrateLoadedMeshConfig(config2) {
44140
44273
  let changed = false;
44141
44274
  if (foldLegacyTopLevelMeshSetting(config2, "magiKindPanels", "mesh_magi_kind_panel_set({ meshId, task_kind, slots })")) changed = true;
@@ -44220,7 +44353,9 @@ ${error48.message || ""}`;
44220
44353
  }
44221
44354
  function saveMeshConfig(config2) {
44222
44355
  const path60 = getMeshConfigPath();
44223
- (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);
44224
44359
  }
44225
44360
  function normalizeRepoIdentity(remoteUrl) {
44226
44361
  let identity = remoteUrl.trim().replace(/[?#].*$/, "").replace(/\/+$/, "");
@@ -44260,7 +44395,10 @@ ${error48.message || ""}`;
44260
44395
  const normalized = normalizeRepoIdentity(repoIdentity);
44261
44396
  return loadMeshConfig().meshes.find((m) => normalizeRepoIdentity(m.repoIdentity) === normalized);
44262
44397
  }
44263
- function createMesh(opts) {
44398
+ function createMesh(...args) {
44399
+ return withMeshConfigWriteLock(() => createMeshUnlocked(...args));
44400
+ }
44401
+ function createMeshUnlocked(opts) {
44264
44402
  const config2 = loadMeshConfig();
44265
44403
  if (config2.meshes.length >= 20) {
44266
44404
  throw new Error("Maximum 20 meshes allowed");
@@ -44289,7 +44427,10 @@ ${error48.message || ""}`;
44289
44427
  saveMeshConfig(config2);
44290
44428
  return mesh;
44291
44429
  }
44292
- function updateMesh(meshId, opts) {
44430
+ function updateMesh(...args) {
44431
+ return withMeshConfigWriteLock(() => updateMeshUnlocked(...args));
44432
+ }
44433
+ function updateMeshUnlocked(meshId, opts) {
44293
44434
  const config2 = loadMeshConfig();
44294
44435
  const mesh = config2.meshes.find((m) => m.id === meshId);
44295
44436
  if (!mesh) return void 0;
@@ -44302,7 +44443,10 @@ ${error48.message || ""}`;
44302
44443
  saveMeshConfig(config2);
44303
44444
  return mesh;
44304
44445
  }
44305
- function deleteMesh(meshId) {
44446
+ function deleteMesh(...args) {
44447
+ return withMeshConfigWriteLock(() => deleteMeshUnlocked(...args));
44448
+ }
44449
+ function deleteMeshUnlocked(meshId) {
44306
44450
  const config2 = loadMeshConfig();
44307
44451
  const idx = config2.meshes.findIndex((m) => m.id === meshId);
44308
44452
  if (idx === -1) return false;
@@ -44349,7 +44493,10 @@ ${error48.message || ""}`;
44349
44493
  }
44350
44494
  return { ok: true, tokenId: presentedTokenId };
44351
44495
  }
44352
- function configureMeshHostPairing(meshId, opts) {
44496
+ function configureMeshHostPairing(...args) {
44497
+ return withMeshConfigWriteLock(() => configureMeshHostPairingUnlocked(...args));
44498
+ }
44499
+ function configureMeshHostPairingUnlocked(meshId, opts) {
44353
44500
  const hostAddress = normalizeManualHostAddress(opts.hostAddress);
44354
44501
  const token = opts.token.trim();
44355
44502
  if (!token) throw new Error("token required");
@@ -44373,7 +44520,10 @@ ${error48.message || ""}`;
44373
44520
  saveMeshConfig(config2);
44374
44521
  return { mesh, meshHost, hostAddress };
44375
44522
  }
44376
- function createMeshHostPairingToken(meshId, opts = {}) {
44523
+ function createMeshHostPairingToken(...args) {
44524
+ return withMeshConfigWriteLock(() => createMeshHostPairingTokenUnlocked(...args));
44525
+ }
44526
+ function createMeshHostPairingTokenUnlocked(meshId, opts = {}) {
44377
44527
  const config2 = loadMeshConfig();
44378
44528
  const mesh = config2.meshes.find((m) => m.id === meshId);
44379
44529
  if (!mesh) return void 0;
@@ -44401,7 +44551,10 @@ ${error48.message || ""}`;
44401
44551
  saveMeshConfig(config2);
44402
44552
  return { mesh, meshHost, token, tokenId, ...expiresAt ? { expiresAt } : {} };
44403
44553
  }
44404
- function applyMeshHostJoinRequest(meshId, opts) {
44554
+ function applyMeshHostJoinRequest(...args) {
44555
+ return withMeshConfigWriteLock(() => applyMeshHostJoinRequestUnlocked(...args));
44556
+ }
44557
+ function applyMeshHostJoinRequestUnlocked(meshId, opts) {
44405
44558
  const config2 = loadMeshConfig();
44406
44559
  const mesh = config2.meshes.find((m) => m.id === meshId);
44407
44560
  if (!mesh) return void 0;
@@ -44466,7 +44619,10 @@ ${error48.message || ""}`;
44466
44619
  saveMeshConfig(config2);
44467
44620
  return { accepted: true, mesh, meshHost: mesh.meshHost, node, tokenId: validation.tokenId };
44468
44621
  }
44469
- function setMeshHostPin(meshId, opts) {
44622
+ function setMeshHostPin(...args) {
44623
+ return withMeshConfigWriteLock(() => setMeshHostPinUnlocked(...args));
44624
+ }
44625
+ function setMeshHostPinUnlocked(meshId, opts) {
44470
44626
  const config2 = loadMeshConfig();
44471
44627
  const mesh = config2.meshes.find((m) => m.id === meshId);
44472
44628
  if (!mesh) return void 0;
@@ -44546,7 +44702,10 @@ ${error48.message || ""}`;
44546
44702
  ...mesh.meshHost.hostNodeId ? { hostNodeId: mesh.meshHost.hostNodeId } : {}
44547
44703
  };
44548
44704
  }
44549
- function markMeshHostPairingJoined(meshId, opts) {
44705
+ function markMeshHostPairingJoined(...args) {
44706
+ return withMeshConfigWriteLock(() => markMeshHostPairingJoinedUnlocked(...args));
44707
+ }
44708
+ function markMeshHostPairingJoinedUnlocked(meshId, opts) {
44550
44709
  const config2 = loadMeshConfig();
44551
44710
  const mesh = config2.meshes.find((m) => m.id === meshId);
44552
44711
  if (!mesh) return void 0;
@@ -44570,7 +44729,10 @@ ${error48.message || ""}`;
44570
44729
  saveMeshConfig(config2);
44571
44730
  return { mesh, meshHost: mesh.meshHost };
44572
44731
  }
44573
- function addNode(meshId, opts) {
44732
+ function addNode(...args) {
44733
+ return withMeshConfigWriteLock(() => addNodeUnlocked(...args));
44734
+ }
44735
+ function addNodeUnlocked(meshId, opts) {
44574
44736
  const config2 = loadMeshConfig();
44575
44737
  const mesh = config2.meshes.find((m) => m.id === meshId);
44576
44738
  if (!mesh) return void 0;
@@ -44617,7 +44779,10 @@ ${error48.message || ""}`;
44617
44779
  saveMeshConfig(config2);
44618
44780
  return node;
44619
44781
  }
44620
- function removeNode(meshId, nodeId) {
44782
+ function removeNode(...args) {
44783
+ return withMeshConfigWriteLock(() => removeNodeUnlocked(...args));
44784
+ }
44785
+ function removeNodeUnlocked(meshId, nodeId) {
44621
44786
  const config2 = loadMeshConfig();
44622
44787
  const mesh = config2.meshes.find((m) => m.id === meshId);
44623
44788
  if (!mesh) return false;
@@ -44629,7 +44794,10 @@ ${error48.message || ""}`;
44629
44794
  saveMeshConfig(config2);
44630
44795
  return true;
44631
44796
  }
44632
- function updateNode(meshId, nodeId, opts) {
44797
+ function updateNode(...args) {
44798
+ return withMeshConfigWriteLock(() => updateNodeUnlocked(...args));
44799
+ }
44800
+ function updateNodeUnlocked(meshId, nodeId, opts) {
44633
44801
  const config2 = loadMeshConfig();
44634
44802
  const mesh = config2.meshes.find((m) => m.id === meshId);
44635
44803
  if (!mesh) return void 0;
@@ -44759,7 +44927,10 @@ ${error48.message || ""}`;
44759
44927
  const config2 = loadMeshConfig();
44760
44928
  return resolveScopedMesh(config2, meshId)?.magiKindPanels?.[key2];
44761
44929
  }
44762
- function setMagiKindPanel(kind, slots, meshId) {
44930
+ function setMagiKindPanel(...args) {
44931
+ return withMeshConfigWriteLock(() => setMagiKindPanelUnlocked(...args));
44932
+ }
44933
+ function setMagiKindPanelUnlocked(kind, slots, meshId) {
44763
44934
  const key2 = normalizeMagiTaskKindKey(kind);
44764
44935
  const stored = loadMeshConfig();
44765
44936
  const mesh = resolveScopedMesh(stored, meshId);
@@ -44776,7 +44947,10 @@ ${error48.message || ""}`;
44776
44947
  saveMeshConfig(stored);
44777
44948
  return normalized;
44778
44949
  }
44779
- function removeMagiKindPanel(kind, meshId) {
44950
+ function removeMagiKindPanel(...args) {
44951
+ return withMeshConfigWriteLock(() => removeMagiKindPanelUnlocked(...args));
44952
+ }
44953
+ function removeMagiKindPanelUnlocked(kind, meshId) {
44780
44954
  let key2;
44781
44955
  try {
44782
44956
  key2 = normalizeMagiTaskKindKey(kind);
@@ -44813,7 +44987,10 @@ ${error48.message || ""}`;
44813
44987
  const normalized = normalizeDifficultyBrainMap(stored);
44814
44988
  return Object.keys(normalized).length > 0 ? normalized : { ...DEFAULT_DIFFICULTY_BRAINS };
44815
44989
  }
44816
- function setDifficultyBrains(map3, meshId) {
44990
+ function setDifficultyBrains(...args) {
44991
+ return withMeshConfigWriteLock(() => setDifficultyBrainsUnlocked(...args));
44992
+ }
44993
+ function setDifficultyBrainsUnlocked(map3, meshId) {
44817
44994
  const normalized = normalizeDifficultyBrainMap(map3);
44818
44995
  const stored = loadMeshConfig();
44819
44996
  const mesh = resolveScopedMesh(stored, meshId);
@@ -44859,7 +45036,10 @@ ${error48.message || ""}`;
44859
45036
  const stored = resolveScopedMesh(config2, meshId)?.policy?.quotaRouting;
44860
45037
  return normalizeQuotaRoutingPolicy(stored) ?? {};
44861
45038
  }
44862
- function setMeshQuotaRouting(input, meshId) {
45039
+ function setMeshQuotaRouting(...args) {
45040
+ return withMeshConfigWriteLock(() => setMeshQuotaRoutingUnlocked(...args));
45041
+ }
45042
+ function setMeshQuotaRoutingUnlocked(input, meshId) {
44863
45043
  const overrides = validateQuotaRoutingOverrides(input);
44864
45044
  const stored = loadMeshConfig();
44865
45045
  const mesh = resolveScopedMesh(stored, meshId);
@@ -44876,6 +45056,10 @@ ${error48.message || ""}`;
44876
45056
  var import_fs5;
44877
45057
  var import_path5;
44878
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;
44879
45063
  var mergeMeshPolicy;
44880
45064
  var MAGI_KIND_PANEL_KINDS;
44881
45065
  var MAX_MAGI_KIND_SLOTS;
@@ -44894,6 +45078,10 @@ ${error48.message || ""}`;
44894
45078
  init_dist();
44895
45079
  init_repo_mesh_types();
44896
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;
44897
45085
  mergeMeshPolicy = mergeAndNormalizePolicy;
44898
45086
  MAGI_KIND_PANEL_KINDS = ["claim_audit", "rca", "design", "freeform"];
44899
45087
  MAX_MAGI_KIND_SLOTS = 24;
@@ -49721,6 +49909,176 @@ The instruction it carried was never delivered to anyone. If it still matters, r
49721
49909
  PARK_RETENTION_EXPIRED_REASON = "parked_task_retention_expired";
49722
49910
  }
49723
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
+ });
49724
50082
  function readPayloadTaskId(entry) {
49725
50083
  const value = entry.payload?.taskId;
49726
50084
  return typeof value === "string" && value.trim() ? value.trim() : "";
@@ -50227,6 +50585,7 @@ The instruction it carried was never delivered to anyone. If it still matters, r
50227
50585
  normalizeMeshTaskPriority: () => normalizeMeshTaskPriority,
50228
50586
  parkTaskTargetPin: () => parkTaskTargetPin,
50229
50587
  reclaimStrandedAssignedTask: () => reclaimStrandedAssignedTask,
50588
+ recordAckedHoldDispatchOutcome: () => recordAckedHoldDispatchOutcome,
50230
50589
  recordDirectDispatchTask: () => recordDirectDispatchTask,
50231
50590
  recordMeshToolCall: () => recordMeshToolCall,
50232
50591
  recordTaskAutoLaunch: () => recordTaskAutoLaunch,
@@ -51125,6 +51484,7 @@ The instruction it carried was never delivered to anyone. If it still matters, r
51125
51484
  init_mesh_task_mode_guardrail();
51126
51485
  init_mesh_task_parking();
51127
51486
  init_mesh_task_mode_guardrail();
51487
+ init_mesh_reconcile_acked_hold();
51128
51488
  ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
51129
51489
  HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
51130
51490
  MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
@@ -61442,6 +61802,10 @@ ${rendered}`, "utf-8");
61442
61802
  if (cachedInline && registry2?.updateInlineMeshNode) {
61443
61803
  registry2.updateInlineMeshNode(req.meshId, cachedInline, node);
61444
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;
61445
61809
  }
61446
61810
  } catch {
61447
61811
  }
@@ -61801,7 +62165,7 @@ ${rendered}`, "utf-8");
61801
62165
  }
61802
62166
  async function registerWorkspaceNodeBestEffort(intent, created, ports, bootstrapStatus) {
61803
62167
  try {
61804
- await ports.registerNode({
62168
+ const published = await ports.registerNode({
61805
62169
  meshId: intent.meshId,
61806
62170
  nodeId: created.nodeId,
61807
62171
  worktreePath: created.worktreePath,
@@ -61809,6 +62173,9 @@ ${rendered}`, "utf-8");
61809
62173
  sourceNodeId: intent.sourceNodeId,
61810
62174
  bootstrapStatus
61811
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
+ }
61812
62179
  } catch (e) {
61813
62180
  LOG2.warn("MeshGraphWorkspace", `node registration (${bootstrapStatus}) failed for ${intent.graphId}/${intent.workspaceRef}: ${e?.message || e}`);
61814
62181
  }
@@ -68019,7 +68386,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
68019
68386
  const base = 1;
68020
68387
  let difficulty = 0;
68021
68388
  const diff = isMeshTaskDifficulty(task.difficulty) ? task.difficulty : void 0;
68022
- if (diff) {
68389
+ if (diff && diff !== "freeform") {
68023
68390
  if (slot.difficulty?.length) {
68024
68391
  difficulty = slot.difficulty.includes(diff) ? 100 : 0;
68025
68392
  } else {
@@ -68886,6 +69253,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
68886
69253
  if (timer) clearTimeout(timer);
68887
69254
  const isQueued = res && typeof res === "object" && res.status === "queued";
68888
69255
  updateSessionDeliveryStatus(delivery.id, isQueued ? "queued" : "delivered");
69256
+ recordAckedHoldDispatchOutcome(ctx.meshId, ctx.task.id, { ok: true });
68889
69257
  if (ctx.task.attemptId) {
68890
69258
  try {
68891
69259
  recordTurnAck({
@@ -68934,6 +69302,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
68934
69302
  }
68935
69303
  LOG2.error("MeshQueue", `Failed to dispatch task via ${ctx.transport} to node ${ctx.nodeId}: ${e?.message}`);
68936
69304
  updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
69305
+ recordAckedHoldDispatchOutcome(ctx.meshId, ctx.task.id, { ok: false, reason: e?.message });
68937
69306
  endTaskDispatchInFlight(ctx.meshId, ctx.task.id);
68938
69307
  try {
68939
69308
  closeAttemptForReassignment({ meshId: ctx.meshId, taskId: ctx.task.id, reason: "dispatch_failed" });
@@ -74573,148 +74942,6 @@ ${cleanBody}`;
74573
74942
  init_mesh_events_utils();
74574
74943
  }
74575
74944
  });
74576
- function resolveTunedReconcileMs(envName, def, min, max) {
74577
- const raw = readNonEmptyString(process.env[envName]);
74578
- if (raw) {
74579
- const parsed = Number.parseInt(raw, 10);
74580
- if (Number.isFinite(parsed) && parsed >= min && parsed <= max) return parsed;
74581
- }
74582
- return def;
74583
- }
74584
- function resolveAckedDeathDeadlineMs() {
74585
- return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
74586
- }
74587
- function resolveAckedTranscriptFastTrackGraceMs() {
74588
- return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
74589
- }
74590
- function resolveAckedHoldHardCeilingMs() {
74591
- return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_HOLD_HARD_CEILING_MS", 90 * 6e4, 0, 24 * 60 * 6e4);
74592
- }
74593
- function inFlightSynthKey(meshId, taskId) {
74594
- return `${meshId}::${taskId}`;
74595
- }
74596
- function taskIdFromSynthKey(meshId, synthKey) {
74597
- const prefix = `${meshId}::`;
74598
- return synthKey.startsWith(prefix) ? synthKey.slice(prefix.length) : synthKey;
74599
- }
74600
- function holdStore() {
74601
- try {
74602
- return MeshRuntimeStore.getInstance();
74603
- } catch {
74604
- return void 0;
74605
- }
74606
- }
74607
- function getHoldState(synthKey, meshId) {
74608
- const cached5 = inFlightAckedHoldState.get(synthKey);
74609
- if (cached5) return cached5;
74610
- const store = holdStore();
74611
- if (!store) return void 0;
74612
- let row;
74613
- try {
74614
- row = store.getInflightHold(taskIdFromSynthKey(meshId, synthKey));
74615
- } catch {
74616
- return void 0;
74617
- }
74618
- if (!row) return void 0;
74619
- const state = {
74620
- liveConfirmedSinceAck: row.holdReason === "live",
74621
- consecutiveReadFailures: row.readFailureCount ?? 0,
74622
- ...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {},
74623
- ...row.heldAt !== null && row.heldAt !== void 0 ? { heldSinceMs: row.heldAt } : {}
74624
- };
74625
- inFlightAckedHoldState.set(synthKey, state);
74626
- return state;
74627
- }
74628
- function setHoldState(synthKey, meshId, state) {
74629
- const store = holdStore();
74630
- let priorHeldSinceMs = state.heldSinceMs ?? inFlightAckedHoldState.get(synthKey)?.heldSinceMs;
74631
- if (priorHeldSinceMs === void 0 && store) {
74632
- try {
74633
- priorHeldSinceMs = store.getInflightHold(taskIdFromSynthKey(meshId, synthKey))?.heldAt ?? void 0;
74634
- } catch {
74635
- }
74636
- }
74637
- const heldSinceMs = priorHeldSinceMs ?? Date.now();
74638
- inFlightAckedHoldState.set(synthKey, { ...state, heldSinceMs });
74639
- if (!store) return;
74640
- try {
74641
- store.upsertInflightHold({
74642
- taskId: taskIdFromSynthKey(meshId, synthKey),
74643
- meshId,
74644
- holdReason: state.liveConfirmedSinceAck ? "live" : "unconfirmed",
74645
- // Only meaningful when the row is NEW — upsertInflightHold deliberately
74646
- // preserves held_at on conflict, so an existing row keeps its original anchor.
74647
- heldAt: heldSinceMs,
74648
- firstIdleSinceAck: state.transcriptIdleSinceMs ?? null,
74649
- readFailureCount: state.consecutiveReadFailures
74650
- });
74651
- } catch {
74652
- }
74653
- }
74654
- function deleteHoldState(synthKey, meshId) {
74655
- inFlightAckedHoldState.delete(synthKey);
74656
- const store = holdStore();
74657
- if (!store) return;
74658
- try {
74659
- store.deleteInflightHold(taskIdFromSynthKey(meshId, synthKey));
74660
- } catch {
74661
- }
74662
- }
74663
- function rehydrateAckedHoldsForMesh(meshId) {
74664
- if (rehydratedHoldMeshes.has(meshId)) return;
74665
- rehydratedHoldMeshes.add(meshId);
74666
- const store = holdStore();
74667
- if (!store) return;
74668
- let rows;
74669
- try {
74670
- rows = store.listInflightHoldsByMesh(meshId);
74671
- } catch {
74672
- return;
74673
- }
74674
- for (const row of rows) {
74675
- const synthKey = inFlightSynthKey(meshId, row.taskId);
74676
- if (inFlightAckedHoldState.has(synthKey)) continue;
74677
- inFlightAckedHoldState.set(synthKey, {
74678
- liveConfirmedSinceAck: row.holdReason === "live",
74679
- consecutiveReadFailures: row.readFailureCount ?? 0,
74680
- ...row.firstIdleSinceAck !== null && row.firstIdleSinceAck !== void 0 ? { transcriptIdleSinceMs: row.firstIdleSinceAck } : {},
74681
- ...row.heldAt !== null && row.heldAt !== void 0 ? { heldSinceMs: row.heldAt } : {}
74682
- });
74683
- }
74684
- if (rows.length > 0) {
74685
- LOG2.info("MeshReconcile", `Rehydrated ${rows.length} persisted acked-hold row(s) for mesh ${meshId} after (re)start`);
74686
- }
74687
- }
74688
- function collectHeldSynthKeysForMesh(meshId) {
74689
- const heldKeys = /* @__PURE__ */ new Set();
74690
- for (const key2 of inFlightAckedHoldState.keys()) {
74691
- if (key2.startsWith(`${meshId}::`)) heldKeys.add(key2);
74692
- }
74693
- const store = holdStore();
74694
- if (store) {
74695
- try {
74696
- for (const row of store.listInflightHoldsByMesh(meshId)) {
74697
- heldKeys.add(inFlightSynthKey(meshId, row.taskId));
74698
- }
74699
- } catch {
74700
- }
74701
- }
74702
- return heldKeys;
74703
- }
74704
- var ACKED_DEATH_CONSECUTIVE_READ_FAILURES;
74705
- var inFlightAckedHoldState;
74706
- var rehydratedHoldMeshes;
74707
- var init_mesh_reconcile_acked_hold = __esm2({
74708
- "src/mesh/mesh-reconcile-acked-hold.ts"() {
74709
- "use strict";
74710
- init_logger();
74711
- init_mesh_runtime_store();
74712
- init_mesh_events_utils();
74713
- ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
74714
- inFlightAckedHoldState = /* @__PURE__ */ new Map();
74715
- rehydratedHoldMeshes = /* @__PURE__ */ new Set();
74716
- }
74717
- });
74718
74945
  function resolveAutoPruneMinAgeMs() {
74719
74946
  const raw = readNonEmptyString(process.env.MESH_AUTO_PRUNE_MIN_AGE_MS);
74720
74947
  if (raw) {
@@ -74946,6 +75173,109 @@ ${cleanBody}`;
74946
75173
  init_mesh_reconcile_identity();
74947
75174
  }
74948
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
+ });
74949
75279
  function selectExpiredLedgerJsonl(files, now, maxAgeMs = LEDGER_JSONL_MAX_AGE_MS) {
74950
75280
  return files.filter((f) => now - f.mtimeMs > maxAgeMs);
74951
75281
  }
@@ -74980,7 +75310,7 @@ ${cleanBody}`;
74980
75310
  }
74981
75311
  function safeUnlink(path60) {
74982
75312
  try {
74983
- (0, import_fs16.unlinkSync)(path60);
75313
+ (0, import_fs17.unlinkSync)(path60);
74984
75314
  return true;
74985
75315
  } catch (e) {
74986
75316
  LOG2.warn("DiskRetention", `Failed to delete ${path60}: ${e?.message || e}`);
@@ -74988,18 +75318,18 @@ ${cleanBody}`;
74988
75318
  }
74989
75319
  }
74990
75320
  function listDirFiles(dir) {
74991
- if (!(0, import_fs16.existsSync)(dir)) return [];
75321
+ if (!(0, import_fs17.existsSync)(dir)) return [];
74992
75322
  const out = [];
74993
75323
  let names;
74994
75324
  try {
74995
- names = (0, import_fs16.readdirSync)(dir);
75325
+ names = (0, import_fs17.readdirSync)(dir);
74996
75326
  } catch {
74997
75327
  return [];
74998
75328
  }
74999
75329
  for (const name of names) {
75000
75330
  const path60 = (0, import_path14.join)(dir, name);
75001
75331
  try {
75002
- const st = (0, import_fs16.statSync)(path60);
75332
+ const st = (0, import_fs17.statSync)(path60);
75003
75333
  if (st.isFile()) out.push({ path: path60, mtimeMs: st.mtimeMs });
75004
75334
  } catch {
75005
75335
  }
@@ -75026,22 +75356,22 @@ ${cleanBody}`;
75026
75356
  }
75027
75357
  function pruneExpiredSessionHostRuntimes(now = Date.now()) {
75028
75358
  const root = (0, import_path14.join)(getConfigDir2(), "session-host");
75029
- if (!(0, import_fs16.existsSync)(root)) return 0;
75359
+ if (!(0, import_fs17.existsSync)(root)) return 0;
75030
75360
  let apps;
75031
75361
  try {
75032
- apps = (0, import_fs16.readdirSync)(root);
75362
+ apps = (0, import_fs17.readdirSync)(root);
75033
75363
  } catch {
75034
75364
  return 0;
75035
75365
  }
75036
75366
  const candidates = [];
75037
75367
  for (const app of apps) {
75038
75368
  const runtimesDir = (0, import_path14.join)(root, app, "runtimes");
75039
- if (!(0, import_fs16.existsSync)(runtimesDir)) continue;
75369
+ if (!(0, import_fs17.existsSync)(runtimesDir)) continue;
75040
75370
  for (const f of listDirFiles(runtimesDir)) {
75041
75371
  if (!f.path.endsWith(".json")) continue;
75042
75372
  let record2 = null;
75043
75373
  try {
75044
- 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"));
75045
75375
  const rec = parsed && typeof parsed === "object" ? parsed.record : null;
75046
75376
  record2 = rec && typeof rec === "object" ? rec : null;
75047
75377
  } catch {
@@ -75087,7 +75417,15 @@ ${cleanBody}`;
75087
75417
  } catch (e) {
75088
75418
  LOG2.warn("DiskRetention", `Ledger rotation cap sweep failed: ${e?.message || e}`);
75089
75419
  }
75090
- 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 };
75091
75429
  }
75092
75430
  async function detectAndSignalOrphanWorktrees(mesh, now = Date.now()) {
75093
75431
  const nodes = Array.isArray(mesh.nodes) ? mesh.nodes : [];
@@ -75138,7 +75476,7 @@ ${cleanBody}`;
75138
75476
  }
75139
75477
  return signalled;
75140
75478
  }
75141
- var import_fs16;
75479
+ var import_fs17;
75142
75480
  var import_path14;
75143
75481
  var DAY_MS2;
75144
75482
  var LEDGER_JSONL_MAX_AGE_MS;
@@ -75148,13 +75486,14 @@ ${cleanBody}`;
75148
75486
  var init_mesh_disk_retention = __esm2({
75149
75487
  "src/mesh/mesh-disk-retention.ts"() {
75150
75488
  "use strict";
75151
- import_fs16 = require("fs");
75489
+ import_fs17 = require("fs");
75152
75490
  import_path14 = require("path");
75153
75491
  init_config();
75154
75492
  init_mesh_ledger();
75155
75493
  init_runtime_surface();
75156
75494
  init_git_worktree();
75157
75495
  init_logger();
75496
+ init_disk_space_preflight();
75158
75497
  DAY_MS2 = 24 * 60 * 60 * 1e3;
75159
75498
  LEDGER_JSONL_MAX_AGE_MS = 30 * DAY_MS2;
75160
75499
  SESSION_HOST_RUNTIME_MAX_AGE_MS = 14 * DAY_MS2;
@@ -76167,6 +76506,7 @@ ${cleanBody}`;
76167
76506
  const { meshId, taskId, sessionId, nodeId, providerType, synthKey, reason, detail } = args;
76168
76507
  updateDirectDispatchStatus(meshId, sessionId, "stale", taskId);
76169
76508
  deleteHoldState(synthKey, meshId);
76509
+ clearAckedHoldDispatchFailureStreak(synthKey);
76170
76510
  try {
76171
76511
  appendLedgerEntry(meshId, {
76172
76512
  kind: "acked_hold_terminalized",
@@ -76222,6 +76562,27 @@ ${cleanBody}`;
76222
76562
  };
76223
76563
  const synthKey = inFlightSynthKey(mesh.id, taskId);
76224
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
+ }
76225
76586
  if (isAcked) {
76226
76587
  const ceilingMs = resolveAckedHoldHardCeilingMs();
76227
76588
  const heldSinceMs = getHoldState(synthKey, mesh.id)?.heldSinceMs;
@@ -81175,6 +81536,69 @@ ${cleanBody}`;
81175
81536
  return void 0;
81176
81537
  }
81177
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
+ }
81178
81602
  function submoduleCommitPresent(submoduleRepoPath, commit) {
81179
81603
  if (!commit) return false;
81180
81604
  try {
@@ -81222,6 +81646,7 @@ ${cleanBody}`;
81222
81646
  }
81223
81647
  var fs51;
81224
81648
  var import_node_child_process11;
81649
+ var import_path17;
81225
81650
  var GIT4;
81226
81651
  var REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES;
81227
81652
  var init_mesh_refine_gitlink_utils = __esm2({
@@ -81229,6 +81654,8 @@ ${cleanBody}`;
81229
81654
  "use strict";
81230
81655
  fs51 = __toESM2(require("fs"));
81231
81656
  import_node_child_process11 = require("child_process");
81657
+ import_path17 = require("path");
81658
+ init_logger();
81232
81659
  init_resolve_executable();
81233
81660
  GIT4 = process.platform === "win32" ? resolveWin32Executable("git") : "git";
81234
81661
  REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
@@ -81314,9 +81741,9 @@ ${cleanBody}`;
81314
81741
  for (const path60 of changed) {
81315
81742
  const baseCommit = readTreeObject(baseRepoRoot, baseHead, path60);
81316
81743
  const branchCommit = readTreeObject(worktreeRoot, branchHead, path60);
81317
- const submoduleRepoPath = (0, import_path17.resolve)(worktreeRoot, path60);
81744
+ const submoduleRepoPath = (0, import_path18.resolve)(worktreeRoot, path60);
81318
81745
  if (baseCommit) {
81319
- ensureSubmoduleCommitLocal(submoduleRepoPath, (0, import_path17.resolve)(baseRepoRoot, path60), baseCommit);
81746
+ ensureSubmoduleCommitLocal(submoduleRepoPath, (0, import_path18.resolve)(baseRepoRoot, path60), baseCommit);
81320
81747
  }
81321
81748
  const markUndeterminable = () => {
81322
81749
  const unavailable = [];
@@ -81462,7 +81889,7 @@ ${cleanBody}`;
81462
81889
  for (const p of conflicts) {
81463
81890
  const commit = resolveByPath.get(p);
81464
81891
  try {
81465
- (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" });
81466
81893
  } catch {
81467
81894
  }
81468
81895
  try {
@@ -81481,13 +81908,13 @@ ${cleanBody}`;
81481
81908
  return { ok: true, branchHead };
81482
81909
  }
81483
81910
  var fs52;
81484
- var import_path17;
81911
+ var import_path18;
81485
81912
  var import_node_child_process12;
81486
81913
  var init_mesh_refine_submodule_converge = __esm2({
81487
81914
  "src/mesh/mesh-refine-submodule-converge.ts"() {
81488
81915
  "use strict";
81489
81916
  fs52 = __toESM2(require("fs"));
81490
- import_path17 = require("path");
81917
+ import_path18 = require("path");
81491
81918
  import_node_child_process12 = require("child_process");
81492
81919
  init_mesh_refine_gitlink_utils();
81493
81920
  }
@@ -81509,10 +81936,10 @@ ${tail}`;
81509
81936
  }
81510
81937
  function writeValidationFailureLog(workspace, index, candidate, streams, now = () => /* @__PURE__ */ new Date()) {
81511
81938
  try {
81512
- const dir = (0, import_path18.join)(workspace, REFINE_VALIDATION_LOG_DIR);
81939
+ const dir = (0, import_path19.join)(workspace, REFINE_VALIDATION_LOG_DIR);
81513
81940
  fs53.mkdirSync(dir, { recursive: true });
81514
81941
  const stamp = now().toISOString().replace(/[:.]/g, "-");
81515
- const file2 = (0, import_path18.join)(dir, `refine-${stamp}-${index}.log`);
81942
+ const file2 = (0, import_path19.join)(dir, `refine-${stamp}-${index}.log`);
81516
81943
  const asText = (v) => typeof v === "string" ? v : v == null ? "" : String(v);
81517
81944
  const shown = candidate.displayCommand || [candidate.command, ...candidate.args || []].join(" ");
81518
81945
  fs53.writeFileSync(
@@ -81700,9 +82127,15 @@ ${e?.stderr || ""}`
81700
82127
  };
81701
82128
  }
81702
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
+ }
81703
82135
  async function classifyPatchEquivalenceFailure(repoRoot, baseHead, branchHead, summary, options = {}) {
81704
82136
  const targetBaseRef = options.targetBaseRef || baseHead;
81705
82137
  const autoPublish = options.autoPublishSubmoduleMainCommits;
82138
+ const submoduleProbeRoot = options.worktreeRoot || repoRoot;
81706
82139
  const evidence = {
81707
82140
  baseHead,
81708
82141
  branchHead,
@@ -81767,20 +82200,19 @@ ${e?.stderr || ""}`
81767
82200
  } catch {
81768
82201
  continue;
81769
82202
  }
81770
- const submoduleRepo = (0, import_path18.join)(repoRoot, p);
81771
- let fastForward;
81772
- let reachableFromOriginMain;
81773
- if (branchCommit) {
81774
- if (baseCommit) {
81775
- fastForward = execGitOk(submoduleRepo, ["merge-base", "--is-ancestor", baseCommit, branchCommit]);
81776
- }
81777
- reachableFromOriginMain = execGitOk(submoduleRepo, ["merge-base", "--is-ancestor", branchCommit, "refs/remotes/origin/main"]);
81778
- }
81779
- 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
+ }));
81780
82210
  }
81781
82211
  } catch {
81782
82212
  }
81783
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;
81784
82216
  const gitlinkFf = summary.gitlinkTrivialFastForward;
81785
82217
  const noResidualDiff = !evidence.diffStat && (!summary.actualPatchId || summary.actualPatchId === "");
81786
82218
  if (ahead === 0 && behind === 0 && noResidualDiff) {
@@ -81801,6 +82233,15 @@ ${e?.stderr || ""}`
81801
82233
  evidence
81802
82234
  };
81803
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
+ }
81804
82245
  const changedGitlinks = submoduleGitlinks.length > 0;
81805
82246
  const allGitlinksFf = changedGitlinks && submoduleGitlinks.every((g) => g.fastForward === true);
81806
82247
  const gateSawUnresolvedGitlinkFf = gitlinkFf?.resolved === false && Array.isArray(gitlinkFf.gitlinks) && gitlinkFf.gitlinks.some((g) => g.fastForward);
@@ -81836,14 +82277,6 @@ ${e?.stderr || ""}`
81836
82277
  };
81837
82278
  }
81838
82279
  }
81839
- function execGitOk(cwd, args) {
81840
- try {
81841
- (0, import_node_child_process13.execFileSync)(GIT4, args, { cwd, encoding: "utf8", maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES, windowsHide: true });
81842
- return true;
81843
- } catch {
81844
- return false;
81845
- }
81846
- }
81847
82280
  async function checkWorktreeChangesPatchEquivalentInRef(repoRoot, ref, worktreeHead) {
81848
82281
  const startedAt = Date.now();
81849
82282
  try {
@@ -82037,7 +82470,7 @@ ${mergeTreeErr?.stderr || ""}`;
82037
82470
  const baseCommit = readTreeObject(repoRoot, baseHead, path60);
82038
82471
  const branchCommit = readTreeObject(repoRoot, branchHead, path60);
82039
82472
  if (!baseCommit || !branchCommit) return false;
82040
- return isSubmoduleFastForward((0, import_path18.resolve)(repoRoot, path60), baseCommit, branchCommit);
82473
+ return isSubmoduleFastForward((0, import_path19.resolve)(repoRoot, path60), baseCommit, branchCommit);
82041
82474
  });
82042
82475
  }
82043
82476
  function collectTrivialFastForwardGitlinkResolutions(worktreeRoot, baseRepoRoot, baseHead, branchHead) {
@@ -82046,8 +82479,8 @@ ${mergeTreeErr?.stderr || ""}`;
82046
82479
  const baseCommit = readTreeObject(baseRepoRoot, baseHead, path60);
82047
82480
  const branchCommit = readTreeObject(worktreeRoot, branchHead, path60);
82048
82481
  if (!baseCommit || !branchCommit) continue;
82049
- const submoduleRepoPath = (0, import_path18.resolve)(worktreeRoot, path60);
82050
- 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);
82051
82484
  if (baseCommit === branchCommit) {
82052
82485
  continue;
82053
82486
  }
@@ -82063,7 +82496,7 @@ ${mergeTreeErr?.stderr || ""}`;
82063
82496
  const changedGitlinks = readChangedGitlinkPaths(repoRoot, baseHead, branchHead).map((path60) => {
82064
82497
  const baseCommit = readTreeObject(repoRoot, baseHead, path60);
82065
82498
  const branchCommit = readTreeObject(repoRoot, branchHead, path60);
82066
- const submoduleRepoPath = (0, import_path18.resolve)(repoRoot, path60);
82499
+ const submoduleRepoPath = (0, import_path19.resolve)(repoRoot, path60);
82067
82500
  const fastForward = !!baseCommit && !!branchCommit && isSubmoduleFastForward(submoduleRepoPath, baseCommit, branchCommit);
82068
82501
  return { path: path60, baseCommit, branchCommit, fastForward };
82069
82502
  });
@@ -82118,7 +82551,7 @@ ${mergeTreeErr?.stderr || ""}`;
82118
82551
  if (!tree) return void 0;
82119
82552
  const updates = paths.map((path60) => `160000 commit ${placeholderCommit} ${path60}`).join("\n");
82120
82553
  if (!updates) return tree;
82121
- 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`);
82122
82555
  const env2 = { ...process.env, GIT_INDEX_FILE: tmpIndex };
82123
82556
  try {
82124
82557
  (0, import_node_child_process13.execFileSync)(GIT4, ["read-tree", tree], { cwd: repoRoot, env: env2, stdio: "ignore" });
@@ -82193,7 +82626,7 @@ ${mergeTreeErr?.stderr || ""}`;
82193
82626
  if (!contentTree) return void 0;
82194
82627
  const updates = branchGitlinks.map((entry) => `160000 commit ${entry.branchCommit} ${entry.path}`).join("\n");
82195
82628
  if (!updates) return contentTree;
82196
- 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`);
82197
82630
  const env2 = { ...process.env, GIT_INDEX_FILE: tmpIndex };
82198
82631
  try {
82199
82632
  (0, import_node_child_process13.execFileSync)(GIT4, ["read-tree", contentTree], { cwd: repoRoot, env: env2, stdio: "ignore" });
@@ -82350,7 +82783,7 @@ ${mergeTreeErr?.stderr || ""}`;
82350
82783
  return match ? { commit: match[1], path: match[2] } : null;
82351
82784
  }).filter((entry) => !!entry);
82352
82785
  for (const gitlink of gitlinks) {
82353
- const submodulePath = (0, import_path18.resolve)(repoRoot, gitlink.path);
82786
+ const submodulePath = (0, import_path19.resolve)(repoRoot, gitlink.path);
82354
82787
  const entry = {
82355
82788
  path: gitlink.path,
82356
82789
  commit: gitlink.commit,
@@ -82377,7 +82810,7 @@ ${mergeTreeErr?.stderr || ""}`;
82377
82810
  entry.localReachable = false;
82378
82811
  if (options.allowAutoPublishSubmoduleMainCommits === true && options.worktreeRoot) {
82379
82812
  try {
82380
- 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);
82381
82814
  if (imported) {
82382
82815
  entry.localReachable = true;
82383
82816
  entry.importedFromWorktree = true;
@@ -82607,13 +83040,13 @@ ${mergeTreeErr?.stderr || ""}`;
82607
83040
  ...extras
82608
83041
  });
82609
83042
  const isPackageManagerValidation = (candidate) => {
82610
- 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, "");
82611
83044
  return ["npm", "pnpm", "yarn", "bun"].includes(command) && candidate.args.some((arg) => arg === "run" || arg === "test" || arg === "exec");
82612
83045
  };
82613
83046
  const dependenciesLikelyMissing = (cwd) => {
82614
- if (!fs53.existsSync((0, import_path18.join)(cwd, "package.json"))) return false;
82615
- if (fs53.existsSync((0, import_path18.join)(cwd, "node_modules"))) return false;
82616
- 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)));
82617
83050
  };
82618
83051
  const needsNodeModules = (candidate, cwd) => isPackageManagerValidation(candidate) && dependenciesLikelyMissing(cwd);
82619
83052
  const isDaemonScopedCommand = (candidate) => {
@@ -82680,7 +83113,7 @@ ${mergeTreeErr?.stderr || ""}`;
82680
83113
  summary.bootstrap = { stage: "legacy" };
82681
83114
  for (const candidate of selection.bootstrapCommands) {
82682
83115
  const startedAt = Date.now();
82683
- 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;
82684
83117
  const timeout = candidate.timeoutMs || REFINE_VALIDATION_TIMEOUT_MS;
82685
83118
  const resolvedCommand = resolveWin32Executable(candidate.command);
82686
83119
  const spawn7 = buildWin32ExecFileSpawn(resolvedCommand, candidate.args);
@@ -82713,7 +83146,7 @@ ${mergeTreeErr?.stderr || ""}`;
82713
83146
  let missingDepsBlocked = false;
82714
83147
  for (const candidate of commandsToRun) {
82715
83148
  const startedAt = Date.now();
82716
- 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;
82717
83150
  const timeout = candidate.timeoutMs || REFINE_VALIDATION_TIMEOUT_MS;
82718
83151
  const bootstrapProvidedDependencies = summary.bootstrap?.stage === "cached" || summary.bootstrap?.stage === "ran" || summary.bootstrap?.stage === "legacy";
82719
83152
  if (!bootstrapProvidedDependencies && needsNodeModules(candidate, cwd)) {
@@ -82780,7 +83213,7 @@ ${mergeTreeErr?.stderr || ""}`;
82780
83213
  summary.status = "passed";
82781
83214
  return summary;
82782
83215
  }
82783
- var import_path18;
83216
+ var import_path19;
82784
83217
  var fs53;
82785
83218
  var import_node_child_process13;
82786
83219
  var REFINE_VALIDATION_TIMEOUT_MS;
@@ -82795,7 +83228,7 @@ ${mergeTreeErr?.stderr || ""}`;
82795
83228
  init_git_status();
82796
83229
  init_refine_config();
82797
83230
  init_worktree_bootstrap_config();
82798
- import_path18 = require("path");
83231
+ import_path19 = require("path");
82799
83232
  fs53 = __toESM2(require("fs"));
82800
83233
  import_node_child_process13 = require("child_process");
82801
83234
  init_resolve_executable();
@@ -82807,7 +83240,7 @@ ${mergeTreeErr?.stderr || ""}`;
82807
83240
  REFINE_VALIDATION_SUMMARY_HEAD_CHARS = 2e3;
82808
83241
  REFINE_VALIDATION_SUMMARY_TAIL_CHARS = 6e3;
82809
83242
  REFINE_VALIDATION_SUMMARY_CHARS = REFINE_VALIDATION_SUMMARY_HEAD_CHARS + REFINE_VALIDATION_SUMMARY_TAIL_CHARS;
82810
- REFINE_VALIDATION_LOG_DIR = (0, import_path18.join)(".adhdev", "logs");
83243
+ REFINE_VALIDATION_LOG_DIR = (0, import_path19.join)(".adhdev", "logs");
82811
83244
  }
82812
83245
  });
82813
83246
  function findOpenRefineDispatchForNode(args) {
@@ -83889,16 +84322,11 @@ ${excerpt}` : "\n--- git output ---\n(none captured)");
83889
84322
  error: submoduleHintPatchEquivalence.error,
83890
84323
  actionableHint: submoduleHintPatchEquivalence.actionableHint
83891
84324
  });
83892
- const classification = await classifyPatchEquivalenceFailure(
83893
- repoRoot,
83894
- baseHead,
83895
- ctx.branchHead,
83896
- submoduleHintPatchEquivalence,
83897
- {
83898
- targetBaseRef: baseHead,
83899
- autoPublishSubmoduleMainCommits: resolveRefineryAutoPublishSubmoduleMainCommits(ctx.mesh, node.workspace).enabled
83900
- }
83901
- );
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
+ });
83902
84330
  return { kind: "terminal", result: {
83903
84331
  success: false,
83904
84332
  code: "patch_equivalence_failed",
@@ -84082,19 +84510,15 @@ ${tail}` : ""
84082
84510
  if (!patchEquivalence.equivalent) {
84083
84511
  const alreadyMergedViaOtherPath = !patchEquivalence.actualPatchId && !!patchEquivalence.expectedPatchId;
84084
84512
  if (!alreadyMergedViaOtherPath) {
84085
- const classification = await classifyPatchEquivalenceFailure(
84086
- repoRoot,
84087
- baseHead,
84088
- branchHead,
84089
- patchEquivalence,
84090
- {
84091
- targetBaseRef: baseHead,
84092
- autoPublishSubmoduleMainCommits: resolveRefineryAutoPublishSubmoduleMainCommits(mesh, node.workspace).enabled
84093
- }
84094
- );
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
+ });
84095
84518
  recordMeshRefineStage(refineStages, "patch_equivalence_classification", "failed", patchEquivalenceStarted, {
84096
84519
  detailedReason: classification.detailedReason,
84097
- recommendedAction: classification.recommendedAction
84520
+ recommendedAction: classification.recommendedAction,
84521
+ ...classification.evidence.submoduleReachabilityUndeterminable ? { submoduleReachabilityUndeterminable: true } : {}
84098
84522
  });
84099
84523
  return { kind: "terminal", result: {
84100
84524
  success: false,
@@ -85473,6 +85897,10 @@ ${e?.stderr || ""}`;
85473
85897
  DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS: () => DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS,
85474
85898
  DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS: () => DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS,
85475
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,
85476
85904
  DUPLICATE_MESH_DISPATCH_CODE: () => DUPLICATE_MESH_DISPATCH_CODE,
85477
85905
  DaemonAgentStreamManager: () => DaemonAgentStreamManager,
85478
85906
  DaemonCdpInitializer: () => DaemonCdpInitializer,
@@ -85497,8 +85925,11 @@ ${e?.stderr || ""}`;
85497
85925
  KNOWN_DIGEST_ALGORITHMS: () => KNOWN_DIGEST_ALGORITHMS,
85498
85926
  LEGACY_UNVERIFIED_ALGORITHM: () => LEGACY_UNVERIFIED_ALGORITHM,
85499
85927
  LOG: () => LOG2,
85928
+ LowDiskSpaceError: () => LowDiskSpaceError,
85500
85929
  MAGI_NEEDS_VERIFICATION_PREVIEW_CAP: () => MAGI_NEEDS_VERIFICATION_PREVIEW_CAP,
85501
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,
85502
85933
  MAX_LEDGER_SLICE_LIMIT: () => MAX_LEDGER_SLICE_LIMIT,
85503
85934
  MAX_SESSIONS_PER_MESH: () => MAX_SESSIONS_PER_MESH,
85504
85935
  MAX_SIZE_ROTATION_GENERATIONS: () => MAX_SIZE_ROTATION_GENERATIONS,
@@ -85628,9 +86059,11 @@ ${e?.stderr || ""}`;
85628
86059
  buildUserChatMessage: () => buildUserChatMessage,
85629
86060
  cancelTask: () => cancelTask,
85630
86061
  canonicalDaemonId: () => canonicalDaemonId,
86062
+ checkDiskSpace: () => checkDiskSpace,
85631
86063
  claimMeshGraphGate: () => claimMeshGraphGate,
85632
86064
  claimNextTask: () => claimNextTask,
85633
86065
  classifyChatMessageVisibility: () => classifyChatMessageVisibility,
86066
+ classifyDiskSpace: () => classifyDiskSpace,
85634
86067
  classifyDuplicateMeshDispatch: () => classifyDuplicateMeshDispatch,
85635
86068
  classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush2,
85636
86069
  classifyP2pRelayFailure: () => classifyP2pRelayFailure,
@@ -85682,6 +86115,7 @@ ${e?.stderr || ""}`;
85682
86115
  deriveMeshReviewInboxItems: () => deriveMeshReviewInboxItems,
85683
86116
  deriveWorkspaceBranchIdentity: () => deriveWorkspaceBranchIdentity,
85684
86117
  deriveWorkspaceOwnerTag: () => deriveWorkspaceOwnerTag,
86118
+ describeDiskSpace: () => describeDiskSpace,
85685
86119
  describeTaskDependencyState: () => describeTaskDependencyState,
85686
86120
  detectAllVersions: () => detectAllVersions,
85687
86121
  detectCLI: () => detectCLI,
@@ -85717,6 +86151,7 @@ ${e?.stderr || ""}`;
85717
86151
  flattenMessageParts: () => flattenMessageParts,
85718
86152
  foldUsageRecords: () => foldUsageRecords,
85719
86153
  forceRefreshQuota: () => forceRefreshQuota2,
86154
+ formatBytes: () => formatBytes,
85720
86155
  formatManifestValidationIssues: () => formatManifestValidationIssues,
85721
86156
  formatMeshTaskModeViolations: () => formatMeshTaskModeViolations,
85722
86157
  forwardAgentStreamsToIdeInstance: () => forwardAgentStreamsToIdeInstance2,
@@ -85834,6 +86269,7 @@ ${e?.stderr || ""}`;
85834
86269
  loadRepoSettings: () => loadRepoSettings,
85835
86270
  loadState: () => loadState,
85836
86271
  logCommand: () => logCommand,
86272
+ logDiskSpaceStatus: () => logDiskSpaceStatus,
85837
86273
  machineCoreFromDaemonId: () => machineCoreFromDaemonId,
85838
86274
  magiAutoLaunchedSessionCleanupDecision: () => magiAutoLaunchedSessionCleanupDecision,
85839
86275
  makeUsage: () => makeUsage,
@@ -85890,6 +86326,7 @@ ${e?.stderr || ""}`;
85890
86326
  partitionSessionHostDiagnosticsSessions: () => import_session_host_core32.partitionSessionHostDiagnosticsSessions,
85891
86327
  partitionSessionHostRecords: () => import_session_host_core32.partitionSessionHostRecords,
85892
86328
  planMeshOnboarding: () => planMeshOnboarding,
86329
+ preflightDiskSpace: () => preflightDiskSpace,
85893
86330
  prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate2,
85894
86331
  prepareSessionModalUpdate: () => prepareSessionModalUpdate2,
85895
86332
  presentationFromAttemptRow: () => presentationFromAttemptRow,
@@ -85911,6 +86348,7 @@ ${e?.stderr || ""}`;
85911
86348
  readChatHistory: () => readChatHistory,
85912
86349
  readClaudeCliSession: () => readSession,
85913
86350
  readCodexCliSession: () => readSession2,
86351
+ readDiskSpace: () => readDiskSpace,
85914
86352
  readHermesCliSession: () => readSession4,
85915
86353
  readLatestCodexRateLimits: () => readLatestCodexRateLimits,
85916
86354
  readLedgerEntries: () => readLedgerEntries,
@@ -85992,6 +86430,7 @@ ${e?.stderr || ""}`;
85992
86430
  resolveTurnAttemptRow: () => resolveTurnAttemptRow,
85993
86431
  resolveWorktreeBaseDir: () => resolveWorktreeBaseDir,
85994
86432
  resolveWorktreePath: () => resolveWorktreePath,
86433
+ rotateCaptureLogIfNeeded: () => rotateCaptureLogIfNeeded,
85995
86434
  runAsyncBatch: () => runAsyncBatch2,
85996
86435
  runGit: () => runGit,
85997
86436
  runMeshWorktreeBootstrap: () => runMeshWorktreeBootstrap,
@@ -89543,7 +89982,7 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89543
89982
  init_state_store();
89544
89983
  var import_child_process5 = require("child_process");
89545
89984
  var import_util22 = require("util");
89546
- var import_fs17 = require("fs");
89985
+ var import_fs18 = require("fs");
89547
89986
  var import_os3 = require("os");
89548
89987
  var path24 = __toESM2(require("path"));
89549
89988
  var fs16 = __toESM2(require("fs"));
@@ -89620,7 +90059,7 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89620
90059
  if (path24.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
89621
90060
  const candidate = trimmed.startsWith("~") ? path24.join((0, import_os3.homedir)(), trimmed.slice(1)) : trimmed;
89622
90061
  const resolved = path24.isAbsolute(candidate) ? candidate : path24.resolve(candidate);
89623
- return (0, import_fs17.existsSync)(resolved) ? resolved : null;
90062
+ return (0, import_fs18.existsSync)(resolved) ? resolved : null;
89624
90063
  }
89625
90064
  const isWin = (0, import_os3.platform)() === "win32";
89626
90065
  const paths = (process.env.PATH || "").split(isWin ? ";" : ":");
@@ -89630,8 +90069,8 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89630
90069
  for (const ext of exes) {
89631
90070
  const fullPath = path24.join(p, trimmed + ext);
89632
90071
  try {
89633
- if ((0, import_fs17.existsSync)(fullPath)) {
89634
- const stat2 = (0, import_fs17.statSync)(fullPath);
90072
+ if ((0, import_fs18.existsSync)(fullPath)) {
90073
+ const stat2 = (0, import_fs18.statSync)(fullPath);
89635
90074
  if (stat2.isFile() && (isWin || stat2.mode & 73)) {
89636
90075
  return fullPath;
89637
90076
  }
@@ -89649,9 +90088,9 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89649
90088
  if (normalized.includes("*")) {
89650
90089
  const username = home.split(/[\\/]/).pop() || "";
89651
90090
  const resolved = normalized.replace("*", username);
89652
- if ((0, import_fs17.existsSync)(resolved)) return resolved;
90091
+ if ((0, import_fs18.existsSync)(resolved)) return resolved;
89653
90092
  } else {
89654
- if ((0, import_fs17.existsSync)(normalized)) return normalized;
90093
+ if ((0, import_fs18.existsSync)(normalized)) return normalized;
89655
90094
  }
89656
90095
  }
89657
90096
  return null;
@@ -89665,7 +90104,7 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89665
90104
  let resolvedCli = cliPath;
89666
90105
  if (!resolvedCli && appPath && os33 === "darwin") {
89667
90106
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
89668
- if ((0, import_fs17.existsSync)(bundledCli)) resolvedCli = bundledCli;
90107
+ if ((0, import_fs18.existsSync)(bundledCli)) resolvedCli = bundledCli;
89669
90108
  }
89670
90109
  if (!resolvedCli && appPath && os33 === "win32") {
89671
90110
  const { dirname: dirname24 } = await import("path");
@@ -89678,7 +90117,7 @@ The pin is NOT cleared automatically: a pin often encodes required context conti
89678
90117
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
89679
90118
  ];
89680
90119
  for (const c of candidates) {
89681
- if ((0, import_fs17.existsSync)(c)) {
90120
+ if ((0, import_fs18.existsSync)(c)) {
89682
90121
  resolvedCli = c;
89683
90122
  break;
89684
90123
  }
@@ -101316,7 +101755,7 @@ ${marker}`,
101316
101755
  var os24 = __toESM2(require("os"));
101317
101756
  var path40 = __toESM2(require("path"));
101318
101757
  var crypto6 = __toESM2(require("crypto"));
101319
- var import_fs18 = require("fs");
101758
+ var import_fs19 = require("fs");
101320
101759
  var import_child_process11 = require("child_process");
101321
101760
  var import_chalk = __toESM2((init_source(), __toCommonJS(source_exports)));
101322
101761
  var fs322 = __toESM2(require("fs"));
@@ -112640,7 +113079,7 @@ ${rawInput}` : rawInput;
112640
113079
  const trimmed = command.trim();
112641
113080
  if (!trimmed) return false;
112642
113081
  if (isExplicitCommand(trimmed)) {
112643
- return (0, import_fs18.existsSync)(expandExecutable(trimmed));
113082
+ return (0, import_fs19.existsSync)(expandExecutable(trimmed));
112644
113083
  }
112645
113084
  try {
112646
113085
  (0, import_child_process11.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -112786,10 +113225,10 @@ ${rawInput}` : rawInput;
112786
113225
  }
112787
113226
  function ensureEmptyDelegatedMcpConfig(workspace) {
112788
113227
  const baseDir = path40.join(os24.tmpdir(), "adhdev-delegated-agent-empty-mcp");
112789
- (0, import_fs18.mkdirSync)(baseDir, { recursive: true });
113228
+ (0, import_fs19.mkdirSync)(baseDir, { recursive: true });
112790
113229
  const workspaceHash = shortHash(path40.resolve(workspace || os24.tmpdir()));
112791
113230
  const filePath = path40.join(baseDir, `${workspaceHash}.json`);
112792
- (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");
112793
113232
  return filePath;
112794
113233
  }
112795
113234
  function buildCoordinatorDelegatedCliLaunchOptions(input) {
@@ -120541,7 +120980,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
120541
120980
  normalizeRepoMeshDeclarativeConfig: normalizeRepoMeshDeclarativeConfig2,
120542
120981
  MESH_JSON_CONFIG_LOCATIONS: MESH_JSON_CONFIG_LOCATIONS2
120543
120982
  } = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
120544
- const { mkdirSync: mkdirSync31, writeFileSync: writeFileSync31 } = await import("fs");
120983
+ const { mkdirSync: mkdirSync32, writeFileSync: writeFileSync31 } = await import("fs");
120545
120984
  const { dirname: dirname24, join: join68 } = await import("path");
120546
120985
  const scaffold = buildMeshJsonConfigScaffold2(mesh);
120547
120986
  const scaffoldJson = serializeMeshJsonConfigScaffold2(scaffold);
@@ -120582,7 +121021,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
120582
121021
  note: "Dry-run: nothing written. Re-run with write=true to persist to the repo (commit target). meshes.json is untouched."
120583
121022
  };
120584
121023
  }
120585
- mkdirSync31(dirname24(absolutePath), { recursive: true });
121024
+ mkdirSync32(dirname24(absolutePath), { recursive: true });
120586
121025
  writeFileSync31(absolutePath, `${scaffoldJson}
120587
121026
  `, "utf-8");
120588
121027
  return {
@@ -120652,7 +121091,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
120652
121091
  normalizeRepoMeshDeclarativeConfig: normalizeRepoMeshDeclarativeConfig2,
120653
121092
  MESH_JSON_CONFIG_LOCATIONS: MESH_JSON_CONFIG_LOCATIONS2
120654
121093
  } = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
120655
- 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");
120656
121095
  const { dirname: dirname24, join: join68 } = await import("path");
120657
121096
  const yaml6 = await Promise.resolve().then(() => (init_js_yaml(), js_yaml_exports));
120658
121097
  const relativePath = MESH_JSON_CONFIG_LOCATIONS2[0];
@@ -120717,7 +121156,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
120717
121156
  note: "Dry-run: nothing written. Re-run with write=true to persist. Only the providerDefaults zone is merged; other repo zones are preserved."
120718
121157
  };
120719
121158
  }
120720
- mkdirSync31(dirname24(absolutePath), { recursive: true });
121159
+ mkdirSync32(dirname24(absolutePath), { recursive: true });
120721
121160
  writeFileSync31(absolutePath, serialized, "utf-8");
120722
121161
  return {
120723
121162
  success: true,
@@ -121674,7 +122113,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
121674
122113
  error: applied.reason
121675
122114
  };
121676
122115
  }
121677
- ctx.inlineMeshCache.set(meshId, applied.mesh);
122116
+ ctx.getCachedInlineMesh(meshId, applied.mesh);
121678
122117
  ctx.invalidateAggregateMeshStatus(meshId);
121679
122118
  try {
121680
122119
  const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
@@ -123026,7 +123465,7 @@ ${ptyResult.output.slice(-2e3)}`);
123026
123465
  workspace
123027
123466
  };
123028
123467
  }
123029
- 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");
123030
123469
  const { dirname: dirname24 } = await import("path");
123031
123470
  const mcpConfigPath = coordinatorSetup.configPath;
123032
123471
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
@@ -123064,7 +123503,7 @@ ${ptyResult.output.slice(-2e3)}`);
123064
123503
  ...mcpServerEnv ? { env: mcpServerEnv } : {}
123065
123504
  });
123066
123505
  try {
123067
- mkdirSync31(dirname24(mcpConfigPath), { recursive: true });
123506
+ mkdirSync32(dirname24(mcpConfigPath), { recursive: true });
123068
123507
  } catch (error48) {
123069
123508
  const message = `Could not prepare MCP config path for automatic setup: ${error48?.message || error48}`;
123070
123509
  LOG2.error("MeshCoordinator", message);
@@ -124092,7 +124531,7 @@ ${ptyResult.output.slice(-2e3)}`);
124092
124531
  init_router_refine();
124093
124532
  var fs54 = __toESM2(require("fs"));
124094
124533
  var import_node_os22 = require("os");
124095
- var import_path19 = require("path");
124534
+ var import_path20 = require("path");
124096
124535
  init_logger();
124097
124536
  init_git_locale();
124098
124537
  init_dist();
@@ -124104,7 +124543,7 @@ ${ptyResult.output.slice(-2e3)}`);
124104
124543
  function acceptableManagedWorktreePaths(resolveWorktreePath2, normalizePath2, repoRoot, meshName, branch, worktreeBaseDir) {
124105
124544
  const safeBranch = branch.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
124106
124545
  const safeMeshName = meshName.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
124107
- 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);
124108
124547
  const candidates = [
124109
124548
  resolveWorktreePath2(repoRoot, meshName, branch, worktreeBaseDir),
124110
124549
  legacyPath
@@ -124131,8 +124570,8 @@ ${ptyResult.output.slice(-2e3)}`);
124131
124570
  function looksLikeCrossTrackWorktreePath(actualPath, normalizePath2) {
124132
124571
  const home = normalizePath2((0, import_node_os22.homedir)());
124133
124572
  return TRACK_CONFIG_DIR_NAMES.some((trackDirName) => {
124134
- const trackWorktreesDir = (0, import_path19.join)(home, trackDirName, "worktrees");
124135
- 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);
124136
124575
  });
124137
124576
  }
124138
124577
  function unexpectedPathRecoveryHint(actualPath, normalizePath2, suffix) {
@@ -124242,7 +124681,7 @@ ${ptyResult.output.slice(-2e3)}`);
124242
124681
  }
124243
124682
  const { resolveWorktreePath: resolveWorktreePath2, listWorktrees: listWorktrees2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
124244
124683
  const normalizePath2 = (value) => {
124245
- const resolved = (0, import_path19.resolve)(value);
124684
+ const resolved = (0, import_path20.resolve)(value);
124246
124685
  try {
124247
124686
  return fs54.realpathSync(resolved);
124248
124687
  } catch {
@@ -124369,7 +124808,7 @@ ${ptyResult.output.slice(-2e3)}`);
124369
124808
  }
124370
124809
  const { resolveWorktreePath: resolveWorktreePath2, listWorktrees: listWorktrees2, removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
124371
124810
  const normalizePath2 = (value) => {
124372
- const resolved = (0, import_path19.resolve)(value);
124811
+ const resolved = (0, import_path20.resolve)(value);
124373
124812
  try {
124374
124813
  return fs54.realpathSync(resolved);
124375
124814
  } catch {
@@ -125037,7 +125476,7 @@ ${ptyResult.output.slice(-2e3)}`);
125037
125476
  init_logger();
125038
125477
  var yaml5 = __toESM2(require_js_yaml());
125039
125478
  var import_os5 = require("os");
125040
- var import_path20 = require("path");
125479
+ var import_path21 = require("path");
125041
125480
  var fs55 = __toESM2(require("fs"));
125042
125481
  var MESH_COORDINATOR_AUTO_IMPORT_FORMATS = ["claude_mcp_json", "hermes_config_yaml", "opencode_json"];
125043
125482
  function isSupportedMeshCoordinatorConfigFormat(format) {
@@ -125078,13 +125517,13 @@ ${ptyResult.output.slice(-2e3)}`);
125078
125517
  }
125079
125518
  function resolveHermesUserHome() {
125080
125519
  const explicitHome = process.env.HERMES_HOME?.trim();
125081
- return explicitHome || (0, import_path20.join)((0, import_os5.homedir)(), ".hermes");
125520
+ return explicitHome || (0, import_path21.join)((0, import_os5.homedir)(), ".hermes");
125082
125521
  }
125083
125522
  function loadHermesCoordinatorBaseConfig(targetConfigPath) {
125084
125523
  const sourceHome = resolveHermesUserHome();
125085
- const sourceConfigPath = (0, import_path20.join)(sourceHome, "config.yaml");
125524
+ const sourceConfigPath = (0, import_path21.join)(sourceHome, "config.yaml");
125086
125525
  if (!fs55.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
125087
- 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 };
125088
125527
  const parsed = parseMeshCoordinatorMcpConfig(fs55.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
125089
125528
  const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
125090
125529
  return { config: baseConfig, sourceHome, sourceConfigPath };
@@ -125118,10 +125557,10 @@ ${ptyResult.output.slice(-2e3)}`);
125118
125557
  return sanitized;
125119
125558
  }
125120
125559
  function copyHermesCoordinatorCredentialFiles(sourceHome, targetHome) {
125121
- 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;
125122
125561
  for (const fileName of [".env", "auth.json"]) {
125123
- const sourcePath = (0, import_path20.join)(sourceHome, fileName);
125124
- 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);
125125
125564
  if (!fs55.existsSync(sourcePath)) continue;
125126
125565
  try {
125127
125566
  fs55.copyFileSync(sourcePath, targetPath);
@@ -126258,6 +126697,7 @@ ${ptyResult.output.slice(-2e3)}`);
126258
126697
  init_track_identity();
126259
126698
  init_normalize();
126260
126699
  init_logger();
126700
+ init_disk_space_preflight();
126261
126701
  var UNICODE_SYMBOLS = {
126262
126702
  ok: "\u2713",
126263
126703
  fail: "\u2717",
@@ -133326,6 +133766,7 @@ data: ${JSON.stringify(msg.data)}
133326
133766
  var path59 = __toESM2(require("path"));
133327
133767
  var import_session_host_core14 = require_dist();
133328
133768
  init_logger();
133769
+ init_disk_space_preflight();
133329
133770
  init_runtime_defaults();
133330
133771
  function createManagedSessionHost2(options) {
133331
133772
  const appName = options.appName;
@@ -133429,6 +133870,7 @@ data: ${JSON.stringify(msg.data)}
133429
133870
  function spawnHost() {
133430
133871
  const entry = resolveEntry();
133431
133872
  verifyConptyPrebuildBeforeSpawn(entry);
133873
+ preflightDiskSpace(instance().configDir, "spawn the session host");
133432
133874
  const nodeExecutable = resolveSessionHostNode();
133433
133875
  let stdio = "ignore";
133434
133876
  let logFd = null;
@@ -133444,7 +133886,20 @@ data: ${JSON.stringify(msg.data)}
133444
133886
  windowsHide: true,
133445
133887
  env: buildEnv(process.env)
133446
133888
  });
133447
- 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();
133448
133903
  if (logFd !== null) {
133449
133904
  try {
133450
133905
  fs62.closeSync(logFd);
@@ -133895,8 +134350,8 @@ data: ${JSON.stringify(msg.data)}
133895
134350
  init_config_dir();
133896
134351
  init_mesh_events();
133897
134352
  init_mesh_reconcile_loop();
133898
- var import_fs19 = require("fs");
133899
- var import_path21 = require("path");
134353
+ var import_fs20 = require("fs");
134354
+ var import_path222 = require("path");
133900
134355
  var import_crypto18 = require("crypto");
133901
134356
  init_logger();
133902
134357
  init_mesh_ledger();
@@ -133964,31 +134419,31 @@ data: ${JSON.stringify(msg.data)}
133964
134419
  } catch {
133965
134420
  return result;
133966
134421
  }
133967
- if (!(0, import_fs19.existsSync)(dir)) return result;
134422
+ if (!(0, import_fs20.existsSync)(dir)) return result;
133968
134423
  let names;
133969
134424
  try {
133970
- names = (0, import_fs19.readdirSync)(dir);
134425
+ names = (0, import_fs20.readdirSync)(dir);
133971
134426
  } catch (e) {
133972
134427
  LOG2.warn("MeshEvents", `Pending-events migration: cannot read ledger dir: ${e?.message || e}`);
133973
134428
  return result;
133974
134429
  }
133975
134430
  for (const name of names) {
133976
134431
  if (!isPendingEventsFile(name)) continue;
133977
- const path60 = (0, import_path21.join)(dir, name);
134432
+ const path60 = (0, import_path222.join)(dir, name);
133978
134433
  result.filesScanned++;
133979
134434
  const claimed = `${path60}.migrating`;
133980
134435
  try {
133981
- (0, import_fs19.renameSync)(path60, claimed);
134436
+ (0, import_fs20.renameSync)(path60, claimed);
133982
134437
  } catch {
133983
134438
  continue;
133984
134439
  }
133985
134440
  let content;
133986
134441
  try {
133987
- content = (0, import_fs19.readFileSync)(claimed, "utf-8");
134442
+ content = (0, import_fs20.readFileSync)(claimed, "utf-8");
133988
134443
  } catch (e) {
133989
134444
  LOG2.warn("MeshEvents", `Pending-events migration: cannot read ${name}; leaving it for the next boot: ${e?.message || e}`);
133990
134445
  try {
133991
- (0, import_fs19.renameSync)(claimed, path60);
134446
+ (0, import_fs20.renameSync)(claimed, path60);
133992
134447
  } catch {
133993
134448
  }
133994
134449
  result.filesRetained++;
@@ -134003,14 +134458,14 @@ data: ${JSON.stringify(msg.data)}
134003
134458
  }
134004
134459
  if (!allImported) {
134005
134460
  try {
134006
- (0, import_fs19.renameSync)(claimed, path60);
134461
+ (0, import_fs20.renameSync)(claimed, path60);
134007
134462
  } catch {
134008
134463
  }
134009
134464
  result.filesRetained++;
134010
134465
  continue;
134011
134466
  }
134012
134467
  try {
134013
- (0, import_fs19.unlinkSync)(claimed);
134468
+ (0, import_fs20.unlinkSync)(claimed);
134014
134469
  result.filesRemoved++;
134015
134470
  } catch (e) {
134016
134471
  LOG2.warn("MeshEvents", `Pending-events migration: imported ${name} but could not unlink it: ${e?.message || e}`);
@@ -135429,14 +135884,77 @@ function createLineParser(onEnvelope) {
135429
135884
  }
135430
135885
  };
135431
135886
  }
135887
+ var establishedSockets = /* @__PURE__ */ new WeakSet();
135432
135888
  var SessionHostClient = class {
135433
135889
  endpoint;
135434
135890
  socket = null;
135435
135891
  requestWaiters = /* @__PURE__ */ new Map();
135436
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();
135437
135896
  constructor(options = {}) {
135438
135897
  this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || "adhdev");
135439
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
+ }
135440
135958
  async connect() {
135441
135959
  if (this.socket && !this.socket.destroyed) return;
135442
135960
  if (this.socket) {
@@ -135462,20 +135980,19 @@ var SessionHostClient = class {
135462
135980
  }
135463
135981
  }));
135464
135982
  socket.on("error", (error48) => {
135465
- for (const waiter of this.requestWaiters.values()) {
135466
- waiter.reject(error48);
135467
- }
135468
- this.requestWaiters.clear();
135469
- if (this.socket === socket) {
135470
- this.socket = null;
135471
- }
135472
- try {
135473
- socket.destroy();
135474
- } catch {
135475
- }
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");
135476
135990
  });
135477
135991
  await new Promise((resolve3, reject) => {
135478
- socket.once("connect", () => resolve3());
135992
+ socket.once("connect", () => {
135993
+ establishedSockets.add(socket);
135994
+ resolve3();
135995
+ });
135479
135996
  socket.once("error", reject);
135480
135997
  });
135481
135998
  }
@@ -135517,6 +136034,7 @@ var SessionHostClient = class {
135517
136034
  if (!this.socket) return;
135518
136035
  const socket = this.socket;
135519
136036
  this.socket = null;
136037
+ this.disconnectedSockets.add(socket);
135520
136038
  for (const waiter of this.requestWaiters.values()) {
135521
136039
  waiter.reject(new Error("Session host client closed"));
135522
136040
  }