@plurnk/plurnk-execs-common 1.3.12 → 1.4.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
@@ -1,40 +1,59 @@
1
1
  # @plurnk/plurnk-execs-common
2
2
 
3
- The **universal subprocess executor** for [plurnk-service](https://github.com/plurnk/plurnk-service)'s `exec` scheme: one package covering the shell + node + python floor *and* whichever host interpreters (`perl`/`ruby`/`php`/`lua`/`awk`/`bc`/…) are present. Install it once and the model gets every subprocess runtime the host can serve — `node` always, the rest detected.
3
+ The **universal subprocess executor** for
4
+ [plurnk-service](https://github.com/plurnk/plurnk-service)'s `exec` scheme. One
5
+ package covers the shell, Node, Python, and whichever supported host
6
+ interpreters are present. Node is guaranteed; the rest are detected.
4
7
 
5
- A `@plurnk/plurnk-execs-*` sibling built on the [plurnk-execs](https://github.com/plurnk/plurnk-execs) framework. **Supersedes the former `-sh`, `-node`, `-python` packages** (folded in here).
8
+ A `@plurnk/plurnk-execs-*` sibling built on the [plurnk-execs](https://github.com/plurnk/plurnk-service/tree/main/plurnk-execs) framework. **Supersedes the former `-sh`, `-node`, `-python` packages** (folded in here).
6
9
 
7
10
  ## How it works
8
11
 
9
- The manifest claims the subprocess runtime tags. The framework's `probe()` (per-tag) lights up `node` unconditionally (the daemon *is* node) and detects the rest via a cheap `command -v`, so the consumer offers the model exactly the platform's runtimes. No per-language packages — one executor adapts to the host.
10
-
11
- | Tag | Binary | Command via |
12
- |---|---|---|
13
- | `sh` 🐚 / `bash` 🐚 | sh / bash | `-c <command>` |
14
- | `node` ⬢ | node | `-e <command>` (always available) |
15
- | `python` / `python3` 🐍 | python3 | `-c <command>` |
16
- | `perl` 🐪 / `ruby` 💎 / `lua` 🌙 | perl / ruby / lua | `-e <command>` |
17
- | `php` 🐘 | php | `-r <command>` |
18
- | `deno` 🦕 | deno | `eval <command>` |
19
- | `bun` 🥟 | bun | `-e <command>` |
20
- | `tcl` 🪶 | tclsh | stdin |
21
- | `bc` 🧮 | bc | stdin (e.g. `6 * 7`) |
22
- | `awk` 🪄 | awk | program arg, empty stdin (`BEGIN { … }`) |
12
+ The manifest claims the subprocess tags. Per-tag `probe()` reports Node
13
+ unconditionally because the daemon already runs on it. A cheap `command -v`
14
+ detects every other interpreter, so one executor adapts to the host.
15
+
16
+ | Tag | Binary | Command via |
17
+ | -------------------------------- | ----------------- | ---------------------------------------- |
18
+ | `sh` 🐚 / `bash` 🐚 | sh / bash | `-c <command>` |
19
+ | `node` ⬢ | node | `-e <command>` (always available) |
20
+ | `python` / `python3` 🐍 | python3 | `-c <command>` |
21
+ | `perl` 🐪 / `ruby` 💎 / `lua` 🌙 | perl / ruby / lua | `-e <command>` |
22
+ | `php` 🐘 | php | `-r <command>` |
23
+ | `deno` 🦕 | deno | `eval <command>` |
24
+ | `bun` 🥟 | bun | `-e <command>` |
25
+ | `tcl` 🪶 | tclsh | stdin |
26
+ | `bc` 🧮 | bc | stdin (for example, `6 * 7`) |
27
+ | `awk` 🪄 | awk | program arg, empty stdin (`BEGIN { … }`) |
23
28
 
24
29
  ### A program with stdin — the `(target)` slot
25
30
 
26
- The table above is the **inline** form: `command` is the program. Put a program in the **`(target)` slot** instead and `command` becomes its **stdin** — a shell runs `sh -c "<target>"` (the shell tokenizes it; we don't), any other interpreter runs `<interpreter> <target>` (a script file). Same two slots, each mapped to its tool's CLI (plurnk-execs#15):
31
+ The table above is the **inline** form: `command` is the program. Put a program
32
+ in the **`(target)` slot** instead and `command` becomes its **stdin**—a shell
33
+ runs `sh -c "<target>"` (the shell tokenizes it), while another interpreter
34
+ runs `<interpreter> <target>` as a script file ({§executor-subprocess-routing}).
27
35
 
36
+ ```plurnk
37
+ <<EXEC[sh](./deploy.sh --prod):yes\nyes\nno:EXEC
38
+ <<EXEC[python](transform.py):3\n1\n4\n1\n5:EXEC
28
39
  ```
29
- <<EXEC[sh](./deploy.sh --prod):yes\nyes\nno:EXEC # run a script, prompts answered on stdin
30
- <<EXEC[python](transform.py):3\n1\n4\n1\n5:EXEC # feed a python script its stdin
31
- ```
32
40
 
33
- All run arbitrary code → `effect: host` → **proposal-gated** (not auto-run). For the snappy auto-run tier, see the pure in-process evaluators (`calc`/`jq`/`wasm`, planned). Input-processing transforms (`sed`, input-driven `awk`) await the EXEC input-channel and aren't claimed here.
41
+ The first operation answers a shell script's prompts through stdin. The second
42
+ feeds records to a Python script.
43
+
44
+ All declared tags run host code, so every invocation is proposal-gated. The
45
+ current installed in-process evaluators are jq, SQLite, and WebAssembly; their
46
+ `pure` or `read` invocations bypass the proposal gate but still return through
47
+ the same next-turn stream path ({§executor-effect}). Input-processing
48
+ transforms (`sed`, input-driven `awk`) await an EXEC input-channel contract and
49
+ are not claimed here.
34
50
 
35
51
  ## Configuration
36
52
 
37
- Per-tag kill-switches (`PLURNK_EXECS_<TAG>=0`) and the `PLURNK_EXECS_ONLY` allowlist are honored by the **framework's** `discover()`, uniformly across every plugin — not here (SPEC §3.3). A disabled tag is not registered at all, so it never reaches this executor. `disable all standard execs except search` → `PLURNK_EXECS_ONLY=search`.
53
+ Per-tag kill-switches (`PLURNK_EXECS_<TAG>=0`) and the
54
+ `PLURNK_EXECS_ONLY` allowlist are honored by framework discovery, uniformly
55
+ across every plugin ({§executor-policy}). A disabled tag is not registered and
56
+ never reaches this executor.
38
57
 
39
58
  ## Tests
40
59
 
package/dist/Common.js CHANGED
@@ -7,7 +7,7 @@ const RECIPES = Object.freeze({
7
7
  node: { bin: "node", arg: (c) => ["-e", c], alwaysAvailable: true },
8
8
  // `python` and `python3` both map to the python3 binary — the only Python we
9
9
  // offer (no python-2 path). `python3` is an alias, not a new capability
10
- // (owner ruling #519): it's the name a coding model types by reflex, and
10
+ // because it is the name a coding model types by reflex, and
11
11
  // it owns the same Python-source body contract as `python`.
12
12
  python: { bin: "python3", arg: (c) => ["-c", c] },
13
13
  python3: { bin: "python3", arg: (c) => ["-c", c] },
@@ -31,8 +31,8 @@ const onPath = (bin) => spawnSync("sh", ["-c", `command -v "$1"`, "sh", bin]).st
31
31
  // up only the interpreters present on this host, so the consumer offers the
32
32
  // model exactly what the platform has — "plurnk supports the host's REPLs out
33
33
  // of the box". The operator kill-switch (PLURNK_EXECS_<tag>=0 / _ONLY) is no
34
- // longer honored here — the framework's discover() applies it uniformly across
35
- // every plugin (SPEC §3.3), so a disabled tag never reaches probe(). All run
34
+ // longer honored here — framework discovery applies it uniformly across every
35
+ // plugin ({§executor-policy}), so a disabled tag never reaches probe(). All run
36
36
  // arbitrary code → effect `host` (inherited, proposal-gated). Reuses
37
37
  // SubprocessExecutor's run() (streaming + process-group abort) via spawnArgs().
38
38
  export default class Common extends SubprocessExecutor {
@@ -41,8 +41,8 @@ export default class Common extends SubprocessExecutor {
41
41
  if (r === undefined)
42
42
  throw new Error(`plurnk-execs-common received unclaimed runtime tag '${runtime}'`);
43
43
  // With a target the program IS the target and the body is its stdin
44
- // (plurnk-execs#15), run as a single script-file positional for EVERY
45
- // interpreter — transient exec (owner ruling, #500): the interpreter
44
+ // ({§executor-subprocess-routing}), run as one script-file positional for every
45
+ // interpreter: the interpreter
46
46
  // READS the file, so no exec bit is consulted and none is ever set.
47
47
  // The old sh/bash `-c` arm made the shell execve() the target instead
48
48
  // (PATH lookup on bare names, +x demanded on EDIT-created scripts) and
@@ -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":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAkB1D,MAAM,OAAO,GAAqC,MAAM,CAAC,MAAM,CAAC;IAC5D,+EAA+E;IAC/E,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE;IACxC,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE;IAC5C,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE;IACnE,6EAA6E;IAC7E,wEAAwE;IACxE,6DAA6D;IAC7D,4DAA4D;IAC5D,MAAM,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE;IACjD,OAAO,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE;IAClD,8BAA8B;IAC9B,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE;IAC5C,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE;IAC5C,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE;IAC1C,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE;IAC1C,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE;IAC9C,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE;IAC1C,GAAG,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE;IAClC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IAC9B,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE;CAClC,CAAC,CAAC;AAEH,2DAA2D;AAC3D,MAAM,CAAC,MAAM,YAAY,GAAsB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AAEnF,+EAA+E;AAC/E,iFAAiF;AACjF,MAAM,MAAM,GAAG,CAAC,GAAW,EAAW,EAAE,CACpC,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AAEvE,+EAA+E;AAC/E,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAC9E,gFAAgF;AAChF,qEAAqE;AACrE,gFAAgF;AAChF,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,kBAAkB;IAC/B,SAAS,CAAC,OAAe,EAAE,OAAe,EAAE,MAAM,GAAkB,IAAI;QACvF,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,CAAC,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,OAAO,GAAG,CAAC,CAAC;QACxG,oEAAoE;QACpE,gFAAgF;QAChF,+BAA+B;QAC/B,oEAAoE;QACpE,sEAAsE;QACtE,uEAAuE;QACvE,sEAAsE;QACtE,eAAe;QACf,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAC3E,CAAC;QACD,qEAAqE;QACrE,sEAAsE;QACtE,IAAI,CAAC,CAAC,KAAK;YAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;QACrF,IAAI,CAAC,CAAC,IAAI;YAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAC/E,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClE,CAAC;IAEQ,KAAK,CAAC,KAAK;QAChB,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAC9F,IAAI,CAAC,CAAC,eAAe;YAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACtG,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;YAChB,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE;YACpC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,cAAc,EAAE,CAAC;IAC/D,CAAC;CACJ"}
package/docs/node.md CHANGED
@@ -8,8 +8,13 @@ The same scoped environment as `sh`: the daemon's own secrets (`PLURNK_*`, provi
8
8
 
9
9
  ## Output
10
10
 
11
- Whatever the snippet writes to stdout streams to the `stdout` channel (stderr → `stderr`); both are text. To return structured data, `console.log(JSON.stringify(x))` and `READ` it back. A thrown error exits non-zero (status 500) with the stack on `stderr`.
11
+ 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.
12
16
 
13
17
  ## Working directory
14
18
 
15
- Runs in the workspace project root by default; `EXEC[node](./dir):…` sets cwd, and relative `import` / `require` / `fs` paths resolve against it.
19
+ Runs in the workspace project root by default. `EXEC[node](./dir):…` sets the
20
+ working directory; relative module and filesystem paths resolve against it.
package/docs/sh.md CHANGED
@@ -4,26 +4,53 @@ A shell command line, run via `sh -c`. Bare `EXEC` (no runtime tag) defaults to
4
4
 
5
5
  ## Environment
6
6
 
7
- The command runs with a **scoped** environment: the host daemon's own secrets — provider API keys and every `PLURNK_*` config var — are stripped before the child sees them, so `printenv` / `env` cannot read plurnk's credentials. The project's own environment passes through unchanged.
7
+ The command receives a **scoped** environment. Provider keys and every
8
+ `PLURNK_*` setting are stripped before the child starts, so `printenv` cannot
9
+ read plurnk's credentials. The project's environment passes through.
8
10
 
9
11
  ## Working directory
10
12
 
11
- `EXEC[sh](./dir):…` runs in `./dir`. With no target the command runs in the workspace's project root — the same place the `file` scheme writes — so it finds files a prior `EDIT` just created, rather than the daemon's cwd.
13
+ `EXEC[sh](./dir):…` runs in `./dir`. With no target, the command runs in the
14
+ workspace project root where file operations write—not in the daemon's own
15
+ working directory.
12
16
 
13
- `(target)` is polymorphic on the filesystem: a **directory** is the cwd (above); a **file** is a **script to run**. `<<EXEC[sh](greet.sh)::EXEC` runs `greet.sh` — an empty body just runs it (note the `::` — empty body); a body becomes its stdin (`<<EXEC[sh](greet.sh):input line:EXEC`). Directory → run *in* it; file → run *it*. The interpreter **reads** the file — no `+x` needed, and none is ever set (transient exec, #500); a `./script.sh` typed in a *body* still meets the kernel's own exec-bit check, so prefer the `(target)` form for scripts you just wrote.
17
+ The target's filesystem type selects its role:
18
+
19
+ - A directory becomes the working directory.
20
+ - A file is the script to run. `<<EXEC[sh](greet.sh)::EXEC` runs it with an
21
+ empty stdin; a nonempty body becomes stdin.
22
+
23
+ The interpreter reads a targeted file directly, so it needs no executable bit.
24
+ A script path authored inside a shell body still follows the kernel's ordinary
25
+ executable-bit rules.
14
26
 
15
27
  ## Channels
16
28
 
17
- Output streams into two channels on the `exec://` entry: `#stdout` (default) and `#stderr` (both `text/stream`). A host-effecting command proposes for review before it runs; a read-only one runs without the review pause. The stream opens when the command concludes — for a quick command, right on your next turn (folded only while it still runs); READ the entry to revisit or slice it. A non-zero exit closes the entry with status 500, the message on `stderr`.
29
+ Every shell invocation is host-effecting and proposes for review before it
30
+ runs. Output then streams under the emitted
31
+ `sh:///<loop>/<turn>/<sequence>` address: `#stdout` is the default channel and
32
+ `#stderr` is the second; both are `text/stream`. Running deltas stay folded and
33
+ the terminal delta opens on a later turn. READ the emitted address to revisit
34
+ or slice it. A nonzero exit closes with status 500; inspect both channels
35
+ because either may carry the useful diagnostic.
18
36
 
19
37
  ## Deadlines & polling — `<timeout, poll>`
20
38
 
21
39
  For a long-running command, the `<L>` slot carries `<TIMEOUT_SECONDS, POLL_SECONDS>` (both seconds):
22
40
 
23
- ```
24
- <<EXEC<1800>:npm run build:EXEC hard-kill at 1800s; wake on completion
25
- <<EXEC<1800,300>:npm run e2e:EXEC bounded at 1800s + wake every 300s
26
- <<EXEC<-1,300>:npm run test:EXEC no deadline (-1) + wake every 300s
41
+ ```plurnk
42
+ <<EXEC<1800>:npm run build:EXEC
43
+ <<EXEC<1800,300>:npm run e2e:EXEC
44
+ <<EXEC<-1,300>:npm run test:EXEC
45
+ <<EXEC<-1,0>:tail -f app.log:EXEC
27
46
  ```
28
47
 
29
- The **timeout** (first, required when the slot is used) bounds the worker — at the deadline the command is killed. **`-1` declines a deadline** (unlimited); the worker is still reaped when the loop ends, and you remain free to `KILL` it. The optional **poll** (second) wakes the loop on that cadence while the stream is open, so you can `READ` partial output and decide to wait or `KILL` — it never interrupts the command. A poll always requires a timeout (it's the second coordinate); bare `EXEC` with no slot runs to completion, bounded only by the loop.
48
+ The first coordinate is the timeout: a positive value kills at that deadline;
49
+ `-1` declines the per-operation deadline; `0` keeps the process only through
50
+ the current turn. Loop teardown still reaps surviving work. The optional
51
+ positive second coordinate fixes the poll cadence while a loop is parked on
52
+ the stream. With no explicit poll, the consumer uses exponential backoff so a
53
+ parked loop can inspect partial output and decide whether to wait or KILL. A
54
+ second coordinate of `0` disables timer polling for that stream; its eventual
55
+ closure still wakes the loop. Polling wakes the loop but never interrupts the
56
+ command.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plurnk/plurnk-execs-common",
3
- "version": "1.3.12",
3
+ "version": "1.4.0",
4
4
  "description": "Universal subprocess executor for plurnk-service's exec scheme — one package exposing the shell + node + python floor plus whichever host interpreters (perl, ruby, php, lua, awk, bc, …) are present.",
5
5
  "keywords": [
6
6
  "plurnk",
@@ -13,13 +13,14 @@
13
13
  "node",
14
14
  "python"
15
15
  ],
16
- "homepage": "https://github.com/plurnk/plurnk-execs-common#readme",
16
+ "homepage": "https://github.com/plurnk/plurnk-service/tree/main/plurnk-execs-common#readme",
17
17
  "bugs": {
18
- "url": "https://github.com/plurnk/plurnk-execs-common/issues"
18
+ "url": "https://repo.possumtech.com/plurnk/plurnk-service/issues"
19
19
  },
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "git+https://github.com/plurnk/plurnk-execs-common.git"
22
+ "url": "git+https://github.com/plurnk/plurnk-service.git",
23
+ "directory": "plurnk-execs-common"
23
24
  },
24
25
  "engines": {
25
26
  "node": ">=26"
@@ -120,14 +121,15 @@
120
121
  ],
121
122
  "scripts": {
122
123
  "test:lint": "tsc --noEmit",
123
- "test:unit": "node --conditions=plurnk-dev --test \"src/**/*.test.ts\"",
124
+ "test:unit": "node --conditions=plurnk-dev --env-file-if-exists=../plurnk-execs/.env.defaults --test \"src/**/*.test.ts\"",
124
125
  "test": "npm run test:lint && npm run test:unit",
126
+ "build:clean": "rm -rf dist",
125
127
  "build:dist": "tsc -p tsconfig.build.json",
126
- "build": "npm run build:dist",
128
+ "build": "npm run build:clean && npm run build:dist",
127
129
  "prepack": "npm run build",
128
130
  "prepublishOnly": "npm audit --audit-level=moderate && npm test"
129
131
  },
130
132
  "peerDependencies": {
131
- "@plurnk/plurnk-execs": "^1.3.12"
133
+ "@plurnk/plurnk-execs": "^1.4.0"
132
134
  }
133
135
  }