@botbuddy/cli 1.40.2 → 1.40.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbuddy/cli",
3
- "version": "1.40.2",
3
+ "version": "1.40.3",
4
4
  "description": "BotBuddy — Swarm coordination CLI for multi-agent workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -107,6 +107,20 @@ async function processStartedAt(pid) {
107
107
  }
108
108
  }
109
109
 
110
+ // The real process-instance probe behind the ownership fence. Tests inject a
111
+ // deterministic one instead of spawning `ps` (BOT-2031).
112
+ const systemProcessProbe = Object.freeze({
113
+ async isAlive(pid) {
114
+ try { process.kill(pid, 0); }
115
+ catch (error) {
116
+ if (error?.code === "ESRCH") return false;
117
+ return true; // EPERM is deliberately conservative.
118
+ }
119
+ return true;
120
+ },
121
+ startedAt: processStartedAt,
122
+ });
123
+
110
124
  function installFenceExitHook() {
111
125
  if (installedFenceExitHook) return;
112
126
  installedFenceExitHook = true;
@@ -120,7 +134,11 @@ function installFenceExitHook() {
120
134
  });
121
135
  }
122
136
 
123
- export function createWaitCheckpointStore({ root = process.cwd(), now = () => new Date() } = {}) {
137
+ export function createWaitCheckpointStore({
138
+ root = process.cwd(),
139
+ now = () => new Date(),
140
+ processProbe = systemProcessProbe,
141
+ } = {}) {
124
142
  const worktree = resolve(root);
125
143
  const directory = join(worktree, ".botbuddy", "waits");
126
144
  const pathFor = (id) => {
@@ -184,12 +202,8 @@ export function createWaitCheckpointStore({ root = process.cwd(), now = () => ne
184
202
  return lock;
185
203
  };
186
204
  const lockIsLive = async (lock) => {
187
- try { process.kill(lock.pid, 0); }
188
- catch (error) {
189
- if (error?.code === "ESRCH") return false;
190
- return true; // EPERM is deliberately conservative.
191
- }
192
- const startedAt = await processStartedAt(lock.pid);
205
+ if (!await processProbe.isAlive(lock.pid)) return false;
206
+ const startedAt = await processProbe.startedAt(lock.pid);
193
207
  // A live PID without a matching process-instance identity is never ownership proof.
194
208
  return startedAt != null && startedAt === lock.process_started_at;
195
209
  };
@@ -310,7 +324,7 @@ export function createWaitCheckpointStore({ root = process.cwd(), now = () => ne
310
324
  const localWaitId = safeId(id);
311
325
  await ensureDirectory();
312
326
  const path = lockPathFor(localWaitId);
313
- const processStartedAtValue = await processStartedAt(process.pid);
327
+ const processStartedAtValue = await processProbe.startedAt(process.pid);
314
328
  if (!processStartedAtValue) {
315
329
  throw new WaitCheckpointError("wait_owner_unknown", "could not establish this process identity for wait recovery");
316
330
  }