@plurnk/plurnk-execs 0.1.0 → 0.3.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
@@ -9,10 +9,12 @@ Framework + contract for `@plurnk/plurnk-execs-*` runtime executor packages. Con
9
9
 
10
10
  ## Exports
11
11
 
12
- - `SpawnArgs`, `RuntimeResolver`types.
13
- - `KNOWN_RUNTIMES` — read-only set of v0 hardcoded runtime tags.
14
- - `isKnownRuntime(runtime)` — predicate.
15
- - `resolveRuntime(runtime, command)` runtime tag + command `SpawnArgs` for `node:child_process.spawn`.
12
+ - `BaseExecutor` — abstract base a `@plurnk/plurnk-execs-*` sibling subclasses: declares its output channels and implements `run(args) → ExecResult`.
13
+ - `SubprocessExecutor` — concrete `BaseExecutor` for subprocess runtimes (sh/node/python): spawns via `resolveRuntime`, streams stdout/stderr, honors cancellation, reports exit code. 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`, `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).
16
18
 
17
19
  ## Tests
18
20
 
package/SPEC.md CHANGED
@@ -1,77 +1,136 @@
1
1
  # plurnk-execs — Specification
2
2
 
3
- Contract for `@plurnk/plurnk-execs-*` sibling packages — runtime executors that plurnk-service's `exec://` scheme dispatches to. Audience: implementer of a runtime executor. Consumer: [plurnk-service](https://github.com/plurnk/plurnk-service) (SPEC.md §6.8, §10).
3
+ Contract for `@plurnk/plurnk-execs-*` sibling packages — runtime executors that plurnk-service's `exec://` scheme dispatches to. Audience: implementer of a runtime executor. Consumer: [plurnk-service](https://github.com/plurnk/plurnk-service) (SPEC.md §6.8, §10). Contract shape settled in plurnk-service#174.
4
4
 
5
5
  ## §1 Role
6
6
 
7
- A runtime executor handles one or more EXEC `runtime` slot values. Today plurnk-service's `Exec` scheme hardcodes the runtime spawn-args mapping for shell / node / python; this repo exports the same logic as `resolveRuntime`. The forward-spec is plugin discovery (one runtime per sibling); v0 ships the hardcoded path.
7
+ A runtime executor handles one or more EXEC `runtime` slot values (`sh`, `node`, `python`, `search`, `news`, …). It is a `BaseExecutor` subclass that declares its output channels and implements `run()`; the framework discovers it from its `package.json` `plurnk` block. The consuming scheme owns all I/O and lifecycle machinery (db, channels, subscriptions, AbortController bridging, wake-on-completion) and hands the executor sinks — the executor stays stateless across runs beyond its construction metadata.
8
8
 
9
- ## §2 v0 surface
9
+ The framework ships `SubprocessExecutor` (§4), the concrete `BaseExecutor` for subprocess runtimes (sh/node/python). plurnk-service's exec scheme still consumes the lower-level `resolveRuntime` / `SpawnArgs` helper on its legacy `streamShellCommand` path; its migration onto `SubprocessExecutor` is phased and on service's own timeline (plurnk-service#174 Q2). Both paths coexist until that cutover.
10
10
 
11
- `resolveRuntime(runtime: string, command: string) → SpawnArgs`:
11
+ ## §2 Executor contract
12
12
 
13
13
  ```ts
14
- interface SpawnArgs {
15
- cmd: string;
16
- args: string[];
17
- useShell: boolean;
14
+ abstract class BaseExecutor {
15
+ readonly runtime: string; // matched tag — "sh" / "search" / "news" / …
16
+ readonly glyph: string;
17
+ constructor(metadata: { runtime: string; glyph: string });
18
+
19
+ // Channels this executor writes to; the scheme seeds the exec entry from
20
+ // these (§2.1). Subprocess runtimes declare { stdout, stderr }; search
21
+ // declares { results }.
22
+ abstract get channels(): Readonly<Record<string, ChannelDecl>>;
23
+
24
+ abstract run(args: ExecArgs): Promise<ExecResult>;
25
+ }
26
+
27
+ interface ChannelDecl { mimetype: string; defaultState?: ChannelState; }
28
+ type ChannelState = "active" | "closed" | "errored";
29
+
30
+ interface ExecArgs {
31
+ runtime: string; // matched tag; multi-tag executors branch on it
32
+ command: string; // EXEC body: shell line / source / search query
33
+ cwd: string | null; // subprocess working dir; null/ignored for logical runtimes
34
+ signal: AbortSignal; // cancellation — executors must honor it
35
+ write: (channel: string, chunk: string) => void; // write a chunk to a declared channel
36
+ setState: (channel: string, state: ChannelState) => void; // drive a declared channel's lifecycle
37
+ emit: (event: TelemetryEvent) => void; // emit telemetry/error (§2.2)
38
+ }
39
+
40
+ interface ExecResult {
41
+ status: number; // 200 ok / 499 aborted / 500 error
42
+ exitCode?: number; // subprocess family only
18
43
  }
19
44
  ```
20
45
 
21
- Maps:
46
+ `run()` must not throw for an expected runtime failure: surface it through `emit` + an `errored` channel state + a non-200 `status`.
22
47
 
23
- | Runtime | Spawn |
24
- |---|---|
25
- | `""` / `"sh"` / `"bash"` | `{ cmd: command, args: [], useShell: true }` |
26
- | `"node"` | `{ cmd: "node", args: ["-e", command], useShell: false }` |
27
- | `"python"` / `"python3"` | `{ cmd: "python3", args: ["-c", command], useShell: false }` |
28
- | any other | `{ cmd: runtime, args: ["-c", command], useShell: false }` (conservative fallback) |
48
+ ### §2.1 Channel topology is executor-declared
49
+
50
+ The executor declares its channels; the consuming scheme seeds the exec entry from `executor.channels` rather than from a static scheme-level manifest (plurnk-service#174 Q1). This keeps channel names honest — `search` exposes `{ results: { mimetype: "application/json" } }`, and the model reads `exec://<coord>/EXEC#results` instead of an overloaded `#stdout`. `write` / `setState` are generic over channel name; writing to an undeclared channel is a contract violation.
51
+
52
+ ### §2.2 Availability probe
29
53
 
30
- `resolveRuntime` never throws. Consumers gate unknown runtimes with `isKnownRuntime(runtime)` and return 501 from the scheme before invoking.
54
+ ```ts
55
+ interface RuntimeAvailability { available: boolean; detail?: string; }
56
+
57
+ abstract class BaseExecutor {
58
+ async probe(): Promise<RuntimeAvailability> { return { available: true }; } // default: available
59
+ }
60
+ ```
31
61
 
32
- `KNOWN_RUNTIMES` is the v0 hardcoded set; equivalent to the union of mapped runtimes above except the conservative fallback.
62
+ `probe()` reports whether the runtime's *environment* is usable here — distinct from whether the *package* is installed (`discover()`). Pure / in-process runtimes (node, sqlite) inherit the available default; runtimes depending on an external binary (`python` → `python3 --version`) or config (`search` → `SEARXNG_URL`) override. `SubprocessExecutor` probes its `binary` getter (`null` = always available).
33
63
 
34
- ## §3 Forward-specplugin discovery
64
+ Consumer contract (plurnk-service#181): probe **once at boot, per package** (not per tag stamp all of a package's tags with the one result), **concurrently under a per-probe timeout**, and **cache**. `probe()` MAY reject; the consumer treats rejection as `{ available: false, detail: <error> }`, so a buggy probe degrades only its runtime. The model is offered a positive list of available runtimes; an attempt at an unavailable one returns **501 carrying `detail`** (so `detail` is model-facing — terse and actionable). A configured default runtime that probes unavailable is a **fail-hard boot error**.
35
65
 
36
- The full constellation pattern (mirroring `plurnk-mimetypes`):
66
+ ### §2.3 Telemetry
67
+
68
+ Runtime failures are emitted as a grammar `TelemetryEvent` via the `emit` sink (plurnk-service#174 Q3); the scheme routes it to the engine's telemetry buffer — the same path grammar's `parse_error` takes. Events are not encoded into `stderr` (that pollutes program output) nor returned on `ExecResult` (that loses mid-run events).
69
+
70
+ - `source`: `"exec:<runtime>"` (e.g. `"exec:search"`) or `"scheme:exec"`.
71
+ - `kind`: producer-minted — `runtime_not_configured`, `spawn_failed`, `exited_nonzero`, `aborted`, and runtime-specific kinds (search: `searxng_unreachable`, `searxng_http_<n>`).
72
+ - `message`: terse, factual. `position`: typically null at the runtime layer.
73
+
74
+ The envelope is mirrored locally (`TelemetryEvent`, `ContentOffset`, `LogCoordinate`) so the framework needs no `@plurnk/plurnk-grammar` dependency; grammar's `dist/schema/TelemetryEvent.json` is the source of truth.
75
+
76
+ ## §3 Discovery
77
+
78
+ `discover(options?) → { registry }`. Scans `<cwd>/node_modules/@plurnk/` (or explicit `packageDirs`) for packages declaring `plurnk.kind === "exec"`, and registers each runtime tag from `plurnk.runtimes[]`:
37
79
 
38
80
  ```json
39
81
  {
40
- "name": "@plurnk/plurnk-execs-<runtime>",
82
+ "name": "@plurnk/plurnk-execs-search",
41
83
  "plurnk": {
42
84
  "kind": "exec",
43
85
  "runtimes": [
44
- { "name": "sh", "glyph": "🐚" },
45
- { "name": "bash", "glyph": "🐚" }
86
+ { "name": "search", "glyph": "🔎" },
87
+ { "name": "news", "glyph": "📰" }
46
88
  ]
47
89
  }
48
90
  }
49
91
  ```
50
92
 
51
- Each sibling registers one or more runtime tags. Plurnk-service scans `node_modules/@plurnk/*` at boot, finds `plurnk.kind === "exec"` packages, registers their handlers. Collision on runtime name: fail-hard.
93
+ A package may claim multiple tags backed by one handler. Tags form a **flat global namespace**; `registry` maps tag → `{ runtime, glyph, packageName }`. Unlike plurnk-mimetypes (last-loaded wins), a tag **collision is fail-hard**: two packages claiming the same runtime is an unresolvable install ambiguity the operator must fix.
52
94
 
53
- Each runtime exports a `BaseExecutor` subclass (or equivalent) with `run(args) Promise<ExecResult>`. Args shape, result shape, AbortSignal handling all settle as the first sub-siblings ship (`plurnk-execs-sh` would be canonical).
95
+ Each runtime exports its `BaseExecutor` subclass; the consumer instantiates it per matched tag with the tag + glyph from the registry. (Module-export convention for the subclass settles as the first siblings ship.)
96
+
97
+ ## §4 Subprocess helper (legacy path)
98
+
99
+ `resolveRuntime(runtime, command) → SpawnArgs` and `isKnownRuntime(runtime)` / `KNOWN_RUNTIMES` translate a subprocess runtime tag into `node:child_process.spawn` arguments:
100
+
101
+ ```ts
102
+ interface SpawnArgs { cmd: string; args: string[]; useShell: boolean; }
103
+ ```
104
+
105
+ | Runtime | Spawn |
106
+ |---|---|
107
+ | `""` / `"sh"` / `"bash"` | `{ cmd: command, args: [], useShell: true }` |
108
+ | `"node"` | `{ cmd: "node", args: ["-e", command], useShell: false }` |
109
+ | `"python"` / `"python3"` | `{ cmd: "python3", args: ["-c", command], useShell: false }` |
110
+ | any other | `{ cmd: runtime, args: ["-c", command], useShell: false }` (conservative fallback) |
54
111
 
55
- Sub-siblings expected: `plurnk-execs-sh` (default subprocess), `plurnk-execs-node`, `plurnk-execs-python`, `plurnk-execs-search` (web search).
112
+ `resolveRuntime` never throws; consumers gate unknown runtimes with `isKnownRuntime` and return 501 before invoking.
56
113
 
57
- ## §4 Consumer surface (plurnk-service today)
114
+ The framework wraps this in **`SubprocessExecutor extends BaseExecutor`** — declares `{ stdout, stderr }` channels and implements `run()` (spawn via `resolveRuntime`, stream into the channels, honor `signal`, `emit` `spawn_failed` on a failed start, return `{ status, exitCode }`). The `plurnk-execs-sh` / `-node` / `-python` siblings subclass it and differ only in their claimed `runtimes[]` tags. plurnk-service consumes `resolveRuntime` directly on its legacy path today and adopts `SubprocessExecutor` when it migrates.
58
115
 
59
- The `exec` scheme in plurnk-service:
116
+ ## §5 Consumer surface (plurnk-service)
60
117
 
61
- 1. Calls `isKnownRuntime(runtime)` returns 501 if false.
62
- 2. Calls `resolveRuntime(runtime, command)` to get `SpawnArgs`.
63
- 3. Passes args to `node:child_process.spawn` and manages the subprocess lifecycle (channels, AbortController, subscription registry, wake-on-completion).
118
+ Per plurnk-service#174, the exec scheme:
64
119
 
65
- Steps 1–2 are this repo's surface. Step 3 stays in the `exec` scheme. The plug-in discovery future (§3) will absorb step 3's invocation into the executor interface, but for v0 the scheme owns the spawn/streaming machinery and consumes this repo only for the runtime-tag translation.
120
+ 1. Resolves the runtime tag against the discovery registry; routes `search` (and future siblings) through the executor's `run()`.
121
+ 2. Seeds the exec entry's channels from `executor.channels`.
122
+ 3. Provides the `write` / `setState` / `emit` sinks bound to its channel-write, channel-state, and engine-telemetry machinery; bridges its AbortController to `args.signal`; maps the `ExecResult` to close-status + wake summary.
123
+ 4. Keeps the legacy `streamShellCommand` path (via `resolveRuntime`) for subprocess runtimes until the `SubprocessExecutor` migration.
66
124
 
67
- ## §5 Forbidden (for future siblings)
125
+ ## §6 Forbidden (for siblings)
68
126
 
69
127
  | ❌ |
70
128
  |---|
71
129
  | Database access |
72
130
  | Imports from `@plurnk/plurnk-service/*` |
73
- | Mutating arguments |
74
- | Holding state across `run` calls beyond config |
131
+ | Mutating `ExecArgs` |
132
+ | Holding state across `run` calls beyond construction metadata |
75
133
  | Reading runtime output via `console.*` |
76
- | Ignoring cancellation signals |
77
- | Spawning processes outside the runtime's domain (e.g. an HTTP runtime spawning subprocesses) |
134
+ | Ignoring `args.signal` |
135
+ | Writing to an undeclared channel |
136
+ | Spawning processes outside the runtime's domain (e.g. an HTTP/search runtime spawning subprocesses) |
@@ -0,0 +1,10 @@
1
+ import type { ChannelDecl, ExecArgs, ExecResult, ExecutorMetadata, RuntimeAvailability } from "./types.ts";
2
+ export default abstract class BaseExecutor {
3
+ readonly runtime: string;
4
+ readonly glyph: string;
5
+ constructor({ runtime, glyph }: ExecutorMetadata);
6
+ abstract get channels(): Readonly<Record<string, ChannelDecl>>;
7
+ abstract run(args: ExecArgs): Promise<ExecResult>;
8
+ probe(): Promise<RuntimeAvailability>;
9
+ }
10
+ //# sourceMappingURL=BaseExecutor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseExecutor.d.ts","sourceRoot":"","sources":["../src/BaseExecutor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAW3G,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,YAAY;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,gBAAgB;IAUhD,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAO/D,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAY3C,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC;CAG9C"}
@@ -0,0 +1,31 @@
1
+ // Base class for runtime executors (parallel to plurnk-mimetypes' BaseHandler).
2
+ // A `@plurnk/plurnk-execs-*` sibling subclasses this and implements `run()`.
3
+ // The framework instantiates one executor per matched runtime tag, injecting
4
+ // the tag + glyph from the package's `plurnk.runtimes[]` manifest entry.
5
+ //
6
+ // The consuming scheme owns all I/O and lifecycle machinery (db, channels,
7
+ // subscriptions, AbortController bridging, wake-on-completion). The executor
8
+ // receives sinks via ExecArgs and nothing more — it stays stateless across
9
+ // runs beyond its construction metadata (SPEC §5).
10
+ export default class BaseExecutor {
11
+ runtime;
12
+ glyph;
13
+ constructor({ runtime, glyph }) {
14
+ this.runtime = runtime;
15
+ this.glyph = glyph;
16
+ }
17
+ // Whether this runtime's execution environment is usable in the current
18
+ // deployment. Default: available (pure / in-process runtimes — e.g. node,
19
+ // sqlite, where the daemon itself satisfies the dependency). Subclasses
20
+ // that depend on an external binary or external config override.
21
+ //
22
+ // The consumer probes once at boot, per package, runs probes concurrently
23
+ // under a per-probe timeout, and caches the result. Unlike `run()`, this
24
+ // MAY reject — the consumer treats a rejection as `{ available: false }` —
25
+ // but returning a crafted `{ available: false, detail }` for an expected
26
+ // miss gives a better model-facing reason than a raw error.
27
+ async probe() {
28
+ return { available: true };
29
+ }
30
+ }
31
+ //# sourceMappingURL=BaseExecutor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseExecutor.js","sourceRoot":"","sources":["../src/BaseExecutor.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,6EAA6E;AAC7E,6EAA6E;AAC7E,yEAAyE;AACzE,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;AAC7E,2EAA2E;AAC3E,mDAAmD;AACnD,MAAM,CAAC,OAAO,OAAgB,YAAY;IAC7B,OAAO,CAAS;IAChB,KAAK,CAAS;IAEvB,YAAY,EAAE,OAAO,EAAE,KAAK,EAAoB;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;IAgBD,wEAAwE;IACxE,0EAA0E;IAC1E,wEAAwE;IACxE,iEAAiE;IACjE,EAAE;IACF,0EAA0E;IAC1E,yEAAyE;IACzE,2EAA2E;IAC3E,yEAAyE;IACzE,4DAA4D;IAC5D,KAAK,CAAC,KAAK;QACP,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;CACJ"}
@@ -0,0 +1,9 @@
1
+ import BaseExecutor from "./BaseExecutor.ts";
2
+ import type { ChannelDecl, ExecArgs, ExecResult, RuntimeAvailability } from "./types.ts";
3
+ export default class SubprocessExecutor extends BaseExecutor {
4
+ get channels(): Readonly<Record<string, ChannelDecl>>;
5
+ protected get binary(): string | null;
6
+ probe(): Promise<RuntimeAvailability>;
7
+ run({ runtime, command, cwd, signal, write, setState, emit }: ExecArgs): Promise<ExecResult>;
8
+ }
9
+ //# sourceMappingURL=SubprocessExecutor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubprocessExecutor.d.ts","sourceRoot":"","sources":["../src/SubprocessExecutor.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,mBAAmB,CAAC;AAE7C,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAWzF,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,YAAY;IACxD,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAKpD;IAKD,SAAS,KAAK,MAAM,IAAI,MAAM,GAAG,IAAI,CAEpC;IAEc,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAqBpD,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;CAwC/F"}
@@ -0,0 +1,89 @@
1
+ import { spawn } from "node:child_process";
2
+ import BaseExecutor from "./BaseExecutor.js";
3
+ import { resolveRuntime } from "./runtime.js";
4
+ // Concrete BaseExecutor for subprocess runtimes (sh, node, python, …). Spawns
5
+ // via resolveRuntime, streams the process's stdout/stderr into the declared
6
+ // channels, honors cancellation, and reports the exit code. The sibling
7
+ // packages (plurnk-execs-sh / -node / -python) subclass this and differ only
8
+ // in which runtime tags they claim in their `plurnk.runtimes[]` manifest.
9
+ //
10
+ // This is the destination of plurnk-service's legacy `streamShellCommand`
11
+ // (service#174 Q2): the scheme migrates onto it on its own timeline; until
12
+ // then both paths coexist.
13
+ export default class SubprocessExecutor extends BaseExecutor {
14
+ get channels() {
15
+ return {
16
+ stdout: { mimetype: "text/stream" },
17
+ stderr: { mimetype: "text/stream" },
18
+ };
19
+ }
20
+ // The executable this runtime depends on, for probe(). `null` = nothing to
21
+ // check (always available — e.g. node, where the daemon already IS the
22
+ // runtime). Subclasses naming an external interpreter override this.
23
+ get binary() {
24
+ return null;
25
+ }
26
+ async probe() {
27
+ const bin = this.binary;
28
+ if (bin === null)
29
+ return { available: true };
30
+ return new Promise((resolve) => {
31
+ let settled = false;
32
+ const done = (r) => { if (!settled) {
33
+ settled = true;
34
+ resolve(r);
35
+ } };
36
+ let out = "";
37
+ const child = spawn(bin, ["--version"], { signal: AbortSignal.timeout(3000) });
38
+ child.stdout?.on("data", (chunk) => { out += chunk.toString("utf8"); });
39
+ child.on("error", (err) => done({
40
+ available: false,
41
+ detail: err.code === "ABORT_ERR"
42
+ ? `${bin} probe timed out`
43
+ : `${bin} not found on PATH`,
44
+ }));
45
+ child.on("close", (code) => done(code === 0
46
+ ? { available: true, detail: out.trim().split("\n")[0] || undefined }
47
+ : { available: false, detail: `${bin} --version exited ${code}` }));
48
+ });
49
+ }
50
+ run({ runtime, command, cwd, signal, write, setState, emit }) {
51
+ const { cmd, args, useShell } = resolveRuntime(runtime, command);
52
+ return new Promise((resolve) => {
53
+ // Abort and close both fire on signal-kill; settle exactly once so
54
+ // channel state isn't transitioned twice.
55
+ let settled = false;
56
+ const finish = (result, state) => {
57
+ if (settled)
58
+ return;
59
+ settled = true;
60
+ setState("stdout", state);
61
+ setState("stderr", state);
62
+ resolve(result);
63
+ };
64
+ const child = spawn(cmd, args, { shell: useShell, signal, cwd: cwd ?? undefined });
65
+ child.stdout?.on("data", (chunk) => write("stdout", chunk.toString("utf8")));
66
+ child.stderr?.on("data", (chunk) => write("stderr", chunk.toString("utf8")));
67
+ child.on("error", (err) => {
68
+ if (err.code === "ABORT_ERR") {
69
+ finish({ status: 499, exitCode: -1 }, "errored");
70
+ return;
71
+ }
72
+ // The process could not be started — a framework-level failure
73
+ // the model benefits from seeing as telemetry (a nonzero exit,
74
+ // by contrast, is the program's own result and lives on stderr).
75
+ emit({ source: `exec:${runtime}`, kind: "spawn_failed", message: err.message });
76
+ finish({ status: 500, exitCode: -1 }, "errored");
77
+ });
78
+ child.on("close", (code, killedBySignal) => {
79
+ if (killedBySignal !== null) {
80
+ finish({ status: 499, exitCode: code ?? -1 }, "errored");
81
+ return;
82
+ }
83
+ const ok = code === 0;
84
+ finish({ status: ok ? 200 : 500, exitCode: code ?? -1 }, ok ? "closed" : "errored");
85
+ });
86
+ });
87
+ }
88
+ }
89
+ //# sourceMappingURL=SubprocessExecutor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubprocessExecutor.js","sourceRoot":"","sources":["../src/SubprocessExecutor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,YAAY,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,8EAA8E;AAC9E,4EAA4E;AAC5E,wEAAwE;AACxE,6EAA6E;AAC7E,0EAA0E;AAC1E,EAAE;AACF,0EAA0E;AAC1E,2EAA2E;AAC3E,2BAA2B;AAC3B,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,YAAY;IACxD,IAAI,QAAQ;QACR,OAAO;YACH,MAAM,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE;YACnC,MAAM,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE;SACtC,CAAC;IACN,CAAC;IAED,2EAA2E;IAC3E,uEAAuE;IACvE,qEAAqE;IACrE,IAAc,MAAM;QAChB,OAAO,IAAI,CAAC;IAChB,CAAC;IAEQ,KAAK,CAAC,KAAK;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QACxB,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC7C,OAAO,IAAI,OAAO,CAAsB,CAAC,OAAO,EAAE,EAAE;YAChD,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,MAAM,IAAI,GAAG,CAAC,CAAsB,EAAQ,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;gBAAC,OAAO,GAAG,IAAI,CAAC;gBAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAAC,CAAC,CAAC,CAAC,CAAC;YACjG,IAAI,GAAG,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/E,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,GAAG,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAChF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC;gBAC5B,SAAS,EAAE,KAAK;gBAChB,MAAM,EAAG,GAA6B,CAAC,IAAI,KAAK,WAAW;oBACvD,CAAC,CAAC,GAAG,GAAG,kBAAkB;oBAC1B,CAAC,CAAC,GAAG,GAAG,oBAAoB;aACnC,CAAC,CAAC,CAAC;YACJ,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC;gBACvC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE;gBACrE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,qBAAqB,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;IACP,CAAC;IAED,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAY;QAClE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjE,OAAO,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,EAAE;YACvC,mEAAmE;YACnE,0CAA0C;YAC1C,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,MAAM,MAAM,GAAG,CAAC,MAAkB,EAAE,KAA2B,EAAQ,EAAE;gBACrE,IAAI,OAAO;oBAAE,OAAO;gBACpB,OAAO,GAAG,IAAI,CAAC;gBACf,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBAC1B,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBAC1B,OAAO,CAAC,MAAM,CAAC,CAAC;YACpB,CAAC,CAAC;YAEF,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,SAAS,EAAE,CAAC,CAAC;YACnF,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACrF,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAErF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBACtD,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;oBACjD,OAAO;gBACX,CAAC;gBACD,+DAA+D;gBAC/D,+DAA+D;gBAC/D,iEAAiE;gBACjE,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;gBAChF,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE;gBACvC,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;oBAC1B,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;oBACzD,OAAO;gBACX,CAAC;gBACD,MAAM,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;gBACtB,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YACxF,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;CACJ"}
@@ -0,0 +1,18 @@
1
+ export interface TelemetryEvent {
2
+ readonly source: string;
3
+ readonly kind: string;
4
+ readonly message?: string | null;
5
+ readonly position?: ContentOffset | LogCoordinate | null;
6
+ readonly [k: string]: unknown;
7
+ }
8
+ export interface ContentOffset {
9
+ readonly type: "content-offset";
10
+ readonly line: number;
11
+ readonly column: number;
12
+ }
13
+ export interface LogCoordinate {
14
+ readonly type: "log-coordinate";
15
+ readonly coordinate: string;
16
+ readonly op?: string;
17
+ }
18
+ //# sourceMappingURL=TelemetryEvent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TelemetryEvent.d.ts","sourceRoot":"","sources":["../src/TelemetryEvent.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,aAAa,GAAG,IAAI,CAAC;IACzD,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACxB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=TelemetryEvent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TelemetryEvent.js","sourceRoot":"","sources":["../src/TelemetryEvent.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import type { Discovery, DiscoverOptions } from "./types.ts";
2
+ export declare function discover(options?: DiscoverOptions): Promise<Discovery>;
3
+ //# sourceMappingURL=discover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAY,MAAM,YAAY,CAAC;AAkBvE,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,SAAS,CAAC,CAkBhF"}
@@ -0,0 +1,92 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ // Scan installed executor packages and build the runtime-tag registry the
4
+ // consuming scheme dispatches on. Parallel to plurnk-mimetypes' discover().
5
+ //
6
+ // Default scan target: `<cwd>/node_modules/@plurnk/`. Tests and unusual
7
+ // layouts can pass `packageDirs` explicitly to skip the scan.
8
+ //
9
+ // A package is recognized as an executor when its `package.json` declares
10
+ // `plurnk.kind === "exec"` and exposes one or more runtime tags via
11
+ // `plurnk.runtimes: { name, glyph? }[]` (SPEC §3). Each entry registers its
12
+ // tag separately; one package can claim many tags backed by the same handler
13
+ // (e.g. the search sibling claims `search`, `news`, `images`, …).
14
+ //
15
+ // Tags are a flat global namespace. Unlike plurnk-mimetypes (last-loaded
16
+ // wins), a tag collision here is a FAIL-HARD install error: two packages
17
+ // claiming the same runtime is an unresolvable ambiguity the operator must
18
+ // fix (SPEC §3, plurnk-execs#1).
19
+ export async function discover(options = {}) {
20
+ const dirs = options.packageDirs ?? await defaultPackageDirs(options.cwd ?? process.cwd());
21
+ const registry = new Map();
22
+ for (const dir of dirs) {
23
+ for (const info of await readExecInfos(dir)) {
24
+ const existing = registry.get(info.runtime);
25
+ if (existing !== undefined) {
26
+ throw new Error(`exec runtime collision: '${info.runtime}' claimed by both `
27
+ + `${existing.packageName} and ${info.packageName}`);
28
+ }
29
+ registry.set(info.runtime, info);
30
+ }
31
+ }
32
+ return { registry };
33
+ }
34
+ async function defaultPackageDirs(cwd) {
35
+ const scope = path.join(cwd, "node_modules", "@plurnk");
36
+ let entries;
37
+ try {
38
+ entries = await fs.readdir(scope, { withFileTypes: true });
39
+ }
40
+ catch {
41
+ return [];
42
+ }
43
+ return entries
44
+ .filter((entry) => entry.isDirectory())
45
+ .map((entry) => path.join(scope, entry.name));
46
+ }
47
+ // Produce one ExecInfo per declared runtime tag. Returns [] for non-executor
48
+ // packages or invalid declarations.
49
+ async function readExecInfos(dir) {
50
+ const pkgPath = path.join(dir, "package.json");
51
+ let raw;
52
+ try {
53
+ raw = await fs.readFile(pkgPath, "utf-8");
54
+ }
55
+ catch {
56
+ return [];
57
+ }
58
+ let pkg;
59
+ try {
60
+ pkg = JSON.parse(raw);
61
+ }
62
+ catch {
63
+ return [];
64
+ }
65
+ if (typeof pkg !== "object" || pkg === null)
66
+ return [];
67
+ const record = pkg;
68
+ const plurnk = record.plurnk;
69
+ if (typeof plurnk !== "object" || plurnk === null)
70
+ return [];
71
+ const plurnkRec = plurnk;
72
+ if (plurnkRec.kind !== "exec")
73
+ return [];
74
+ if (!Array.isArray(plurnkRec.runtimes))
75
+ return [];
76
+ const packageName = typeof record.name === "string" ? record.name : "";
77
+ const infos = [];
78
+ for (const entry of plurnkRec.runtimes) {
79
+ if (typeof entry !== "object" || entry === null)
80
+ continue;
81
+ const e = entry;
82
+ if (typeof e.name !== "string" || e.name === "")
83
+ continue;
84
+ infos.push({
85
+ runtime: e.name,
86
+ glyph: typeof e.glyph === "string" ? e.glyph : "",
87
+ packageName,
88
+ });
89
+ }
90
+ return infos;
91
+ }
92
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
- export type { SpawnArgs, RuntimeResolver } from "./types.ts";
1
+ export { default as BaseExecutor } from "./BaseExecutor.ts";
2
+ export { default as SubprocessExecutor } from "./SubprocessExecutor.ts";
3
+ export { discover } from "./discover.ts";
2
4
  export { KNOWN_RUNTIMES, isKnownRuntime, resolveRuntime } from "./runtime.ts";
5
+ export type { ChannelState, ChannelDecl, ExecutorMetadata, ExecArgs, ExecResult, RuntimeAvailability, ExecInfo, ExecRegistry, Discovery, DiscoverOptions, SpawnArgs, RuntimeResolver, } from "./types.ts";
6
+ export type { TelemetryEvent, ContentOffset, LogCoordinate } from "./TelemetryEvent.ts";
3
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9E,YAAY,EACR,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,QAAQ,EACR,UAAU,EACV,mBAAmB,EACnB,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,eAAe,EACf,SAAS,EACT,eAAe,GAClB,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,7 @@
1
+ // Framework surface
2
+ export { default as BaseExecutor } from "./BaseExecutor.js";
3
+ export { default as SubprocessExecutor } from "./SubprocessExecutor.js";
4
+ export { discover } from "./discover.js";
5
+ // Runtime-tag → spawn-args helper (subprocess family; legacy scheme path)
1
6
  export { KNOWN_RUNTIMES, isKnownRuntime, resolveRuntime } from "./runtime.js";
2
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,0EAA0E;AAC1E,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,3 +1,43 @@
1
+ import type { TelemetryEvent } from "./TelemetryEvent.ts";
2
+ export type ChannelState = "active" | "closed" | "errored";
3
+ export interface ChannelDecl {
4
+ mimetype: string;
5
+ defaultState?: ChannelState;
6
+ }
7
+ export interface ExecutorMetadata {
8
+ runtime: string;
9
+ glyph: string;
10
+ }
11
+ export interface ExecArgs {
12
+ runtime: string;
13
+ command: string;
14
+ cwd: string | null;
15
+ signal: AbortSignal;
16
+ write: (channel: string, chunk: string) => void;
17
+ setState: (channel: string, state: ChannelState) => void;
18
+ emit: (event: TelemetryEvent) => void;
19
+ }
20
+ export interface ExecResult {
21
+ status: number;
22
+ exitCode?: number;
23
+ }
24
+ export interface RuntimeAvailability {
25
+ available: boolean;
26
+ detail?: string;
27
+ }
28
+ export interface ExecInfo {
29
+ runtime: string;
30
+ glyph: string;
31
+ packageName: string;
32
+ }
33
+ export type ExecRegistry = ReadonlyMap<string, ExecInfo>;
34
+ export interface Discovery {
35
+ registry: ExecRegistry;
36
+ }
37
+ export interface DiscoverOptions {
38
+ cwd?: string;
39
+ packageDirs?: string[];
40
+ }
1
41
  export interface SpawnArgs {
2
42
  /** Command to invoke (e.g. "node", "python3", or — when useShell — the raw command). */
3
43
  cmd: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,SAAS;IACtB,wFAAwF;IACxF,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,mGAAmG;IACnG,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,SAAS,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAI1D,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAM3D,MAAM,WAAW,WAAW;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC/B;AAKD,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACjB;AAOD,MAAM,WAAW,QAAQ;IAGrB,OAAO,EAAE,MAAM,CAAC;IAEhB,OAAO,EAAE,MAAM,CAAC;IAGhB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnB,MAAM,EAAE,WAAW,CAAC;IAEpB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEhD,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAGzD,IAAI,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CACzC;AAKD,MAAM,WAAW,UAAU;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD,MAAM,WAAW,mBAAmB;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,QAAQ;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACvB;AAID,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEzD,MAAM,WAAW,SAAS;IACtB,QAAQ,EAAE,YAAY,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAG5B,GAAG,CAAC,EAAE,MAAM,CAAC;IAGb,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAID,MAAM,WAAW,SAAS;IACtB,wFAAwF;IACxF,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,mGAAmG;IACnG,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,SAAS,CAAC"}
package/dist/types.js CHANGED
@@ -1,9 +1,12 @@
1
1
  // Runtime executor contract. Each `@plurnk/plurnk-execs-*` sibling declares
2
- // one or more runtime tags (`sh`, `bash`, `python`, `search`, etc.) and
3
- // provides the dispatch logic for those tags.
2
+ // one or more runtime tags (`sh`, `bash`, `python`, `search`, `news`, …) in
3
+ // its `package.json` `plurnk.runtimes[]` block, and provides a BaseExecutor
4
+ // subclass implementing the dispatch for those tags.
4
5
  //
5
- // v0 surface: runtime tag spawn-args translator (the only piece
6
- // plurnk-service's exec scheme needs migrated out of its own codebase).
7
- // Plugin discovery / framework registry is forward-spec see SPEC.md.
6
+ // The framework surface is `BaseExecutor.run()` + `discover()`. The runtime
7
+ // tag spawn-args translator (`SpawnArgs` / `resolveRuntime`) is retained as
8
+ // a subprocess-family helper: plurnk-service's exec scheme still consumes it
9
+ // on its legacy subprocess path until the deferred SubprocessExecutor
10
+ // migration (service#174 Q2). See SPEC.md.
8
11
  export {};
9
12
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,wEAAwE;AACxE,8CAA8C;AAC9C,EAAE;AACF,kEAAkE;AAClE,wEAAwE;AACxE,uEAAuE"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,4EAA4E;AAC5E,4EAA4E;AAC5E,qDAAqD;AACrD,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,sEAAsE;AACtE,2CAA2C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plurnk/plurnk-execs",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Framework + contract for the @plurnk/plurnk-execs-* runtime executor family.",
5
5
  "keywords": ["plurnk", "exec", "runtime", "executor"],
6
6
  "homepage": "https://github.com/plurnk/plurnk-execs#readme",