@plurnk/plurnk-execs-common 1.16.5 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -10
- package/dist/Common.d.ts.map +1 -1
- package/dist/Common.js +4 -9
- package/dist/Common.js.map +1 -1
- package/docs/awk.md +30 -0
- package/docs/bc.md +22 -0
- package/docs/bun.md +22 -0
- package/docs/deno.md +23 -0
- package/docs/lua.md +23 -0
- package/docs/node.md +48 -9
- package/docs/perl.md +23 -0
- package/docs/python3.md +26 -0
- package/docs/ruby.md +26 -0
- package/docs/sh.md +54 -21
- package/docs/tcl.md +23 -0
- package/package.json +32 -12
package/README.md
CHANGED
|
@@ -25,27 +25,31 @@ 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
|
|
29
|
+
literal `\n` separators keeping the invocation on one discovery line.
|
|
30
|
+
|
|
28
31
|
### A script — the `(target)` slot
|
|
29
32
|
|
|
30
33
|
The table above is the **inline** form: the body is the program. A file in the
|
|
31
34
|
`(target)` slot is instead the script each interpreter reads directly, and the
|
|
32
|
-
body becomes that script's stdin. A `{cwd
|
|
33
|
-
selects the working directory
|
|
34
|
-
({§executor-
|
|
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.
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
### EXEC0 (./deploy.sh)
|
|
40
|
+
````sh (./deploy.sh)
|
|
38
41
|
yes
|
|
39
42
|
yes
|
|
40
43
|
no
|
|
44
|
+
````
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
````python3 (transform.py) [{"args": ["--format","json"]}]
|
|
43
47
|
3
|
|
44
48
|
1
|
|
45
49
|
4
|
|
46
50
|
1
|
|
47
51
|
5
|
|
48
|
-
|
|
52
|
+
````
|
|
49
53
|
|
|
50
54
|
The first operation answers a shell script's prompts through stdin. The second
|
|
51
55
|
feeds records to a Python script.
|
|
@@ -53,9 +57,8 @@ feeds records to a Python script.
|
|
|
53
57
|
All declared tags run host code, so every invocation is proposal-gated. The
|
|
54
58
|
current installed in-process evaluators are jq and SQLite; their
|
|
55
59
|
`pure` or `read` invocations bypass the proposal gate but still return through
|
|
56
|
-
the same next-turn stream path ({§executor-effect}).
|
|
57
|
-
|
|
58
|
-
are not claimed here.
|
|
60
|
+
the same next-turn stream path ({§executor-effect}). Inline programs have no
|
|
61
|
+
separate input channel; script targets receive stdin from the body.
|
|
59
62
|
|
|
60
63
|
## Configuration
|
|
61
64
|
|
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,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"Common.d.ts","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,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;IAEc,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAOnD;CACJ"}
|
package/dist/Common.js
CHANGED
|
@@ -13,7 +13,7 @@ const RECIPES = Object.freeze({
|
|
|
13
13
|
bun: { bin: "bun", arg: (c) => ["-e", c] },
|
|
14
14
|
tcl: { bin: "tclsh", stdin: true },
|
|
15
15
|
bc: { bin: "bc", stdin: true },
|
|
16
|
-
awk: { bin: "awk", bare: true },
|
|
16
|
+
awk: { bin: "awk", bare: true, script: (target) => ["-f", target] },
|
|
17
17
|
});
|
|
18
18
|
// Exposed for tests / consumers wanting the candidate set.
|
|
19
19
|
export const RUNTIME_TAGS = Object.freeze(Object.keys(RECIPES));
|
|
@@ -34,15 +34,10 @@ export default class Common extends SubprocessExecutor {
|
|
|
34
34
|
if (r === undefined)
|
|
35
35
|
throw new Error(`plurnk-execs-common received unclaimed runtime tag '${runtime}'`);
|
|
36
36
|
// With a target the program IS the target and the body is its stdin
|
|
37
|
-
// ({§executor-subprocess-routing})
|
|
38
|
-
//
|
|
39
|
-
// READS the file, so no exec bit is consulted and none is ever set.
|
|
40
|
-
// The old shell `-c` arm made the shell execve() the target instead
|
|
41
|
-
// (PATH lookup on bare names, +x demanded on EDIT-created scripts) and
|
|
42
|
-
// doubled as an unsanctioned command-line side door — commands belong
|
|
43
|
-
// in the body.
|
|
37
|
+
// ({§executor-subprocess-routing}). The interpreter reads the file;
|
|
38
|
+
// no executable bit is consulted or changed.
|
|
44
39
|
if (target !== null) {
|
|
45
|
-
return { cmd: r.bin, args: [target], useShell: false, stdin: command };
|
|
40
|
+
return { cmd: r.bin, args: r.script?.(target) ?? [target], useShell: false, stdin: command };
|
|
46
41
|
}
|
|
47
42
|
// Trailing newline so line-oriented readers (bc, tclsh) evaluate the
|
|
48
43
|
// final line before EOF rather than erroring on an unterminated line.
|
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,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"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"}
|
package/docs/awk.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# awk
|
|
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
|
+
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. To process data,
|
|
9
|
+
name the file(s) in `[{"args": [...]}]`, or run a script target and feed it the body
|
|
10
|
+
as stdin.
|
|
11
|
+
|
|
12
|
+
````awk [{"args": ["data.csv"]}] <!-- the body is the program -->
|
|
13
|
+
BEGIN { FS = "," }
|
|
14
|
+
NR > 1 { total += $3 }
|
|
15
|
+
END { printf "rows=%d total=%.2f\n", NR - 1, total }
|
|
16
|
+
````
|
|
17
|
+
|
|
18
|
+
````awk (tools/summarize.awk) <!-- the script runs; the body is its stdin -->
|
|
19
|
+
alpha,1
|
|
20
|
+
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`.
|
|
27
|
+
|
|
28
|
+
`[{"env": {"NAME": "value"}}]` on the same fence line sets variables for this run
|
|
29
|
+
alone, over the entries in your `env` registry; names are the shell's, and plurnk's own
|
|
30
|
+
(`PLURNK_*`, provider credentials) are refused by name.
|
package/docs/bc.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# bc
|
|
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
|
+
The body is a `bc` program fed on stdin (a trailing newline is added, so the last
|
|
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 -->
|
|
12
|
+
scale=6
|
|
13
|
+
22/7
|
|
14
|
+
2^64
|
|
15
|
+
````
|
|
16
|
+
|
|
17
|
+
Each expression prints its value on its own line to `#stdout`; `#stderr`
|
|
18
|
+
carries parse errors such as `syntax error`. The exit status is 0 even when
|
|
19
|
+
a line failed to parse, so read `#stderr` when a result is missing. A script
|
|
20
|
+
target (`bc (rates.bc)`) runs that file with the body as stdin.
|
|
21
|
+
Use bc for exact decimal or big-integer arithmetic; for anything with strings,
|
|
22
|
+
loops over data, or JSON, reach for `awk`, `node`, or `sh`.
|
package/docs/bun.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# bun
|
|
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
|
+
The body is TypeScript or JavaScript, run with `bun -e`. A script target runs
|
|
8
|
+
that file and receives the body as stdin; `[{"args": [...]}]` passes literal
|
|
9
|
+
arguments, readable as `Bun.argv` or `process.argv`.
|
|
10
|
+
|
|
11
|
+
````bun <!-- the body is the program -->
|
|
12
|
+
const file = Bun.file("package.json");
|
|
13
|
+
console.log((await file.json()).name);
|
|
14
|
+
````
|
|
15
|
+
|
|
16
|
+
````bun (scripts/build.ts) [{"args": ["--watch=false"]}]
|
|
17
|
+
````
|
|
18
|
+
|
|
19
|
+
`console.log` streams to `#stdout`, `console.error` to `#stderr`; an uncaught
|
|
20
|
+
error or `process.exit(1)` closes with status 500. Prefer `node` unless the
|
|
21
|
+
project is a Bun project: node is always present, bun only when the host
|
|
22
|
+
has it.
|
package/docs/deno.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# deno
|
|
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
|
+
The body is TypeScript or JavaScript, run with `deno eval` (permissions are
|
|
8
|
+
Deno's defaults for `eval`; import what you need from the project or a URL).
|
|
9
|
+
A script target runs that file and receives the body as stdin;
|
|
10
|
+
`[{"args": [...]}]` passes literal arguments, readable as `Deno.args`.
|
|
11
|
+
|
|
12
|
+
````deno <!-- the body is the program -->
|
|
13
|
+
const versions: Record<string, string> = Deno.version;
|
|
14
|
+
console.log(JSON.stringify(versions));
|
|
15
|
+
````
|
|
16
|
+
|
|
17
|
+
````deno (scripts/check.ts) [{"args": ["--strict"]}]
|
|
18
|
+
````
|
|
19
|
+
|
|
20
|
+
`console.log` streams to `#stdout`, `console.error` to `#stderr`; an uncaught
|
|
21
|
+
error or `Deno.exit(1)` closes with status 500. Prefer `node` when the task
|
|
22
|
+
does not need Deno specifically: node is always present, deno only when the
|
|
23
|
+
host has it.
|
package/docs/lua.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# lua
|
|
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
|
+
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 arguments,
|
|
9
|
+
readable through the `arg` table.
|
|
10
|
+
|
|
11
|
+
````lua <!-- the body is the program -->
|
|
12
|
+
local t = { 3, 1, 2 }
|
|
13
|
+
table.sort(t)
|
|
14
|
+
print(table.concat(t, ","))
|
|
15
|
+
````
|
|
16
|
+
|
|
17
|
+
````lua (scripts/lint.lua) [{"args": ["src/main.lua"]}]
|
|
18
|
+
````
|
|
19
|
+
|
|
20
|
+
`print` streams to `#stdout`, `io.stderr:write` to `#stderr`; `error(...)`
|
|
21
|
+
or `os.exit(1)` closes with status 500. The standalone interpreter is the
|
|
22
|
+
host's `lua` on PATH; project modules resolve through its ordinary
|
|
23
|
+
`package.path` from the working directory.
|
package/docs/node.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
A JavaScript snippet, run via `node -e`. Node is the daemon's own runtime, so it's always available (no PATH probe).
|
|
4
4
|
|
|
5
|
+
````node <!-- the body is the snippet -->
|
|
6
|
+
const os = require("node:os");
|
|
7
|
+
console.log(JSON.stringify({ platform: os.platform(), cpus: os.cpus().length }));
|
|
8
|
+
````
|
|
9
|
+
|
|
10
|
+
## Live input
|
|
11
|
+
|
|
12
|
+
`[{"stdin": "open"}]` keeps stdin open for later SENDs to the receipt's execution
|
|
13
|
+
address. Without it, initial input ends with EOF as usual.
|
|
14
|
+
|
|
15
|
+
````node [{"stdin": "open"}]
|
|
16
|
+
process.stdin.on("data", chunk => process.stdout.write(chunk));
|
|
17
|
+
````
|
|
18
|
+
|
|
19
|
+
Using the address returned by that invocation (here `node:///ab3d5678`):
|
|
20
|
+
|
|
21
|
+
````SEND (node:///ab3d5678)
|
|
22
|
+
hello
|
|
23
|
+
|
|
24
|
+
````
|
|
25
|
+
|
|
26
|
+
The blank line before the closing fence supplies a newline after `hello`.
|
|
27
|
+
SEND adds no newline of its own. Its receipt acknowledges pipe delivery, not
|
|
28
|
+
program completion. READ that same address to inspect stdout while it runs.
|
|
29
|
+
|
|
30
|
+
````SEND (node:///ab3d5678) [{"eof": true}]
|
|
31
|
+
````
|
|
32
|
+
|
|
33
|
+
EOF closes stdin, not the process. KILL terminates the execution. Any worker
|
|
34
|
+
in the workspace can send input to the same execution address.
|
|
35
|
+
|
|
5
36
|
## Environment
|
|
6
37
|
|
|
7
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.
|
|
@@ -9,17 +40,25 @@ The same scoped environment as `sh`: the daemon's own secrets (`PLURNK_*`, provi
|
|
|
9
40
|
## Output
|
|
10
41
|
|
|
11
42
|
Whatever the snippet writes to stdout streams to `#stdout`; stderr streams to
|
|
12
|
-
`#stderr`. Both are text under the
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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.
|
|
16
50
|
|
|
17
51
|
## Working directory
|
|
18
52
|
|
|
19
53
|
Runs in the workspace project root by default, or the daemon's own cwd in a
|
|
20
|
-
workspace without one; a `{cwd
|
|
54
|
+
workspace without one; a `[{"cwd": "<directory>"}]` block on the opening fence line selects
|
|
21
55
|
another. The target is a script, never a command or a directory:
|
|
22
|
-
|
|
23
|
-
stdin
|
|
24
|
-
|
|
25
|
-
names
|
|
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
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# perl
|
|
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
|
+
The body is Perl code, run with `perl -e`. A script target runs that file and
|
|
8
|
+
receives the body as stdin; `[{"args": [...]}]` passes literal script arguments.
|
|
9
|
+
|
|
10
|
+
````perl <!-- the body is the program -->
|
|
11
|
+
use strict; use warnings;
|
|
12
|
+
my %count; $count{$_}++ for qw(a b a c a);
|
|
13
|
+
printf "%s=%d\n", $_, $count{$_} for sort keys %count;
|
|
14
|
+
````
|
|
15
|
+
|
|
16
|
+
````perl (tools/rename.pl) [{"args": ["--dry-run"]}]
|
|
17
|
+
````
|
|
18
|
+
|
|
19
|
+
stdout streams to `#stdout`, stderr to `#stderr`; `die` or a nonzero `exit`
|
|
20
|
+
closes with status 500. The environment is scoped exactly as for `sh`
|
|
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}`.
|
package/docs/python3.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# python3
|
|
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
|
+
The body is Python code, run with `python3 -c`. A script target instead runs
|
|
8
|
+
that file and receives the body as stdin. Script arguments and working directory
|
|
9
|
+
are optional header metadata:
|
|
10
|
+
|
|
11
|
+
````python3 <!-- the body is the program -->
|
|
12
|
+
import json, sys
|
|
13
|
+
print(json.dumps({"python": list(sys.version_info[:2])}))
|
|
14
|
+
````
|
|
15
|
+
|
|
16
|
+
````python3 (tools/report.py) [{"args": ["--help"]}]
|
|
17
|
+
````
|
|
18
|
+
|
|
19
|
+
Each argument is a literal string, without shell expansion. `[{"cwd": "<directory>"}]`
|
|
20
|
+
selects the working directory; otherwise it remains the workspace root. The
|
|
21
|
+
same options apply to local and `worker://` script targets. Native skill files
|
|
22
|
+
retain their sibling imports and source-relative assets.
|
|
23
|
+
|
|
24
|
+
`[{"env": {"NAME": "value"}}]` on the same fence line sets variables for this run
|
|
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.
|
package/docs/ruby.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# ruby
|
|
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
|
+
The body is Ruby code, run with `ruby -e`. A script target runs that file and
|
|
8
|
+
receives the body as stdin; `[{"args": [...]}]` passes literal `ARGV` entries.
|
|
9
|
+
|
|
10
|
+
````ruby <!-- the body is the program -->
|
|
11
|
+
require "json"
|
|
12
|
+
words = %w[alpha beta alpha]
|
|
13
|
+
puts JSON.generate(words.tally)
|
|
14
|
+
````
|
|
15
|
+
|
|
16
|
+
````ruby (bin/migrate.rb) [{"args": ["--check"]}]
|
|
17
|
+
````
|
|
18
|
+
|
|
19
|
+
`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
|
+
Gems resolve from the project's ordinary Ruby environment; `[{"cwd": "<directory>"}]`
|
|
22
|
+
selects the working directory when the project's `Gemfile` lives elsewhere.
|
|
23
|
+
|
|
24
|
+
`[{"env": {"NAME": "value"}}]` on the same fence line sets variables for this run
|
|
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.
|
package/docs/sh.md
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
# sh
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
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
|
+
The `sh` fence runs the body via `sh -c`, character-perfect including whitespace.
|
|
8
|
+
|
|
9
|
+
````sh <!-- the body is the script itself -->
|
|
10
|
+
printf 'hello\n' > hello.txt
|
|
11
|
+
wc -l hello.txt
|
|
12
|
+
````
|
|
5
13
|
|
|
6
14
|
## Environment
|
|
7
15
|
|
|
@@ -13,51 +21,76 @@ read plurnk's credentials. The project's environment passes through.
|
|
|
13
21
|
|
|
14
22
|
The working directory is the workspace project root — where file operations
|
|
15
23
|
write — or, in a workspace without one, the directory the shell would run in
|
|
16
|
-
anyway. A `{cwd
|
|
24
|
+
anyway. A `[{"cwd": "<directory>"}]` block on the opening fence line overrides it for its body:
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
### EXEC0 {cwd=./dir}
|
|
26
|
+
````sh [{"cwd": "./dir"}]
|
|
20
27
|
pwd
|
|
21
|
-
|
|
28
|
+
````
|
|
22
29
|
|
|
23
30
|
The receipt always names the directory the command ran in.
|
|
24
31
|
|
|
25
|
-
|
|
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
|
|
26
41
|
stdin; a nonempty body becomes its stdin. The interpreter reads the script
|
|
27
42
|
directly, so it needs no executable bit; a script path authored inside a shell
|
|
28
43
|
body still follows the kernel's ordinary executable-bit rules.
|
|
29
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
|
+
|
|
30
49
|
The target is a program — a script — never a command and never a directory. A
|
|
31
50
|
target that is not a script is refused before anything runs.
|
|
32
51
|
|
|
33
52
|
## Channels
|
|
34
53
|
|
|
35
54
|
Every shell invocation is host-effecting and proposes for review before it
|
|
36
|
-
runs. Output then streams under the
|
|
37
|
-
`sh
|
|
38
|
-
`#stderr` is the second; both are `text/stream`. While it runs,
|
|
39
|
-
reports each channel's size and growth and READ can
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
runs. Output then streams under the receipt's `stream` address, such as
|
|
56
|
+
`sh:///ab3d5678`: `#stdout` is the default channel and
|
|
57
|
+
`#stderr` is the second; both are `text/stream`. While it runs, the packet's
|
|
58
|
+
`## Delegation` streams list reports each channel's size and growth and READ can
|
|
59
|
+
inspect any range. On
|
|
60
|
+
completion, the harness adds one `_plurnk` READ per channel: its first page
|
|
61
|
+
(up to 16 lines), `range` extent, and terminal exit status. READ the `stream`
|
|
62
|
+
address for more; the `log:///…/READ` item holds only its recorded page:
|
|
63
|
+
|
|
64
|
+
````READ (sh:///ab3d5678#stdout) <17,40>
|
|
65
|
+
````
|
|
66
|
+
|
|
67
|
+
A nonzero exit closes with status 500; inspect both channels because either
|
|
68
|
+
may carry the useful diagnostic.
|
|
69
|
+
|
|
70
|
+
The `log:///…/sh` receipt's own body is the program exactly as you sent it,
|
|
71
|
+
never output: output lives on the stream and in the harness READs. A receipt
|
|
72
|
+
with a non-200 status and no `stream` address ran nothing; its body is still
|
|
73
|
+
your program, and its Problem says why it was refused.
|
|
43
74
|
|
|
44
75
|
## Deadlines & polling — `<timeout, poll>`
|
|
45
76
|
|
|
46
|
-
For a long-running command, the `<L>` slot carries `<
|
|
77
|
+
For a long-running command, the `<L>` slot carries `<timeout, poll>` in minutes:
|
|
47
78
|
|
|
48
|
-
|
|
49
|
-
### EXEC0 <1800>
|
|
79
|
+
````sh <30>
|
|
50
80
|
npm run build
|
|
81
|
+
````
|
|
51
82
|
|
|
52
|
-
|
|
83
|
+
````sh <30,5>
|
|
53
84
|
npm run e2e
|
|
85
|
+
````
|
|
54
86
|
|
|
55
|
-
|
|
87
|
+
````sh <-1,5>
|
|
56
88
|
npm run test
|
|
89
|
+
````
|
|
57
90
|
|
|
58
|
-
|
|
91
|
+
````sh <-1,0>
|
|
59
92
|
tail -f app.log
|
|
60
|
-
|
|
93
|
+
````
|
|
61
94
|
|
|
62
95
|
The first coordinate is the timeout: a positive value kills at that deadline;
|
|
63
96
|
`-1` declines the deadline and the process outlives the loop — it runs until it
|
package/docs/tcl.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# tcl
|
|
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
|
+
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; `[{"args": [...]}]`
|
|
9
|
+
passes literal arguments, readable as `$argv`.
|
|
10
|
+
|
|
11
|
+
````tcl <!-- the body is the program -->
|
|
12
|
+
set words {alpha beta alpha}
|
|
13
|
+
foreach w $words { dict incr count $w }
|
|
14
|
+
puts [dict get $count alpha]
|
|
15
|
+
````
|
|
16
|
+
|
|
17
|
+
````tcl (tests/all.tcl) [{"args": ["-verbose","bps"]}]
|
|
18
|
+
````
|
|
19
|
+
|
|
20
|
+
`puts` streams to `#stdout`, `puts stderr ...` to `#stderr`; an uncaught error
|
|
21
|
+
or `exit 1` closes with status 500 with the Tcl error info on stderr. tclsh
|
|
22
|
+
evaluates the script line by line, so an incomplete command at the end is an
|
|
23
|
+
error, not a silent no-op.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plurnk/plurnk-execs-common",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
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",
|
|
@@ -67,7 +67,9 @@
|
|
|
67
67
|
"required": false,
|
|
68
68
|
"kind": "script"
|
|
69
69
|
},
|
|
70
|
-
"
|
|
70
|
+
"example": {
|
|
71
|
+
"body": "console.log(42)"
|
|
72
|
+
}
|
|
71
73
|
}
|
|
72
74
|
},
|
|
73
75
|
{
|
|
@@ -84,7 +86,9 @@
|
|
|
84
86
|
"required": false,
|
|
85
87
|
"kind": "script"
|
|
86
88
|
},
|
|
87
|
-
"
|
|
89
|
+
"example": {
|
|
90
|
+
"body": "print(42)"
|
|
91
|
+
}
|
|
88
92
|
}
|
|
89
93
|
},
|
|
90
94
|
{
|
|
@@ -101,7 +105,9 @@
|
|
|
101
105
|
"required": false,
|
|
102
106
|
"kind": "script"
|
|
103
107
|
},
|
|
104
|
-
"
|
|
108
|
+
"example": {
|
|
109
|
+
"body": "print 42;"
|
|
110
|
+
}
|
|
105
111
|
}
|
|
106
112
|
},
|
|
107
113
|
{
|
|
@@ -118,7 +124,9 @@
|
|
|
118
124
|
"required": false,
|
|
119
125
|
"kind": "script"
|
|
120
126
|
},
|
|
121
|
-
"
|
|
127
|
+
"example": {
|
|
128
|
+
"body": "puts 42"
|
|
129
|
+
}
|
|
122
130
|
}
|
|
123
131
|
},
|
|
124
132
|
{
|
|
@@ -135,7 +143,9 @@
|
|
|
135
143
|
"required": false,
|
|
136
144
|
"kind": "script"
|
|
137
145
|
},
|
|
138
|
-
"
|
|
146
|
+
"example": {
|
|
147
|
+
"body": "print(42)"
|
|
148
|
+
}
|
|
139
149
|
}
|
|
140
150
|
},
|
|
141
151
|
{
|
|
@@ -152,7 +162,9 @@
|
|
|
152
162
|
"required": false,
|
|
153
163
|
"kind": "script"
|
|
154
164
|
},
|
|
155
|
-
"
|
|
165
|
+
"example": {
|
|
166
|
+
"body": "console.log(42)"
|
|
167
|
+
}
|
|
156
168
|
}
|
|
157
169
|
},
|
|
158
170
|
{
|
|
@@ -169,7 +181,9 @@
|
|
|
169
181
|
"required": false,
|
|
170
182
|
"kind": "script"
|
|
171
183
|
},
|
|
172
|
-
"
|
|
184
|
+
"example": {
|
|
185
|
+
"body": "console.log(42)"
|
|
186
|
+
}
|
|
173
187
|
}
|
|
174
188
|
},
|
|
175
189
|
{
|
|
@@ -186,7 +200,9 @@
|
|
|
186
200
|
"required": false,
|
|
187
201
|
"kind": "script"
|
|
188
202
|
},
|
|
189
|
-
"
|
|
203
|
+
"example": {
|
|
204
|
+
"body": "puts 42"
|
|
205
|
+
}
|
|
190
206
|
}
|
|
191
207
|
},
|
|
192
208
|
{
|
|
@@ -203,7 +219,9 @@
|
|
|
203
219
|
"required": false,
|
|
204
220
|
"kind": "script"
|
|
205
221
|
},
|
|
206
|
-
"
|
|
222
|
+
"example": {
|
|
223
|
+
"body": "6 * 7"
|
|
224
|
+
}
|
|
207
225
|
}
|
|
208
226
|
},
|
|
209
227
|
{
|
|
@@ -220,7 +238,9 @@
|
|
|
220
238
|
"required": false,
|
|
221
239
|
"kind": "script"
|
|
222
240
|
},
|
|
223
|
-
"
|
|
241
|
+
"example": {
|
|
242
|
+
"body": "BEGIN { print 42 }"
|
|
243
|
+
}
|
|
224
244
|
}
|
|
225
245
|
}
|
|
226
246
|
]
|
|
@@ -250,6 +270,6 @@
|
|
|
250
270
|
"prepublishOnly": "npm audit --audit-level=moderate && npm test"
|
|
251
271
|
},
|
|
252
272
|
"peerDependencies": {
|
|
253
|
-
"@plurnk/plurnk-execs": "^1.
|
|
273
|
+
"@plurnk/plurnk-execs": "^1.18.0"
|
|
254
274
|
}
|
|
255
275
|
}
|