aicodeman 1.12.0 → 1.12.2

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.
Files changed (85) hide show
  1. package/dist/proc-tree.d.ts +50 -0
  2. package/dist/proc-tree.d.ts.map +1 -0
  3. package/dist/proc-tree.js +68 -0
  4. package/dist/proc-tree.js.map +1 -0
  5. package/dist/session.d.ts +18 -3
  6. package/dist/session.d.ts.map +1 -1
  7. package/dist/session.js +25 -5
  8. package/dist/session.js.map +1 -1
  9. package/dist/tmux-manager.d.ts +37 -1
  10. package/dist/tmux-manager.d.ts.map +1 -1
  11. package/dist/tmux-manager.js +113 -32
  12. package/dist/tmux-manager.js.map +1 -1
  13. package/dist/utils/claude-cli-resolver.d.ts +40 -1
  14. package/dist/utils/claude-cli-resolver.d.ts.map +1 -1
  15. package/dist/utils/claude-cli-resolver.js +74 -27
  16. package/dist/utils/claude-cli-resolver.js.map +1 -1
  17. package/dist/web/public/admin-ui.js.gz +0 -0
  18. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  19. package/dist/web/public/{app.8998c1b3.js → app.2e9ffd31.js} +4 -4
  20. package/dist/web/public/app.2e9ffd31.js.br +0 -0
  21. package/dist/web/public/app.2e9ffd31.js.gz +0 -0
  22. package/dist/web/public/constants.e7175b95.js.gz +0 -0
  23. package/dist/web/public/cron-ui.js.gz +0 -0
  24. package/dist/web/public/entrance-animations.js.gz +0 -0
  25. package/dist/web/public/i18n.0fbea500.js.gz +0 -0
  26. package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
  27. package/dist/web/public/index.html +5 -5
  28. package/dist/web/public/index.html.br +0 -0
  29. package/dist/web/public/index.html.gz +0 -0
  30. package/dist/web/public/input-cjk.63794d0b.js.gz +0 -0
  31. package/dist/web/public/keyboard-accessory.9936227d.js.gz +0 -0
  32. package/dist/web/public/{mobile-handlers.bc2b8c1d.js → mobile-handlers.32fdd57f.js} +62 -37
  33. package/dist/web/public/mobile-handlers.32fdd57f.js.br +0 -0
  34. package/dist/web/public/mobile-handlers.32fdd57f.js.gz +0 -0
  35. package/dist/web/public/mobile-overview.js.gz +0 -0
  36. package/dist/web/public/mobile.32cacde5.css.gz +0 -0
  37. package/dist/web/public/notification-manager.5d229063.js.gz +0 -0
  38. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  39. package/dist/web/public/panels-ui.1d4203e0.js.gz +0 -0
  40. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  41. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  42. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  43. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  44. package/dist/web/public/session-ui.1356a4f4.js.gz +0 -0
  45. package/dist/web/public/settings-ui.01a1ae7d.js.gz +0 -0
  46. package/dist/web/public/styles.50cd52bd.css.gz +0 -0
  47. package/dist/web/public/subagent-windows.4cc8b005.js.gz +0 -0
  48. package/dist/web/public/sw.js.gz +0 -0
  49. package/dist/web/public/terminal-ui.78c71f3a.js +4 -0
  50. package/dist/web/public/terminal-ui.78c71f3a.js.br +0 -0
  51. package/dist/web/public/terminal-ui.78c71f3a.js.gz +0 -0
  52. package/dist/web/public/ultracode-panel.js.gz +0 -0
  53. package/dist/web/public/ultracode-windows.js.gz +0 -0
  54. package/dist/web/public/upload.html.gz +0 -0
  55. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  56. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  57. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  58. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  59. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  60. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  61. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  62. package/dist/web/public/vendor/xterm.css.gz +0 -0
  63. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  64. package/dist/web/public/voice-input.085e9e73.js.gz +0 -0
  65. package/dist/web/public/webview-tabs.js.gz +0 -0
  66. package/dist/web/routes/file-routes.d.ts.map +1 -1
  67. package/dist/web/routes/file-routes.js +20 -0
  68. package/dist/web/routes/file-routes.js.map +1 -1
  69. package/dist/web/routes/session-routes.d.ts.map +1 -1
  70. package/dist/web/routes/session-routes.js +26 -9
  71. package/dist/web/routes/session-routes.js.map +1 -1
  72. package/dist/web/routes/ws-routes.d.ts.map +1 -1
  73. package/dist/web/routes/ws-routes.js +9 -2
  74. package/dist/web/routes/ws-routes.js.map +1 -1
  75. package/dist/web/server.d.ts.map +1 -1
  76. package/dist/web/server.js +18 -0
  77. package/dist/web/server.js.map +1 -1
  78. package/package.json +1 -1
  79. package/dist/web/public/app.8998c1b3.js.br +0 -0
  80. package/dist/web/public/app.8998c1b3.js.gz +0 -0
  81. package/dist/web/public/mobile-handlers.bc2b8c1d.js.br +0 -0
  82. package/dist/web/public/mobile-handlers.bc2b8c1d.js.gz +0 -0
  83. package/dist/web/public/terminal-ui.a7da43e6.js +0 -3
  84. package/dist/web/public/terminal-ui.a7da43e6.js.br +0 -0
  85. package/dist/web/public/terminal-ui.a7da43e6.js.gz +0 -0
@@ -348,7 +348,43 @@ export declare class TmuxManager extends EventEmitter implements TerminalMultipl
348
348
  */
349
349
  respawnPane(options: RespawnPaneOptions): Promise<number | null>;
350
350
  private sessionExists;
351
- private getChildPids;
351
+ /** One `ps` snapshot of the whole process table, cached briefly. */
352
+ private static procSnapshot;
353
+ /** Single-flight guard so a hung `ps` cannot pile up parallel refreshes. */
354
+ private static procRefresh;
355
+ /**
356
+ * Fork ONE `ps` asynchronously and cache the parent -> children map.
357
+ *
358
+ * Async on purpose: a synchronous fork here would block the event loop on every
359
+ * stats tick, and under the procfs pathology this module exists to survive,
360
+ * `execSync`'s timeout cannot return at all (spawnSync waits for the unkillable
361
+ * child) — freezing the whole server where a hung async poll only costs staleness.
362
+ */
363
+ private static refreshProcSnapshot;
364
+ /**
365
+ * Best snapshot WITHOUT forking: returns the cache, kicking off a background
366
+ * refresh when it has gone stale, and never blocks. Stats and window-title
367
+ * consumers tolerate data one interval old; nothing that KILLS may use this.
368
+ */
369
+ private childrenByParent;
370
+ /**
371
+ * Descendants from a snapshot that is not the cached one — the kill path's variant.
372
+ *
373
+ * killSession re-scans for survivors between SIGTERM and SIGKILL, and the wait in
374
+ * between (200ms) sits far inside the cache TTL (2000ms): reading the cache there
375
+ * returns the pre-SIGTERM state verbatim, so children spawned since are invisible
376
+ * and SIGKILL aims at stale PIDs, guarded only by kill(pid, 0) — which cannot
377
+ * detect PID reuse.
378
+ *
379
+ * It forces a refresh rather than guaranteeing recency: an already-running refresh
380
+ * is reused, so the snapshot can predate this call by up to one `ps` runtime. A
381
+ * strict postdate guarantee would mean chaining a second `ps` behind every
382
+ * in-flight one, which is the fork storm this code exists to avoid.
383
+ *
384
+ * Bounded by design: waiting forever would freeze killSession before it reaches
385
+ * its process-group and tmux fallbacks.
386
+ */
387
+ private getChildPidsFresh;
352
388
  private isProcessAlive;
353
389
  private verifyProcessesDead;
354
390
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tmux-manager.d.ts","sourceRoot":"","sources":["../src/tmux-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tmux-manager.d.ts","sourceRoot":"","sources":["../src/tmux-manager.ts"],"names":[],"mappings":"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"}
@@ -21,7 +21,8 @@
21
21
  * @module tmux-manager
22
22
  */
23
23
  import { EventEmitter } from 'node:events';
24
- import { execSync, exec } from 'node:child_process';
24
+ import { collectDescendants } from './proc-tree.js';
25
+ import { execSync, exec, execFile } from 'node:child_process';
25
26
  import { promisify } from 'node:util';
26
27
  const execAsync = promisify(exec);
27
28
  import { existsSync, readFileSync, mkdirSync } from 'node:fs';
@@ -39,6 +40,14 @@ import { decideReconnect, advanceBackoff, freshReconnectState, resetReconnectSta
39
40
  // Timing Constants
40
41
  // ============================================================================
41
42
  import { EXEC_TIMEOUT_MS } from './config/exec-timeout.js';
43
+ /** How long a cached process snapshot stays usable. */
44
+ const PROC_SNAPSHOT_TTL_MS = 2000;
45
+ /**
46
+ * How long the kill path waits for a fresh snapshot before giving up on it.
47
+ * Shorter than EXEC_TIMEOUT_MS on purpose: killSession has two further strategies
48
+ * (process group, tmux kill-session) and must reach them even when `ps` is wedged.
49
+ */
50
+ const PROC_SNAPSHOT_WAIT_MS = 1500;
42
51
  import { DEFAULT_TMUX_HISTORY_LIMIT, DEFAULT_TERMINAL_BUFFER_MAX_BYTES } from './config/terminal-history.js';
43
52
  /**
44
53
  * Extra stdout headroom for the full-history `capture-pane` child process on
@@ -1817,28 +1826,102 @@ export class TmuxManager extends EventEmitter {
1817
1826
  return false;
1818
1827
  }
1819
1828
  }
1820
- // Get all child process PIDs recursively
1821
- getChildPids(pid) {
1822
- const pids = [];
1823
- try {
1824
- const output = execSync(`pgrep -P ${pid}`, {
1825
- encoding: 'utf-8',
1826
- timeout: EXEC_TIMEOUT_MS,
1827
- }).trim();
1828
- if (output) {
1829
- for (const childPid of output
1830
- .split('\n')
1831
- .map((p) => parseInt(p, 10))
1832
- .filter((p) => !Number.isNaN(p))) {
1833
- pids.push(childPid);
1834
- pids.push(...this.getChildPids(childPid));
1829
+ /** One `ps` snapshot of the whole process table, cached briefly. */
1830
+ static procSnapshot = null;
1831
+ /** Single-flight guard so a hung `ps` cannot pile up parallel refreshes. */
1832
+ static procRefresh = null;
1833
+ /**
1834
+ * Fork ONE `ps` asynchronously and cache the parent -> children map.
1835
+ *
1836
+ * Async on purpose: a synchronous fork here would block the event loop on every
1837
+ * stats tick, and under the procfs pathology this module exists to survive,
1838
+ * `execSync`'s timeout cannot return at all (spawnSync waits for the unkillable
1839
+ * child) — freezing the whole server where a hung async poll only costs staleness.
1840
+ */
1841
+ static refreshProcSnapshot() {
1842
+ const inFlight = TmuxManager.procRefresh;
1843
+ // Reuse an in-flight refresh — unless it is old enough to be presumed stuck.
1844
+ if (inFlight && Date.now() - inFlight.started < EXEC_TIMEOUT_MS * 2)
1845
+ return inFlight.promise;
1846
+ const started = Date.now();
1847
+ const promise = new Promise((resolve) => {
1848
+ execFile('ps', ['-eo', 'pid=,ppid='], { timeout: EXEC_TIMEOUT_MS, maxBuffer: 8 * 1024 * 1024 }, (err, out) => {
1849
+ if (TmuxManager.procRefresh?.started === started)
1850
+ TmuxManager.procRefresh = null;
1851
+ if (err) {
1852
+ // ANY error, not just an empty one: a timed-out or truncated `ps` yields
1853
+ // partial output, and caching that as fresh would make whole subtrees
1854
+ // invisible — including to the kill path. Stale beats wrong.
1855
+ console.error('[TmuxManager] process snapshot failed:', err);
1856
+ resolve(TmuxManager.procSnapshot?.byParent ?? new Map());
1857
+ return;
1835
1858
  }
1836
- }
1859
+ const byParent = new Map();
1860
+ for (const line of String(out).split('\n')) {
1861
+ const parts = line.trim().split(/\s+/);
1862
+ if (parts.length < 2)
1863
+ continue;
1864
+ const pid = parseInt(parts[0], 10);
1865
+ const ppid = parseInt(parts[1], 10);
1866
+ if (Number.isNaN(pid) || Number.isNaN(ppid))
1867
+ continue;
1868
+ const list = byParent.get(ppid);
1869
+ if (list)
1870
+ list.push(pid);
1871
+ else
1872
+ byParent.set(ppid, [pid]);
1873
+ }
1874
+ TmuxManager.procSnapshot = { at: Date.now(), byParent };
1875
+ resolve(byParent);
1876
+ });
1877
+ });
1878
+ TmuxManager.procRefresh = { started, promise };
1879
+ return promise;
1880
+ }
1881
+ /**
1882
+ * Best snapshot WITHOUT forking: returns the cache, kicking off a background
1883
+ * refresh when it has gone stale, and never blocks. Stats and window-title
1884
+ * consumers tolerate data one interval old; nothing that KILLS may use this.
1885
+ */
1886
+ childrenByParent() {
1887
+ const cached = TmuxManager.procSnapshot;
1888
+ if (!cached || Date.now() - cached.at >= PROC_SNAPSHOT_TTL_MS) {
1889
+ void TmuxManager.refreshProcSnapshot();
1890
+ }
1891
+ return cached?.byParent ?? new Map();
1892
+ }
1893
+ /**
1894
+ * Descendants from a snapshot that is not the cached one — the kill path's variant.
1895
+ *
1896
+ * killSession re-scans for survivors between SIGTERM and SIGKILL, and the wait in
1897
+ * between (200ms) sits far inside the cache TTL (2000ms): reading the cache there
1898
+ * returns the pre-SIGTERM state verbatim, so children spawned since are invisible
1899
+ * and SIGKILL aims at stale PIDs, guarded only by kill(pid, 0) — which cannot
1900
+ * detect PID reuse.
1901
+ *
1902
+ * It forces a refresh rather than guaranteeing recency: an already-running refresh
1903
+ * is reused, so the snapshot can predate this call by up to one `ps` runtime. A
1904
+ * strict postdate guarantee would mean chaining a second `ps` behind every
1905
+ * in-flight one, which is the fork storm this code exists to avoid.
1906
+ *
1907
+ * Bounded by design: waiting forever would freeze killSession before it reaches
1908
+ * its process-group and tmux fallbacks.
1909
+ */
1910
+ async getChildPidsFresh(pid) {
1911
+ let byParent;
1912
+ try {
1913
+ byParent = await Promise.race([
1914
+ TmuxManager.refreshProcSnapshot(),
1915
+ new Promise((_, reject) => setTimeout(() => reject(new Error('proc snapshot timeout')), PROC_SNAPSHOT_WAIT_MS)),
1916
+ ]);
1837
1917
  }
1838
1918
  catch {
1839
- // No children or command failed
1919
+ console.warn('[TmuxManager] process snapshot did not return in time; using the cached one');
1920
+ byParent = TmuxManager.procSnapshot?.byParent ?? new Map();
1840
1921
  }
1841
- return pids;
1922
+ return collectDescendants(pid, byParent, {
1923
+ onTruncated: (root, cap, reason) => console.warn(`[TmuxManager] descendant walk for ${root} hit the ${cap}-${reason} cap; truncating`),
1924
+ });
1842
1925
  }
1843
1926
  // Check if a process is still alive
1844
1927
  isProcessAlive(pid) {
@@ -1934,7 +2017,7 @@ export class TmuxManager extends EventEmitter {
1934
2017
  console.log(`[TmuxManager] Killing session ${session.muxName} (PID ${currentPid})`);
1935
2018
  const allPids = [currentPid];
1936
2019
  // Strategy 1: Kill all child processes recursively
1937
- let childPids = this.getChildPids(currentPid);
2020
+ let childPids = await this.getChildPidsFresh(currentPid);
1938
2021
  if (childPids.length > 0) {
1939
2022
  console.log(`[TmuxManager] Found ${childPids.length} child processes to kill`);
1940
2023
  allPids.push(...childPids);
@@ -1949,7 +2032,7 @@ export class TmuxManager extends EventEmitter {
1949
2032
  }
1950
2033
  }
1951
2034
  await new Promise((resolve) => setTimeout(resolve, TMUX_KILL_WAIT_MS));
1952
- childPids = this.getChildPids(currentPid);
2035
+ childPids = await this.getChildPidsFresh(currentPid);
1953
2036
  for (const childPid of childPids) {
1954
2037
  if (this.isProcessAlive(childPid)) {
1955
2038
  try {
@@ -2148,16 +2231,14 @@ export class TmuxManager extends EventEmitter {
2148
2231
  timeout: EXEC_TIMEOUT_MS,
2149
2232
  })).stdout.trim();
2150
2233
  const [rss, cpu] = psOutput.split(/\s+/).map((x) => parseFloat(x) || 0);
2234
+ // From the shared snapshot: this runs per session on every stats tick, and a
2235
+ // pgrep per session was a fork per session per interval.
2151
2236
  let childCount = 0;
2152
2237
  try {
2153
- const childOutput = (await execAsync(`pgrep -P ${session.pid} | wc -l`, {
2154
- encoding: 'utf-8',
2155
- timeout: EXEC_TIMEOUT_MS,
2156
- })).stdout.trim();
2157
- childCount = parseInt(childOutput, 10) || 0;
2238
+ childCount = (this.childrenByParent().get(session.pid) ?? []).length;
2158
2239
  }
2159
2240
  catch {
2160
- // No children or command failed
2241
+ // No children or snapshot unavailable
2161
2242
  }
2162
2243
  return {
2163
2244
  memoryMB: Math.round((rss / 1024) * 10) / 10,
@@ -2186,11 +2267,11 @@ export class TmuxManager extends EventEmitter {
2186
2267
  try {
2187
2268
  // Step 1: Get descendant PIDs
2188
2269
  const descendantMap = new Map();
2189
- const pgrepOutput = (await execAsync(`for p in ${sessionPids.join(' ')}; do children=$(pgrep -P $p 2>/dev/null | tr '\\n' ','); echo "$p:$children"; done`, {
2190
- encoding: 'utf-8',
2191
- timeout: EXEC_TIMEOUT_MS,
2192
- })).stdout.trim();
2193
- for (const line of pgrepOutput.split('\n')) {
2270
+ // Derived from the ONE snapshot instead of a shell loop that forks a pgrep
2271
+ // per session — the shape that turned into a fork storm under load.
2272
+ const byParent = this.childrenByParent();
2273
+ const childLines = sessionPids.map((p) => `${p}:${(byParent.get(p) ?? []).join(',')}`).join('\n');
2274
+ for (const line of childLines.split('\n')) {
2194
2275
  const [pidStr, childrenStr] = line.split(':');
2195
2276
  const sessionPid = parseInt(pidStr, 10);
2196
2277
  if (!Number.isNaN(sessionPid)) {