@songsid/agend 2.1.1-beta.7 → 2.1.1-beta.8

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.
@@ -1,3 +1,4 @@
1
+ import { execFileSync } from "node:child_process";
1
2
  /**
2
3
  * Keep systemd's notification socket private to the fleet process. The socket
3
4
  * path is a capability: any child that inherits it can send READY/WATCHDOG/
@@ -9,4 +10,10 @@
9
10
  */
10
11
  export declare function consumeNotifySocket(environment: NodeJS.ProcessEnv): string | undefined;
11
12
  export declare function buildNotifyEnvironment(environment: NodeJS.ProcessEnv, socket: string): NodeJS.ProcessEnv;
13
+ /** Only the process recorded as the fleet owner may exercise the capability. */
14
+ export declare function isFleetOwner(dataDir?: string, pid?: number): boolean;
15
+ type NotifyExecutor = (file: string, args: readonly string[], options: Parameters<typeof execFileSync>[2]) => unknown;
16
+ /** Exported for a focused test of the exact helper environment. */
17
+ export declare function sendSystemdNotification(state: string, socket: string, environment: NodeJS.ProcessEnv, execute?: NotifyExecutor): void;
12
18
  export declare function sdNotify(state: string): void;
19
+ export {};
package/dist/sd-notify.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import { execFileSync } from "node:child_process";
2
+ import { readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { getAgendHome } from "./paths.js";
2
5
  /**
3
6
  * Keep systemd's notification socket private to the fleet process. The socket
4
7
  * path is a capability: any child that inherits it can send READY/WATCHDOG/
@@ -10,23 +13,36 @@ import { execFileSync } from "node:child_process";
10
13
  */
11
14
  export function consumeNotifySocket(environment) {
12
15
  const socket = environment.NOTIFY_SOCKET;
13
- if (socket)
14
- delete environment.NOTIFY_SOCKET;
16
+ delete environment.NOTIFY_SOCKET;
15
17
  return socket || undefined;
16
18
  }
17
19
  export function buildNotifyEnvironment(environment, socket) {
18
20
  return { ...environment, NOTIFY_SOCKET: socket };
19
21
  }
20
22
  const notifySocket = consumeNotifySocket(process.env);
23
+ /** Only the process recorded as the fleet owner may exercise the capability. */
24
+ export function isFleetOwner(dataDir = getAgendHome(), pid = process.pid) {
25
+ try {
26
+ const fleetPid = Number.parseInt(readFileSync(join(dataDir, "fleet.pid"), "utf8").trim(), 10);
27
+ return Number.isSafeInteger(fleetPid) && fleetPid === pid;
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ /** Exported for a focused test of the exact helper environment. */
34
+ export function sendSystemdNotification(state, socket, environment, execute = execFileSync) {
35
+ execute("systemd-notify", [state], {
36
+ env: buildNotifyEnvironment(environment, socket),
37
+ stdio: "ignore",
38
+ timeout: 5000,
39
+ });
40
+ }
21
41
  export function sdNotify(state) {
22
- if (!notifySocket)
42
+ if (!notifySocket || !isFleetOwner())
23
43
  return;
24
44
  try {
25
- execFileSync("systemd-notify", [state], {
26
- env: buildNotifyEnvironment(process.env, notifySocket),
27
- stdio: "ignore",
28
- timeout: 5000,
29
- });
45
+ sendSystemdNotification(state, notifySocket, process.env);
30
46
  }
31
47
  catch { /* best effort */ }
32
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sd-notify.js","sourceRoot":"","sources":["../src/sd-notify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAA8B;IAChE,MAAM,MAAM,GAAG,WAAW,CAAC,aAAa,CAAC;IACzC,IAAI,MAAM;QAAE,OAAO,WAAW,CAAC,aAAa,CAAC;IAC7C,OAAO,MAAM,IAAI,SAAS,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,WAA8B,EAC9B,MAAc;IAEd,OAAO,EAAE,GAAG,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,YAAY,GAAG,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAEtD,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,IAAI,CAAC,YAAY;QAAE,OAAO;IAC1B,IAAI,CAAC;QACH,YAAY,CAAC,gBAAgB,EAAE,CAAC,KAAK,CAAC,EAAE;YACtC,GAAG,EAAE,sBAAsB,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC;YACtD,KAAK,EAAE,QAAQ;YACf,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;AAC/B,CAAC"}
1
+ {"version":3,"file":"sd-notify.js","sourceRoot":"","sources":["../src/sd-notify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAA8B;IAChE,MAAM,MAAM,GAAG,WAAW,CAAC,aAAa,CAAC;IACzC,OAAO,WAAW,CAAC,aAAa,CAAC;IACjC,OAAO,MAAM,IAAI,SAAS,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,WAA8B,EAC9B,MAAc;IAEd,OAAO,EAAE,GAAG,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,YAAY,GAAG,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAEtD,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAC1B,OAAO,GAAG,YAAY,EAAE,EACxB,GAAG,GAAG,OAAO,CAAC,GAAG;IAEjB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAC9B,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,EACvD,EAAE,CACH,CAAC;QACF,OAAO,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,GAAG,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAQD,mEAAmE;AACnE,MAAM,UAAU,uBAAuB,CACrC,KAAa,EACb,MAAc,EACd,WAA8B,EAC9B,UAA0B,YAAY;IAEtC,OAAO,CAAC,gBAAgB,EAAE,CAAC,KAAK,CAAC,EAAE;QACjC,GAAG,EAAE,sBAAsB,CAAC,WAAW,EAAE,MAAM,CAAC;QAChD,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,EAAE;QAAE,OAAO;IAC7C,IAAI,CAAC;QACH,uBAAuB,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;AAC/B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@songsid/agend",
3
- "version": "2.1.1-beta.7",
3
+ "version": "2.1.1-beta.8",
4
4
  "description": "Multi-agent fleet daemon — run any coding CLI (Claude, Gemini, Codex, OpenCode) from Telegram",
5
5
  "type": "module",
6
6
  "bin": {
@@ -4,8 +4,12 @@ After=network.target
4
4
 
5
5
  [Service]
6
6
  Type=notify
7
- # Node delegates AF_UNIX datagram sends to systemd-notify, so the helper must
8
- # be accepted. src/sd-notify.ts keeps NOTIFY_SOCKET out of all other children.
7
+ # NotifyAccess must stay "all": sdNotify() delivers via a short-lived
8
+ # systemd-notify child, so "main"/"exec" reject it with
9
+ # "Got notification message from PID <helper>, but reception only permitted
10
+ # for main PID <service>" (Result=protocol), breaking READY/WATCHDOG.
11
+ # The capability is instead contained in src/sd-notify.ts, which removes
12
+ # NOTIFY_SOCKET from the environment so no other child process inherits it.
9
13
  NotifyAccess=all
10
14
  TimeoutStartSec=0
11
15
  WatchdogSec=60