@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 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=<directory>}` block on the heading
33
- selects the working directory; the body remains the program
34
- ({§executor-subprocess-routing}).
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
- ```example
37
- ### EXEC0 (./deploy.sh)
40
+ ````sh (./deploy.sh)
38
41
  yes
39
42
  yes
40
43
  no
44
+ ````
41
45
 
42
- ### EXEC0 [python3] (transform.py)
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}). Input-processing
57
- transforms (`sed`, input-driven `awk`) await an EXEC input-channel contract and
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
 
@@ -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;AAkC3E,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,CAmBtG;IAEc,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAOnD;CACJ"}
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}), run as one script-file positional for every
38
- // interpreter: the interpreter
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.
@@ -1 +1 @@
1
- {"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"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"}
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 emitted `node:///<loop>/<turn>/<sequence>`
13
- address. To return structured data, use `console.log(JSON.stringify(value))`
14
- and READ that address. A thrown error exits nonzero (status 500) with its stack
15
- on stderr.
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=<directory>}` block on the heading selects
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
- `### EXEC0 [node] (tool.js)` runs that JavaScript file and receives the body as
23
- stdin; anything else is refused before anything runs. Relative module and
24
- filesystem paths resolve against the working directory. The receipt always
25
- names it.
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}`.
@@ -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
- A bare `EXEC` is the shell. The body is the command line, run via `sh -c`,
4
- character-perfect including whitespace. `[sh]` names the shell explicitly.
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=<directory>}` block on the heading overrides it for its body:
24
+ anyway. A `[{"cwd": "<directory>"}]` block on the opening fence line overrides it for its body:
17
25
 
18
- ```example
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
- A script target runs that script: `### EXEC0 (greet.sh)` runs it with an empty
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 emitted
37
- `sh:///<loop>/<turn>/<sequence>` address: `#stdout` is the default channel and
38
- `#stderr` is the second; both are `text/stream`. While it runs, Child Streams
39
- reports each channel's size and growth and READ can inspect any range. On
40
- completion, one terminal delta becomes visible. A nonzero exit closes with
41
- status 500; inspect both channels
42
- because either may carry the useful diagnostic.
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 `<TIMEOUT_SECONDS, POLL_SECONDS>` (both seconds):
77
+ For a long-running command, the `<L>` slot carries `<timeout, poll>` in minutes:
47
78
 
48
- ```example
49
- ### EXEC0 <1800>
79
+ ````sh <30>
50
80
  npm run build
81
+ ````
51
82
 
52
- ### EXEC0 <1800,300>
83
+ ````sh <30,5>
53
84
  npm run e2e
85
+ ````
54
86
 
55
- ### EXEC0 <-1,300>
87
+ ````sh <-1,5>
56
88
  npm run test
89
+ ````
57
90
 
58
- ### EXEC0 <-1,0>
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.16.5",
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
- "signature": "JavaScript code"
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
- "signature": "Python code"
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
- "signature": "Perl code"
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
- "signature": "Ruby code"
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
- "signature": "Lua code"
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
- "signature": "TypeScript or JavaScript code"
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
- "signature": "TypeScript or JavaScript code"
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
- "signature": "Tcl code"
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
- "signature": "bc expression or code"
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
- "signature": "AWK code"
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.16.5"
273
+ "@plurnk/plurnk-execs": "^1.18.0"
254
274
  }
255
275
  }