@plurnk/plurnk-execs-common 3.0.0 → 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 +42 -48
- package/dist/Common.d.ts +2 -1
- package/dist/Common.d.ts.map +1 -1
- package/dist/Common.js +11 -35
- package/dist/Common.js.map +1 -1
- package/dist/runtimes.d.ts.map +1 -1
- package/dist/runtimes.js +9 -161
- package/dist/runtimes.js.map +1 -1
- package/docs/js.md +18 -0
- package/docs/python3.md +6 -7
- package/docs/sh.md +13 -23
- package/package.json +6 -7
- package/.env.defaults +0 -11
- package/.env.example +0 -13
- package/docs/awk.md +0 -21
- package/docs/bc.md +0 -17
- package/docs/bun.md +0 -18
- package/docs/deno.md +0 -19
- package/docs/lua.md +0 -20
- package/docs/node.md +0 -44
- package/docs/perl.md +0 -19
- package/docs/ruby.md +0 -20
- package/docs/tcl.md +0 -20
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# @plurnk/plurnk-execs-common
|
|
2
2
|
|
|
3
|
-
The **
|
|
4
|
-
[plurnk-service](https://github.com/plurnk/plurnk-service)'s `
|
|
5
|
-
package offers the shell, Node.js, and Python 3
|
|
6
|
-
|
|
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
|
|
15
|
-
|
|
16
|
-
| Tag
|
|
17
|
-
|
|
|
18
|
-
| `sh` 🐚
|
|
19
|
-
| `
|
|
20
|
-
| `python3` 🐍
|
|
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
|
-
###
|
|
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
|
|
34
|
-
`(target)` slot
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
42
|
-
yes
|
|
43
|
-
no
|
|
34
|
+
--release "two words"
|
|
44
35
|
```
|
|
45
36
|
|
|
46
|
-
```python3 (transform.py)
|
|
47
|
-
|
|
48
|
-
1
|
|
49
|
-
4
|
|
50
|
-
1
|
|
51
|
-
5
|
|
37
|
+
```python3 (transform.py)
|
|
38
|
+
--format json
|
|
52
39
|
```
|
|
53
40
|
|
|
54
|
-
|
|
55
|
-
|
|
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
|
|
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;
|
package/dist/Common.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Common.d.ts","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,
|
|
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 {
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
37
|
-
// ({§executor-subprocess-
|
|
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:
|
|
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-
|
|
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;
|
package/dist/Common.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"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"}
|
package/dist/runtimes.d.ts.map
CHANGED
|
@@ -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;
|
|
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-
|
|
2
|
-
// ({§executor-
|
|
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;
|
|
9
|
+
role: "the shell program; arguments when the target is a script",
|
|
10
10
|
required: false,
|
|
11
11
|
},
|
|
12
12
|
target: {
|
|
13
|
-
role: "script
|
|
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: "
|
|
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;
|
|
29
|
+
role: "JavaScript program; arguments when the target is a script",
|
|
30
30
|
required: false,
|
|
31
31
|
},
|
|
32
32
|
target: {
|
|
33
|
-
role: "script
|
|
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;
|
|
48
|
+
role: "Python program; arguments when the target is a script",
|
|
49
49
|
required: false,
|
|
50
50
|
},
|
|
51
51
|
target: {
|
|
52
|
-
role: "script
|
|
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
|
package/dist/runtimes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimes.js","sourceRoot":"","sources":["../src/runtimes.ts"],"names":[],"mappings":"AAAA
|
|
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
|
|
4
|
-
|
|
5
|
-
|
|
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)
|
|
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
|
|
13
|
-
a nonempty body
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
`
|
|
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.
|
|
35
|
-
|
|
36
|
-
directory the command ran
|
|
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 `
|
|
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.
|
|
4
|
-
"description": "
|
|
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
|
-
"
|
|
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
|
|
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": "
|
|
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.
|