adhdev 1.0.82-rc.24 → 1.0.82-rc.25

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.
@@ -8,7 +8,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
8
8
 
9
9
  // src/index.ts
10
10
  import { randomUUID as randomUUID2 } from "crypto";
11
- import * as fs6 from "fs";
11
+ import * as fs7 from "fs";
12
12
  import * as path6 from "path";
13
13
  import {
14
14
  SessionHostClient,
@@ -289,8 +289,8 @@ var PtySessionRuntime = class {
289
289
  let cwd = this.payload.workspace || process.cwd();
290
290
  if (cwd) {
291
291
  try {
292
- const stat = fs2.statSync(cwd);
293
- if (!stat.isDirectory()) cwd = os.homedir();
292
+ const stat2 = fs2.statSync(cwd);
293
+ if (!stat2.isDirectory()) cwd = os.homedir();
294
294
  } catch {
295
295
  cwd = os.homedir();
296
296
  }
@@ -542,8 +542,8 @@ var HostUpgradeLease = class {
542
542
  try {
543
543
  if (this.binding.helperFileIdentity && (this.fileIdentity() !== this.binding.helperFileIdentity || digest(fs3.readFileSync(this.binding.helperPath)) !== this.binding.helperSha256)) throw new Error("native_host_helper_file_identity_changed");
544
544
  if (fs3.existsSync(this.journal)) {
545
- const stat = fs3.lstatSync(this.journal);
546
- if (!stat.isFile() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || stat.mode & 63) throw new Error("native_host_lease_untrusted");
545
+ const stat2 = fs3.lstatSync(this.journal);
546
+ if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.uid !== process.getuid?.() || stat2.mode & 63) throw new Error("native_host_lease_untrusted");
547
547
  const value = JSON.parse(fs3.readFileSync(this.journal, "utf8"));
548
548
  if (value.schema !== 1 || value.endpoint !== this.endpoint || !Number.isSafeInteger(value.epoch) || value.epoch < 0 || typeof value.held !== "boolean" || (value.held ? typeof value.owner !== "string" || typeof value.tokenHash !== "string" || !/^[a-f0-9]{64}$/.test(value.tokenHash) : value.owner !== null || value.tokenHash !== null)) throw new Error("native_host_lease_corrupt");
549
549
  this.state = value;
@@ -644,8 +644,8 @@ var SessionHostStorage = class {
644
644
  /** Unknown/corrupt recovery files also veto idle admission; reads names only. */
645
645
  hasRuntimeEntries() {
646
646
  if (!fs4.existsSync(this.runtimesDir)) return false;
647
- const stat = fs4.lstatSync(this.runtimesDir);
648
- if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("native_host_runtime_storage_untrusted");
647
+ const stat2 = fs4.lstatSync(this.runtimesDir);
648
+ if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw new Error("native_host_runtime_storage_untrusted");
649
649
  return fs4.readdirSync(this.runtimesDir).length > 0;
650
650
  }
651
651
  loadAll() {
@@ -1777,8 +1777,59 @@ var SessionHostServer = class extends EventEmitter {
1777
1777
  }
1778
1778
  };
1779
1779
 
1780
+ // src/threadpool-watchdog.ts
1781
+ import * as fs6 from "fs";
1782
+ import * as os2 from "os";
1783
+ var THREADPOOL_WATCHDOG_INTERVAL_MS = 15e3;
1784
+ var THREADPOOL_WATCHDOG_STALL_MS = 12e4;
1785
+ function defaultProbe(done) {
1786
+ fs6.stat(os2.tmpdir(), () => done());
1787
+ }
1788
+ function startThreadpoolWatchdog(options) {
1789
+ const intervalMs = options.intervalMs ?? THREADPOOL_WATCHDOG_INTERVAL_MS;
1790
+ const stallMs = options.stallMs ?? THREADPOOL_WATCHDOG_STALL_MS;
1791
+ const probe = options.probe ?? defaultProbe;
1792
+ const now = options.now ?? Date.now;
1793
+ let inFlightSince = null;
1794
+ let stopped = false;
1795
+ const tick = () => {
1796
+ if (stopped) return;
1797
+ if (inFlightSince !== null) {
1798
+ const stalledForMs = now() - inFlightSince;
1799
+ if (stalledForMs >= stallMs) {
1800
+ stopped = true;
1801
+ clearInterval(timer);
1802
+ options.onStall(stalledForMs);
1803
+ }
1804
+ return;
1805
+ }
1806
+ const startedAt = now();
1807
+ inFlightSince = startedAt;
1808
+ probe(() => {
1809
+ if (inFlightSince === startedAt) inFlightSince = null;
1810
+ });
1811
+ };
1812
+ const timer = setInterval(tick, intervalMs);
1813
+ timer.unref?.();
1814
+ return {
1815
+ stop() {
1816
+ stopped = true;
1817
+ clearInterval(timer);
1818
+ },
1819
+ tick
1820
+ };
1821
+ }
1822
+ function writeStderrLineSync(line) {
1823
+ try {
1824
+ fs6.writeSync(2, `${line}
1825
+ `);
1826
+ } catch {
1827
+ }
1828
+ }
1829
+
1780
1830
  // src/index.ts
1781
1831
  var SESSION_HOST_APP_NAME = process.env.ADHDEV_SESSION_HOST_NAME || "adhdev";
1832
+ var SHUTDOWN_DEADLINE_MS = 1e4;
1782
1833
  var INSTANCE_CONFIG_DIR = resolveInstanceConfigDir2(process.env);
1783
1834
  var INSTANCE_IPC_KEY = resolveSessionHostIpcKey(INSTANCE_CONFIG_DIR);
1784
1835
  function getSessionHostEndpoint() {
@@ -1789,15 +1840,15 @@ function getSessionHostStorageRoot() {
1789
1840
  }
1790
1841
  function getSessionHostPidFile(appName) {
1791
1842
  const dir = INSTANCE_CONFIG_DIR;
1792
- if (!fs6.existsSync(dir)) fs6.mkdirSync(dir, { recursive: true });
1843
+ if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
1793
1844
  return path6.join(dir, `${appName}-session-host.pid`);
1794
1845
  }
1795
1846
  function writeSessionHostPid(appName) {
1796
- fs6.writeFileSync(getSessionHostPidFile(appName), String(process.pid), "utf8");
1847
+ fs7.writeFileSync(getSessionHostPidFile(appName), String(process.pid), "utf8");
1797
1848
  }
1798
1849
  function removeSessionHostPid(appName) {
1799
1850
  try {
1800
- fs6.unlinkSync(getSessionHostPidFile(appName));
1851
+ fs7.unlinkSync(getSessionHostPidFile(appName));
1801
1852
  } catch {
1802
1853
  }
1803
1854
  }
@@ -1819,10 +1870,10 @@ async function runServer() {
1819
1870
  let upgradeBinding;
1820
1871
  const pinFile = process.env.ADHDEV_WORKER_GUARDIAN_PINS_FILE;
1821
1872
  if (pinFile) {
1822
- const stat = fs6.lstatSync(pinFile);
1823
- if (process.platform !== "darwin" || fs6.realpathSync(pinFile) !== pinFile || !stat.isFile() || stat.uid !== process.getuid?.() || stat.mode & 63) throw new Error("guardian_launch_pins_untrusted");
1824
- const pins = JSON.parse(fs6.readFileSync(pinFile, "utf8"));
1825
- if (pins.nodePath !== fs6.realpathSync(process.execPath) || pins.hostEntryPath !== fs6.realpathSync(process.argv[1]) || pins.stateDir !== path6.join(INSTANCE_CONFIG_DIR, "session-host")) throw new Error("guardian_launch_executable_or_instance_mismatch");
1873
+ const stat2 = fs7.lstatSync(pinFile);
1874
+ if (process.platform !== "darwin" || fs7.realpathSync(pinFile) !== pinFile || !stat2.isFile() || stat2.uid !== process.getuid?.() || stat2.mode & 63) throw new Error("guardian_launch_pins_untrusted");
1875
+ const pins = JSON.parse(fs7.readFileSync(pinFile, "utf8"));
1876
+ if (pins.nodePath !== fs7.realpathSync(process.execPath) || pins.hostEntryPath !== fs7.realpathSync(process.argv[1]) || pins.stateDir !== path6.join(INSTANCE_CONFIG_DIR, "session-host")) throw new Error("guardian_launch_executable_or_instance_mismatch");
1826
1877
  upgradeBinding = resolveGuardianArtifact(pins);
1827
1878
  }
1828
1879
  const server = new SessionHostServer({
@@ -1834,15 +1885,31 @@ async function runServer() {
1834
1885
  if (!upgradeBinding) writeSessionHostPid(SESSION_HOST_APP_NAME);
1835
1886
  await server.start();
1836
1887
  if (upgradeBinding) writeSessionHostPid(SESSION_HOST_APP_NAME);
1837
- process.on("SIGINT", async () => {
1838
- await server.stop();
1839
- removeSessionHostPid(SESSION_HOST_APP_NAME);
1840
- process.exit(0);
1841
- });
1842
- process.on("SIGTERM", async () => {
1888
+ const shutdown = async () => {
1889
+ const deadline = setTimeout(() => {
1890
+ writeStderrLineSync(`[session-host] stop() did not finish within ${SHUTDOWN_DEADLINE_MS / 1e3}s; exiting anyway.`);
1891
+ removeSessionHostPid(SESSION_HOST_APP_NAME);
1892
+ process.exit(1);
1893
+ }, SHUTDOWN_DEADLINE_MS);
1894
+ deadline.unref?.();
1843
1895
  await server.stop();
1844
1896
  removeSessionHostPid(SESSION_HOST_APP_NAME);
1845
1897
  process.exit(0);
1898
+ };
1899
+ process.on("SIGINT", shutdown);
1900
+ process.on("SIGTERM", shutdown);
1901
+ startThreadpoolWatchdog({
1902
+ onStall: (stalledForMs) => {
1903
+ writeStderrLineSync(
1904
+ `[session-host] libuv thread pool made no progress for ${Math.round(stalledForMs / 1e3)}s (PTY writes cannot complete); exiting so the daemon respawns the host.`
1905
+ );
1906
+ try {
1907
+ server.flushAllPersistence();
1908
+ } catch {
1909
+ }
1910
+ removeSessionHostPid(SESSION_HOST_APP_NAME);
1911
+ process.exit(1);
1912
+ }
1846
1913
  });
1847
1914
  process.on("exit", () => {
1848
1915
  server.flushAllPersistence();
@@ -2184,6 +2251,7 @@ ${err?.stack || ""}`);
2184
2251
  export {
2185
2252
  SessionHostServer,
2186
2253
  createUncaughtExceptionLimiter,
2187
- resolveGuardianArtifact
2254
+ resolveGuardianArtifact,
2255
+ startThreadpoolWatchdog
2188
2256
  };
2189
2257
  //# sourceMappingURL=index.mjs.map