@plurnk/plurnk-execs-common 1.20.0 → 1.21.1
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/.env.defaults +11 -0
- package/.env.example +11 -13
- package/README.md +14 -7
- package/docs/awk.md +10 -19
- package/docs/bc.md +9 -14
- package/docs/bun.md +8 -12
- package/docs/deno.md +10 -14
- package/docs/lua.md +11 -14
- package/docs/node.md +19 -39
- package/docs/perl.md +11 -15
- package/docs/python3.md +10 -18
- package/docs/ruby.md +8 -14
- package/docs/sh.md +50 -65
- package/docs/tcl.md +8 -11
- package/package.json +4 -3
package/.env.defaults
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
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
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
# @plurnk/plurnk-execs-common — environment
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# PLURNK_EXECS_BC=0
|
|
15
|
-
# PLURNK_EXECS_AWK=0
|
|
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/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The **universal subprocess executor** for
|
|
4
4
|
[plurnk-service](https://github.com/plurnk/plurnk-service)'s `exec` scheme. One
|
|
5
|
-
package
|
|
6
|
-
interpreters
|
|
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.
|
|
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
|
|
|
@@ -25,7 +25,7 @@ detects every other interpreter, so one executor adapts to the host.
|
|
|
25
25
|
| `bc` 🧮 | bc | stdin (for example, `6 * 7`) |
|
|
26
26
|
| `awk` 🪄 | awk | program arg, empty stdin (`BEGIN { … }`) |
|
|
27
27
|
|
|
28
|
-
Each runtime's catalog Summary includes a short executable inline body, with
|
|
28
|
+
Each enabled runtime's catalog Summary includes a short executable inline body, with
|
|
29
29
|
literal `\n` separators keeping the invocation on one discovery line.
|
|
30
30
|
|
|
31
31
|
### A script — the `(target)` slot
|
|
@@ -37,19 +37,19 @@ selects the working directory. Script arguments use `[{"args": ["arg",...]}]`;
|
|
|
37
37
|
each string is passed literally, without shell expansion ({§executor-metadata}).
|
|
38
38
|
These options work for local, Worker, and Skill script targets alike.
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
```sh (./deploy.sh)
|
|
41
41
|
yes
|
|
42
42
|
yes
|
|
43
43
|
no
|
|
44
|
-
|
|
44
|
+
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
```python3 (transform.py) [{"args": ["--format","json"]}]
|
|
47
47
|
3
|
|
48
48
|
1
|
|
49
49
|
4
|
|
50
50
|
1
|
|
51
51
|
5
|
|
52
|
-
|
|
52
|
+
```
|
|
53
53
|
|
|
54
54
|
The first operation answers a shell script's prompts through stdin. The second
|
|
55
55
|
feeds records to a Python script.
|
|
@@ -62,6 +62,13 @@ separate input channel; script targets receive stdin from the body.
|
|
|
62
62
|
|
|
63
63
|
## Configuration
|
|
64
64
|
|
|
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
|
+
|
|
65
72
|
Per-tag kill-switches (`PLURNK_EXECS_<TAG>=0`) and the
|
|
66
73
|
`PLURNK_EXECS_ONLY` allowlist are honored by framework discovery, uniformly
|
|
67
74
|
across every plugin ({§executor-policy}). A disabled tag is not registered and
|
package/docs/awk.md
CHANGED
|
@@ -1,30 +1,21 @@
|
|
|
1
1
|
# awk
|
|
2
2
|
|
|
3
|
-
For continuing input, launch with `[{"stdin": "open"}]`, then SEND exact text to the
|
|
4
|
-
returned execution address; `[{"eof": true}]` closes stdin. See the
|
|
5
|
-
[live-input example](node.md#live-input), including newline framing.
|
|
6
|
-
|
|
7
3
|
The body is the AWK program, passed as the one positional argument with an
|
|
8
|
-
empty stdin: with no input file it only runs `BEGIN` blocks.
|
|
9
|
-
|
|
10
|
-
as stdin.
|
|
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 the
|
|
7
|
+
executor family's (`sh.md`); `exit 1` in the program closes with status 500.
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
```awk [{"args": ["data.csv"]}] <!-- the body is the program -->
|
|
13
10
|
BEGIN { FS = "," }
|
|
14
11
|
NR > 1 { total += $3 }
|
|
15
12
|
END { printf "rows=%d total=%.2f\n", NR - 1, total }
|
|
16
|
-
|
|
13
|
+
```
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
```awk (tools/summarize.awk) <!-- the script runs; the body is its stdin -->
|
|
19
16
|
alpha,1
|
|
20
17
|
beta,2
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Output goes to `#stdout`, diagnostics to `#stderr`; `exit 1` in the program
|
|
24
|
-
closes with status 500. `[{"cwd": "<directory>"}]` selects the working directory
|
|
25
|
-
for relative file arguments. AWK is the right tool for column arithmetic and
|
|
26
|
-
line reshaping over text; for JSON use `jq`, for anything else `node` or `sh`.
|
|
18
|
+
```
|
|
27
19
|
|
|
28
|
-
`[{"
|
|
29
|
-
|
|
30
|
-
(`PLURNK_*`, provider credentials) are refused by name.
|
|
20
|
+
Live input (`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md`
|
|
21
|
+
shows.
|
package/docs/bc.md
CHANGED
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
# bc
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
6
|
|
|
7
|
-
|
|
8
|
-
line evaluates). Arbitrary precision: set `scale` before dividing, or every
|
|
9
|
-
quotient is truncated to an integer.
|
|
10
|
-
|
|
11
|
-
````bc <!-- the body is the program -->
|
|
7
|
+
```bc <!-- the body is the program -->
|
|
12
8
|
scale=6
|
|
13
9
|
22/7
|
|
14
10
|
2^64
|
|
15
|
-
|
|
11
|
+
```
|
|
16
12
|
|
|
17
13
|
Each expression prints its value on its own line to `#stdout`; `#stderr`
|
|
18
|
-
carries parse errors such as `syntax error
|
|
19
|
-
a line failed to parse, so
|
|
20
|
-
target (`bc (rates.bc)`) runs that file with the body as stdin.
|
|
21
|
-
|
|
22
|
-
loops over data, or JSON, reach for `awk`, `node`, or `sh`.
|
|
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
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
# bun
|
|
2
2
|
|
|
3
|
-
For continuing input, launch with `[{"stdin": "open"}]`, then SEND exact text to the
|
|
4
|
-
returned execution address; `[{"eof": true}]` closes stdin. See the
|
|
5
|
-
[live-input example](node.md#live-input), including newline framing.
|
|
6
|
-
|
|
7
3
|
The body is TypeScript or JavaScript, run with `bun -e`. A script target runs
|
|
8
4
|
that file and receives the body as stdin; `[{"args": [...]}]` passes literal
|
|
9
|
-
arguments, readable as `Bun.argv` or `process.argv`.
|
|
5
|
+
arguments, readable as `Bun.argv` or `process.argv`. Node is always present;
|
|
6
|
+
bun only when the host has it.
|
|
10
7
|
|
|
11
|
-
|
|
8
|
+
```bun <!-- the body is the program -->
|
|
12
9
|
const file = Bun.file("package.json");
|
|
13
10
|
console.log((await file.json()).name);
|
|
14
|
-
|
|
11
|
+
```
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
```bun (scripts/build.ts) [{"args": ["--watch=false"]}]
|
|
14
|
+
```
|
|
18
15
|
|
|
19
16
|
`console.log` streams to `#stdout`, `console.error` to `#stderr`; an uncaught
|
|
20
|
-
error or `process.exit(1)` closes with status 500.
|
|
21
|
-
|
|
22
|
-
has it.
|
|
17
|
+
error or `process.exit(1)` closes with status 500. Live input
|
|
18
|
+
(`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md` shows.
|
package/docs/deno.md
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
# deno
|
|
2
2
|
|
|
3
|
-
For continuing input, launch with `[{"stdin": "open"}]`, then SEND exact text to the
|
|
4
|
-
returned execution address; `[{"eof": true}]` closes stdin. See the
|
|
5
|
-
[live-input example](node.md#live-input), including newline framing.
|
|
6
|
-
|
|
7
3
|
The body is TypeScript or JavaScript, run with `deno eval` (permissions are
|
|
8
|
-
Deno's defaults for `eval`;
|
|
9
|
-
|
|
10
|
-
|
|
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.
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
```deno <!-- the body is the program -->
|
|
13
10
|
const versions: Record<string, string> = Deno.version;
|
|
14
11
|
console.log(JSON.stringify(versions));
|
|
15
|
-
|
|
12
|
+
```
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
```deno (scripts/check.ts) [{"args": ["--strict"]}]
|
|
15
|
+
```
|
|
19
16
|
|
|
20
17
|
`console.log` streams to `#stdout`, `console.error` to `#stderr`; an uncaught
|
|
21
|
-
error or `Deno.exit(1)` closes with status 500.
|
|
22
|
-
|
|
23
|
-
host has it.
|
|
18
|
+
error or `Deno.exit(1)` closes with status 500. Live input
|
|
19
|
+
(`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md` shows.
|
package/docs/lua.md
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
# lua
|
|
2
2
|
|
|
3
|
-
For continuing input, launch with `[{"stdin": "open"}]`, then SEND exact text to the
|
|
4
|
-
returned execution address; `[{"eof": true}]` closes stdin. See the
|
|
5
|
-
[live-input example](node.md#live-input), including newline framing.
|
|
6
|
-
|
|
7
3
|
The body is Lua code, run with `lua -e`. A script target runs that file and
|
|
8
|
-
receives the body as stdin; `[{"args": [...]}]` passes literal script
|
|
9
|
-
readable through the `arg` table.
|
|
4
|
+
receives the body as stdin; `[{"args": [...]}]` passes literal script
|
|
5
|
+
arguments, readable through the `arg` table.
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
```lua <!-- the body is the program -->
|
|
12
8
|
local t = { 3, 1, 2 }
|
|
13
9
|
table.sort(t)
|
|
14
10
|
print(table.concat(t, ","))
|
|
15
|
-
|
|
11
|
+
```
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
```lua (scripts/lint.lua) [{"args": ["src/main.lua"]}]
|
|
14
|
+
```
|
|
19
15
|
|
|
20
|
-
`print` streams to `#stdout`, `io.stderr:write` to `#stderr`; `error(...)`
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
`print` streams to `#stdout`, `io.stderr:write` to `#stderr`; `error(...)` or
|
|
17
|
+
`os.exit(1)` closes with status 500. 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
CHANGED
|
@@ -1,64 +1,44 @@
|
|
|
1
1
|
# node
|
|
2
2
|
|
|
3
|
-
A JavaScript snippet, run via `node -e`. Node is the daemon's own runtime, so it
|
|
3
|
+
A JavaScript snippet, run via `node -e`. Node is the daemon's own runtime, so it
|
|
4
|
+
is always available (no PATH probe).
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
```node <!-- the body is the snippet -->
|
|
6
7
|
const os = require("node:os");
|
|
7
8
|
console.log(JSON.stringify({ platform: os.platform(), cpus: os.cpus().length }));
|
|
8
|
-
|
|
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, first page, exit status and lifetime
|
|
16
|
+
are the executor family'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 (status 500) with its stack on stderr.
|
|
9
19
|
|
|
10
20
|
## Live input
|
|
11
21
|
|
|
12
22
|
`[{"stdin": "open"}]` keeps stdin open for later SENDs to the receipt's execution
|
|
13
23
|
address. Without it, initial input ends with EOF as usual.
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
```node [{"stdin": "open"}]
|
|
16
26
|
process.stdin.on("data", chunk => process.stdout.write(chunk));
|
|
17
|
-
|
|
27
|
+
```
|
|
18
28
|
|
|
19
29
|
Using the address returned by that invocation (here `node:///ab3d5678`):
|
|
20
30
|
|
|
21
|
-
|
|
31
|
+
```SEND (node:///ab3d5678)
|
|
22
32
|
hello
|
|
23
33
|
|
|
24
|
-
|
|
34
|
+
```
|
|
25
35
|
|
|
26
36
|
The blank line before the closing fence supplies a newline after `hello`.
|
|
27
37
|
SEND adds no newline of its own. Its receipt acknowledges pipe delivery, not
|
|
28
38
|
program completion. READ that same address to inspect stdout while it runs.
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
```SEND (node:///ab3d5678) [{"eof": true}]
|
|
41
|
+
```
|
|
32
42
|
|
|
33
43
|
EOF closes stdin, not the process. KILL terminates the execution. Any worker
|
|
34
44
|
in the workspace can send input to the same execution address.
|
|
35
|
-
|
|
36
|
-
## Environment
|
|
37
|
-
|
|
38
|
-
The same scoped environment as `sh`: the daemon's own secrets (`PLURNK_*`, provider keys) are stripped, so `process.env` inside the snippet sees the project's environment, not plurnk's.
|
|
39
|
-
|
|
40
|
-
## Output
|
|
41
|
-
|
|
42
|
-
Whatever the snippet writes to stdout streams to `#stdout`; stderr streams to
|
|
43
|
-
`#stderr`. Both are text under the receipt's `stream` address, such as
|
|
44
|
-
`node:///ab3d5678`. On completion, the harness adds a READ of each channel's
|
|
45
|
-
first page (up to 16 lines). READ the stream address for additional lines;
|
|
46
|
-
the log READ holds only its recorded page. To return structured data, use
|
|
47
|
-
`console.log(JSON.stringify(value))`. A thrown error exits nonzero (status 500)
|
|
48
|
-
with its stack on stderr. The receipt's own body is the snippet as you sent
|
|
49
|
-
it, never output; a non-200 receipt with no `stream` address ran nothing.
|
|
50
|
-
|
|
51
|
-
## Working directory
|
|
52
|
-
|
|
53
|
-
Runs in the workspace project root by default, or the daemon's own cwd in a
|
|
54
|
-
workspace without one; a `[{"cwd": "<directory>"}]` block on the opening fence line selects
|
|
55
|
-
another. The target is a script, never a command or a directory:
|
|
56
|
-
`node (tool.js)` runs that JavaScript file and receives the body as
|
|
57
|
-
stdin. `[{"args": ["--format","json"]}]` passes literal script arguments, also for
|
|
58
|
-
`worker://` and `skill://` targets. Relative imports resolve from the script;
|
|
59
|
-
ordinary relative filesystem paths resolve from cwd. The receipt names cwd
|
|
60
|
-
when it differs from the project root.
|
|
61
|
-
|
|
62
|
-
`[{"env": {"NAME": "value"}}]` on the same fence line sets variables for this run
|
|
63
|
-
alone, over the entries in your `env` registry; names are the shell's, and plurnk's own
|
|
64
|
-
(`PLURNK_*`, provider credentials) are refused by name.
|
package/docs/perl.md
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
# perl
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[
|
|
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 the executor family's (`sh.md`):
|
|
7
|
+
`die` or a nonzero `exit` closes with status 500.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
receives the body as stdin; `[{"args": [...]}]` passes literal script arguments.
|
|
9
|
-
|
|
10
|
-
````perl <!-- the body is the program -->
|
|
9
|
+
```perl <!-- the body is the program -->
|
|
11
10
|
use strict; use warnings;
|
|
12
11
|
my %count; $count{$_}++ for qw(a b a c a);
|
|
13
12
|
printf "%s=%d\n", $_, $count{$_} for sort keys %count;
|
|
14
|
-
|
|
13
|
+
```
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
```perl (tools/rename.pl) [{"args": ["--dry-run"]}]
|
|
16
|
+
```
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
(plurnk's own settings and provider keys are stripped). Use `-n`/`-p`-style
|
|
22
|
-
one-liners by writing the loop yourself, or run a script target over the
|
|
23
|
-
files you name in `{args}`.
|
|
18
|
+
Live input (`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md`
|
|
19
|
+
shows.
|
package/docs/python3.md
CHANGED
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
# python3
|
|
2
2
|
|
|
3
|
-
For continuing input, launch with `[{"stdin": "open"}]`, then SEND exact text to the
|
|
4
|
-
returned execution address; `[{"eof": true}]` closes stdin. See the
|
|
5
|
-
[live-input example](node.md#live-input), including newline framing.
|
|
6
|
-
|
|
7
3
|
The body is Python code, run with `python3 -c`. A script target instead runs
|
|
8
|
-
that file and receives the body as stdin
|
|
9
|
-
|
|
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`).
|
|
10
7
|
|
|
11
|
-
|
|
8
|
+
```python3 <!-- the body is the program -->
|
|
12
9
|
import json, sys
|
|
13
10
|
print(json.dumps({"python": list(sys.version_info[:2])}))
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
````python3 (tools/report.py) [{"args": ["--help"]}]
|
|
17
|
-
````
|
|
11
|
+
```
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
same options apply to local and `worker://` script targets. Native skill files
|
|
22
|
-
retain their sibling imports and source-relative assets.
|
|
13
|
+
```python3 (tools/report.py) [{"args": ["--help"]}]
|
|
14
|
+
```
|
|
23
15
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
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/ruby.md
CHANGED
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
# ruby
|
|
2
2
|
|
|
3
|
-
For continuing input, launch with `[{"stdin": "open"}]`, then SEND exact text to the
|
|
4
|
-
returned execution address; `[{"eof": true}]` closes stdin. See the
|
|
5
|
-
[live-input example](node.md#live-input), including newline framing.
|
|
6
|
-
|
|
7
3
|
The body is Ruby code, run with `ruby -e`. A script target runs that file and
|
|
8
4
|
receives the body as stdin; `[{"args": [...]}]` passes literal `ARGV` entries.
|
|
9
5
|
|
|
10
|
-
|
|
6
|
+
```ruby <!-- the body is the program -->
|
|
11
7
|
require "json"
|
|
12
8
|
words = %w[alpha beta alpha]
|
|
13
9
|
puts JSON.generate(words.tally)
|
|
14
|
-
|
|
10
|
+
```
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
```ruby (bin/migrate.rb) [{"args": ["--check"]}]
|
|
13
|
+
```
|
|
18
14
|
|
|
19
15
|
`puts` and `print` stream to `#stdout`, `warn` to `#stderr`; an unrescued
|
|
20
|
-
exception or `exit 1` closes with status 500 with the backtrace on stderr.
|
|
21
|
-
|
|
16
|
+
exception or `exit 1` closes with status 500 with the backtrace on stderr. Gems
|
|
17
|
+
resolve from the project's ordinary Ruby environment; `[{"cwd": "<directory>"}]`
|
|
22
18
|
selects the working directory when the project's `Gemfile` lives elsewhere.
|
|
23
|
-
|
|
24
|
-
`[{"
|
|
25
|
-
alone, over the entries in your `env` registry; names are the shell's, and plurnk's own
|
|
26
|
-
(`PLURNK_*`, provider credentials) are refused by name.
|
|
19
|
+
Environment metadata is the executor family's (`sh.md`). Live input
|
|
20
|
+
(`[{"stdin": "open"}]`, SEND, `[{"eof": true}]`) is as `node.md` shows.
|
package/docs/sh.md
CHANGED
|
@@ -1,92 +1,77 @@
|
|
|
1
1
|
# sh
|
|
2
2
|
|
|
3
|
-
For continuing input, launch with `[{"stdin": "open"}]`, then SEND exact text to the
|
|
4
|
-
returned execution address; `[{"eof": true}]` closes stdin. See the
|
|
5
|
-
[live-input example](node.md#live-input), including newline framing.
|
|
6
|
-
|
|
7
3
|
The `sh` fence runs the body via `sh -c`, character-perfect including whitespace.
|
|
8
4
|
|
|
9
|
-
|
|
5
|
+
```sh <!-- the body is the script itself -->
|
|
10
6
|
printf 'hello\n' > hello.txt
|
|
11
7
|
wc -l hello.txt
|
|
12
|
-
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
A script target runs that script: `sh (greet.sh)` runs it with an empty stdin;
|
|
11
|
+
a nonempty body becomes its stdin. The interpreter reads the script directly,
|
|
12
|
+
so it needs no executable bit; a script path authored inside a shell body still
|
|
13
|
+
follows the kernel's ordinary executable-bit rules. Script arguments go in
|
|
14
|
+
`[{"args": ["--release","two words"]}]`: each string is one literal argument,
|
|
15
|
+
without shell expansion. The target is a program, never a command and never a
|
|
16
|
+
directory; a target that is not a script is refused before anything runs. The
|
|
17
|
+
same options apply to local, `worker://`, and `skill://` script targets across
|
|
18
|
+
every interpreter.
|
|
13
19
|
|
|
14
20
|
## Environment
|
|
15
21
|
|
|
16
|
-
The command receives a
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
The command receives a scoped environment: provider keys and every `PLURNK_*`
|
|
23
|
+
setting are stripped before the child starts, so `printenv` cannot read
|
|
24
|
+
plurnk's credentials, and the project's environment passes through.
|
|
25
|
+
`[{"env": {"LC_ALL": "C"}}]` on the fence line sets variables for this run
|
|
26
|
+
alone, over the entries in the `env` registry (`env.md`); plurnk's own names
|
|
27
|
+
are refused by name.
|
|
19
28
|
|
|
20
29
|
## Working directory
|
|
21
30
|
|
|
22
|
-
The working directory is the workspace project root
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
````sh [{"cwd": "./dir"}]
|
|
27
|
-
pwd
|
|
28
|
-
````
|
|
29
|
-
|
|
30
|
-
The receipt always names the directory the command ran in.
|
|
31
|
-
|
|
32
|
-
`env` on the same line sets variables for this run alone, over the entries in
|
|
33
|
-
your `env` registry; plurnk's own names (`PLURNK_*`, provider credentials) are
|
|
34
|
-
refused by name:
|
|
35
|
-
|
|
36
|
-
````sh [{"env": {"LC_ALL": "C"}}]
|
|
37
|
-
sort names.txt
|
|
38
|
-
````
|
|
39
|
-
|
|
40
|
-
A script target runs that script: `sh (greet.sh)` runs it with an empty
|
|
41
|
-
stdin; a nonempty body becomes its stdin. The interpreter reads the script
|
|
42
|
-
directly, so it needs no executable bit; a script path authored inside a shell
|
|
43
|
-
body still follows the kernel's ordinary executable-bit rules.
|
|
44
|
-
|
|
45
|
-
Script arguments go in `[{"args": ["--release","two words"]}]`: each string is
|
|
46
|
-
one literal argument, without shell expansion. The same options apply to
|
|
47
|
-
local, `worker://`, and `skill://` script targets across the common interpreters.
|
|
48
|
-
|
|
49
|
-
The target is a program — a script — never a command and never a directory. A
|
|
50
|
-
target that is not a script is refused before anything runs.
|
|
31
|
+
The working directory is the workspace project root, or in a workspace without
|
|
32
|
+
one the directory the shell would run in anyway. `[{"cwd": "<directory>"}]` on
|
|
33
|
+
the fence line overrides it for its body; the receipt always names the
|
|
34
|
+
directory the command ran in.
|
|
51
35
|
|
|
52
36
|
## Channels
|
|
53
37
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
`path` for more; the `log:///…/READ` item holds only its recorded page:
|
|
63
|
-
|
|
64
|
-
````READ (sh:///ab3d5678#stdout) <17,40>
|
|
65
|
-
````
|
|
38
|
+
An execution is a host effect, admitted under the loop's policy. Output streams
|
|
39
|
+
under the receipt's `stream` address, such as `sh:///ab3d5678`: `#stdout` is
|
|
40
|
+
the default channel and `#stderr` the second; both are `text/stream`. While it
|
|
41
|
+
runs, the packet's `## Delegation` streams list reports each channel's size and
|
|
42
|
+
growth, and READ can inspect any range. On completion, the harness adds one
|
|
43
|
+
`_plurnk` READ per channel: its first page, `range` extent, and terminal exit
|
|
44
|
+
status. READ the observation's `path` for more; the `log:///…/READ` item holds
|
|
45
|
+
only its recorded page:
|
|
66
46
|
|
|
67
|
-
|
|
68
|
-
|
|
47
|
+
```READ (sh:///ab3d5678#stdout) <17,40>
|
|
48
|
+
```
|
|
69
49
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
with a non-200 status and no
|
|
73
|
-
|
|
50
|
+
A nonzero exit closes with status 500; stdout and stderr are separate channels,
|
|
51
|
+
and a diagnostic may be on either. The `log:///…/sh` receipt's own body is the
|
|
52
|
+
program exactly as sent, never output. A receipt with a non-200 status and no
|
|
53
|
+
`stream` address ran nothing; its body is still the program, and its Problem
|
|
54
|
+
says why it was refused.
|
|
74
55
|
|
|
75
56
|
## Lifetime
|
|
76
57
|
|
|
77
58
|
How long a command may run is one metadata field; absent, it ends with the loop.
|
|
78
59
|
|
|
79
|
-
|
|
60
|
+
```sh [{"lifetime": "30m"}]
|
|
80
61
|
npm run e2e
|
|
81
|
-
|
|
62
|
+
```
|
|
82
63
|
|
|
83
|
-
|
|
64
|
+
```sh [{"lifetime": "detached"}]
|
|
84
65
|
npm run dev
|
|
85
|
-
|
|
66
|
+
```
|
|
86
67
|
|
|
87
68
|
A duration (`30s`, `30m`, `2h`) kills the command at that deadline. `detached`
|
|
88
|
-
outlives the loop
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
69
|
+
outlives the loop: it runs until it exits or is KILLed. `turn` keeps the command
|
|
70
|
+
only through the current turn. While a stream is live, observation wakes arrive
|
|
71
|
+
on the daemon's cadence and present it for inspection.
|
|
72
|
+
|
|
73
|
+
## Live input
|
|
74
|
+
|
|
75
|
+
`[{"stdin": "open"}]` keeps stdin open for later SENDs to the returned execution
|
|
76
|
+
address; `[{"eof": true}]` closes it. The worked example, including newline
|
|
77
|
+
framing, is on `node.md`.
|
package/docs/tcl.md
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
# tcl
|
|
2
2
|
|
|
3
|
-
For continuing input, launch with `[{"stdin": "open"}]`, then SEND exact text to the
|
|
4
|
-
returned execution address; `[{"eof": true}]` closes stdin. See the
|
|
5
|
-
[live-input example](node.md#live-input), including newline framing.
|
|
6
|
-
|
|
7
3
|
The body is a Tcl script fed to `tclsh` on stdin (a trailing newline is added).
|
|
8
|
-
A script target runs that file and receives the body as stdin;
|
|
9
|
-
passes literal arguments, readable as `$argv`.
|
|
4
|
+
A script target runs that file and receives the body as stdin;
|
|
5
|
+
`[{"args": [...]}]` passes literal arguments, readable as `$argv`.
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
```tcl <!-- the body is the program -->
|
|
12
8
|
set words {alpha beta alpha}
|
|
13
9
|
foreach w $words { dict incr count $w }
|
|
14
10
|
puts [dict get $count alpha]
|
|
15
|
-
|
|
11
|
+
```
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
```tcl (tests/all.tcl) [{"args": ["-verbose","bps"]}]
|
|
14
|
+
```
|
|
19
15
|
|
|
20
16
|
`puts` streams to `#stdout`, `puts stderr ...` to `#stderr`; an uncaught error
|
|
21
17
|
or `exit 1` closes with status 500 with the Tcl error info on stderr. tclsh
|
|
22
18
|
evaluates the script line by line, so an incomplete command at the end is an
|
|
23
|
-
error, not a silent no-op.
|
|
19
|
+
error, not a silent no-op. Live input (`[{"stdin": "open"}]`, SEND,
|
|
20
|
+
`[{"eof": true}]`) is as `node.md` shows.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plurnk/plurnk-execs-common",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.1",
|
|
4
4
|
"description": "Universal subprocess executor for plurnk-service's exec scheme — one package exposing the shell, Node.js, Python 3, and supported host interpreters.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"plurnk",
|
|
@@ -255,12 +255,13 @@
|
|
|
255
255
|
"files": [
|
|
256
256
|
"dist/**/*",
|
|
257
257
|
"README.md",
|
|
258
|
+
".env.defaults",
|
|
258
259
|
".env.example",
|
|
259
260
|
"docs/**/*"
|
|
260
261
|
],
|
|
261
262
|
"scripts": {
|
|
262
263
|
"test:lint": "tsc --noEmit",
|
|
263
|
-
"test:unit": "node --conditions=plurnk-dev --env-file-if-exists=../plurnk-execs/.env.defaults --test \"src/**/*.test.ts\"",
|
|
264
|
+
"test:unit": "node --conditions=plurnk-dev --env-file-if-exists=.env.defaults --env-file-if-exists=../plurnk-execs/.env.defaults --test \"src/**/*.test.ts\"",
|
|
264
265
|
"test": "npm run test:lint && npm run test:unit",
|
|
265
266
|
"build:clean": "rm -rf dist",
|
|
266
267
|
"build:dist": "tsc -p tsconfig.build.json",
|
|
@@ -269,6 +270,6 @@
|
|
|
269
270
|
"prepublishOnly": "npm audit --audit-level=moderate && npm test"
|
|
270
271
|
},
|
|
271
272
|
"peerDependencies": {
|
|
272
|
-
"@plurnk/plurnk-execs": "^1.
|
|
273
|
+
"@plurnk/plurnk-execs": "^1.21.1"
|
|
273
274
|
}
|
|
274
275
|
}
|