@cotal-ai/seat 0.57.0 → 0.59.0

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 (45) hide show
  1. package/README.md +26 -1
  2. package/dist/artifacts.d.ts +14 -0
  3. package/dist/artifacts.d.ts.map +1 -0
  4. package/dist/artifacts.js +40 -0
  5. package/dist/artifacts.js.map +1 -0
  6. package/dist/client.d.ts +6 -9
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +14 -3
  9. package/dist/client.js.map +1 -1
  10. package/dist/custodian.d.ts +5 -0
  11. package/dist/custodian.d.ts.map +1 -1
  12. package/dist/custodian.js +134 -28
  13. package/dist/custodian.js.map +1 -1
  14. package/dist/diagnostic.d.ts +13 -0
  15. package/dist/diagnostic.d.ts.map +1 -0
  16. package/dist/diagnostic.js +43 -0
  17. package/dist/diagnostic.js.map +1 -0
  18. package/dist/handle.d.ts +2 -4
  19. package/dist/handle.d.ts.map +1 -1
  20. package/dist/handle.js +1 -1
  21. package/dist/handle.js.map +1 -1
  22. package/dist/index.d.ts +4 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +4 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/launcher.d.ts +2 -0
  27. package/dist/launcher.d.ts.map +1 -1
  28. package/dist/launcher.js +55 -33
  29. package/dist/launcher.js.map +1 -1
  30. package/dist/oom.d.ts +18 -0
  31. package/dist/oom.d.ts.map +1 -0
  32. package/dist/oom.js +28 -0
  33. package/dist/oom.js.map +1 -0
  34. package/dist/protocol.d.ts +12 -8
  35. package/dist/protocol.d.ts.map +1 -1
  36. package/dist/protocol.js.map +1 -1
  37. package/dist/reap.d.ts +35 -2
  38. package/dist/reap.d.ts.map +1 -1
  39. package/dist/reap.js +142 -14
  40. package/dist/reap.js.map +1 -1
  41. package/dist/record.d.ts +12 -0
  42. package/dist/record.d.ts.map +1 -1
  43. package/dist/record.js +15 -1
  44. package/dist/record.js.map +1 -1
  45. package/package.json +2 -2
package/README.md CHANGED
@@ -12,6 +12,16 @@ named `custody transport unsupported on <platform>` error on darwin and win32. T
12
12
  in-process node-pty fallback here. The manager's `pty` runtime still spawns in-process off
13
13
  Linux and only `adopt` throws that named error.
14
14
 
15
+ `peerCredentials(socket)` and its `PeerCredentials` type are exported from the package root.
16
+ For a connected Linux Unix socket, the function returns the kernel's peer `pid`, `uid` and
17
+ `gid` using the same `SO_PEERCRED` helper as custody. Callers must compare that identity
18
+ against their own authorization policy; a PID is not a lifecycle or ownership fence. It
19
+ throws for an unsupported transport or missing native helper, and for a socket without a
20
+ file descriptor. No PTY or custodian is started by reading the peer identity.
21
+
22
+ The custodian raises its child's `oom_score_adj` to 500 and writes one line to `custodian.log`
23
+ when the kernel refuses.
24
+
15
25
  The Linux `SO_PEERCRED` helper is compiled for the host arch by `pnpm build`. That is a
16
26
  developer tree, not a publishable one: it prints a host-dev-build banner and writes
17
27
  `build/Release/linux-<arch>/peercred.node`. Pack and publish require both `linux-x64`
@@ -38,11 +48,18 @@ observation. A manager worker connects to that custodian over a 0600 filesystem
38
48
  authenticated by `SO_PEERCRED` uid match plus a per-seat capability token. Path possession is
39
49
  not enough. Child exit is pushed to every authenticated controller socket. After the child
40
50
  exits and the last authenticated client disconnects, the custodian closes the Unix server, unlinks the
41
- socket and record, and exits. An active child, or a still-connected observer of an exited
51
+ socket, and exits. The custody record stays until `reapSeat` verifies process departure. If the
52
+ recorded group leader is absent but its numeric process group still has members, ownership is
53
+ unproved: reaping refuses without signalling those members or deleting the record. An active child, or a still-connected observer of an exited
42
54
  child, keeps the process. A connected socket that never authenticated does not: it owns no
43
55
  session, no output subscription and no wait, so a settle owes it nothing. A seat whose child has
44
56
  already exited at listen stays up briefly so the launcher can adopt it.
45
57
 
58
+ A reap signals the custodian and the child only while each carries its recorded start identity.
59
+ The child's descendants are not in the record, so the reap kills the child's process group by
60
+ membership. The record carries no authentication, so a same-uid process that rewrites it chooses
61
+ what the next reap signals. `docs/security.md` lists both as accepted residuals.
62
+
46
63
  A custodian with no authenticated controller stops its child and exits after `UNATTENDED_MS`
47
64
  (ten minutes, overridable at launch with `COTAL_SEAT_UNATTENDED_MS`). The window restarts at each
48
65
  disconnect, so a manager that detaches and re-adopts keeps its seats; one that crashes, or a suite
@@ -55,5 +72,13 @@ Every custodian carries `--cotal-run <marker>` on its argv and `COTAL_RUN` in it
55
72
  `censusCustodians(run?)` reads that marker back out of `/proc/<pid>/cmdline`, which is
56
73
  world-readable, so a reaper can find and attribute orphans without walking `/proc/*/cwd`.
57
74
 
75
+ `drainSeats(root, { drain })` lists the custody records under a root. A record that cannot be
76
+ read, or whose start and boot identity do not tie its pids to this boot, is reported as `refused`
77
+ and left on disk, with or without `drain`. A seat whose child still holds its recorded start
78
+ identity is reported as `live-child` and never signalled. With `drain`, every other seat goes
79
+ through `reapSeat`. One it cannot prove gone is reported as `refused` and left on disk, and
80
+ `reapSeat` may already have sent `SIGKILL` to its custodian.
81
+ `cotal seats [--drain]` is the operator command over it.
82
+
58
83
  Generation CAS, the crash journal, N/N-1 protocol compatibility, and manager-worker activation
59
84
  are later milestones. This package currently speaks a single implicit controller.
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Remove a seat's launch artifacts (the record's `artifacts`). Called only where this package
3
+ * can prove the seat's child gone or never started: the custodian when it observes its child's exit
4
+ * or fails to start one, the launcher when it refuses before any process exists, and the reap once it
5
+ * has proved the seat gone. Losing a connection to the custodian proves none of these, so nothing on
6
+ * the client side calls this.
7
+ *
8
+ * `root` is the temp dir of the process that wrote them (the record's `artifactRoot`). Refuses,
9
+ * before removing anything, a path that is not a `cotal-` directory directly under it. Otherwise it
10
+ * tries every directory and then throws naming each one it could not remove, so the caller can keep
11
+ * those owned and try again.
12
+ */
13
+ export declare function discardSeatArtifacts(artifacts: readonly string[] | undefined, root: string | undefined): void;
14
+ //# sourceMappingURL=artifacts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAiB7G"}
@@ -0,0 +1,40 @@
1
+ import { rmSync } from "node:fs";
2
+ import { basename, dirname, resolve } from "node:path";
3
+ /** Every launch artifact directory name starts with this (core launch-artifacts). Repeated here
4
+ * because this package depends on nothing else in the repo, and it guards a recursive removal. */
5
+ const DIR_PREFIX = "cotal-";
6
+ /**
7
+ * Remove a seat's launch artifacts (the record's `artifacts`). Called only where this package
8
+ * can prove the seat's child gone or never started: the custodian when it observes its child's exit
9
+ * or fails to start one, the launcher when it refuses before any process exists, and the reap once it
10
+ * has proved the seat gone. Losing a connection to the custodian proves none of these, so nothing on
11
+ * the client side calls this.
12
+ *
13
+ * `root` is the temp dir of the process that wrote them (the record's `artifactRoot`). Refuses,
14
+ * before removing anything, a path that is not a `cotal-` directory directly under it. Otherwise it
15
+ * tries every directory and then throws naming each one it could not remove, so the caller can keep
16
+ * those owned and try again.
17
+ */
18
+ export function discardSeatArtifacts(artifacts, root) {
19
+ if (!artifacts?.length)
20
+ return;
21
+ if (root === undefined)
22
+ throw new Error(`refusing to remove launch artifacts ${artifacts.join(", ")}: no temp dir recorded for them`);
23
+ const base = resolve(root);
24
+ for (const dir of artifacts) {
25
+ if (dirname(resolve(dir)) !== base || !basename(dir).startsWith(DIR_PREFIX))
26
+ throw new Error(`refusing to remove launch artifact ${dir}: not a ${DIR_PREFIX}* directory directly under ${base}`);
27
+ }
28
+ const failed = [];
29
+ for (const dir of artifacts) {
30
+ try {
31
+ rmSync(dir, { recursive: true, force: true });
32
+ }
33
+ catch (e) {
34
+ failed.push(`${dir} (${e.message})`);
35
+ }
36
+ }
37
+ if (failed.length)
38
+ throw new Error(`could not remove launch artifact ${failed.join(", ")}`);
39
+ }
40
+ //# sourceMappingURL=artifacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEvD;mGACmG;AACnG,MAAM,UAAU,GAAG,QAAQ,CAAC;AAE5B;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAwC,EAAE,IAAwB;IACrG,IAAI,CAAC,SAAS,EAAE,MAAM;QAAE,OAAO;IAC/B,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IACtI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;YACzE,MAAM,IAAI,KAAK,CAAC,sCAAsC,GAAG,WAAW,UAAU,8BAA8B,IAAI,EAAE,CAAC,CAAC;IACxH,CAAC;IACD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,KAAM,CAAW,CAAC,OAAO,GAAG,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IACD,IAAI,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC9F,CAAC"}
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type StopMode } from "./protocol.js";
1
+ import { type SeatExit, type StopMode } from "./protocol.js";
2
2
  import type { SeatRecord } from "./record.js";
3
3
  export interface HelloInfo {
4
4
  name: string;
@@ -6,10 +6,7 @@ export interface HelloInfo {
6
6
  cols: number;
7
7
  rows: number;
8
8
  status: "running" | "exited";
9
- exit?: {
10
- code?: number;
11
- signal?: number;
12
- };
9
+ exit?: SeatExit;
13
10
  }
14
11
  export declare class SeatClient {
15
12
  private readonly record;
@@ -23,6 +20,7 @@ export declare class SeatClient {
23
20
  private exits;
24
21
  private helloInfo;
25
22
  private pendingExit;
23
+ private pendingExitInfo;
26
24
  private closed;
27
25
  constructor(record: SeatRecord);
28
26
  connect(): Promise<HelloInfo>;
@@ -33,15 +31,14 @@ export declare class SeatClient {
33
31
  rows: number;
34
32
  }>;
35
33
  subscribeOutput(fn: (data: Buffer) => void): Promise<() => void>;
34
+ /** How the child ended, once the custodian has said so (hello, exit event, or wait-exit). */
35
+ exitInfo(): SeatExit | undefined;
36
36
  onExit(fn: () => void): () => void;
37
37
  write(data: string): Promise<number>;
38
38
  resize(cols: number, rows: number): Promise<void>;
39
39
  interrupt(): Promise<void>;
40
40
  stop(mode: StopMode): Promise<void>;
41
- waitExit(): Promise<{
42
- code?: number;
43
- signal?: number;
44
- } | undefined>;
41
+ waitExit(): Promise<SeatExit | undefined>;
45
42
  health(): Promise<{
46
43
  pid: number;
47
44
  status: "running" | "exited";
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAQD,qBAAa,UAAU;IAaT,OAAO,CAAC,QAAQ,CAAC,MAAM;IAZnC,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,MAAM,CAA6C;IAC3D,OAAO,CAAC,gBAAgB,CAAuC;IAC/D,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAS;gBAEM,MAAM,EAAE,UAAU;IAEzC,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;IAyCnC,IAAI,IAAI,SAAS;IAKX,QAAQ,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAMjE,eAAe,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IAgBtE,MAAM,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAW5B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMpC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjD,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAK1B,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnC,QAAQ,IAAI,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAOnE,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAMxF,KAAK,IAAI,IAAI;IASb,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,QAAQ;IAsBhB,OAAO,CAAC,OAAO;CAchB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,QAAQ,EAGb,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AAQD,qBAAa,UAAU;IAcT,OAAO,CAAC,QAAQ,CAAC,MAAM;IAbnC,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,MAAM,CAA6C;IAC3D,OAAO,CAAC,gBAAgB,CAAuC;IAC/D,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,MAAM,CAAS;gBAEM,MAAM,EAAE,UAAU;IAEzC,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;IAyCnC,IAAI,IAAI,SAAS;IAKX,QAAQ,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAMjE,eAAe,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IAgBtE,6FAA6F;IAC7F,QAAQ,IAAI,QAAQ,GAAG,SAAS;IAIhC,MAAM,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAW5B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMpC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjD,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAK1B,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnC,QAAQ,IAAI,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAOzC,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAMxF,KAAK,IAAI,IAAI;IASb,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,QAAQ;IA2BhB,OAAO,CAAC,OAAO;CAchB"}
package/dist/client.js CHANGED
@@ -12,6 +12,7 @@ export class SeatClient {
12
12
  exits = new Set();
13
13
  helloInfo;
14
14
  pendingExit = false;
15
+ pendingExitInfo;
15
16
  closed = false;
16
17
  constructor(record) {
17
18
  this.record = record;
@@ -57,7 +58,7 @@ export class SeatClient {
57
58
  cols: reply.cols,
58
59
  rows: reply.rows,
59
60
  status: this.pendingExit ? "exited" : reply.status,
60
- ...(reply.exit ? { exit: reply.exit } : {}),
61
+ ...((reply.exit ?? this.pendingExitInfo) ? { exit: reply.exit ?? this.pendingExitInfo } : {}),
61
62
  };
62
63
  return this.helloInfo;
63
64
  }
@@ -90,6 +91,10 @@ export class SeatClient {
90
91
  this.pendingSubscribe = undefined;
91
92
  }
92
93
  }
94
+ /** How the child ended, once the custodian has said so (hello, exit event, or wait-exit). */
95
+ exitInfo() {
96
+ return this.helloInfo?.exit ?? this.pendingExitInfo;
97
+ }
93
98
  onExit(fn) {
94
99
  if (this.helloInfo?.status === "exited" || this.pendingExit) {
95
100
  queueMicrotask(fn);
@@ -167,10 +172,16 @@ export class SeatClient {
167
172
  return;
168
173
  }
169
174
  if (msg.event === "exit") {
170
- if (this.helloInfo)
175
+ if (this.helloInfo) {
171
176
  this.helloInfo.status = "exited";
172
- else
177
+ if (msg.exit)
178
+ this.helloInfo.exit = msg.exit;
179
+ }
180
+ else {
173
181
  this.pendingExit = true;
182
+ if (msg.exit)
183
+ this.pendingExitInfo = msg.exit;
184
+ }
174
185
  for (const fn of this.exits)
175
186
  fn();
176
187
  this.exits.clear();
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,11 @@ export interface CustodianLaunch {
17
17
  * Resolved by the LAUNCHER, because the launcher scrubs the environment it hands this process
18
18
  * (the child must not inherit the caller's), so an env override read here would never see one. */
19
19
  unattendedMs?: number;
20
+ /** The launch's private temporary directories, copied onto the seat record. This custodian removes
21
+ * them once it sees its child exit, the one exit it observes directly. */
22
+ artifacts?: string[];
23
+ /** The launcher's temp dir, which every entry of `artifacts` must sit directly under. */
24
+ artifactRoot?: string;
20
25
  }
21
26
  export declare function runCustodian(launch: CustodianLaunch): Promise<void>;
22
27
  //# sourceMappingURL=custodian.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"custodian.d.ts","sourceRoot":"","sources":["../src/custodian.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;oEACgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;uGAEmG;IACnG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD,wBAAsB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAugBzE"}
1
+ {"version":3,"file":"custodian.d.ts","sourceRoot":"","sources":["../src/custodian.ts"],"names":[],"mappings":"AA4BA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;oEACgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;uGAEmG;IACnG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;+EAC2E;IAC3E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,yFAAyF;IACzF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD,wBAAsB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAsmBzE"}
package/dist/custodian.js CHANGED
@@ -1,12 +1,15 @@
1
- import { appendFileSync, chmodSync, mkdirSync, readFileSync, unlinkSync } from "node:fs";
1
+ import { appendFileSync, chmodSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
2
2
  import { createServer } from "node:net";
3
3
  import { dirname } from "node:path";
4
4
  import * as pty from "@lydell/node-pty";
5
5
  import Headless from "@xterm/headless";
6
6
  import { SerializeAddon } from "@xterm/addon-serialize";
7
+ import { discardSeatArtifacts } from "./artifacts.js";
7
8
  import { peerCredentials } from "./peercred.js";
9
+ import { preferSeatForOomKill } from "./oom.js";
8
10
  import { CONFIRM_TIMEOUT_MS, DEFAULT_COLS, DEFAULT_ROWS, FrameReader, GRACE_MS, MAX_FRAME_SIZE, PROTOCOL_VERSION, SCROLLBACK_ROWS, UNATTENDED_MS as UNATTENDED_DEFAULT_MS, encodeFrame, } from "./protocol.js";
9
- import { RECORD_VERSION, bootToken, processStartToken, writeRecord } from "./record.js";
11
+ import { ConnectorDiagnosticReader } from "./diagnostic.js";
12
+ import { RECORD_VERSION, bootToken, exitPath, processStartToken, writeRecord } from "./record.js";
10
13
  import { StartupConfirmMatcher, unmatchedConfirmMessage } from "./startup-confirm.js";
11
14
  function send(sock, msg) {
12
15
  if (!sock.writable)
@@ -25,13 +28,50 @@ export async function runCustodian(launch) {
25
28
  if (e.code !== "ENOENT")
26
29
  throw e;
27
30
  }
28
- const proc = pty.spawn(launch.command, launch.args, {
29
- name: "xterm-256color",
30
- cols: DEFAULT_COLS,
31
- rows: DEFAULT_ROWS,
32
- cwd: launch.cwd,
33
- env: launch.env,
34
- });
31
+ // Removes the launch's files, logging rather than throwing: a refused path must not take down the
32
+ // custodian of a live seat.
33
+ const discardArtifacts = (artifacts) => {
34
+ try {
35
+ discardSeatArtifacts(artifacts, launch.artifactRoot);
36
+ }
37
+ catch (e) {
38
+ note(`${e.message}\n`);
39
+ }
40
+ };
41
+ const note = (line) => {
42
+ try {
43
+ if (launch.logPath)
44
+ appendFileSync(launch.logPath, line, { mode: 0o600 });
45
+ else
46
+ process.stderr.write(line);
47
+ }
48
+ catch {
49
+ /* the seat directory may already be gone */
50
+ }
51
+ };
52
+ let proc;
53
+ try {
54
+ proc = pty.spawn(launch.command, launch.args, {
55
+ name: "xterm-256color",
56
+ cols: DEFAULT_COLS,
57
+ rows: DEFAULT_ROWS,
58
+ cwd: launch.cwd,
59
+ env: launch.env,
60
+ });
61
+ }
62
+ catch (e) {
63
+ // No child was started, so none will read the files.
64
+ discardArtifacts(launch.artifacts);
65
+ throw e;
66
+ }
67
+ const oomPref = preferSeatForOomKill(proc.pid);
68
+ if (!oomPref.applied) {
69
+ const line = `oom preference not applied to child ${proc.pid}: ${oomPref.reason}\n`;
70
+ if (launch.logPath)
71
+ appendFileSync(launch.logPath, line, { mode: 0o600 });
72
+ else
73
+ process.stderr.write(line);
74
+ }
35
75
  // Pin both start identities NOW, before the child can exit and be reaped: a successor that finds
36
76
  // these pids later must be able to tell this custodian and this child from an unrelated process
37
77
  // that inherited the pid. A zombie still reports its start token, a reaped pid does not: a child
@@ -57,6 +97,7 @@ export async function runCustodian(launch) {
57
97
  let cols = DEFAULT_COLS;
58
98
  let rows = DEFAULT_ROWS;
59
99
  let exit;
100
+ const diagnostic = new ConnectorDiagnosticReader();
60
101
  const dataSubs = new Map();
61
102
  const waiters = new Map();
62
103
  const controllers = new Set();
@@ -72,6 +113,8 @@ export async function runCustodian(launch) {
72
113
  let server;
73
114
  /** Wait for the first adopter when the child has already exited at listen. */
74
115
  const LAUNCH_HANDOFF_MS = 5_000;
116
+ /** How long a child already gone from /proc may wait for node-pty to report how it ended. */
117
+ const EXIT_STATUS_GRACE_MS = 1_000;
75
118
  const UNATTENDED_MS = launch.unattendedMs ?? UNATTENDED_DEFAULT_MS;
76
119
  if (confirmMatcher) {
77
120
  confirmTimer = setTimeout(() => {
@@ -107,6 +150,20 @@ export async function runCustodian(launch) {
107
150
  return true;
108
151
  }
109
152
  };
153
+ /**
154
+ * Mark a child that /proc shows gone as exited WITHOUT a status, but only once node-pty has had
155
+ * time to report the status itself. node-pty reports an exit only when the pty closes, and when a
156
+ * descendant still holds the pty open it forces that close 200 ms after reaping the child. The
157
+ * exit event carries whatever is known when it is sent, so marking earlier sent no status.
158
+ */
159
+ let goneSince;
160
+ const markGone = () => {
161
+ if (!alive || !childGone())
162
+ return;
163
+ goneSince ??= Date.now();
164
+ if (Date.now() - goneSince >= EXIT_STATUS_GRACE_MS)
165
+ markExited({});
166
+ };
110
167
  const settleTerminal = () => {
111
168
  if (alive || settling || !ready)
112
169
  return;
@@ -173,13 +230,8 @@ export async function runCustodian(launch) {
173
230
  if (e.code !== "ENOENT")
174
231
  throw e;
175
232
  }
176
- try {
177
- unlinkSync(launch.recordPath);
178
- }
179
- catch (e) {
180
- if (e.code !== "ENOENT")
181
- throw e;
182
- }
233
+ // The custody record is retained on disk until verified reaping can consume it;
234
+ // reapSeat proves kernel process identities and removes the record directory.
183
235
  process.exit(0);
184
236
  };
185
237
  /**
@@ -249,19 +301,76 @@ export async function runCustodian(launch) {
249
301
  return;
250
302
  }
251
303
  alive = false;
252
- exit = info ?? exit ?? {};
304
+ const last = diagnostic.read();
305
+ exit = { ...(info ?? exit ?? {}), ...(last ? { diagnostic: last } : {}) };
306
+ // Kept beside the custody record so a reap that runs after every controller is gone, even in a
307
+ // successor manager, can still say how the child ended. Renamed into place, so a reader never
308
+ // sees half a record.
309
+ const exitFile = exitPath(launch.recordPath);
310
+ try {
311
+ writeFileSync(`${exitFile}.tmp`, `${JSON.stringify(exit)}\n`, { mode: 0o600 });
312
+ renameSync(`${exitFile}.tmp`, exitFile);
313
+ }
314
+ catch (e) {
315
+ // A seat directory that is already gone has nobody left to read the record. Any other failure
316
+ // loses the only account a later reap has, so it is said where an operator can find it, and
317
+ // the reap reports the record missing or unreadable.
318
+ if (e.code !== "ENOENT") {
319
+ const line = `exit record not written: ${e.message}\n`;
320
+ try {
321
+ unlinkSync(`${exitFile}.tmp`);
322
+ }
323
+ catch {
324
+ /* never created */
325
+ }
326
+ try {
327
+ if (launch.logPath)
328
+ appendFileSync(launch.logPath, line, { mode: 0o600 });
329
+ else
330
+ process.stderr.write(line);
331
+ }
332
+ catch {
333
+ /* the log can sit on the same failed storage */
334
+ }
335
+ }
336
+ }
337
+ // The child is gone, so it has made every read it will make. Remove its files before anyone is
338
+ // told of the exit, and drop the removed ones from the record so a later reap does not remove the
339
+ // same names again. One that could not be removed stays listed, so the reap that proves this seat
340
+ // gone tries it again. Losing a controller's connection is not this: only the child's exit is.
341
+ if (record.artifacts) {
342
+ discardArtifacts(record.artifacts);
343
+ const left = record.artifacts.filter((dir) => existsSync(dir));
344
+ if (left.length)
345
+ record.artifacts = left;
346
+ else {
347
+ delete record.artifacts;
348
+ delete record.artifactRoot;
349
+ }
350
+ if (ready) {
351
+ try {
352
+ const tmp = `${launch.recordPath}.tmp`;
353
+ writeRecord(tmp, record);
354
+ renameSync(tmp, launch.recordPath);
355
+ }
356
+ catch (e) {
357
+ note(`${e.message}\n`);
358
+ }
359
+ }
360
+ }
253
361
  if (confirmTimer) {
254
362
  clearTimeout(confirmTimer);
255
363
  confirmTimer = undefined;
256
364
  }
257
365
  for (const sock of controllers)
258
- send(sock, { event: "exit" });
366
+ send(sock, { event: "exit", exit });
259
367
  resolveWaiters();
260
368
  settleTerminal();
261
369
  armUnobservedHandoff();
262
370
  };
263
371
  proc.onData((d) => {
264
372
  term.write(d);
373
+ diagnostic.push(d);
265
374
  if (early.length < MAX_FRAME_SIZE) {
266
375
  early += early.length + d.length > MAX_FRAME_SIZE ? d.slice(0, MAX_FRAME_SIZE - early.length) : d;
267
376
  }
@@ -287,8 +396,7 @@ export async function runCustodian(launch) {
287
396
  reap = undefined;
288
397
  return;
289
398
  }
290
- if (childGone())
291
- markExited({});
399
+ markGone();
292
400
  }, 50);
293
401
  reap.unref();
294
402
  const stopChild = (mode) => {
@@ -316,6 +424,7 @@ export async function runCustodian(launch) {
316
424
  // Bind the pids to THIS boot: their start tokens are ticks since boot and the record outlives a
317
425
  // reboot on disk, so without this a survivor could match an innocent process on the next boot.
318
426
  ...(bootId === undefined ? {} : { bootId }),
427
+ ...(launch.artifacts?.length ? { artifacts: launch.artifacts, artifactRoot: launch.artifactRoot } : {}),
319
428
  };
320
429
  server = createServer((sock) => {
321
430
  const reader = new FrameReader();
@@ -407,8 +516,7 @@ export async function runCustodian(launch) {
407
516
  clearTimeout(handoffTimer);
408
517
  handoffTimer = undefined;
409
518
  }
410
- if (alive && childGone())
411
- markExited({});
519
+ markGone();
412
520
  send(sock, {
413
521
  id: req.id,
414
522
  ok: true,
@@ -421,7 +529,7 @@ export async function runCustodian(launch) {
421
529
  ...(exit ? { exit } : {}),
422
530
  });
423
531
  if (!alive)
424
- send(sock, { event: "exit" });
532
+ send(sock, { event: "exit", ...(exit ? { exit } : {}) });
425
533
  return;
426
534
  }
427
535
  case "snapshot": {
@@ -439,7 +547,7 @@ export async function runCustodian(launch) {
439
547
  if (early)
440
548
  send(sock, { event: "output", sub, data: Buffer.from(early, "utf8").toString("base64") });
441
549
  if (!alive)
442
- send(sock, { event: "exit", sub });
550
+ send(sock, { event: "exit", sub, ...(exit ? { exit } : {}) });
443
551
  return;
444
552
  }
445
553
  case "unsubscribe-output": {
@@ -483,8 +591,7 @@ export async function runCustodian(launch) {
483
591
  return;
484
592
  }
485
593
  case "wait-exit": {
486
- if (alive && childGone())
487
- markExited({});
594
+ markGone();
488
595
  if (!alive) {
489
596
  send(sock, { id: req.id, ok: true, op: "wait-exit", exit });
490
597
  return;
@@ -495,8 +602,7 @@ export async function runCustodian(launch) {
495
602
  return;
496
603
  }
497
604
  case "health": {
498
- if (alive && childGone())
499
- markExited({});
605
+ markGone();
500
606
  send(sock, {
501
607
  id: req.id,
502
608
  ok: true,