@openape/nest 1.1.1 → 1.1.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 (2) hide show
  1. package/dist/index.mjs +59 -9
  2. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -264,6 +264,21 @@ module.exports = {
264
264
  }
265
265
  `;
266
266
  }
267
+ function startScriptPath(agentName) {
268
+ return join3(AGENTS_DIR, agentName, "start.sh");
269
+ }
270
+ function startScriptContents(agentName) {
271
+ const ecosystem = ecosystemPath(agentName);
272
+ const log2 = `/var/log/openape/${agentName}-pm2.log`;
273
+ return `#!/bin/bash
274
+ # Auto-generated by Pm2Supervisor for agent '${agentName}'.
275
+ set -e
276
+ export HOME="/Users/${agentName}"
277
+ export PM2_HOME="$HOME/.pm2"
278
+ mkdir -p "$(dirname "${log2}")"
279
+ exec pm2 startOrReload ${ecosystem} >> ${log2} 2>&1 < /dev/null
280
+ `;
281
+ }
267
282
  var Pm2Supervisor = class {
268
283
  constructor(deps) {
269
284
  this.deps = deps;
@@ -278,7 +293,7 @@ var Pm2Supervisor = class {
278
293
  try {
279
294
  await this.startOrReload(agent.name);
280
295
  } catch (err) {
281
- this.deps.log(`pm2-supervisor: ${agent.name} startOrReload failed: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`);
296
+ this.deps.log(`pm2-supervisor: ${agent.name} reconcile errored: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`);
282
297
  } finally {
283
298
  this.inflight.delete(agent.name);
284
299
  }
@@ -305,17 +320,52 @@ var Pm2Supervisor = class {
305
320
  mkdirSync3(dir, { recursive: true, mode: 493 });
306
321
  const path = ecosystemPath(agentName);
307
322
  writeFileSync3(path, ecosystemContents(this.deps.apesBin, agentName), { mode: 420 });
308
- await this.runAsAgent(agentName, ["pm2", "startOrReload", path]);
309
- this.deps.log(`pm2-supervisor: ${agentName} bridge (re)started via pm2`);
323
+ const startPath = startScriptPath(agentName);
324
+ writeFileSync3(startPath, startScriptContents(agentName), { mode: 493 });
325
+ void path;
326
+ try {
327
+ await this.runAsAgent(agentName, ["bash", startPath]);
328
+ } catch {
329
+ }
330
+ let online = false;
331
+ try {
332
+ const { stdout } = await this.runAsAgent(agentName, ["pm2", "jlist"]);
333
+ const json = stdout.match(/\[\s*\{.*\}\s*\]/s)?.[0];
334
+ if (json) {
335
+ const list = JSON.parse(json);
336
+ online = list.some((p) => p.name === pm2AppName(agentName) && p.pm2_env?.status === "online");
337
+ }
338
+ } catch {
339
+ }
340
+ if (online) {
341
+ this.deps.log(`pm2-supervisor: ${agentName} bridge online (pm2)`);
342
+ } else {
343
+ this.deps.log(`pm2-supervisor: ${agentName} bridge NOT online \u2014 see /var/log/openape/${agentName}-pm2.log`);
344
+ }
310
345
  }
311
346
  /** Run a pm2 subcommand AS the agent — escapes-helper does the
312
- * setuid switch, then exec's pm2 in the agent's uid. */
347
+ * setuid switch, then exec's pm2 in the agent's uid.
348
+ *
349
+ * cwd: the agent process inherits cwd from the spawning Nest
350
+ * daemon, whose cwd is /var/openape/nest (mode 750, no access for
351
+ * other uids). Without setting cwd to a world-readable dir, the
352
+ * child's first `process.cwd()` call (which Node does internally
353
+ * during module loading) throws EACCES. /tmp is the most portable
354
+ * always-writable location.
355
+ */
313
356
  async runAsAgent(agentName, args) {
314
- return execFileAsync2(
315
- this.deps.apesBin,
316
- ["run", "--as", agentName, "--wait", "--", ...args],
317
- { maxBuffer: 1024 * 1024, env: process.env, timeout: 6e4 }
318
- );
357
+ try {
358
+ return await execFileAsync2(
359
+ this.deps.apesBin,
360
+ ["run", "--as", agentName, "--wait", "--", ...args],
361
+ { maxBuffer: 1024 * 1024, env: process.env, timeout: 6e4, cwd: "/tmp" }
362
+ );
363
+ } catch (err) {
364
+ const e = err;
365
+ const detail = (e.stderr ?? "").trim().split("\n").slice(-3).join(" / ");
366
+ const stdoutDetail = (e.stdout ?? "").trim().split("\n").slice(-2).join(" / ");
367
+ throw new Error(`${e.message?.split("\n")[0] ?? "execFile failed"} | stderr: ${detail || "<empty>"} | stdout: ${stdoutDetail || "<empty>"}`);
368
+ }
319
369
  }
320
370
  };
321
371
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openape/nest",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "OpenApe Nest — local control-plane daemon that supervises agent processes on this computer. Talks to troop SP for ownership state, spawns/destroys agents via DDISA always-grants, supervises chat-bridge children (replacing per-agent launchd plists).",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -17,8 +17,8 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "ofetch": "^1.4.1",
20
- "@openape/core": "0.16.0",
21
- "@openape/cli-auth": "0.4.0"
20
+ "@openape/cli-auth": "0.4.0",
21
+ "@openape/core": "0.16.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@antfu/eslint-config": "^7.6.1",