@plurnk/plurnk-execs-common 3.0.1 → 3.0.2

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
@@ -1,9 +1,9 @@
1
1
  # @plurnk/plurnk-execs-common
2
2
 
3
- The **universal subprocess executor** for
4
- [plurnk-service](https://github.com/plurnk/plurnk-service)'s `exec` scheme. One
5
- package offers the shell, Node.js, and Python 3 by default, with other supported
6
- host interpreters available as opt-ins. Node is guaranteed; the rest are detected.
3
+ The **subprocess executor** for
4
+ [plurnk-service](https://github.com/plurnk/plurnk-service)'s runtime-tag execution (`sh`, `js`, `python3`). One
5
+ package offers the shell, Node.js, and Python 3. Node is guaranteed; the rest
6
+ are detected.
7
7
 
8
8
  A `@plurnk/plurnk-execs-*` sibling built on the [plurnk-execs](https://github.com/plurnk/plurnk-service/tree/main/plurnk-execs) framework.
9
9
 
@@ -11,69 +11,63 @@ A `@plurnk/plurnk-execs-*` sibling built on the [plurnk-execs](https://github.co
11
11
 
12
12
  The manifest claims the subprocess tags. Per-tag `probe()` reports Node
13
13
  unconditionally because the daemon already runs on it. A cheap `command -v`
14
- detects every other interpreter, so one executor adapts to the host.
15
-
16
- | Tag | Binary | Inline body via |
17
- | -------------------------------- | ----------------- | ---------------------------------------- |
18
- | `sh` 🐚 | sh | `-c <body>` |
19
- | `node` ⬢ | node | `-e <body>` (always available) |
20
- | `python3` 🐍 | python3 | `-c <body>` |
21
- | `perl` 🐪 / `ruby` 💎 / `lua` 🌙 | perl / ruby / lua | `-e <body>` |
22
- | `deno` 🦕 | deno | `eval <body>` |
23
- | `bun` 🥟 | bun | `-e <body>` |
24
- | `tcl` 🪶 | tclsh | stdin |
25
- | `bc` 🧮 | bc | stdin (for example, `6 * 7`) |
26
- | `awk` 🪄 | awk | program arg, empty stdin (`BEGIN { … }`) |
14
+ detects `sh` and `python3`, so one executor adapts to the host.
15
+
16
+ | Tag | Binary | Inline body via |
17
+ | ------------ | ------- | ------------------------------ |
18
+ | `sh` 🐚 | sh | `-c <body>` |
19
+ | `js` ⬢ | node | `-e <body>` (always available) |
20
+ | `python3` 🐍 | python3 | `-c <body>` |
27
21
 
28
22
  Each enabled runtime's catalog Summary includes a short executable inline body, with
29
23
  literal `\n` separators keeping the invocation on one discovery line.
30
24
 
31
- ### A script — the `(target)` slot
25
+ ### The `(target)` slot — a script or working directory
32
26
 
33
- The table above is the **inline** form: the body is the program. A file in the
34
- `(target)` slot is instead the script each interpreter reads directly, and the
35
- body becomes that script's stdin. A `[{"cwd": "<directory>"}]` block on the heading
36
- selects the working directory. Script arguments use `[{"args": ["arg",...]}]`;
37
- each string is passed literally, without shell expansion ({§executor-metadata}).
38
- These options work for local, Worker, and Skill script targets alike.
27
+ The table above is the **inline** form: the body is the program. A directory in
28
+ the `(target)` slot selects the working directory for that inline program. A
29
+ file in the `(target)` slot is instead the script each interpreter reads
30
+ directly, and the body is tokenized by shell quoting (`tokenizeArgv`) into the
31
+ script's arguments ({§executor-subprocess}, {§executor-contract}).
39
32
 
40
33
  ```sh (./deploy.sh)
41
- yes
42
- yes
43
- no
34
+ --release "two words"
44
35
  ```
45
36
 
46
- ```python3 (transform.py) [{"args": ["--format","json"]}]
47
- 3
48
- 1
49
- 4
50
- 1
51
- 5
37
+ ```python3 (transform.py)
38
+ --format json
52
39
  ```
53
40
 
54
- The first operation answers a shell script's prompts through stdin. The second
55
- feeds records to a Python script.
56
-
57
- All declared tags run host code, so every invocation is proposal-gated. The
58
- current installed in-process evaluators are jq and SQLite; their
59
- `pure` or `read` invocations bypass the proposal gate but still return through
60
- the same next-turn stream path ({§executor-effect}). Inline programs have no
61
- separate input channel; script targets receive stdin from the body.
41
+ All declared tags run host code, so every invocation is proposal-gated ({§executor-results}). Inline programs have no
42
+ separate input channel; script targets receive their arguments from the body.
62
43
 
63
44
  ## Configuration
64
45
 
65
- The shipped [`.env.defaults`](./.env.defaults) disables `perl`, `ruby`, `lua`,
66
- `deno`, `bun`, `tcl`, `bc`, and `awk`. To expose one, set its switch to `1`
67
- in the ordinary environment cascade and restart the service; commented opt-ins
68
- are in [`.env.example`](./.env.example). For example, `PLURNK_EXECS_PERL=1`
69
- enables the Perl executor when Perl is installed. These switches do not prevent
70
- calling an interpreter through `sh`.
71
-
72
46
  Per-tag kill-switches (`PLURNK_EXECS_<TAG>=0`) and the
73
47
  `PLURNK_EXECS_ONLY` allowlist are honored by framework discovery, uniformly
74
48
  across every extension ({§executor-policy}). A disabled tag is not registered and
75
49
  never reaches this executor.
76
50
 
51
+ ## Alignment with Node's permission framework
52
+
53
+ Node's `--permission` model is natively conditional: unflagged `js` invocations run
54
+ with normal Node semantics, while passing `--permission` flags through
55
+ `NODE_OPTIONS` confines `js` child processes at access time (`ERR_ACCESS_DENIED`)
56
+ without adding any PLURNK-specific knob or altering default behavior.
57
+
58
+ | Step | Existing surface | Effect |
59
+ | --- | --- | --- |
60
+ | 1. Remove out-of-model interpreters | `PLURNK_EXECS_ONLY=js` | Unregisters `sh` and `python3` at discovery ({§executor-policy}); downstream layers cannot re-enable them. |
61
+ | 2. Confine `js` children | `NODE_OPTIONS="--permission --allow-fs-read=<workspace> --allow-fs-write=<workspace>"` | Confines filesystem reads and writes to `<workspace>` and denies `child_process` spawning (`ERR_ACCESS_DENIED`). |
62
+ | 3. Discover daemon envelope (optional) | `node --permission-audit ...` | Audits paths the daemon itself touches (run root, checkout, `node_modules`) before launching the daemon under `--permission`. |
63
+
64
+ **Scope choices** ({§execution-output-identity}):
65
+
66
+ - **Workspace scope** (`plurnk_env (add)` with `scope: "workspace"`): `NODE_OPTIONS` reaches both `js` execution children and Node-based MCP server subprocesses in the workspace.
67
+ - **Session scope** (`plurnk_env (add)` with `scope: "session"`): `NODE_OPTIONS` reaches `js` execution children of that session only.
68
+
69
+ **Honest ledger:** Node's permission model provides same-UID accident containment, not adversarial security boundaries. PLURNK owns authority, consent, and audit, and never claims containment; for OS-account separation, combine with `PLURNK_EXECS_SPAWN_USER` ({§executor-policy}) or an external container/VM sandbox.
70
+
77
71
  ## Tests
78
72
 
79
73
  `test:lint`, `test:unit`. Live-eval tests auto-skip where the interpreter is absent.
package/dist/Common.d.ts CHANGED
@@ -1,6 +1,7 @@
1
+ import { type RuntimeTag } from "@plurnk/plurnk-contracts";
1
2
  import { SubprocessExecutor } from "@plurnk/plurnk-execs";
2
3
  import type { RuntimeAvailability, SpawnArgs } from "@plurnk/plurnk-execs";
3
- export declare const RUNTIME_TAGS: readonly string[];
4
+ export declare const RUNTIME_TAGS: readonly RuntimeTag[];
4
5
  export default class Common extends SubprocessExecutor {
5
6
  #private;
6
7
  protected spawnArgs(runtime: string, command: string, target?: string | null): SpawnArgs;
@@ -1 +1 @@
1
- {"version":3,"file":"Common.d.ts","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAwB,MAAM,sBAAsB,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAmC3E,eAAO,MAAM,YAAY,EAAE,SAAS,MAAM,EAAwC,CAAC;AAenF,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,kBAAkB;;IAClD,UAAmB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,GAAG,IAAW,GAAG,SAAS,CActG;IAQc,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAOnD;CACJ"}
1
+ {"version":3,"file":"Common.d.ts","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAsC,MAAM,sBAAsB,CAAC;AAC9F,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAmB3E,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAA8D,CAAC;AAK7G,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,kBAAkB;;IAClD,UAAmB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,GAAG,IAAW,GAAG,SAAS,CAUtG;IAQc,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAOnD;CACJ"}
package/dist/Common.js CHANGED
@@ -1,53 +1,29 @@
1
1
  import { spawnSync } from "node:child_process";
2
- import { SubprocessExecutor, SpawnAccounts, Shell } from "@plurnk/plurnk-execs";
2
+ import { isExecutionOp } from "@plurnk/plurnk-contracts";
3
+ import { SubprocessExecutor, SpawnAccounts, Shell, tokenizeArgv } from "@plurnk/plurnk-execs";
3
4
  const RECIPES = Object.freeze({
4
- // Subprocess floor. `sh`'s bin is the shell the environment names ({§executor-shell}), resolved at use.
5
+ // Subprocess floor. `sh`'s bin is the shell the environment names ({§executor-subprocess}), resolved at use.
5
6
  sh: { bin: "sh", arg: (c) => ["-c", c] },
6
- node: { bin: "node", arg: (c) => ["-e", c], alwaysAvailable: true },
7
+ js: { bin: "node", arg: (c) => ["-e", c], alwaysAvailable: true },
7
8
  python3: { bin: "python3", arg: (c) => ["-c", c] },
8
- // Detected host interpreters.
9
- perl: { bin: "perl", arg: (c) => ["-e", c] },
10
- ruby: { bin: "ruby", arg: (c) => ["-e", c] },
11
- lua: { bin: "lua", arg: (c) => ["-e", c] },
12
- deno: { bin: "deno", arg: (c) => ["eval", c] },
13
- bun: { bin: "bun", arg: (c) => ["-e", c] },
14
- tcl: { bin: "tclsh", stdin: true },
15
- bc: { bin: "bc", stdin: true },
16
- awk: { bin: "awk", bare: true, script: (target) => ["-f", target] },
17
9
  });
18
10
  // Exposed for tests / consumers wanting the candidate set.
19
- export const RUNTIME_TAGS = Object.freeze(Object.keys(RECIPES));
20
- // PATH presence via POSIX `command -v` — robust across interpreters that don't
21
- // support `--version` (tclsh, bc, some awks). bin is from the fixed table above.
22
- const onPath = (bin) => spawnSync("sh", ["-c", `command -v "$1"`, "sh", bin], { ...SpawnAccounts.options() }).status === 0; // {§executor-spawn-account}
23
- // Detection harness: one package claiming the common-REPL tags. probe() lights
24
- // up only the interpreters present on this host, so the consumer offers the
25
- // model exactly what the platform has — "plurnk supports the host's REPLs out
26
- // of the box". The operator kill-switch (PLURNK_EXECS_<tag>=0 / _ONLY) is no
27
- // longer honored here — framework discovery applies it uniformly across every
28
- // extension ({§executor-policy}), so a disabled tag never reaches probe(). All run
29
- // arbitrary code → effect `host` (inherited, proposal-gated). Reuses
30
- // SubprocessExecutor's run() (streaming + process-group abort) via spawnArgs().
11
+ export const RUNTIME_TAGS = Object.freeze(Object.keys(RECIPES).filter(isExecutionOp));
12
+ const onPath = (bin) => spawnSync("sh", ["-c", `command -v "$1"`, "sh", bin], { ...SpawnAccounts.options() }).status === 0; // {§executor-policy}
31
13
  export default class Common extends SubprocessExecutor {
32
14
  spawnArgs(runtime, command, target = null) {
33
15
  const r = Common.#recipe(runtime);
34
16
  if (r === undefined)
35
17
  throw new Error(`plurnk-execs-common received unclaimed runtime tag '${runtime}'`);
36
- // With a target the program IS the target and the body is its stdin
37
- // ({§executor-subprocess-routing}). The interpreter reads the file;
38
- // no executable bit is consulted or changed.
18
+ // With a target the program IS the target and the body is its arguments,
19
+ // tokenized by shell quoting ({§executor-subprocess}, {§executor-contract}).
20
+ // The interpreter reads the file; no executable bit is consulted or changed.
39
21
  if (target !== null) {
40
- return { cmd: r.bin, args: r.script?.(target) ?? [target], useShell: false, stdin: command };
22
+ return { cmd: r.bin, args: [target, ...tokenizeArgv(command)], useShell: false };
41
23
  }
42
- // Trailing newline so line-oriented readers (bc, tclsh) evaluate the
43
- // final line before EOF rather than erroring on an unterminated line.
44
- if (r.stdin)
45
- return { cmd: r.bin, args: [], useShell: false, stdin: `${command}\n` };
46
- if (r.bare)
47
- return { cmd: r.bin, args: [command], useShell: false, stdin: "" };
48
24
  return { cmd: r.bin, args: r.arg(command), useShell: false };
49
25
  }
50
- // {§executor-shell} `sh` runs the environment's shell; every other recipe is fixed.
26
+ // {§executor-subprocess} `sh` runs the environment's shell; every other recipe is fixed.
51
27
  static #recipe(runtime) {
52
28
  const r = RECIPES[runtime];
53
29
  return runtime === "sh" && r !== undefined ? { ...r, bin: Shell.current().path } : r;
@@ -1 +1 @@
1
- {"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtimes.d.ts","sourceRoot":"","sources":["../src/runtimes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAsN/D,eAAO,MAAM,QAAQ,QAAO,WAAW,EAAoE,CAAC"}
1
+ {"version":3,"file":"runtimes.d.ts","sourceRoot":"","sources":["../src/runtimes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA8D/D,eAAO,MAAM,QAAQ,QAAO,WAAW,EAAoE,CAAC"}
package/dist/runtimes.js CHANGED
@@ -1,16 +1,16 @@
1
- // {§executor-dynamic-runtimes} The common package's declarations. `sh` names the shell it runs
2
- // ({§executor-shell}), resolved on this host; every other declaration is fixed.
1
+ // {§executor-discovery} The common package's declarations. `sh` names the shell it runs
2
+ // ({§executor-subprocess}), resolved on this host; every other declaration is fixed.
3
3
  import { Shell } from "@plurnk/plurnk-execs";
4
4
  const SH = {
5
5
  name: "sh",
6
6
  glyph: "🐚",
7
7
  invocation: {
8
8
  body: {
9
- role: "the shell program; stdin when the target is a script",
9
+ role: "the shell program; arguments when the target is a script",
10
10
  required: false,
11
11
  },
12
12
  target: {
13
- role: "script; never a command or a directory",
13
+ role: "script, or working directory for an inline program",
14
14
  required: false,
15
15
  kind: "script",
16
16
  },
@@ -21,16 +21,16 @@ const SH = {
21
21
  };
22
22
  const FIXED = [
23
23
  {
24
- name: "node",
24
+ name: "js",
25
25
  glyph: "⬢",
26
26
  summary: "Run JavaScript code or scripts with Node.js.",
27
27
  invocation: {
28
28
  body: {
29
- role: "JavaScript program; stdin when the target is a script",
29
+ role: "JavaScript program; arguments when the target is a script",
30
30
  required: false,
31
31
  },
32
32
  target: {
33
- role: "script; never a command or a directory",
33
+ role: "script, or working directory for an inline program",
34
34
  required: false,
35
35
  kind: "script",
36
36
  },
@@ -45,11 +45,11 @@ const FIXED = [
45
45
  summary: "Run Python 3 code or scripts.",
46
46
  invocation: {
47
47
  body: {
48
- role: "Python program; stdin when the target is a script",
48
+ role: "Python program; arguments when the target is a script",
49
49
  required: false,
50
50
  },
51
51
  target: {
52
- role: "script; never a command or a directory",
52
+ role: "script, or working directory for an inline program",
53
53
  required: false,
54
54
  kind: "script",
55
55
  },
@@ -58,158 +58,6 @@ const FIXED = [
58
58
  },
59
59
  },
60
60
  },
61
- {
62
- name: "perl",
63
- glyph: "🐪",
64
- summary: "Run Perl code or scripts.",
65
- invocation: {
66
- body: {
67
- role: "Perl program; stdin when the target is a script",
68
- required: false,
69
- },
70
- target: {
71
- role: "script; never a command or a directory",
72
- required: false,
73
- kind: "script",
74
- },
75
- example: {
76
- body: "print 42;",
77
- },
78
- },
79
- },
80
- {
81
- name: "ruby",
82
- glyph: "💎",
83
- summary: "Run Ruby code or scripts.",
84
- invocation: {
85
- body: {
86
- role: "Ruby program; stdin when the target is a script",
87
- required: false,
88
- },
89
- target: {
90
- role: "script; never a command or a directory",
91
- required: false,
92
- kind: "script",
93
- },
94
- example: {
95
- body: "puts 42",
96
- },
97
- },
98
- },
99
- {
100
- name: "lua",
101
- glyph: "🌙",
102
- summary: "Run Lua code or scripts.",
103
- invocation: {
104
- body: {
105
- role: "Lua program; stdin when the target is a script",
106
- required: false,
107
- },
108
- target: {
109
- role: "script; never a command or a directory",
110
- required: false,
111
- kind: "script",
112
- },
113
- example: {
114
- body: "print(42)",
115
- },
116
- },
117
- },
118
- {
119
- name: "deno",
120
- glyph: "🦕",
121
- summary: "Run TypeScript or JavaScript code or scripts with Deno.",
122
- invocation: {
123
- body: {
124
- role: "Deno program; stdin when the target is a script",
125
- required: false,
126
- },
127
- target: {
128
- role: "script; never a command or a directory",
129
- required: false,
130
- kind: "script",
131
- },
132
- example: {
133
- body: "console.log(42)",
134
- },
135
- },
136
- },
137
- {
138
- name: "bun",
139
- glyph: "🥟",
140
- summary: "Run TypeScript or JavaScript code or scripts with Bun.",
141
- invocation: {
142
- body: {
143
- role: "Bun program; stdin when the target is a script",
144
- required: false,
145
- },
146
- target: {
147
- role: "script; never a command or a directory",
148
- required: false,
149
- kind: "script",
150
- },
151
- example: {
152
- body: "console.log(42)",
153
- },
154
- },
155
- },
156
- {
157
- name: "tcl",
158
- glyph: "🪶",
159
- summary: "Run Tcl code or scripts.",
160
- invocation: {
161
- body: {
162
- role: "Tcl program; stdin when the target is a script",
163
- required: false,
164
- },
165
- target: {
166
- role: "script; never a command or a directory",
167
- required: false,
168
- kind: "script",
169
- },
170
- example: {
171
- body: "puts 42",
172
- },
173
- },
174
- },
175
- {
176
- name: "bc",
177
- glyph: "🧮",
178
- summary: "Evaluate calculations with bc.",
179
- invocation: {
180
- body: {
181
- role: "bc program; stdin when the target is a script",
182
- required: false,
183
- },
184
- target: {
185
- role: "script; never a command or a directory",
186
- required: false,
187
- kind: "script",
188
- },
189
- example: {
190
- body: "6 * 7",
191
- },
192
- },
193
- },
194
- {
195
- name: "awk",
196
- glyph: "🪄",
197
- summary: "Run AWK code or scripts.",
198
- invocation: {
199
- body: {
200
- role: "AWK program; stdin when the target is a script",
201
- required: false,
202
- },
203
- target: {
204
- role: "script; never a command or a directory",
205
- required: false,
206
- kind: "script",
207
- },
208
- example: {
209
- body: "BEGIN { print 42 }",
210
- },
211
- },
212
- },
213
61
  ];
214
62
  export const runtimes = () => [{ ...SH, summary: Shell.summary(Shell.current()) }, ...FIXED];
215
63
  //# sourceMappingURL=runtimes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtimes.js","sourceRoot":"","sources":["../src/runtimes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtimes.js","sourceRoot":"","sources":["../src/runtimes.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,qFAAqF;AACrF,OAAO,EAAE,KAAK,EAAoB,MAAM,sBAAsB,CAAC;AAE/D,MAAM,EAAE,GAAiC;IACrC,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;IACX,UAAU,EAAE;QACR,IAAI,EAAE;YACF,IAAI,EAAE,0DAA0D;YAChE,QAAQ,EAAE,KAAK;SAClB;QACD,MAAM,EAAE;YACJ,IAAI,EAAE,oDAAoD;YAC1D,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,QAAQ;SACjB;QACD,OAAO,EAAE;YACL,IAAI,EAAE,oBAAoB;SAC7B;KACJ;CACJ,CAAC;AAEF,MAAM,KAAK,GAA2B;IAClC;QACI,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,GAAG;QACV,OAAO,EAAE,8CAA8C;QACvD,UAAU,EAAE;YACR,IAAI,EAAE;gBACF,IAAI,EAAE,2DAA2D;gBACjE,QAAQ,EAAE,KAAK;aAClB;YACD,MAAM,EAAE;gBACJ,IAAI,EAAE,oDAAoD;gBAC1D,QAAQ,EAAE,KAAK;gBACf,IAAI,EAAE,QAAQ;aACjB;YACD,OAAO,EAAE;gBACL,IAAI,EAAE,iBAAiB;aAC1B;SACJ;KACJ;IACD;QACI,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,+BAA+B;QACxC,UAAU,EAAE;YACR,IAAI,EAAE;gBACF,IAAI,EAAE,uDAAuD;gBAC7D,QAAQ,EAAE,KAAK;aAClB;YACD,MAAM,EAAE;gBACJ,IAAI,EAAE,oDAAoD;gBAC1D,QAAQ,EAAE,KAAK;gBACf,IAAI,EAAE,QAAQ;aACjB;YACD,OAAO,EAAE;gBACL,IAAI,EAAE,WAAW;aACpB;SACJ;KACJ;CACJ,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAkB,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC"}
package/docs/js.md ADDED
@@ -0,0 +1,18 @@
1
+ # js
2
+
3
+ A JavaScript snippet, run via `node -e`. Node is the daemon's own runtime, so it
4
+ is always available (no PATH probe).
5
+
6
+ ```js <!-- the body is the snippet -->
7
+ const os = require("node:os");
8
+ console.log(JSON.stringify({ platform: os.platform(), cpus: os.cpus().length }));
9
+ ```
10
+
11
+ `js (tool.js)` runs that JavaScript file and passes the body as its arguments
12
+ (tokenized by shell quoting), also for `session://` and `skill://` targets.
13
+ Relative imports resolve from the script; ordinary relative filesystem paths
14
+ resolve from the working directory. Environment, working directory, channels,
15
+ output on completion, exit status and lifetime are every subprocess executor's,
16
+ as `plurnk:///sh.md` states. Stdout is text, so structured output is serialized
17
+ (`console.log(JSON.stringify(value))`); a thrown error exits nonzero with its
18
+ stack on stderr.
package/docs/python3.md CHANGED
@@ -1,18 +1,17 @@
1
1
  # python3
2
2
 
3
- The body is Python code, run with `python3 -c`. A script target instead runs
4
- that file and receives the body as stdin; `[{"args": [...]}]` passes literal
5
- arguments and `[{"cwd": "<directory>"}]` selects the working directory, as for
6
- every interpreter (`sh.md`).
3
+ The body is Python code, run with `python3 -c`. A directory in the `(target)`
4
+ slot selects the working directory for that inline code. A script target instead
5
+ runs that file and passes the body as its arguments (tokenized by shell
6
+ quoting), as for every interpreter (`plurnk:///sh.md`).
7
7
 
8
8
  ```python3 <!-- the body is the program -->
9
9
  import json, sys
10
10
  print(json.dumps({"python": list(sys.version_info[:2])}))
11
11
  ```
12
12
 
13
- ```python3 (tools/report.py) [{"args": ["--help"]}]
13
+ ```python3 (tools/report.py)
14
+ --help
14
15
  ```
15
16
 
16
17
  Native skill files retain their sibling imports and source-relative assets.
17
- Live input (`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md`
18
- shows.
package/docs/sh.md CHANGED
@@ -9,31 +9,27 @@ printf 'hello\n' > hello.txt
9
9
  wc -l hello.txt
10
10
  ```
11
11
 
12
- A script target runs that script: `sh (greet.sh)` runs it with an empty stdin;
13
- a nonempty body becomes its stdin. The interpreter reads the script directly,
14
- so it needs no executable bit; a script path authored inside a shell body still
15
- follows the kernel's ordinary executable-bit rules. Script arguments go in
16
- `[{"args": ["--release","two words"]}]`: each string is one literal argument,
17
- without shell expansion. The target is a program, never a command and never a
18
- directory; a target that is not a script is refused before anything runs. The
19
- same options apply to local, `worker://`, and `skill://` script targets across
20
- every interpreter.
12
+ A script target runs that script: `sh (greet.sh)` runs it with no arguments;
13
+ a nonempty body is tokenized by shell quoting and passed as its arguments
14
+ (plain words split on whitespace, quoted arguments stay whole, nothing is
15
+ expanded). The interpreter reads the script directly, so it needs no executable
16
+ bit; a script path authored inside a shell body still follows the kernel's
17
+ ordinary executable-bit rules. The same applies to local, `session://`, and
18
+ `skill://` script targets across every interpreter.
21
19
 
22
20
  ## Environment
23
21
 
24
22
  The command receives a scoped environment: provider keys and every `PLURNK_*`
25
23
  setting are stripped before the child starts, so `printenv` cannot read
26
- plurnk's credentials, and the project's environment passes through.
27
- `[{"env": {"LC_ALL": "C"}}]` on the fence line sets variables for this run
28
- alone, over the entries in the `env` registry (`env.md`); plurnk's own names
29
- are refused by name.
24
+ plurnk's credentials, and the project's environment passes through, overlaid
25
+ with the `env` registry (`mcp:///plurnk_env.md`).
30
26
 
31
27
  ## Working directory
32
28
 
33
29
  The working directory is the workspace project root, or in a workspace without
34
- one the directory the shell would run in anyway. `[{"cwd": "<directory>"}]` on
35
- the fence line overrides it for its body; a receipt names the directory,
36
- relative to the project root, only when the command ran elsewhere.
30
+ one the directory the shell would run in anyway. A directory in the `(target)`
31
+ slot overrides it for an inline body (`sh (packages/api)`); a receipt names the
32
+ directory, relative to the project root, only when the command ran elsewhere.
37
33
 
38
34
  ## Channels
39
35
 
@@ -67,10 +63,4 @@ npm test
67
63
 
68
64
  Expiry closes the stream with status 504. By contrast, `WAIT [30]` limits one
69
65
  wait to 30 seconds without stopping the command. Without `lifetime`,
70
- the command is loop-bound; see `env.md` for other lifetime values.
71
-
72
- ## Live input
73
-
74
- `[{"stdin": "open"}]` keeps stdin open for later SENDs to the returned execution
75
- address; `[{"eof": true}]` closes it. The worked example, including newline
76
- framing, is on `node.md`.
66
+ the command is loop-bound; see `mcp:///plurnk_env.md` for other `lifetime` values (`detached`, `turn`).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@plurnk/plurnk-execs-common",
3
- "version": "3.0.1",
4
- "description": "Universal subprocess executor for plurnk-service's exec scheme — one package exposing the shell, Node.js, Python 3, and supported host interpreters.",
3
+ "version": "3.0.2",
4
+ "description": "Subprocess executor for plurnk-service's exec scheme — exposing the shell, Node.js, and Python 3.",
5
5
  "keywords": [
6
6
  "plurnk",
7
7
  "exec",
@@ -10,7 +10,7 @@
10
10
  "subprocess",
11
11
  "repl",
12
12
  "shell",
13
- "node",
13
+ "js",
14
14
  "python3"
15
15
  ],
16
16
  "homepage": "https://github.com/plurnk/plurnk-service/tree/main/plurnk-execs-common#readme",
@@ -49,13 +49,11 @@
49
49
  "files": [
50
50
  "dist/**/*",
51
51
  "README.md",
52
- ".env.defaults",
53
- ".env.example",
54
52
  "docs/**/*"
55
53
  ],
56
54
  "scripts": {
57
55
  "test:lint": "tsc --noEmit",
58
- "test:unit": "node --conditions=plurnk-dev --env-file-if-exists=.env.defaults --env-file-if-exists=../plurnk-execs/.env.defaults --test ${PLURNK_TEST_CONCURRENCY:+--test-concurrency=$PLURNK_TEST_CONCURRENCY} \"src/**/*.test.ts\"",
56
+ "test:unit": "node --conditions=plurnk-dev --env-file-if-exists=../plurnk-execs/.env.defaults --experimental-test-coverage --test-coverage-include-all '--test-coverage-include=src/**' --test ${PLURNK_TEST_CONCURRENCY:+--test-concurrency=$PLURNK_TEST_CONCURRENCY} \"src/**/*.test.ts\"",
59
57
  "test": "npm run test:lint && npm run test:unit",
60
58
  "build:clean": "rm -rf dist",
61
59
  "build:dist": "tsc -p tsconfig.build.json",
@@ -64,7 +62,8 @@
64
62
  "prepublishOnly": "npm audit --audit-level=moderate && npm test"
65
63
  },
66
64
  "peerDependencies": {
65
+ "@plurnk/plurnk-contracts": "^7.0.0",
67
66
  "@plurnk/plurnk-execs": "^4.0.0"
68
67
  },
69
- "gitHead": "d2647f7ec0d352b276714f22a93267aac04634b3"
68
+ "gitHead": "db65532b51408a2014f7ff53a288d834ff6694f2"
70
69
  }
package/.env.defaults DELETED
@@ -1,11 +0,0 @@
1
- # @plurnk/plurnk-execs-common — secondary interpreters are opt-in.
2
- # Set a runtime to 1 to register it; its interpreter must also be on PATH.
3
- # sh, node, and python3 remain enabled through the executor framework's default.
4
- PLURNK_EXECS_PERL=0
5
- PLURNK_EXECS_RUBY=0
6
- PLURNK_EXECS_LUA=0
7
- PLURNK_EXECS_DENO=0
8
- PLURNK_EXECS_BUN=0
9
- PLURNK_EXECS_TCL=0
10
- PLURNK_EXECS_BC=0
11
- PLURNK_EXECS_AWK=0
package/.env.example DELETED
@@ -1,13 +0,0 @@
1
- # @plurnk/plurnk-execs-common — environment
2
-
3
- # sh, node, and python3 are enabled when their interpreter is available.
4
- # Uncomment any optional runtime to enable it at the next service start.
5
- # An enabled runtime still requires its interpreter on PATH.
6
- # PLURNK_EXECS_PERL=1
7
- # PLURNK_EXECS_RUBY=1
8
- # PLURNK_EXECS_LUA=1
9
- # PLURNK_EXECS_DENO=1
10
- # PLURNK_EXECS_BUN=1
11
- # PLURNK_EXECS_TCL=1
12
- # PLURNK_EXECS_BC=1
13
- # PLURNK_EXECS_AWK=1
package/docs/awk.md DELETED
@@ -1,21 +0,0 @@
1
- # awk
2
-
3
- The body is the AWK program, passed as the one positional argument with an
4
- empty stdin: with no input file it only runs `BEGIN` blocks. Input files are
5
- named in `[{"args": [...]}]`; a script target runs that file and receives the
6
- body as stdin. Working directory, environment, channels and exit status are
7
- every subprocess executor's (`sh.md`); `exit 1` in the program is a nonzero `exitCode`.
8
-
9
- ```awk [{"args": ["data.csv"]}] <!-- the body is the program -->
10
- BEGIN { FS = "," }
11
- NR > 1 { total += $3 }
12
- END { printf "rows=%d total=%.2f\n", NR - 1, total }
13
- ```
14
-
15
- ```awk (tools/summarize.awk) <!-- the script runs; the body is its stdin -->
16
- alpha,1
17
- beta,2
18
- ```
19
-
20
- Live input (`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md`
21
- shows.
package/docs/bc.md DELETED
@@ -1,17 +0,0 @@
1
- # bc
2
-
3
- The body is a `bc` program fed on stdin (a trailing newline is added, so the
4
- last line evaluates). Arbitrary precision: `scale` is set before dividing, or
5
- every quotient is truncated to an integer.
6
-
7
- ```bc <!-- the body is the program -->
8
- scale=6
9
- 22/7
10
- 2^64
11
- ```
12
-
13
- Each expression prints its value on its own line to `#stdout`; `#stderr`
14
- carries parse errors such as `syntax error`, and the exit status is 0 even when
15
- a line failed to parse, so a missing result is explained on `#stderr`. A script
16
- target (`bc (rates.bc)`) runs that file with the body as stdin. Live input
17
- (`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md` shows.
package/docs/bun.md DELETED
@@ -1,18 +0,0 @@
1
- # bun
2
-
3
- The body is TypeScript or JavaScript, run with `bun -e`. A script target runs
4
- that file and receives the body as stdin; `[{"args": [...]}]` passes literal
5
- arguments, readable as `Bun.argv` or `process.argv`. Node is always present;
6
- bun only when the host has it.
7
-
8
- ```bun <!-- the body is the program -->
9
- const file = Bun.file("package.json");
10
- console.log((await file.json()).name);
11
- ```
12
-
13
- ```bun (scripts/build.ts) [{"args": ["--watch=false"]}]
14
- ```
15
-
16
- `console.log` streams to `#stdout`, `console.error` to `#stderr`; an uncaught
17
- error or `process.exit(1)` is a nonzero `exitCode`. Live input
18
- (`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md` shows.
package/docs/deno.md DELETED
@@ -1,19 +0,0 @@
1
- # deno
2
-
3
- The body is TypeScript or JavaScript, run with `deno eval` (permissions are
4
- Deno's defaults for `eval`; imports come from the project or a URL). A script
5
- target runs that file and receives the body as stdin; `[{"args": [...]}]` passes
6
- literal arguments, readable as `Deno.args`. Node is always present; deno only
7
- when the host has it.
8
-
9
- ```deno <!-- the body is the program -->
10
- const versions: Record<string, string> = Deno.version;
11
- console.log(JSON.stringify(versions));
12
- ```
13
-
14
- ```deno (scripts/check.ts) [{"args": ["--strict"]}]
15
- ```
16
-
17
- `console.log` streams to `#stdout`, `console.error` to `#stderr`; an uncaught
18
- error or `Deno.exit(1)` is a nonzero `exitCode`. Live input
19
- (`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md` shows.
package/docs/lua.md DELETED
@@ -1,20 +0,0 @@
1
- # lua
2
-
3
- The body is Lua code, run with `lua -e`. A script target runs that file and
4
- receives the body as stdin; `[{"args": [...]}]` passes literal script
5
- arguments, readable through the `arg` table.
6
-
7
- ```lua <!-- the body is the program -->
8
- local t = { 3, 1, 2 }
9
- table.sort(t)
10
- print(table.concat(t, ","))
11
- ```
12
-
13
- ```lua (scripts/lint.lua) [{"args": ["src/main.lua"]}]
14
- ```
15
-
16
- `print` streams to `#stdout`, `io.stderr:write` to `#stderr`; `error(...)` or
17
- `os.exit(1)` is a nonzero `exitCode`. The standalone interpreter is the host's
18
- `lua` on PATH; project modules resolve through its ordinary `package.path` from
19
- the working directory. Live input (`[{"stdin": "open"}]`, SEND,
20
- `[{"eof": true}]`) is as `node.md` shows.
package/docs/node.md DELETED
@@ -1,44 +0,0 @@
1
- # node
2
-
3
- A JavaScript snippet, run via `node -e`. Node is the daemon's own runtime, so it
4
- is always available (no PATH probe).
5
-
6
- ```node <!-- the body is the snippet -->
7
- const os = require("node:os");
8
- console.log(JSON.stringify({ platform: os.platform(), cpus: os.cpus().length }));
9
- ```
10
-
11
- `node (tool.js)` runs that JavaScript file and receives the body as stdin;
12
- `[{"args": ["--format","json"]}]` passes literal script arguments, also for
13
- `worker://` and `skill://` targets. Relative imports resolve from the script;
14
- ordinary relative filesystem paths resolve from the working directory.
15
- Environment, working directory, channels, output on completion, exit status and lifetime
16
- are every subprocess executor's, as `sh.md` states. Stdout is text, so structured
17
- output is serialized (`console.log(JSON.stringify(value))`); a thrown error
18
- exits nonzero with its stack on stderr.
19
-
20
- ## Live input
21
-
22
- `[{"stdin": "open"}]` keeps stdin open for later SENDs to the receipt's execution
23
- address. Without it, initial input ends with EOF as usual.
24
-
25
- ```node [{"stdin": "open"}]
26
- process.stdin.on("data", chunk => process.stdout.write(chunk));
27
- ```
28
-
29
- Using the address returned by that invocation (here `node:///ab3d5678`):
30
-
31
- ```SEND (node:///ab3d5678)
32
- hello
33
-
34
- ```
35
-
36
- The blank line before the closing fence supplies a newline after `hello`.
37
- SEND adds no newline of its own. Its receipt acknowledges pipe delivery, not
38
- program completion. READ that same address to inspect stdout while it runs.
39
-
40
- ```SEND (node:///ab3d5678) [{"eof": true}]
41
- ```
42
-
43
- EOF closes stdin, not the process. KILL terminates the execution. Any worker
44
- in the workspace can send input to the same execution address.
package/docs/perl.md DELETED
@@ -1,19 +0,0 @@
1
- # perl
2
-
3
- The body is Perl code, run with `perl -e`; `-n`/`-p` have no equivalent here,
4
- so a line loop is written in the body. A script target runs that file and
5
- receives the body as stdin; `[{"args": [...]}]` passes literal arguments.
6
- Environment, channels and exit status are every subprocess executor's (`sh.md`):
7
- `die` or a nonzero `exit` is a nonzero `exitCode`.
8
-
9
- ```perl <!-- the body is the program -->
10
- use strict; use warnings;
11
- my %count; $count{$_}++ for qw(a b a c a);
12
- printf "%s=%d\n", $_, $count{$_} for sort keys %count;
13
- ```
14
-
15
- ```perl (tools/rename.pl) [{"args": ["--dry-run"]}]
16
- ```
17
-
18
- Live input (`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md`
19
- shows.
package/docs/ruby.md DELETED
@@ -1,20 +0,0 @@
1
- # ruby
2
-
3
- The body is Ruby code, run with `ruby -e`. A script target runs that file and
4
- receives the body as stdin; `[{"args": [...]}]` passes literal `ARGV` entries.
5
-
6
- ```ruby <!-- the body is the program -->
7
- require "json"
8
- words = %w[alpha beta alpha]
9
- puts JSON.generate(words.tally)
10
- ```
11
-
12
- ```ruby (bin/migrate.rb) [{"args": ["--check"]}]
13
- ```
14
-
15
- `puts` and `print` stream to `#stdout`, `warn` to `#stderr`; an unrescued
16
- exception or `exit 1` is a nonzero `exitCode` with the backtrace on stderr. Gems
17
- resolve from the project's ordinary Ruby environment; `[{"cwd": "<directory>"}]`
18
- selects the working directory when the project's `Gemfile` lives elsewhere.
19
- Environment metadata is every subprocess executor's (`sh.md`). Live input
20
- (`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md` shows.
package/docs/tcl.md DELETED
@@ -1,20 +0,0 @@
1
- # tcl
2
-
3
- The body is a Tcl script fed to `tclsh` on stdin (a trailing newline is added).
4
- A script target runs that file and receives the body as stdin;
5
- `[{"args": [...]}]` passes literal arguments, readable as `$argv`.
6
-
7
- ```tcl <!-- the body is the program -->
8
- set words {alpha beta alpha}
9
- foreach w $words { dict incr count $w }
10
- puts [dict get $count alpha]
11
- ```
12
-
13
- ```tcl (tests/all.tcl) [{"args": ["-verbose","bps"]}]
14
- ```
15
-
16
- `puts` streams to `#stdout`, `puts stderr ...` to `#stderr`; an uncaught error
17
- or `exit 1` is a nonzero `exitCode` with the Tcl error info on stderr. tclsh
18
- evaluates the script line by line, so an incomplete command at the end is an
19
- error, not a silent no-op. Live input (`[{"stdin": "open"}]`, SEND,
20
- `[{"eof": true}]`) is as `node.md` shows.