@parcha/pi-durable-disk 0.1.0-beta.19 → 0.1.0-beta.21

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/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.0-beta.21 (2026-10-21)
6
+
7
+ - `supervise --no-restart` is in the usage text and the reference: it turns off the local driver's restart on failure (`localHost({ restart: false })`), so an instance that exits stays down until the supervisor's next pass.
8
+
9
+ ## 0.1.0-beta.20 (2026-10-20)
10
+
11
+ - A start mark keeper whose rewrite fails because the run's directory moved after its check now warns that the directory is no longer the one it started on, and stops. Before, the `PDA_START_MARK` warning said the rewrite failed (ENOENT or ENOTDIR). Nothing is written in either case; only the stated reason changes.
12
+ - The local-disk env conformance cases watch with a 100 ms poll, so pi's fixed 3 s wait for a report keeps seconds of slack on a loaded runner; the product's 1 s watch default is unchanged.
13
+
5
14
  ## 0.1.0-beta.19 (2026-10-20)
6
15
 
7
16
  - An instance whose app released the run ends by itself: `pi-durable-disk run --app` exits 0 once `onOpen` has returned and the run is released, so the unit does not stay up with no mount.
package/dist/claim.d.ts CHANGED
@@ -234,6 +234,11 @@ export declare function writtenSince(dir: string, since: number, limit?: number)
234
234
  fresh: string[];
235
235
  unchecked: string | null;
236
236
  }>;
237
+ /**
238
+ * The token an instance holds when it was given none (`--token-stdin` read nothing): enough to reuse its live mount, never
239
+ * to mount. A restart in place gets it from a driver that hands the token to the first incarnation only (localHost).
240
+ */
241
+ export declare const NO_TOKEN = "none";
237
242
  /**
238
243
  * Take the run's claim: mount `<disk>:/runs/<id>` exclusively at `<mountRoot>/runs/<id>` and verify it. A live mount of
239
244
  * the same run already there is kept (in-place restart); a dead one is cleaned first. With no mount there, a stale archil
@@ -242,11 +247,6 @@ export declare function writtenSince(dir: string, since: number, limit?: number)
242
247
  * verifying write is refused, MOUNTPOINT_NOT_EMPTY when the mountpoint cannot be emptied or archil still finds it not
243
248
  * empty, MOUNT_FAILED (exit 1) for a daemon of this host that is still running there.
244
249
  */
245
- /**
246
- * The token an instance holds when it was given none (`--token-stdin` read nothing): enough to reuse its live mount, never
247
- * to mount. A restart in place gets it from a driver that hands the token to the first incarnation only (localHost).
248
- */
249
- export declare const NO_TOKEN = "none";
250
250
  export declare function acquire(opts: AcquireOptions): Promise<Claim>;
251
251
  /** One exclusive mount of a path, as `withClaim` holds it: its own mountpoint, never reused. */
252
252
  export interface ExclusiveMount {
package/dist/claim.js CHANGED
@@ -7,7 +7,7 @@ import { lstat, mkdir, open, readdir, readFile, rmdir, stat } from "node:fs/prom
7
7
  import { basename, isAbsolute, join } from "node:path";
8
8
  import { setTimeout as sleep } from "node:timers/promises";
9
9
  import { fileURLToPath } from "node:url";
10
- import { ClaimError, FencedError, HeldError, ownWriteFenced } from "./errors.js";
10
+ import { ClaimError, EXIT_DATAERR, FencedError, HeldError, ownWriteFenced } from "./errors.js";
11
11
  export const DEFAULT_MOUNT_ROOT = "/mnt/archil";
12
12
  /** This package's `bin/archil-scoped`. A deployment installs a root-owned copy and passes its path as `archil`. */
13
13
  export const ARCHIL_SCOPED = fileURLToPath(new URL("../bin/archil-scoped", import.meta.url));
@@ -620,7 +620,7 @@ export async function writtenSince(dir, since, limit = STRAY_CHECK_LIMIT) {
620
620
  return { fresh, unchecked: null };
621
621
  }
622
622
  /** The exit of a start refused for the app's own writes before its claim (EX_DATAERR): a restart would write them again. */
623
- const EXIT_WRITTEN_BEFORE_MOUNT = 65;
623
+ const EXIT_WRITTEN_BEFORE_MOUNT = EXIT_DATAERR;
624
624
  /** How many entries a directory holds; 0 when it cannot be read. */
625
625
  const entries = (dir) => readdir(dir).then((names) => names.length, () => 0);
626
626
  /**
@@ -701,6 +701,11 @@ async function verifyTarget(host, path, mountpoint, probe) {
701
701
  throw ownWriteFenced(join(mountpoint, CLAIM_PROBE), err);
702
702
  }
703
703
  }
704
+ /**
705
+ * The token an instance holds when it was given none (`--token-stdin` read nothing): enough to reuse its live mount, never
706
+ * to mount. A restart in place gets it from a driver that hands the token to the first incarnation only (localHost).
707
+ */
708
+ export const NO_TOKEN = "none";
704
709
  /**
705
710
  * Take the run's claim: mount `<disk>:/runs/<id>` exclusively at `<mountRoot>/runs/<id>` and verify it. A live mount of
706
711
  * the same run already there is kept (in-place restart); a dead one is cleaned first. With no mount there, a stale archil
@@ -709,11 +714,6 @@ async function verifyTarget(host, path, mountpoint, probe) {
709
714
  * verifying write is refused, MOUNTPOINT_NOT_EMPTY when the mountpoint cannot be emptied or archil still finds it not
710
715
  * empty, MOUNT_FAILED (exit 1) for a daemon of this host that is still running there.
711
716
  */
712
- /**
713
- * The token an instance holds when it was given none (`--token-stdin` read nothing): enough to reuse its live mount, never
714
- * to mount. A restart in place gets it from a driver that hands the token to the first incarnation only (localHost).
715
- */
716
- export const NO_TOKEN = "none";
717
717
  export async function acquire(opts) {
718
718
  const { ref, token } = opts;
719
719
  const path = runPath(ref.id);
package/dist/cli.d.ts CHANGED
@@ -3,7 +3,6 @@ import { type Parking } from "./park.js";
3
3
  import { type RunServer } from "./serve.js";
4
4
  import { type ArchilControl, type DiskClient } from "./supervise.js";
5
5
  import { type DurableRun } from "./run.js";
6
- /** "30s", "500ms", "2m", "1h", or plain milliseconds. */
7
6
  /**
8
7
  * Whether the lease watchdog may kill every other process in the instance's cgroup: only inside its own systemd unit,
9
8
  * whose cgroup holds nothing but the instance and its commands. Elsewhere the cgroup may be shared (a login session, an
@@ -21,6 +20,7 @@ export declare function watchdogOwnsCgroup(holder: Record<string, unknown>, opti
21
20
  owns: boolean;
22
21
  warning?: string;
23
22
  };
23
+ /** "30s", "500ms", "2m", "1h", or plain milliseconds. */
24
24
  export declare function parseDuration(text: string): number;
25
25
  /** `--run-as NAME|UID[:GID]`: the user the agent's commands run as, with its group and home from /etc/passwd when listed. */
26
26
  export declare function runUser(spec: string, passwd?: string): {
package/dist/cli.js CHANGED
@@ -42,7 +42,7 @@ const USAGE = `usage:
42
42
  [--user U] [--group G] [--app MODULE] [--run-arg ARG ...] [--lease-expiry 90s] [--stonith-timeout 30s]
43
43
  [--start-grace 90s] [--start-backoff-max 10m] [--stop-timeout 30s] [--token-ttl 24h] [--token-prefix P] [--demand] [--create] [--env K=V ...] [--log-dir DIR]
44
44
  [--archil BIN] [--control-timeout 10s] [--sweep-tokens] [--token-grace 15m]
45
- [--park-threshold 60s] [--api-key-env NAME]
45
+ [--park-threshold 60s] [--no-restart] [--api-key-env NAME]
46
46
  with --host docker: --image IMAGE [--app-root DIR] [--fleet F] [--name-prefix P] [--run-as USER]
47
47
  [--docker-arg ARG ...] [--apparmor auto|PROFILE|none] [--docker BIN]
48
48
  pi-durable-disk supervise --check --disk D --region R [--mount-root DIR] [--user U] [--group G] [--check-id-prefix P]
@@ -51,7 +51,6 @@ const USAGE = `usage:
51
51
  pi-durable-disk release --id ID [--mount-root DIR]
52
52
  pi-durable-disk fork --disk D --region R --id ID --new-id NEW [--mount-root DIR] [--archil BIN] [--token-prefix P]
53
53
  [--api-key-env NAME]`;
54
- /** "30s", "500ms", "2m", "1h", or plain milliseconds. */
55
54
  /**
56
55
  * Whether the lease watchdog may kill every other process in the instance's cgroup: only inside its own systemd unit,
57
56
  * whose cgroup holds nothing but the instance and its commands. Elsewhere the cgroup may be shared (a login session, an
@@ -90,6 +89,7 @@ export function watchdogOwnsCgroup(holder, options = {}) {
90
89
  return refuse(`the parent shares cgroup ${own}, so this process only inherited the handle`);
91
90
  return { owns: true };
92
91
  }
92
+ /** "30s", "500ms", "2m", "1h", or plain milliseconds. */
93
93
  export function parseDuration(text) {
94
94
  const m = /^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(text.trim());
95
95
  if (!m)
@@ -219,7 +219,9 @@ async function runInstance(values) {
219
219
  throw new UsageError(`--serve-host ${serveHost} is not loopback: name a --serve-token-file`);
220
220
  const serveToken = tokenFile === undefined ? undefined : readServeToken(tokenFile);
221
221
  const mountRoot = str(values["mount-root"], DEFAULT_MOUNT_ROOT);
222
- const root = dir ?? join(mountRoot, runPath(ref.id));
222
+ // On a disk the id names the run's directory: an unsafe one stops the instance here (INVALID_ARGUMENT), before it serves.
223
+ if (dir === undefined)
224
+ runPath(ref.id);
223
225
  const log = (event, extra = {}) => process.stderr.write(`${JSON.stringify({ at: new Date().toISOString(), event, run: ref.id, ...extra })}\n`);
224
226
  // The app's factory runs once the claim is held (`afterClaim`), so `ctx.root` is the live directory whenever app code
225
227
  // runs; what it returns opens the Harness. Serve starts before the open, with the root options the factory fills in.
package/dist/errors.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /** EX_DATAERR: the run's data refuses to open (a store behind its seal, an unreadable `run.json`); a restart cannot help. */
2
+ export declare const EXIT_DATAERR = 65;
3
+ /** EX_SOFTWARE: this package cannot read the head of pi's store (pi's schema moved); a restart cannot help. */
4
+ export declare const EXIT_SOFTWARE = 70;
1
5
  /** EX_TEMPFAIL: the claim was revoked or its mount failed; nothing this process writes can become durable. */
2
6
  export declare const EXIT_FENCED = 75;
3
7
  /**
package/dist/errors.js CHANGED
@@ -2,6 +2,10 @@
2
2
  // another); both are terminal for the host's process supervisor, which must not restart into a run it lost.
3
3
  // A module's own errors extend FencedError or HeldError (overriding `code`) so one `instanceof` or `exitCodeFor` covers
4
4
  // them all, e.g. `class StoreFencedError extends FencedError` with `{ code: "STORE_FENCED" }`.
5
+ /** EX_DATAERR: the run's data refuses to open (a store behind its seal, an unreadable `run.json`); a restart cannot help. */
6
+ export const EXIT_DATAERR = 65;
7
+ /** EX_SOFTWARE: this package cannot read the head of pi's store (pi's schema moved); a restart cannot help. */
8
+ export const EXIT_SOFTWARE = 70;
5
9
  /** EX_TEMPFAIL: the claim was revoked or its mount failed; nothing this process writes can become durable. */
6
10
  export const EXIT_FENCED = 75;
7
11
  /**
@@ -182,7 +182,6 @@ export function sandboxName(prefix, runId, now) {
182
182
  const stamp = `${now.toString(36)}${Math.floor(Math.random() * 1296).toString(36).padStart(2, "0")}`;
183
183
  return `${prefix}${slug}-${stamp}`.slice(0, 63);
184
184
  }
185
- /** The last line of a command's output that parses as JSON, or null. */
186
185
  /**
187
186
  * What the launcher printed, for a start it gave no reason for: the last 4 KB, or that it printed nothing. It prints only
188
187
  * its state; the mount token is in a root-only file it reads, never in its output.
@@ -191,6 +190,7 @@ function launcherOutput(text) {
191
190
  const out = text.trim();
192
191
  return out ? `the launcher printed: ${out.slice(-4096)}` : "the launcher printed nothing and exited 0";
193
192
  }
193
+ /** The last line of a command's output that parses as JSON, or null. */
194
194
  function lastJson(text) {
195
195
  for (const line of text.trim().split("\n").reverse()) {
196
196
  try {
@@ -17,7 +17,7 @@ import { hostname } from "node:os";
17
17
  import { extname, join } from "node:path";
18
18
  import { fileURLToPath } from "node:url";
19
19
  import { ARCHIL_SCOPED, DEAD_CONNECTION, DEFAULT_MOUNT_ROOT, runPath } from "../claim.js";
20
- import { EXIT_FENCED, EXIT_HELD, PdaError } from "../errors.js";
20
+ import { EXIT_DATAERR, EXIT_FENCED, EXIT_HELD, EXIT_SOFTWARE, PdaError } from "../errors.js";
21
21
  import { LOCAL_PARK_THRESHOLD_MS } from "../park.js";
22
22
  import { processTable, thisBoot } from "../process-table.js";
23
23
  import { attemptEnv } from "./attempt-env.js";
@@ -44,10 +44,6 @@ const FUSERMOUNT = "/usr/bin/fusermount";
44
44
  const UMOUNT = "/usr/bin/umount";
45
45
  /** How long a stat of the mountpoint may take before its daemon counts as alive but stuck (never removed). */
46
46
  const STAT_TIMEOUT_MS = 3_000;
47
- /** EX_DATAERR: a store behind its seal or a bad run.json (run.ts names it EXIT_DATAERR). */
48
- const EXIT_DATAERR = 65;
49
- /** EX_SOFTWARE: the store's head is unreadable (pi's schema moved); run.json says failed, STORE_HEAD_UNREADABLE. */
50
- const EXIT_SOFTWARE = 70;
51
47
  /** Exits a restart cannot fix: 65 data error, 70 store head unreadable, 75 fenced, 76 held. */
52
48
  export const TERMINAL_EXITS = [EXIT_DATAERR, EXIT_SOFTWARE, EXIT_FENCED, EXIT_HELD];
53
49
  // The package's own CLI, with the extension this module has: `.ts` from a checkout, `.js` once built.
package/dist/place.d.ts CHANGED
@@ -43,7 +43,6 @@ export type RunnerOrder = {
43
43
  env: Record<string, string>;
44
44
  stdin?: string;
45
45
  };
46
- /** What the place reads of the run, the way it reads it: `run.json`, and on a disk the run's delegations. */
47
46
  /**
48
47
  * What the place reads of the run, the way it reads it: `run.json`; on a disk, the run's delegations; and the boxes the
49
48
  * place made for its runners, each as a receipt (`HostBox`: provider, kind, from, to, list price per second and where
package/dist/run.d.ts CHANGED
@@ -3,17 +3,14 @@ import { Harness } from "@earendil-works/pi-durable";
3
3
  import type { HarnessOptions, Seq, Storage, ToolRegistration } from "@earendil-works/pi-durable";
4
4
  import type { SqliteDatabase, SqliteExecutor } from "@earendil-works/pi-durable/storage/sqlite";
5
5
  import { type AcquireOptions, type ArchilHost, type Claim, type RunRef } from "./claim.js";
6
- import { FencedError, PdaError } from "./errors.js";
6
+ import { EXIT_DATAERR, EXIT_SOFTWARE, FencedError, PdaError } from "./errors.js";
7
7
  import { type ArchilStore, type Profile } from "./store.js";
8
8
  import { type ClaimDir, type PersistRecord, type RunRecord, type RunStatus } from "./status.js";
9
9
  /** The same-host owner lock under the run's root. */
10
10
  export declare const OWNER_LOCK = "owner.lock";
11
11
  /** pi's store under the claim's `store/` directory. */
12
12
  export declare const STORE_FILE = "run.sqlite";
13
- /** EX_DATAERR: the run's data refuses to open (a store behind its seal, an unreadable `run.json`); a restart cannot help. */
14
- export declare const EXIT_DATAERR = 65;
15
- /** EX_SOFTWARE: this package cannot read the head of pi's store (pi's schema moved); a restart cannot help. */
16
- export declare const EXIT_SOFTWARE = 70;
13
+ export { EXIT_DATAERR, EXIT_SOFTWARE };
17
14
  export type RunErrorCode = "INVALID_ARGUMENT" | "STORE_HEAD_UNREADABLE" | "RUN_RELEASED";
18
15
  /**
19
16
  * Bad options, a call on a released run, or a store whose head cannot be read (STORE_HEAD_UNREADABLE: the run is marked
package/dist/run.js CHANGED
@@ -12,7 +12,7 @@ import { Harness } from "@earendil-works/pi-durable";
12
12
  import { acquire } from "./claim.js";
13
13
  import { reapOrRefuse } from "./commands.js";
14
14
  import { archilEnv } from "./env.js";
15
- import { EXIT_FENCED, FencedError, HeldError, ownWriteFenced, PdaError } from "./errors.js";
15
+ import { EXIT_DATAERR, EXIT_FENCED, EXIT_SOFTWARE, FencedError, HeldError, ownWriteFenced, PdaError } from "./errors.js";
16
16
  import { openArchilStore } from "./store.js";
17
17
  import { LeaseWatchdog } from "./watchdog.js";
18
18
  import { currentHolder, DEFAULT_HEARTBEAT_MS, DEFAULT_LEASE_EXPIRY_MS, DEFAULT_LEASE_MARGIN_MS, keepStartMark, openClaimDir, persistRecord, readRunRecord, RUN_JSON, RunRecordError, writeRunRecord, } from "./status.js";
@@ -20,10 +20,7 @@ import { currentHolder, DEFAULT_HEARTBEAT_MS, DEFAULT_LEASE_EXPIRY_MS, DEFAULT_L
20
20
  export const OWNER_LOCK = "owner.lock";
21
21
  /** pi's store under the claim's `store/` directory. */
22
22
  export const STORE_FILE = "run.sqlite";
23
- /** EX_DATAERR: the run's data refuses to open (a store behind its seal, an unreadable `run.json`); a restart cannot help. */
24
- export const EXIT_DATAERR = 65;
25
- /** EX_SOFTWARE: this package cannot read the head of pi's store (pi's schema moved); a restart cannot help. */
26
- export const EXIT_SOFTWARE = 70;
23
+ export { EXIT_DATAERR, EXIT_SOFTWARE };
27
24
  /**
28
25
  * Bad options, a call on a released run, or a store whose head cannot be read (STORE_HEAD_UNREADABLE: the run is marked
29
26
  * `failed` and released, exit 70).
package/dist/status.js CHANGED
@@ -7,7 +7,7 @@ import { open, readFile, rename, rm, stat } from "node:fs/promises";
7
7
  import { hostname } from "node:os";
8
8
  import { join } from "node:path";
9
9
  import { Worker } from "node:worker_threads";
10
- import { FencedError, ownWriteFenced, PdaError } from "./errors.js";
10
+ import { EXIT_DATAERR, FencedError, ownWriteFenced, PdaError } from "./errors.js";
11
11
  import { fdPath, hold } from "./held-fd.js";
12
12
  import { thisBoot } from "./process-table.js";
13
13
  export const RUN_JSON = "run.json";
@@ -23,7 +23,7 @@ export const RUN_STATUSES = ["running", "sleeping", "paused", "done", "failed"];
23
23
  /** `run.json` is missing a field, has one of the wrong type, or is not JSON. Exit 65 (EX_DATAERR): a restart cannot fix it. */
24
24
  export class RunRecordError extends PdaError {
25
25
  constructor(message, options = {}) {
26
- super("RUN_JSON_INVALID", message, { cause: options.cause, exitCode: 65 });
26
+ super("RUN_JSON_INVALID", message, { cause: options.cause, exitCode: EXIT_DATAERR });
27
27
  }
28
28
  }
29
29
  const isInstant = (value) => typeof value === "string" && Number.isFinite(Date.parse(value));
@@ -184,8 +184,9 @@ export function parseStartMark(text) {
184
184
  // watchdog's is (src/watchdog.ts says why). One refresh at a time, all synchronous: a stop (the message) is handled only
185
185
  // between two refreshes, so none is still writing once the thread has exited. It writes only while `dir` is still the
186
186
  // directory it first saw (its device and inode, read on this thread, so a stalled mount never holds the caller's): a path
187
- // that names another (a descriptor number reused) or none is never written, and the keeper stops. Its first failure goes
188
- // to the main thread, once.
187
+ // that names another (a descriptor number reused) or none is never written, and the keeper stops. A rewrite that fails is
188
+ // checked the same way, so a directory that moved between the check and the write is reported as moved, not as a failed
189
+ // write. Its first failure goes to the main thread, once.
189
190
  const KEEPER_SOURCE = `"use strict";
190
191
  const fs = require("node:fs");
191
192
  const path = require("node:path");
@@ -200,19 +201,23 @@ const report = (message) => {
200
201
  reported = true;
201
202
  parentPort.postMessage(message);
202
203
  };
203
- function refresh() {
204
- if (stopped) return;
204
+ // Why dir is no longer the directory the keeper first saw, or null while it is (the first call records it).
205
+ function moved() {
205
206
  let now;
206
207
  try {
207
208
  now = fs.statSync(dir, { bigint: true });
208
209
  } catch (error) {
209
- stopped = true;
210
- return report("its directory cannot be reached (" + (error.code || error.message) + "), so it is no longer the directory the keeper started on");
210
+ return "its directory cannot be reached (" + (error.code || error.message) + "), so it is no longer the directory the keeper started on";
211
211
  }
212
212
  first ??= { dev: now.dev, ino: now.ino };
213
- if (now.dev !== first.dev || now.ino !== first.ino) {
213
+ return now.dev === first.dev && now.ino === first.ino ? null : "its directory is no longer the directory the keeper started on";
214
+ }
215
+ function refresh() {
216
+ if (stopped) return;
217
+ const away = moved();
218
+ if (away) {
214
219
  stopped = true;
215
- return report("its directory is no longer the directory the keeper started on");
220
+ return report(away);
216
221
  }
217
222
  let text;
218
223
  try {
@@ -245,6 +250,12 @@ function refresh() {
245
250
  fs.closeSync(handle);
246
251
  }
247
252
  } catch (error) {
253
+ // The directory may have moved after the check above: then that is the reason, and the keeper stops.
254
+ const away = moved();
255
+ if (away) {
256
+ stopped = true;
257
+ return report(away);
258
+ }
248
259
  report("rewriting it failed (" + (error.code || error.message) + ")");
249
260
  }
250
261
  }
@@ -18,8 +18,7 @@ export declare const lapsed: (shared: BigInt64Array, now: bigint) => boolean;
18
18
  * SIGKILL the instance's commands: the process group of each direct child (pi starts each command as its own group's
19
19
  * leader), or the child alone when it shares the instance's group; with `ownCgroup`, every other process of the cgroup.
20
20
  * Never the instance or its group. A process this user may not signal (sudo's archil helpers) is skipped. Returns the
21
- * number of signals sent. Where there is no /proc (macOS) the processes come from one ps listing, and there is no cgroup. `stat` lines are `pid (comm) state ppid pgrp ...`, read after the last `)` since comm may hold
22
- * spaces and parentheses.
21
+ * number of signals sent. Where there is no /proc (macOS) the processes come from one ps listing, and there is no cgroup.
23
22
  */
24
23
  export declare const sweep: (instance: number, options?: SweepOptions) => number;
25
24
  /** The main thread's handle on the watchdog thread. */
package/dist/watchdog.js CHANGED
@@ -30,6 +30,8 @@ function lapsed(shared, now) {
30
30
  return true;
31
31
  }
32
32
 
33
+ // A stat line is "pid (comm) state ppid pgrp ...": its fields are read after the last ")", since comm may hold spaces and
34
+ // parentheses.
33
35
  function stat(proc, pid) {
34
36
  try {
35
37
  const text = fs.readFileSync(path.join(proc, String(pid), "stat"), "utf8");
@@ -126,8 +128,7 @@ export const lapsed = compiled.lapsed;
126
128
  * SIGKILL the instance's commands: the process group of each direct child (pi starts each command as its own group's
127
129
  * leader), or the child alone when it shares the instance's group; with `ownCgroup`, every other process of the cgroup.
128
130
  * Never the instance or its group. A process this user may not signal (sudo's archil helpers) is skipped. Returns the
129
- * number of signals sent. Where there is no /proc (macOS) the processes come from one ps listing, and there is no cgroup. `stat` lines are `pid (comm) state ppid pgrp ...`, read after the last `)` since comm may hold
130
- * spaces and parentheses.
131
+ * number of signals sent. Where there is no /proc (macOS) the processes come from one ps listing, and there is no cgroup.
131
132
  */
132
133
  export const sweep = compiled.sweep;
133
134
  /** The main thread's handle on the watchdog thread. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parcha/pi-durable-disk",
3
- "version": "0.1.0-beta.19",
3
+ "version": "0.1.0-beta.21",
4
4
  "description": "A durable pi host on a network disk (Archil): one owner per run, a fence, durable commits, and a supervisor.",
5
5
  "keywords": [
6
6
  "pi",