@wrongstack/tools 0.296.4 → 0.297.0

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 (46) hide show
  1. package/dist/audit.js +15 -0
  2. package/dist/audit.js.map +2 -2
  3. package/dist/bash.js +15 -0
  4. package/dist/bash.js.map +2 -2
  5. package/dist/builtin.js +42 -0
  6. package/dist/builtin.js.map +2 -2
  7. package/dist/codebase-index/index.js +27 -0
  8. package/dist/codebase-index/index.js.map +2 -2
  9. package/dist/codebase-index/project-server-client.d.ts.map +1 -1
  10. package/dist/codebase-index/project-server.js +16 -0
  11. package/dist/codebase-index/project-server.js.map +2 -2
  12. package/dist/exec.js +15 -0
  13. package/dist/exec.js.map +2 -2
  14. package/dist/format.js +15 -0
  15. package/dist/format.js.map +2 -2
  16. package/dist/index.js +42 -0
  17. package/dist/index.js.map +2 -2
  18. package/dist/install.js +15 -0
  19. package/dist/install.js.map +2 -2
  20. package/dist/languages/index.js +15 -0
  21. package/dist/languages/index.js.map +2 -2
  22. package/dist/lint.js +15 -0
  23. package/dist/lint.js.map +2 -2
  24. package/dist/next-steps.d.ts +23 -0
  25. package/dist/next-steps.d.ts.map +1 -1
  26. package/dist/next-steps.js +4 -0
  27. package/dist/next-steps.js.map +2 -2
  28. package/dist/outdated.js +15 -0
  29. package/dist/outdated.js.map +2 -2
  30. package/dist/pack.js +42 -0
  31. package/dist/pack.js.map +2 -2
  32. package/dist/process-registry.d.ts +9 -0
  33. package/dist/process-registry.d.ts.map +1 -1
  34. package/dist/process-registry.js +15 -0
  35. package/dist/process-registry.js.map +2 -2
  36. package/dist/ps-slash.js +15 -0
  37. package/dist/ps-slash.js.map +2 -2
  38. package/dist/read.js +27 -0
  39. package/dist/read.js.map +2 -2
  40. package/dist/test.js +15 -0
  41. package/dist/test.js.map +2 -2
  42. package/dist/tool-tier.js +42 -0
  43. package/dist/tool-tier.js.map +2 -2
  44. package/dist/typecheck.js +15 -0
  45. package/dist/typecheck.js.map +2 -2
  46. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -549,6 +549,7 @@ var init_process_registry = __esm({
549
549
  }
550
550
  /** Get all tracked processes. */
551
551
  list() {
552
+ this._pruneAllStale();
552
553
  return Array.from(this.processes.values());
553
554
  }
554
555
  /** Get processes filtered by name (e.g. 'bash', 'exec'). */
@@ -579,6 +580,7 @@ var init_process_registry = __esm({
579
580
  * Combined stats for observability — used by /ps and the TUI status bar.
580
581
  */
581
582
  stats() {
583
+ this._pruneAllStale();
582
584
  return {
583
585
  activeCount: this.activeCount,
584
586
  backgroundCount: this.activeBackgroundCount,
@@ -818,6 +820,19 @@ var init_process_registry = __esm({
818
820
  this.processes.delete(pid);
819
821
  }
820
822
  }
823
+ /**
824
+ * Remove every stale entry, not just one PID. `list()`/`stats()` — the
825
+ * surfaces the TUI status bar and `/ps` poll — must prune too: a child
826
+ * whose 'close' event never fires (e.g. Windows grandchildren holding stdio
827
+ * open) would otherwise linger in the registry until someone looks up its
828
+ * exact PID, and PID reuse meanwhile makes `get()`/`kill()` target the
829
+ * wrong process. RAM-leak audit 2026-07-31, MEDIUM.
830
+ */
831
+ _pruneAllStale() {
832
+ for (const [pid, entry] of this.processes) {
833
+ if (this._isStaleEntry(entry)) this.processes.delete(pid);
834
+ }
835
+ }
821
836
  };
822
837
  }
823
838
  });
@@ -12198,6 +12213,10 @@ var ProjectServerConnection = class {
12198
12213
  isConnected() {
12199
12214
  return this.socket !== null && !this.socket.destroyed && this.info !== null;
12200
12215
  }
12216
+ /** Safe LRU candidate: no request, connect, or health probe is in flight. */
12217
+ isEvictable() {
12218
+ return this.pending.size === 0 && this.connecting === null && this.healthCheck === null;
12219
+ }
12201
12220
  async checkHealth(spawnIfMissing = false, timeoutMs = SERVER_HEALTH_TIMEOUT_MS) {
12202
12221
  await this.ensureConnected(spawnIfMissing);
12203
12222
  if (this.healthCheck) return this.healthCheck;
@@ -12596,7 +12615,26 @@ var ProjectServerConnection = class {
12596
12615
  }
12597
12616
  };
12598
12617
  var connections = /* @__PURE__ */ new Map();
12618
+ var MAX_CACHED_CONNECTIONS = 8;
12599
12619
  var heartbeatTimer;
12620
+ function forgetConnection(endpoint, connection) {
12621
+ if (connections.get(endpoint) === connection) connections.delete(endpoint);
12622
+ connection.close();
12623
+ connectionStates.delete(endpoint);
12624
+ if (latestConnectionState.endpoint !== endpoint) return;
12625
+ latestConnectionState = [...connectionStates.values()].at(-1) ?? {
12626
+ status: isProjectIndexServerAvailable() ? "offline" : "unavailable",
12627
+ connected: false
12628
+ };
12629
+ }
12630
+ function trimConnectionCache(protectedConnection) {
12631
+ if (connections.size <= MAX_CACHED_CONNECTIONS) return;
12632
+ for (const [endpoint, connection] of connections) {
12633
+ if (connections.size <= MAX_CACHED_CONNECTIONS) break;
12634
+ if (connection === protectedConnection || !connection.isEvictable()) continue;
12635
+ forgetConnection(endpoint, connection);
12636
+ }
12637
+ }
12600
12638
  function ensureHeartbeatLoop() {
12601
12639
  if (heartbeatTimer) return;
12602
12640
  heartbeatTimer = setInterval(() => {
@@ -12619,7 +12657,11 @@ function connectionFor(projectRoot, indexDir) {
12619
12657
  if (!connection) {
12620
12658
  connection = new ProjectServerConnection(projectRoot, indexDir, endpoint);
12621
12659
  connections.set(endpoint, connection);
12660
+ } else {
12661
+ connections.delete(endpoint);
12662
+ connections.set(endpoint, connection);
12622
12663
  }
12664
+ trimConnectionCache(connection);
12623
12665
  return connection;
12624
12666
  }
12625
12667
  function callProjectIndexServer(op, args, options) {