@bitsocial/bitsocial-cli 0.19.71 → 0.19.72

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/README.md CHANGED
@@ -421,7 +421,7 @@ EXAMPLES
421
421
  $ bitsocial challenge install ./my-local-challenge
422
422
  ```
423
423
 
424
- _See code: [src/cli/commands/challenge/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/challenge/install.ts)_
424
+ _See code: [src/cli/commands/challenge/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/challenge/install.ts)_
425
425
 
426
426
  ## `bitsocial challenge list`
427
427
 
@@ -447,7 +447,7 @@ EXAMPLES
447
447
  $ bitsocial challenge list -q
448
448
  ```
449
449
 
450
- _See code: [src/cli/commands/challenge/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/challenge/list.ts)_
450
+ _See code: [src/cli/commands/challenge/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/challenge/list.ts)_
451
451
 
452
452
  ## `bitsocial challenge ls`
453
453
 
@@ -501,7 +501,7 @@ EXAMPLES
501
501
  $ bitsocial challenge remove @scope/my-challenge
502
502
  ```
503
503
 
504
- _See code: [src/cli/commands/challenge/remove.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/challenge/remove.ts)_
504
+ _See code: [src/cli/commands/challenge/remove.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/challenge/remove.ts)_
505
505
 
506
506
  ## `bitsocial challenge rm NAME`
507
507
 
@@ -615,7 +615,7 @@ EXAMPLES
615
615
  $ bitsocial community create --jsonFile ./create-options.json
616
616
  ```
617
617
 
618
- _See code: [src/cli/commands/community/create.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/community/create.ts)_
618
+ _See code: [src/cli/commands/community/create.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/community/create.ts)_
619
619
 
620
620
  ## `bitsocial community delete ADDRESSES`
621
621
 
@@ -640,7 +640,7 @@ EXAMPLES
640
640
  $ bitsocial community delete 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu
641
641
  ```
642
642
 
643
- _See code: [src/cli/commands/community/delete.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/community/delete.ts)_
643
+ _See code: [src/cli/commands/community/delete.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/community/delete.ts)_
644
644
 
645
645
  ## `bitsocial community edit ADDRESS`
646
646
 
@@ -710,7 +710,7 @@ EXAMPLES
710
710
  $ bitsocial community edit bitsocial.bso --jsonFile ./edit-options.json
711
711
  ```
712
712
 
713
- _See code: [src/cli/commands/community/edit.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/community/edit.ts)_
713
+ _See code: [src/cli/commands/community/edit.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/community/edit.ts)_
714
714
 
715
715
  ## `bitsocial community export [ADDRESS]`
716
716
 
@@ -751,7 +751,7 @@ EXAMPLES
751
751
  $ bitsocial community export --publicKey 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu
752
752
  ```
753
753
 
754
- _See code: [src/cli/commands/community/export.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/community/export.ts)_
754
+ _See code: [src/cli/commands/community/export.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/community/export.ts)_
755
755
 
756
756
  ## `bitsocial community get [ADDRESS]`
757
757
 
@@ -782,7 +782,7 @@ EXAMPLES
782
782
  $ bitsocial community get --publicKey 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu
783
783
  ```
784
784
 
785
- _See code: [src/cli/commands/community/get.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/community/get.ts)_
785
+ _See code: [src/cli/commands/community/get.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/community/get.ts)_
786
786
 
787
787
  ## `bitsocial community list`
788
788
 
@@ -805,7 +805,7 @@ EXAMPLES
805
805
  $ bitsocial community list
806
806
  ```
807
807
 
808
- _See code: [src/cli/commands/community/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/community/list.ts)_
808
+ _See code: [src/cli/commands/community/list.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/community/list.ts)_
809
809
 
810
810
  ## `bitsocial community start ADDRESSES`
811
811
 
@@ -839,7 +839,7 @@ EXAMPLES
839
839
  $ bitsocial community start $(bitsocial community list -q) --concurrency 1
840
840
  ```
841
841
 
842
- _See code: [src/cli/commands/community/start.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/community/start.ts)_
842
+ _See code: [src/cli/commands/community/start.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/community/start.ts)_
843
843
 
844
844
  ## `bitsocial community stop ADDRESSES`
845
845
 
@@ -864,7 +864,7 @@ EXAMPLES
864
864
  $ bitsocial community stop Qmb99crTbSUfKXamXwZBe829Vf6w5w5TktPkb6WstC9RFW
865
865
  ```
866
866
 
867
- _See code: [src/cli/commands/community/stop.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/community/stop.ts)_
867
+ _See code: [src/cli/commands/community/stop.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/community/stop.ts)_
868
868
 
869
869
  ## `bitsocial daemon`
870
870
 
@@ -911,7 +911,7 @@ EXAMPLES
911
911
  $ bitsocial daemon --no-allowPrivateKeyExport
912
912
  ```
913
913
 
914
- _See code: [src/cli/commands/daemon.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/daemon.ts)_
914
+ _See code: [src/cli/commands/daemon.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/daemon.ts)_
915
915
 
916
916
  ## `bitsocial help [COMMAND]`
917
917
 
@@ -977,7 +977,7 @@ EXAMPLES
977
977
  $ bitsocial logs --stdout -f
978
978
  ```
979
979
 
980
- _See code: [src/cli/commands/logs.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/logs.ts)_
980
+ _See code: [src/cli/commands/logs.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/logs.ts)_
981
981
 
982
982
  ## `bitsocial update check`
983
983
 
@@ -994,7 +994,7 @@ EXAMPLES
994
994
  $ bitsocial update check
995
995
  ```
996
996
 
997
- _See code: [src/cli/commands/update/check.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/update/check.ts)_
997
+ _See code: [src/cli/commands/update/check.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/update/check.ts)_
998
998
 
999
999
  ## `bitsocial update install [VERSION]`
1000
1000
 
@@ -1026,7 +1026,7 @@ EXAMPLES
1026
1026
  $ bitsocial update install --no-restart-daemons
1027
1027
  ```
1028
1028
 
1029
- _See code: [src/cli/commands/update/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/update/install.ts)_
1029
+ _See code: [src/cli/commands/update/install.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/update/install.ts)_
1030
1030
 
1031
1031
  ## `bitsocial update versions`
1032
1032
 
@@ -1048,7 +1048,7 @@ EXAMPLES
1048
1048
  $ bitsocial update versions --limit 5
1049
1049
  ```
1050
1050
 
1051
- _See code: [src/cli/commands/update/versions.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.71/src/cli/commands/update/versions.ts)_
1051
+ _See code: [src/cli/commands/update/versions.ts](https://github.com/bitsocialnet/bitsocial-cli/blob/v0.19.72/src/cli/commands/update/versions.ts)_
1052
1052
  <!-- commandsstop -->
1053
1053
 
1054
1054
  ## Contribution
@@ -37,18 +37,37 @@ export interface DaemonState {
37
37
  export declare function parseSystemdUnitFromCgroup(content: string): string | undefined;
38
38
  /** Read the systemd unit owning `pid` (or the current process when "self") from /proc, or undefined. */
39
39
  export declare function readSystemdUnit(pid: number | "self"): Promise<string | undefined>;
40
+ /**
41
+ * MainPID of a systemd unit as reported by the system manager, or undefined when it cannot be
42
+ * determined (systemctl missing, unit unknown, MainPID=0). `systemctl --user` units are invisible
43
+ * to the system manager and resolve to undefined — the daemon is then treated as unsupervised,
44
+ * matching the restart path, which also only drives the system manager.
45
+ */
46
+ export declare function readUnitMainPid(unit: string): Promise<number | undefined>;
47
+ /** Parent PID of `pid` from /proc/<pid>/stat, or undefined. */
48
+ export declare function readParentPid(pid: number): Promise<number | undefined>;
40
49
  /**
41
50
  * Detect whether THIS process was started by systemd, and under which unit. systemd sets
42
- * $INVOCATION_ID for every service it spawns; the unit name comes from this process's own cgroup.
43
- * `env`/`readUnit` are injectable for testing. Returns undefined when not systemd-supervised.
51
+ * $INVOCATION_ID for every service it spawns and the unit name comes from this process's own
52
+ * cgroup — but BOTH are inherited by every descendant of any service (e.g. all processes inside a
53
+ * CI runner's agent service, issue #92), so unit membership alone is not ownership. The daemon is
54
+ * only systemd-supervised when it is the unit's main process (or its direct child, covering
55
+ * `ExecStart=/bin/sh -c …` wrappers); otherwise restarting the unit would bounce an unrelated
56
+ * service. `env`/`readUnit`/`getMainPid`/`self` are injectable for testing. Returns undefined when
57
+ * not systemd-supervised.
44
58
  */
45
- export declare function detectSelfSupervisor(env?: NodeJS.ProcessEnv, readUnit?: (pid: number | "self") => Promise<string | undefined>): Promise<DaemonSupervisor | undefined>;
59
+ export declare function detectSelfSupervisor(env?: NodeJS.ProcessEnv, readUnit?: (pid: number | "self") => Promise<string | undefined>, getMainPid?: (unit: string) => Promise<number | undefined>, self?: {
60
+ pid: number;
61
+ ppid: number;
62
+ }): Promise<DaemonSupervisor | undefined>;
46
63
  /**
47
64
  * Resolve the supervisor for a daemon described by `state`. Prefers the `supervisor` it recorded
48
- * at startup; for legacy daemons that predate that field, falls back to inferring the unit from the
49
- * live process's cgroup. `readUnit` is injectable for testing.
65
+ * at startup (already ownership-verified by detectSelfSupervisor); for legacy daemons that predate
66
+ * that field, falls back to inferring the unit from the live process's cgroup, with the same
67
+ * MainPID ownership check as detectSelfSupervisor (issue #92).
68
+ * `readUnit`/`getMainPid`/`getParentPid` are injectable for testing.
50
69
  */
51
- export declare function resolveDaemonSupervisor(state: DaemonState, readUnit?: (pid: number | "self") => Promise<string | undefined>): Promise<DaemonSupervisor | undefined>;
70
+ export declare function resolveDaemonSupervisor(state: DaemonState, readUnit?: (pid: number | "self") => Promise<string | undefined>, getMainPid?: (unit: string) => Promise<number | undefined>, getParentPid?: (pid: number) => Promise<number | undefined>): Promise<DaemonSupervisor | undefined>;
52
71
  /** Write a daemon state file atomically (write to .tmp then rename). */
53
72
  export declare function writeDaemonState(state: DaemonState): Promise<void>;
54
73
  /** Read all state files from the daemon states directory. */
@@ -42,27 +42,76 @@ export async function readSystemdUnit(pid) {
42
42
  return undefined; // no /proc (non-Linux) or unreadable — treat as unsupervised
43
43
  }
44
44
  }
45
+ /**
46
+ * MainPID of a systemd unit as reported by the system manager, or undefined when it cannot be
47
+ * determined (systemctl missing, unit unknown, MainPID=0). `systemctl --user` units are invisible
48
+ * to the system manager and resolve to undefined — the daemon is then treated as unsupervised,
49
+ * matching the restart path, which also only drives the system manager.
50
+ */
51
+ export async function readUnitMainPid(unit) {
52
+ try {
53
+ const { stdout } = await execFileAsync("systemctl", ["show", "--property=MainPID", "--value", unit]);
54
+ const mainPid = Number(String(stdout).trim());
55
+ return Number.isInteger(mainPid) && mainPid > 0 ? mainPid : undefined;
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
60
+ }
61
+ /** Parent PID of `pid` from /proc/<pid>/stat, or undefined. */
62
+ export async function readParentPid(pid) {
63
+ try {
64
+ const stat = await fs.readFile(`/proc/${pid}/stat`, "utf-8");
65
+ // Format: `pid (comm) state ppid …` — comm may itself contain spaces or parens, so the
66
+ // fields are only parseable after the LAST closing paren.
67
+ const afterComm = stat.slice(stat.lastIndexOf(")") + 2);
68
+ const ppid = Number(afterComm.split(" ")[1]);
69
+ return Number.isInteger(ppid) && ppid > 0 ? ppid : undefined;
70
+ }
71
+ catch {
72
+ return undefined;
73
+ }
74
+ }
45
75
  /**
46
76
  * Detect whether THIS process was started by systemd, and under which unit. systemd sets
47
- * $INVOCATION_ID for every service it spawns; the unit name comes from this process's own cgroup.
48
- * `env`/`readUnit` are injectable for testing. Returns undefined when not systemd-supervised.
77
+ * $INVOCATION_ID for every service it spawns and the unit name comes from this process's own
78
+ * cgroup — but BOTH are inherited by every descendant of any service (e.g. all processes inside a
79
+ * CI runner's agent service, issue #92), so unit membership alone is not ownership. The daemon is
80
+ * only systemd-supervised when it is the unit's main process (or its direct child, covering
81
+ * `ExecStart=/bin/sh -c …` wrappers); otherwise restarting the unit would bounce an unrelated
82
+ * service. `env`/`readUnit`/`getMainPid`/`self` are injectable for testing. Returns undefined when
83
+ * not systemd-supervised.
49
84
  */
50
- export async function detectSelfSupervisor(env = process.env, readUnit = readSystemdUnit) {
85
+ export async function detectSelfSupervisor(env = process.env, readUnit = readSystemdUnit, getMainPid = readUnitMainPid, self = { pid: process.pid, ppid: process.ppid }) {
51
86
  if (!env.INVOCATION_ID)
52
87
  return undefined;
53
88
  const unit = await readUnit("self");
54
- return unit ? { type: "systemd", unit } : undefined;
89
+ if (!unit)
90
+ return undefined;
91
+ const mainPid = await getMainPid(unit);
92
+ if (mainPid === undefined || (mainPid !== self.pid && mainPid !== self.ppid))
93
+ return undefined;
94
+ return { type: "systemd", unit };
55
95
  }
56
96
  /**
57
97
  * Resolve the supervisor for a daemon described by `state`. Prefers the `supervisor` it recorded
58
- * at startup; for legacy daemons that predate that field, falls back to inferring the unit from the
59
- * live process's cgroup. `readUnit` is injectable for testing.
98
+ * at startup (already ownership-verified by detectSelfSupervisor); for legacy daemons that predate
99
+ * that field, falls back to inferring the unit from the live process's cgroup, with the same
100
+ * MainPID ownership check as detectSelfSupervisor (issue #92).
101
+ * `readUnit`/`getMainPid`/`getParentPid` are injectable for testing.
60
102
  */
61
- export async function resolveDaemonSupervisor(state, readUnit = readSystemdUnit) {
103
+ export async function resolveDaemonSupervisor(state, readUnit = readSystemdUnit, getMainPid = readUnitMainPid, getParentPid = readParentPid) {
62
104
  if (state.supervisor)
63
105
  return state.supervisor;
64
106
  const unit = await readUnit(state.pid);
65
- return unit ? { type: "systemd", unit } : undefined;
107
+ if (!unit)
108
+ return undefined;
109
+ const mainPid = await getMainPid(unit);
110
+ if (mainPid === undefined)
111
+ return undefined;
112
+ if (mainPid !== state.pid && mainPid !== (await getParentPid(state.pid)))
113
+ return undefined;
114
+ return { type: "systemd", unit };
66
115
  }
67
116
  function stateFilePath(pid) {
68
117
  return path.join(DAEMON_STATES_DIR, `${pid}-daemon.state`);
@@ -871,5 +871,5 @@
871
871
  ]
872
872
  }
873
873
  },
874
- "version": "0.19.71"
874
+ "version": "0.19.72"
875
875
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitsocial/bitsocial-cli",
3
- "version": "0.19.71",
3
+ "version": "0.19.72",
4
4
  "description": "Command line interface to Bitsocial API",
5
5
  "types": "./dist/index.d.ts",
6
6
  "homepage": "https://github.com/bitsocialnet/bitsocial-cli",
@@ -119,7 +119,7 @@
119
119
  "@oclif/plugin-help": "6.2.36",
120
120
  "@oclif/plugin-not-found": "3.2.73",
121
121
  "@oclif/table": "0.5.1",
122
- "@pkcprotocol/pkc-js": "0.0.45",
122
+ "@pkcprotocol/pkc-js": "0.0.47",
123
123
  "dataobject-parser": "1.2.22",
124
124
  "decompress": "4.2.1",
125
125
  "env-paths": "2.2.1",