@warlock.js/process 0.0.0-stage → 5.34.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.
package/llms-full.txt ADDED
@@ -0,0 +1,157 @@
1
+ # Warlock Process — full skills
2
+
3
+ > Package: `@warlock.js/process`
4
+
5
+ > Generated artifact. Concatenates every SKILL.md and reference file under `@warlock.js/process/skills/`. Re-run `node scripts/generate-llms.mjs` after any change.
6
+
7
+ ## supervise-processes `@warlock.js/process/supervise-processes/SKILL.md`
8
+
9
+ ---
10
+ name: supervise-processes
11
+ description: Start, limit, list, stop and recover app-owned workers or terminals using @warlock.js/process. Covers supervisor, ProcessNotOwnedError, spawnPty and warlock add process. Use for child process ownership and resource caps.
12
+ ---
13
+
14
+ # Supervise app-owned processes
15
+
16
+ Use `npx warlock add process` to pin the family package, create
17
+ `src/config/process.ts`, export `processes` from `src/app/processes/index.ts`,
18
+ and wire recovery/shutdown through `src/app/main.ts`. A second run preserves
19
+ existing files. Set a unique owner and registry per app instance.
20
+
21
+ ```ts
22
+ import { supervisor, ProcessNotOwnedError } from "@warlock.js/process";
23
+
24
+ const processes = supervisor({
25
+ owner: "example-app",
26
+ registry: "storage/processes/registry.json",
27
+ defaults: { timeoutMs: 30_000, memoryBytes: 512 * 1024 * 1024 },
28
+ });
29
+ await processes.recover({ keep: (entry) => entry.labels.persistent === "yes" });
30
+ const worker = await processes.spawn({
31
+ kind: "worker",
32
+ command: process.execPath,
33
+ args: ["-e", 'console.log("ready"); setTimeout(() => {}, 1000)'],
34
+ cwd: process.cwd(),
35
+ env: { WORKER_MODE: "once" },
36
+ labels: { room: "demo", member: "one" },
37
+ limits: { timeoutMs: 10_000 },
38
+ });
39
+ worker.stdout.pipe(process.stdout);
40
+ worker.stderr.pipe(process.stderr);
41
+ console.log(await processes.list({ labels: { room: "demo" } }));
42
+ await processes.stop({ labels: { room: "demo", member: "one" } });
43
+ await worker.stop(); // idempotent after exit
44
+ console.log(await worker.exited); // reason, code, signal, peakMemoryBytes
45
+ try {
46
+ await processes.stopPid(worker.pid); // an exited PID is no longer registered
47
+ } catch (error) {
48
+ if (!(error instanceof ProcessNotOwnedError)) throw error;
49
+ }
50
+ await processes.stop(); // without a filter, stops all verified entries
51
+ await processes.stopAll(); // releases registry, permanently closes supervisor
52
+ ```
53
+
54
+ No name/pattern stops. Labels match every requested key/value. `stop()` selects
55
+ all entries. `stopPid()` verifies ownership or throws `ProcessNotOwnedError`.
56
+ Recovery clears stale identities, adopts those selected by `keep`, and stops
57
+ other verified entries. Default recovery stops verified orphans. Adopted children
58
+ cannot regain stdio or original exit codes. Always recover before spawning.
59
+
60
+ The input `kind` is the workload category; listing calls it `type`.
61
+ Ownership is random environment token + PID + OS start time, with an isolated
62
+ group on POSIX; commands never prove ownership.
63
+ Do not expose tokens or the private registry. A second live supervisor for the
64
+ same registry fails. Corruption or incomplete leases require inspection.
65
+
66
+ ## Terminals
67
+
68
+ Install optional peer `node-pty` only for terminals. Import happens lazily.
69
+
70
+ ```ts
71
+ import { supervisor } from "@warlock.js/process";
72
+
73
+ const terminals = supervisor({ owner: "terminals", registry: "storage/terminals.json" });
74
+ await terminals.recover();
75
+ const terminal = await terminals.spawnPty({
76
+ kind: "terminal",
77
+ command: "/bin/sh",
78
+ args: [],
79
+ columns: 100,
80
+ rows: 30,
81
+ labels: { room: "demo" },
82
+ });
83
+ terminal.stdout.pipe(process.stdout);
84
+ terminal.write("printf 'hello\\n'\n");
85
+ terminal.resize(120, 40);
86
+ await terminal.stop();
87
+ console.log(await terminal.exited);
88
+ await terminals.stopAll();
89
+ ```
90
+
91
+ PTY stdout combines terminal output; stderr is empty. `stdin` is writable too.
92
+
93
+ ## Resource and lifecycle decisions
94
+
95
+ - Linux attempts a per-child cgroup v2 inside an already delegated directory
96
+ (`cgroupRoot` overrides discovery). It does not request root or change the
97
+ host's controllers. Denied writes fall back to `rlimit-polling`.
98
+ For memory enforcement the delegated parent must be empty, with memory
99
+ enabled; put the app in a separate leaf and use the parent as `cgroupRoot`.
100
+ - Limits: `timeoutMs`, `memoryBytes`, `cpuSeconds`, Linux-only
101
+ `virtualMemoryBytes`. All are positive safe integers. Linux ignores
102
+ `RLIMIT_RSS`; fallback RSS accounting covers the leader and can overshoot.
103
+ V8 reserves large address space; avoid small address-space limits.
104
+ - macOS reads `ps` start times with `LC_ALL=C TZ=UTC`, applies CPU/data rlimits
105
+ and polls tree RSS. Windows uses PowerShell/CIM creation times, polls tree
106
+ working sets (`enforcement: "rss-polling"`) and stops verified trees with
107
+ `taskkill /PID <pid> /T /F`. Memory caps on both are softer than Linux cgroups.
108
+ - Both use a Node guardian as the handle PID. It proves the random token from
109
+ its own environment through a local socket/named pipe, gates workload launch
110
+ until registry persistence, and survives supervisor restarts for recovery.
111
+ Memory includes the guardian and its descendants. No identity-helper setup
112
+ or custom native compilation is needed.
113
+ - Windows needs PowerShell/CIM. `cpuSeconds` is POSIX-only and
114
+ `virtualMemoryBytes` Linux-only; unsupported limits fail before launch.
115
+ Timeouts apply everywhere. Windows always forces the PID tree immediately;
116
+ Job Objects remain a future hard-containment improvement. `spawnPty` uses
117
+ optional `node-pty` on Windows/ConPTY too (use `powershell.exe` as the command).
118
+ - Read `enforcement` on listed entries. Kernel cgroup peaks include descendants;
119
+ sampled peaks can miss short-lived descendants. Reasons are `exit`, `timeout`, `memory-cap`,
120
+ `stopped`; allocation failures from rlimits may be ordinary exits.
121
+ - Without cgroups, descendants that create a session can escape; a leader that
122
+ exits cannot be re-verified for escalation. This is not a hostile-code sandbox
123
+ or an atomic identity-and-signal API. Windows trees also have discovery/PID-reuse
124
+ races and require a live verified guardian for stopping.
125
+ - The generated `Application.onValidateBoot` awaits recovery and fails boot on
126
+ error; `Application.onShutdown` awaits cleanup. For manual wiring, use the same
127
+ hooks. Consume worker output to avoid backpressure.
128
+ `exited` reports leader exit; await stream `end` events as well when collecting output.
129
+ - With devtools installed, the generated `app/processes/devtools.ts` exports a
130
+ read-only list source, discovered only in development. No stop endpoint ships.
131
+
132
+ Platform source references and delegation details:
133
+ https://warlock.js.org/v/latest/process/.
134
+
135
+ ## Configuration validation and guardian credentials
136
+
137
+ `supervisor()` requires nonempty string `owner` and `registry` options. Missing,
138
+ null or invalid configuration throws `TypeError` immediately, naming the first
139
+ invalid option (owner before registry). Validate deployment configuration before
140
+ starting work:
141
+
142
+ ```ts
143
+ import { supervisor } from "@warlock.js/process";
144
+
145
+ const processes = supervisor({
146
+ owner: "test-workers",
147
+ registry: "storage/test-workers.json",
148
+ });
149
+ ```
150
+
151
+ On macOS and Windows, only the guardian receives `WARLOCK_PROCESS_TOKEN` and
152
+ `WARLOCK_PROCESS_LAUNCH`. It authenticates ownership over its socket/named pipe;
153
+ both private variables are removed before spawning the workload (case-insensitively
154
+ on Windows). Ordinary environment entries reach the workload. Linux continues
155
+ to forward the token because ownership is checked through `/proc/<pid>/environ`.
156
+
157
+
package/llms.txt ADDED
@@ -0,0 +1,9 @@
1
+ # Warlock Process
2
+
3
+ > Package: `@warlock.js/process`
4
+
5
+ > App-owned child process supervision with verified identity and resource limits
6
+
7
+ ## Skills
8
+
9
+ - [supervise-processes](@warlock.js/process/supervise-processes/SKILL.md): Start, limit, list, stop and recover app-owned workers or terminals using @warlock.js/process. Covers supervisor, ProcessNotOwnedError, spawnPty and warlock add process. Use for child process ownership and resource caps.
package/package.json CHANGED
@@ -1,6 +1,51 @@
1
1
  {
2
2
  "name": "@warlock.js/process",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "description": "App-owned child process supervision with verified identity and resource limits",
4
+ "keywords": [
5
+ "warlock",
6
+ "process",
7
+ "supervisor",
8
+ "pty"
9
+ ],
10
+ "author": "hassanzohdy",
11
+ "license": "MIT",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/warlockjs/framework.git",
15
+ "directory": "packages/process"
16
+ },
17
+ "bugs": {
18
+ "url": "https://github.com/warlockjs/framework/issues"
19
+ },
20
+ "homepage": "https://warlock.js.org",
21
+ "engines": {
22
+ "node": ">=22.15.0"
23
+ },
24
+ "peerDependencies": {
25
+ "node-pty": "^1.0.0"
26
+ },
27
+ "peerDependenciesMeta": {
28
+ "node-pty": {
29
+ "optional": true
30
+ }
31
+ },
32
+ "warlock": {
33
+ "environment": "server"
34
+ },
35
+ "version": "5.34.0",
36
+ "main": "./cjs/index.cjs",
37
+ "module": "./esm/index.mjs",
38
+ "types": "./esm/index.d.mts",
39
+ "exports": {
40
+ ".": {
41
+ "import": {
42
+ "types": "./esm/index.d.mts",
43
+ "default": "./esm/index.mjs"
44
+ },
45
+ "require": {
46
+ "types": "./esm/index.d.mts",
47
+ "default": "./cjs/index.cjs"
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,147 @@
1
+ ---
2
+ name: supervise-processes
3
+ description: Start, limit, list, stop and recover app-owned workers or terminals using @warlock.js/process. Covers supervisor, ProcessNotOwnedError, spawnPty and warlock add process. Use for child process ownership and resource caps.
4
+ ---
5
+
6
+ # Supervise app-owned processes
7
+
8
+ Use `npx warlock add process` to pin the family package, create
9
+ `src/config/process.ts`, export `processes` from `src/app/processes/index.ts`,
10
+ and wire recovery/shutdown through `src/app/main.ts`. A second run preserves
11
+ existing files. Set a unique owner and registry per app instance.
12
+
13
+ ```ts
14
+ import { supervisor, ProcessNotOwnedError } from "@warlock.js/process";
15
+
16
+ const processes = supervisor({
17
+ owner: "example-app",
18
+ registry: "storage/processes/registry.json",
19
+ defaults: { timeoutMs: 30_000, memoryBytes: 512 * 1024 * 1024 },
20
+ });
21
+ await processes.recover({ keep: (entry) => entry.labels.persistent === "yes" });
22
+ const worker = await processes.spawn({
23
+ kind: "worker",
24
+ command: process.execPath,
25
+ args: ["-e", 'console.log("ready"); setTimeout(() => {}, 1000)'],
26
+ cwd: process.cwd(),
27
+ env: { WORKER_MODE: "once" },
28
+ labels: { room: "demo", member: "one" },
29
+ limits: { timeoutMs: 10_000 },
30
+ });
31
+ worker.stdout.pipe(process.stdout);
32
+ worker.stderr.pipe(process.stderr);
33
+ console.log(await processes.list({ labels: { room: "demo" } }));
34
+ await processes.stop({ labels: { room: "demo", member: "one" } });
35
+ await worker.stop(); // idempotent after exit
36
+ console.log(await worker.exited); // reason, code, signal, peakMemoryBytes
37
+ try {
38
+ await processes.stopPid(worker.pid); // an exited PID is no longer registered
39
+ } catch (error) {
40
+ if (!(error instanceof ProcessNotOwnedError)) throw error;
41
+ }
42
+ await processes.stop(); // without a filter, stops all verified entries
43
+ await processes.stopAll(); // releases registry, permanently closes supervisor
44
+ ```
45
+
46
+ No name/pattern stops. Labels match every requested key/value. `stop()` selects
47
+ all entries. `stopPid()` verifies ownership or throws `ProcessNotOwnedError`.
48
+ Recovery clears stale identities, adopts those selected by `keep`, and stops
49
+ other verified entries. Default recovery stops verified orphans. Adopted children
50
+ cannot regain stdio or original exit codes. Always recover before spawning.
51
+
52
+ The input `kind` is the workload category; listing calls it `type`.
53
+ Ownership is random environment token + PID + OS start time, with an isolated
54
+ group on POSIX; commands never prove ownership.
55
+ Do not expose tokens or the private registry. A second live supervisor for the
56
+ same registry fails. Corruption or incomplete leases require inspection.
57
+
58
+ ## Terminals
59
+
60
+ Install optional peer `node-pty` only for terminals. Import happens lazily.
61
+
62
+ ```ts
63
+ import { supervisor } from "@warlock.js/process";
64
+
65
+ const terminals = supervisor({ owner: "terminals", registry: "storage/terminals.json" });
66
+ await terminals.recover();
67
+ const terminal = await terminals.spawnPty({
68
+ kind: "terminal",
69
+ command: "/bin/sh",
70
+ args: [],
71
+ columns: 100,
72
+ rows: 30,
73
+ labels: { room: "demo" },
74
+ });
75
+ terminal.stdout.pipe(process.stdout);
76
+ terminal.write("printf 'hello\\n'\n");
77
+ terminal.resize(120, 40);
78
+ await terminal.stop();
79
+ console.log(await terminal.exited);
80
+ await terminals.stopAll();
81
+ ```
82
+
83
+ PTY stdout combines terminal output; stderr is empty. `stdin` is writable too.
84
+
85
+ ## Resource and lifecycle decisions
86
+
87
+ - Linux attempts a per-child cgroup v2 inside an already delegated directory
88
+ (`cgroupRoot` overrides discovery). It does not request root or change the
89
+ host's controllers. Denied writes fall back to `rlimit-polling`.
90
+ For memory enforcement the delegated parent must be empty, with memory
91
+ enabled; put the app in a separate leaf and use the parent as `cgroupRoot`.
92
+ - Limits: `timeoutMs`, `memoryBytes`, `cpuSeconds`, Linux-only
93
+ `virtualMemoryBytes`. All are positive safe integers. Linux ignores
94
+ `RLIMIT_RSS`; fallback RSS accounting covers the leader and can overshoot.
95
+ V8 reserves large address space; avoid small address-space limits.
96
+ - macOS reads `ps` start times with `LC_ALL=C TZ=UTC`, applies CPU/data rlimits
97
+ and polls tree RSS. Windows uses PowerShell/CIM creation times, polls tree
98
+ working sets (`enforcement: "rss-polling"`) and stops verified trees with
99
+ `taskkill /PID <pid> /T /F`. Memory caps on both are softer than Linux cgroups.
100
+ - Both use a Node guardian as the handle PID. It proves the random token from
101
+ its own environment through a local socket/named pipe, gates workload launch
102
+ until registry persistence, and survives supervisor restarts for recovery.
103
+ Memory includes the guardian and its descendants. No identity-helper setup
104
+ or custom native compilation is needed.
105
+ - Windows needs PowerShell/CIM. `cpuSeconds` is POSIX-only and
106
+ `virtualMemoryBytes` Linux-only; unsupported limits fail before launch.
107
+ Timeouts apply everywhere. Windows always forces the PID tree immediately;
108
+ Job Objects remain a future hard-containment improvement. `spawnPty` uses
109
+ optional `node-pty` on Windows/ConPTY too (use `powershell.exe` as the command).
110
+ - Read `enforcement` on listed entries. Kernel cgroup peaks include descendants;
111
+ sampled peaks can miss short-lived descendants. Reasons are `exit`, `timeout`, `memory-cap`,
112
+ `stopped`; allocation failures from rlimits may be ordinary exits.
113
+ - Without cgroups, descendants that create a session can escape; a leader that
114
+ exits cannot be re-verified for escalation. This is not a hostile-code sandbox
115
+ or an atomic identity-and-signal API. Windows trees also have discovery/PID-reuse
116
+ races and require a live verified guardian for stopping.
117
+ - The generated `Application.onValidateBoot` awaits recovery and fails boot on
118
+ error; `Application.onShutdown` awaits cleanup. For manual wiring, use the same
119
+ hooks. Consume worker output to avoid backpressure.
120
+ `exited` reports leader exit; await stream `end` events as well when collecting output.
121
+ - With devtools installed, the generated `app/processes/devtools.ts` exports a
122
+ read-only list source, discovered only in development. No stop endpoint ships.
123
+
124
+ Platform source references and delegation details:
125
+ https://warlock.js.org/v/latest/process/.
126
+
127
+ ## Configuration validation and guardian credentials
128
+
129
+ `supervisor()` requires nonempty string `owner` and `registry` options. Missing,
130
+ null or invalid configuration throws `TypeError` immediately, naming the first
131
+ invalid option (owner before registry). Validate deployment configuration before
132
+ starting work:
133
+
134
+ ```ts
135
+ import { supervisor } from "@warlock.js/process";
136
+
137
+ const processes = supervisor({
138
+ owner: "test-workers",
139
+ registry: "storage/test-workers.json",
140
+ });
141
+ ```
142
+
143
+ On macOS and Windows, only the guardian receives `WARLOCK_PROCESS_TOKEN` and
144
+ `WARLOCK_PROCESS_LAUNCH`. It authenticates ownership over its socket/named pipe;
145
+ both private variables are removed before spawning the workload (case-insensitively
146
+ on Windows). Ordinary environment entries reach the workload. Linux continues
147
+ to forward the token because ownership is checked through `/proc/<pid>/environ`.