@plurnk/plurnk-execs 0.4.6 → 0.4.7

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.
Files changed (2) hide show
  1. package/README.md +49 -8
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -4,17 +4,58 @@ Framework + contract for `@plurnk/plurnk-execs-*` runtime executor packages. Con
4
4
 
5
5
  ## Documentation
6
6
 
7
- - [`SPEC.md`](./SPEC.md) — author-facing contract.
8
- - Constellation: [plurnk-grammar](https://github.com/plurnk/plurnk-grammar) (EXEC AST), [plurnk-providers](https://github.com/plurnk/plurnk-providers), [plurnk-schemes](https://github.com/plurnk/plurnk-schemes), [plurnk-mimetypes](https://github.com/plurnk/plurnk-mimetypes).
7
+ - [`SPEC.md`](./SPEC.md) — the authoritative author-facing contract. This README is the orientation.
8
+ - Constellation: [plurnk-grammar](https://github.com/plurnk/plurnk-grammar) (EXEC AST), [plurnk-providers](https://github.com/plurnk/plurnk-providers), [plurnk-schemes](https://github.com/plurnk/plurnk-schemes), [plurnk-mimetypes](https://github.com/plurnk/plurnk-mimetypes) (the reference family this one mirrors).
9
+
10
+ ## Write an executor
11
+
12
+ Ship an executor by publishing a package — **under any scope** (`@acme/whatever`; discovery keys on `plurnk.kind`, not the `@plurnk` scope) — that declares its runtime tags and default-exports a `BaseExecutor` subclass.
13
+
14
+ ### 1. Declare tags in `package.json`
15
+
16
+ ```json
17
+ {
18
+ "plurnk": {
19
+ "kind": "exec",
20
+ "runtimes": [
21
+ { "name": "cobol", "glyph": "🗄", "example": "EXEC[cobol]:DISPLAY 'HI'.:EXEC" }
22
+ ]
23
+ }
24
+ }
25
+ ```
26
+
27
+ One package may claim many tags (the search sibling claims `search`/`news`/`images`/…); each `runtimes[]` entry registers independently. `glyph` is display; **`example`** is a one-line, self-documenting usage example (`EXEC[tag]:body:EXEC`) surfaced verbatim in the model's tools sheet — omit it and the tag just isn't advertised with a usage line.
28
+
29
+ ### 2. Default-export a `BaseExecutor` subclass
30
+
31
+ The framework instantiates **one executor per tag**, injecting `{ runtime, glyph }` (`ExecutorMetadata`) — branch on `this.runtime` when one class backs several tags. Two ways in:
32
+
33
+ - **Subprocess runtimes** (the common case): subclass **`SubprocessExecutor`** and override one hook — `spawnArgs(runtime, command) → { cmd, args, useShell, stdin? }`. You inherit stdout/stderr streaming, process-group abort, **env scoping**, and exit-code reporting. Override the `binary` getter so `probe()` checks it's on PATH (`null` = always available).
34
+ - **Logical / in-process runtimes** (sqlite, search, wasm, jq): subclass **`BaseExecutor`** directly and implement:
35
+ - `get channels()` — the output channels you write, each `{ mimetype, defaultState? }`.
36
+ - `run(args) → ExecResult` — do the work, resolve `{ status }`. Never throw for an expected failure — `emit` telemetry and set the channel to `errored` instead.
37
+ - `probe()` *(optional)* — `{ available, detail? }`; defaults to available. Override when you depend on an external binary or config (the `detail` is model-facing on a 501).
38
+ - `effect(target)` *(optional)* — `"pure" | "read" | "host"`; the consumer maps it to its proposal policy (host → propose, read/pure → auto-run inline). Classify the **target only**, never the command. Defaults to `host` (the safe end).
39
+
40
+ ### 3. What `run` receives (`ExecArgs`) — sinks, never the substrate
41
+
42
+ `{ runtime, command, cwd, env, signal, write(channel, chunk), setState(channel, state), emit(event) }`. The executor gets sinks and honors `signal` — never the db, subscriptions, or wake machinery (those stay in the consumer). `cwd` is the parsed EXEC target; **`env`**, when the consumer scopes it, is exactly the environment a spawned child should see (the host's own secrets already dropped — never inherit `process.env` for model-run children yourself). Stay stateless across runs beyond your construction metadata.
43
+
44
+ ## Discovery & trust
45
+
46
+ `discover(options?)` scans **every installed package** under `<cwd>/node_modules` — scope-agnostic — for `plurnk.kind === "exec"`, returning `{ registry, skipped }`.
47
+
48
+ - **Tag collisions are fail-hard.** Two packages claiming the same tag throws at discovery, naming both — deliberately stricter than plurnk-mimetypes' last-wins. A runtime tag is an executable dispatch key, so a third party silently shadowing `python` is exactly the failure we refuse to let ship quietly; the operator resolves it.
49
+ - **Trust gate.** `discover()` honors **`PLURNK_PLUGINS_TRUSTED_ONLY`** (host posture, plurnk-service#229): unset/`""`/`0` → every package registers (default, no regression); any value → `@plurnk/*` always trusted plus a comma-separated allowlist (`1` = first-party only). An untrusted package is discovered but **not** registered and returned in `Discovery.skipped` for the consumer to note — never a crash.
9
50
 
10
51
  ## Exports
11
52
 
12
- - `BaseExecutor` — abstract base a `@plurnk/plurnk-execs-*` sibling subclasses: declares its output channels, implements `run(args) → ExecResult`, and optionally overrides `probe()` (env availability) and `effect(target)` (proposal gating).
13
- - `SubprocessExecutor` — concrete `BaseExecutor` for subprocess runtimes (sh/node/python): spawns via `resolveRuntime`, streams stdout/stderr, honors cancellation (process-group kill on abort), reports exit code, probes its `binary`. Siblings subclass it.
14
- - `discover(options?)` — scans `node_modules/@plurnk/` for `plurnk.kind === "exec"` packages and builds the runtime-tag registry (fail-hard on tag collision).
15
- - `ExecArgs`, `ExecResult`, `ChannelDecl`, `ChannelState`, `ExecutorMetadata`, `RuntimeAvailability`, `Effect`, `ExecInfo`, `ExecRegistry`, `Discovery`, `DiscoverOptions` — contract types.
16
- - `TelemetryEvent`, `ContentOffset`, `LogCoordinate` — local mirror of grammar's telemetry envelope (the `emit` sink's payload).
17
- - `resolveRuntime(runtime, command)`, `isKnownRuntime(runtime)`, `KNOWN_RUNTIMES`, `SpawnArgs`, `RuntimeResolver` — subprocess-family helper for the consumer's legacy spawn path (§4).
53
+ - `BaseExecutor` — abstract base: `channels`, `run(args)`, optional `probe()` / `effect(target)`.
54
+ - `SubprocessExecutor` — concrete base for subprocess runtimes; override `spawnArgs()` (and `binary`). Streaming + process-group abort + env scoping + exit code, inherited.
55
+ - `discover(options?)` — the scope-agnostic registry scan (trust-gated, fail-hard on collision).
56
+ - Contract types: `ExecArgs`, `ExecResult`, `ChannelDecl`, `ChannelState`, `ExecutorMetadata`, `RuntimeAvailability`, `Effect`, `ExecInfo`, `ExecRegistry`, `Discovery`, `DiscoverOptions`.
57
+ - `TelemetryEvent`, `ContentOffset`, `LogCoordinate` — the `emit` sink's payload (mirror of grammar's telemetry envelope).
58
+ - `resolveRuntime`, `isKnownRuntime`, `KNOWN_RUNTIMES`, `SpawnArgs`, `RuntimeResolver` — subprocess-family helper for the consumer's legacy spawn path (SPEC §4).
18
59
 
19
60
  ## Tests
20
61
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plurnk/plurnk-execs",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "description": "Framework + contract for the @plurnk/plurnk-execs-* runtime executor family.",
5
5
  "keywords": [
6
6
  "plurnk",