@plurnk/plurnk-execs 0.4.18 → 0.4.20
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/SPEC.md +20 -1
- package/dist/BaseExecutor.d.ts.map +1 -1
- package/dist/BaseExecutor.js +11 -9
- package/dist/BaseExecutor.js.map +1 -1
- package/dist/SubprocessExecutor.js +10 -10
- package/dist/SubprocessExecutor.js.map +1 -1
- package/dist/discover.d.ts +4 -1
- package/dist/discover.d.ts.map +1 -1
- package/dist/discover.js +188 -182
- package/dist/discover.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +5 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +27 -20
- package/dist/runtime.js.map +1 -1
- package/package.json +3 -3
package/SPEC.md
CHANGED
|
@@ -93,6 +93,25 @@ Runtime failures are emitted as a grammar `TelemetryEvent` via the `emit` sink (
|
|
|
93
93
|
|
|
94
94
|
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.
|
|
95
95
|
|
|
96
|
+
### §2.5 Deadlines & polling — the executor stays oblivious
|
|
97
|
+
|
|
98
|
+
An EXEC op may carry a `<L>` line-marker slot read as `[TIMEOUT_SECONDS, POLL_SECONDS?]` (plurnk-grammar#39, plurnk-service#277): `<1800>` hard-kills at 1800s, `<-1>` declines a per-exec deadline (still loop-life bounded), `<1800,300>` adds a 300s loop-poll. **None of this touches the executor contract.** `run()` stays stream-only and abort-driven:
|
|
99
|
+
|
|
100
|
+
- The **timeout** is the consumer's: at the deadline it fires `args.signal` — arriving as an ordinary abort the executor already honors (the §4 process-group SIGHUP→grace→KILL path). No deadline awareness in the executor.
|
|
101
|
+
- The **poll** is purely the consumer's loop: it wakes on a cadence while the channel is `active`, reading the partial output the executor already streams incrementally via `write`. The executor never sees a tick; it's non-destructive.
|
|
102
|
+
|
|
103
|
+
So the feature is contract-free for executors and applies to all of them uniformly: a long-runner is bounded/watched by the op slot, a fast/logical executor (search) terminates before the first tick and the slot is a no-op.
|
|
104
|
+
|
|
105
|
+
### §2.6 Output addressing — the executor produces, the consumer reads
|
|
106
|
+
|
|
107
|
+
An executor is a **producer, not a reader.** Its whole output contract is `run()` writing channels (`write` / `setState` / `emit`); the consumer streams those into an ordinary log entry addressed at **`<tag>://<coord>`** (the run's `<runtime>:///<loop>/<turn>/<seq>`), and every READ/FIND over that output is the consumer's uniform entry machinery — identical for `sh`, `search`, `sqlite`, and MCP alike. The executor never reads, slices, summarizes, or orients its own output.
|
|
108
|
+
|
|
109
|
+
The executor's only scheme-facing contribution is a **derived manifest** — `OutputScheme.manifestFromRuntime({ name, glyph, channels, defaultChannel })`, built from the runtime declaration, no separate authoring — so the consumer can mint a per-tag output scheme (name = the tag) and the model can address `<tag>://`. `defaultChannel` (first declared channel; subprocess → `stdout`) is where a bare `READ <tag>://<coord>` lands. `discover()` is unchanged (static install/config truth, §3); activation (§3.2) is the consumer's runtime overlay.
|
|
110
|
+
|
|
111
|
+
**No executor read-face; no per-runtime read, no orientation receipt.** `BaseExecutor` implements no `read`/`find`, and none is wired downstream — not one sibling in the family overrides them (the "rich" `sqlite`/MCP included), and the consumer's per-tag scheme serves every READ through its single `DefaultRead` resolver (which holds the `Mimetypes` instance + output store the executor never sees) over the stored entry. Orientation is **model-pulled**: the model probes an output's shape by querying the entry (FIND / READ with jsonpath / glob / line-range) against the neutral `{ mimetype, tokens, lines }` every entry carries, pulling only the slice it wants. An engine-pushed shape digest *is* the catalog-as-index the paradigm forbids ("the instant it did, it would be an index again") — so there is none, and the answer to service#240's *"where is the OrientIndex receipt built?"* is **nowhere; nothing builds one.** A `<tag>://` entry is folded by default, so output never floods context regardless; the one real risk — a chatty runtime filling sqlite — is a daemon storage-cap concern, not an executor one.
|
|
112
|
+
|
|
113
|
+
MCP is the proof, not the exception: `plurnk-execs-mcp` is a plain producer — `run()` calls the tool and writes its JSON result to a `results` channel, exactly as `search` writes `results` — with no `read`, no `find`, no summary. Bring a need and it maps onto the log; the log paradigm already orients, and the executor never curates.
|
|
114
|
+
|
|
96
115
|
## §3 Discovery
|
|
97
116
|
|
|
98
117
|
`discover(options?) → { registry }`. Scans **every installed package** under `<cwd>/node_modules` — scope-agnostic (scoped and unscoped) — for those declaring `plurnk.kind === "exec"`, and registers each runtime tag from `plurnk.runtimes[]`. The scan is deliberately not limited to `@plurnk/*`: a **third party** can publish an executor under their own scope (`@acme/acme-execs-foo`) and have it discovered with no involvement from this project. (For the batteries-included set, an aggregator package — `@plurnk/plurnk-execs-all` — depends on the framework's daughters flat so one install surfaces them all; the framework itself stays contract-only.)
|
|
@@ -189,7 +208,7 @@ interface SpawnArgs { cmd: string; args: string[]; useShell: boolean; }
|
|
|
189
208
|
|
|
190
209
|
`resolveRuntime` never throws; consumers gate unknown runtimes with `isKnownRuntime` and return 501 before invoking.
|
|
191
210
|
|
|
192
|
-
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 }`). Subclasses with their own interpreter table override the **`protected spawnArgs(runtime, command) → SpawnArgs`** hook (default delegates to `resolveRuntime`) — and so inherit run()'s streaming + process-group abort handling. `SpawnArgs.stdin?` lets filter-style runtimes feed their program/input via stdin (`bc`, `tclsh`; or `""` for an `awk` BEGIN with EOF). On abort it
|
|
211
|
+
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 }`). Subclasses with their own interpreter table override the **`protected spawnArgs(runtime, command) → SpawnArgs`** hook (default delegates to `resolveRuntime`) — and so inherit run()'s streaming + process-group abort handling. `SpawnArgs.stdin?` lets filter-style runtimes feed their program/input via stdin (`bc`, `tclsh`; or `""` for an `awk` BEGIN with EOF). On abort it signals the whole **process group** (`detached` spawn + `process.kill(-pid, …)`) so shell grandchildren can't leak (plurnk-execs#4): the default abort is a polite **SIGHUP**, once, no escalation; a `KILL[code]` reason carrying `{ signal }` delivers exactly that signal, fire-and-forget; only the consumer's loop-end housekeeping reason (`{ housekeeping: true, graceMs }`) escalates SIGHUP→**SIGKILL** after the consumer-sourced grace (never a magic number here). The `plurnk-execs-common` sibling subclasses it — claiming the whole subprocess set (sh/bash/node/python plus detected host interpreters) via a recipe table behind a `spawnArgs()` / `probe()` override. `isKnownRuntime` / `KNOWN_RUNTIMES` are the legacy 501 gate; the discovery registry + `probe()` supersede them once a consumer wires the registry.
|
|
193
212
|
|
|
194
213
|
## §5 Consumer surface (plurnk-service)
|
|
195
214
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseExecutor.d.ts","sourceRoot":"","sources":["../src/BaseExecutor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAWnH,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,YAAa,YAAW,aAAa;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,gBAAgB;
|
|
1
|
+
{"version":3,"file":"BaseExecutor.d.ts","sourceRoot":"","sources":["../src/BaseExecutor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAWnH,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,YAAa,YAAW,aAAa;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,gBAAgB;IAehD,IAAI,QAAQ,IAAI,cAAc,CAS7B;IAID,IAAI,cAAc,IAAI,MAAM,CAE3B;IAOD,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;IAW3C,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;CAGzC"}
|
package/dist/BaseExecutor.js
CHANGED
|
@@ -7,7 +7,7 @@ import { OutputScheme } from "@plurnk/plurnk-schemes";
|
|
|
7
7
|
// The consuming scheme owns all I/O and lifecycle machinery (db, channels,
|
|
8
8
|
// subscriptions, AbortController bridging, wake-on-completion). The executor
|
|
9
9
|
// receives sinks via ExecArgs and nothing more — it stays stateless across
|
|
10
|
-
// runs beyond its construction metadata (SPEC §5).
|
|
10
|
+
// runs beyond its construction metadata (SPEC §5; the statelessness rule is §6).
|
|
11
11
|
export default class BaseExecutor {
|
|
12
12
|
runtime;
|
|
13
13
|
glyph;
|
|
@@ -15,14 +15,16 @@ export default class BaseExecutor {
|
|
|
15
15
|
this.runtime = runtime;
|
|
16
16
|
this.glyph = glyph;
|
|
17
17
|
}
|
|
18
|
-
// --- executor
|
|
19
|
-
// The executor
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
18
|
+
// --- output addressing: the executor produces, the consumer reads (SPEC §2.6)
|
|
19
|
+
// The executor is a PRODUCER. Its output streams (via run()'s write/setState)
|
|
20
|
+
// into a consumer-held log entry addressed at `<tag>://<coord>`; every READ /
|
|
21
|
+
// FIND over that entry is the consumer's uniform machinery, identical across
|
|
22
|
+
// every tag (MCP no exception). The executor's only scheme-facing job is to
|
|
23
|
+
// DECLARE the output scheme's manifest — derived from the runtime decl via
|
|
24
|
+
// schemes' `manifestFromRuntime`, which is the sole reason it conforms to
|
|
25
|
+
// SchemeHandler. It serves no read: BaseExecutor implements no read/find and
|
|
26
|
+
// none is wired downstream — no sibling overrides them, and orientation is
|
|
27
|
+
// model-pulled (the model queries the entry), never an executor-built digest.
|
|
26
28
|
get manifest() {
|
|
27
29
|
return OutputScheme.manifestFromRuntime({
|
|
28
30
|
name: this.runtime,
|
package/dist/BaseExecutor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseExecutor.js","sourceRoot":"","sources":["../src/BaseExecutor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAItD,gFAAgF;AAChF,6EAA6E;AAC7E,6EAA6E;AAC7E,yEAAyE;AACzE,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;AAC7E,2EAA2E;AAC3E,
|
|
1
|
+
{"version":3,"file":"BaseExecutor.js","sourceRoot":"","sources":["../src/BaseExecutor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAItD,gFAAgF;AAChF,6EAA6E;AAC7E,6EAA6E;AAC7E,yEAAyE;AACzE,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;AAC7E,2EAA2E;AAC3E,iFAAiF;AACjF,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;IAED,+EAA+E;IAC/E,8EAA8E;IAC9E,8EAA8E;IAC9E,6EAA6E;IAC7E,4EAA4E;IAC5E,2EAA2E;IAC3E,0EAA0E;IAC1E,6EAA6E;IAC7E,2EAA2E;IAC3E,8EAA8E;IAC9E,IAAI,QAAQ;QACR,OAAO,YAAY,CAAC,mBAAmB,CAAC;YACpC,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,MAAM,CAAC,WAAW,CACxB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAC7E;YACD,cAAc,EAAE,IAAI,CAAC,cAAc;SACtC,CAAC,CAAC;IACP,CAAC;IAED,yEAAyE;IACzE,oEAAoE;IACpE,IAAI,cAAc;QACd,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,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;IAED,uEAAuE;IACvE,2EAA2E;IAC3E,0EAA0E;IAC1E,yEAAyE;IACzE,qEAAqE;IACrE,4EAA4E;IAC5E,iEAAiE;IACjE,MAAM,CAAC,OAAsB;QACzB,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import BaseExecutor from "./BaseExecutor.js";
|
|
3
|
-
import
|
|
3
|
+
import Runtime from "./runtime.js";
|
|
4
4
|
// KILL[code]: an abort reason carrying `{ signal }` (a Unix signal name or
|
|
5
5
|
// number) delivers exactly that signal, once, fire-and-forget — no escalation;
|
|
6
6
|
// the model asked for a specific code. Absent → null → the polite default.
|
|
@@ -48,6 +48,11 @@ export default class SubprocessExecutor extends BaseExecutor {
|
|
|
48
48
|
const bin = this.binary;
|
|
49
49
|
if (bin === null)
|
|
50
50
|
return { available: true };
|
|
51
|
+
// No internal deadline. The per-probe timeout is the consumer's — set
|
|
52
|
+
// once from its env and applied uniformly across the family (SPEC §2.2);
|
|
53
|
+
// the executor stays oblivious to deadlines here exactly as it does for
|
|
54
|
+
// run() (SPEC §2.5). A timed-out probe is surfaced consumer-side as the
|
|
55
|
+
// rejection→unavailable it already treats any probe failure as.
|
|
51
56
|
return new Promise((resolve) => {
|
|
52
57
|
let settled = false;
|
|
53
58
|
const done = (r) => { if (!settled) {
|
|
@@ -55,25 +60,20 @@ export default class SubprocessExecutor extends BaseExecutor {
|
|
|
55
60
|
resolve(r);
|
|
56
61
|
} };
|
|
57
62
|
let out = "";
|
|
58
|
-
const child = spawn(bin, ["--version"]
|
|
63
|
+
const child = spawn(bin, ["--version"]);
|
|
59
64
|
child.stdout?.on("data", (chunk) => { out += chunk.toString("utf8"); });
|
|
60
|
-
child.on("error", (
|
|
61
|
-
available: false,
|
|
62
|
-
detail: err.code === "ABORT_ERR"
|
|
63
|
-
? `${bin} probe timed out`
|
|
64
|
-
: `${bin} not found on PATH`,
|
|
65
|
-
}));
|
|
65
|
+
child.on("error", () => done({ available: false, detail: `${bin} not found on PATH` }));
|
|
66
66
|
child.on("close", (code) => done(code === 0
|
|
67
67
|
? { available: true, detail: out.trim().split("\n")[0] || undefined }
|
|
68
68
|
: { available: false, detail: `${bin} --version exited ${code}` }));
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
// Translate the matched tag + command into spawn args. Default delegates to
|
|
72
|
-
//
|
|
72
|
+
// Runtime.resolve (sh/node/python); subclasses with their own interpreter
|
|
73
73
|
// table (e.g. the common-REPL harness) override this — and so inherit run()'s
|
|
74
74
|
// streaming + process-group abort handling rather than reimplementing it.
|
|
75
75
|
spawnArgs(runtime, command) {
|
|
76
|
-
return
|
|
76
|
+
return Runtime.resolve(runtime, command);
|
|
77
77
|
}
|
|
78
78
|
run({ runtime, command, cwd, env, signal, write, setState, emit }) {
|
|
79
79
|
const { cmd, args, useShell, stdin } = this.spawnArgs(runtime, command);
|
|
@@ -1 +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,
|
|
1
|
+
{"version":3,"file":"SubprocessExecutor.js","sourceRoot":"","sources":["../src/SubprocessExecutor.ts"],"names":[],"mappings":"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"}
|
package/dist/discover.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import type { Discovery, DiscoverOptions } from "./types.ts";
|
|
2
|
-
export
|
|
2
|
+
export default class Discover {
|
|
3
|
+
#private;
|
|
4
|
+
static scan(options?: DiscoverOptions): Promise<Discovery>;
|
|
5
|
+
}
|
|
3
6
|
//# sourceMappingURL=discover.d.ts.map
|
package/dist/discover.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAyB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAyB,MAAM,YAAY,CAAC;AAkDpF,MAAM,CAAC,OAAO,OAAO,QAAQ;;WACZ,IAAI,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,SAAS,CAAC;CA0LvE"}
|
package/dist/discover.js
CHANGED
|
@@ -11,13 +11,16 @@ import path from "node:path";
|
|
|
11
11
|
import { pathToFileURL } from "node:url";
|
|
12
12
|
// Scan installed executor packages and build the runtime-tag registry the
|
|
13
13
|
// consuming scheme dispatches on. Parallel to plurnk-mimetypes' discover().
|
|
14
|
+
// The public `discover()` entry (SPEC §3) is re-exported from index.ts over
|
|
15
|
+
// `Discover.scan`; static cross-refs use the explicit `Discover.` binding so a
|
|
16
|
+
// detached re-export stays callable.
|
|
14
17
|
//
|
|
15
18
|
// Default scan target: every installed package under `<cwd>/node_modules` —
|
|
16
19
|
// scope-agnostic, so third-party executors (`@acme/foo`) are discovered too,
|
|
17
20
|
// not just `@plurnk/*`. Tests and unusual layouts can pass `packageDirs`
|
|
18
21
|
// explicitly to skip the scan.
|
|
19
22
|
//
|
|
20
|
-
// The PLURNK_PLUGINS_TRUSTED_ONLY gate (plurnk-service#229; see
|
|
23
|
+
// The PLURNK_PLUGINS_TRUSTED_ONLY gate (plurnk-service#229; see `#isTrusted`)
|
|
21
24
|
// filters the scope-agnostic scan: when on, an untrusted third-party package is
|
|
22
25
|
// discovered but not registered, returned in `Discovery.skipped` for the
|
|
23
26
|
// consumer to note. Off by default — no regression.
|
|
@@ -47,194 +50,197 @@ import { pathToFileURL } from "node:url";
|
|
|
47
50
|
// wins), a tag collision here is a FAIL-HARD install error: two packages
|
|
48
51
|
// claiming the same runtime is an unresolvable ambiguity the operator must
|
|
49
52
|
// fix (SPEC §3, plurnk-execs#1).
|
|
50
|
-
export
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
53
|
+
export default class Discover {
|
|
54
|
+
static async scan(options = {}) {
|
|
55
|
+
const dirs = options.packageDirs ?? await Discover.#defaultPackageDirs(options.cwd ?? process.cwd());
|
|
56
|
+
const registry = new Map();
|
|
57
|
+
const skipped = new Set();
|
|
58
|
+
for (const dir of dirs) {
|
|
59
|
+
const manifest = await Discover.#readExecManifest(dir);
|
|
60
|
+
if (manifest === null)
|
|
61
|
+
continue; // not an exec package
|
|
62
|
+
// Host plugin-trust gate (plurnk-service#229), enforced BEFORE any
|
|
63
|
+
// tag is read or — critically — any dynamic runtimes hook is
|
|
64
|
+
// imported: an untrusted third-party package is discovered but not
|
|
65
|
+
// registered, and its code is never executed. Recorded for the
|
|
66
|
+
// consumer's telemetry note, never crashed on.
|
|
67
|
+
if (!Discover.#isTrusted(manifest.packageName)) {
|
|
68
|
+
skipped.add(manifest.packageName);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
for (const info of await Discover.#readExecInfos(dir, manifest)) {
|
|
72
|
+
const existing = registry.get(info.runtime);
|
|
73
|
+
if (existing !== undefined) {
|
|
74
|
+
throw new Error(`exec runtime collision: '${info.runtime}' claimed by both `
|
|
75
|
+
+ `${existing.packageName} and ${info.packageName}`);
|
|
76
|
+
}
|
|
77
|
+
registry.set(info.runtime, info);
|
|
72
78
|
}
|
|
73
|
-
registry.set(info.runtime, info);
|
|
74
79
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
80
|
+
return { registry, skipped: [...skipped].sort() };
|
|
81
|
+
}
|
|
82
|
+
// Host plugin-trust gate, read from PLURNK_PLUGINS_TRUSTED_ONLY — the SAME
|
|
83
|
+
// env var plurnk-service decides once and every scope-agnostic discovery
|
|
84
|
+
// surface enforces (plurnk-service#229). Mirrors plurnk-service's
|
|
85
|
+
// PluginTrust.isTrusted (we can't import across the package boundary, so the
|
|
86
|
+
// ~5-line policy is duplicated, not shared):
|
|
87
|
+
// unset / "" / "0" → OFF: every installed package trusted (no regression).
|
|
88
|
+
// any value → ON: `@plurnk/*` always trusted, plus a comma-separated
|
|
89
|
+
// allowlist of additionally-trusted package names;
|
|
90
|
+
// "1" (naming no real package) = on, zero third-party.
|
|
91
|
+
static #isTrusted(packageName) {
|
|
92
|
+
const gate = process.env.PLURNK_PLUGINS_TRUSTED_ONLY;
|
|
93
|
+
if (gate === undefined || gate === "" || gate === "0")
|
|
94
|
+
return true;
|
|
95
|
+
if (packageName.startsWith("@plurnk/"))
|
|
96
|
+
return true;
|
|
97
|
+
return gate.split(",").map((s) => s.trim()).includes(packageName);
|
|
98
|
+
}
|
|
99
|
+
// Enumerate every installed package directory — scoped (`@scope/name`) and
|
|
100
|
+
// unscoped (`name`) — under `<cwd>/node_modules`. The scan is scope-agnostic
|
|
101
|
+
// so a THIRD PARTY can publish an executor under their own scope (`@acme/foo`)
|
|
102
|
+
// and have it discovered with no involvement from us; `#readExecInfos` keeps
|
|
103
|
+
// only the packages that declare `plurnk.kind === "exec"`.
|
|
104
|
+
static async #defaultPackageDirs(cwd) {
|
|
105
|
+
const nm = path.join(cwd, "node_modules");
|
|
106
|
+
let entries;
|
|
107
|
+
try {
|
|
108
|
+
entries = await fs.readdir(nm, { withFileTypes: true });
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
const dirs = [];
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
if (!entry.isDirectory() || entry.name === ".bin" || entry.name === ".cache")
|
|
116
|
+
continue;
|
|
117
|
+
if (entry.name.startsWith("@")) {
|
|
118
|
+
const scopeDir = path.join(nm, entry.name);
|
|
119
|
+
try {
|
|
120
|
+
const scoped = await fs.readdir(scopeDir, { withFileTypes: true });
|
|
121
|
+
for (const s of scoped)
|
|
122
|
+
if (s.isDirectory())
|
|
123
|
+
dirs.push(path.join(scopeDir, s.name));
|
|
124
|
+
}
|
|
125
|
+
catch { /* unreadable scope dir — skip */ }
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
dirs.push(path.join(nm, entry.name));
|
|
120
129
|
}
|
|
121
|
-
catch { /* unreadable scope dir — skip */ }
|
|
122
130
|
}
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
return dirs;
|
|
132
|
+
}
|
|
133
|
+
// Read a package's `package.json` and return its manifest iff it declares
|
|
134
|
+
// `plurnk.kind === "exec"`. Returns null for non-executor packages, a missing
|
|
135
|
+
// or malformed `package.json` — discover() silently skips those (they are not
|
|
136
|
+
// "skipped by trust", just not exec packages).
|
|
137
|
+
static async #readExecManifest(dir) {
|
|
138
|
+
let raw;
|
|
139
|
+
try {
|
|
140
|
+
raw = await fs.readFile(path.join(dir, "package.json"), "utf-8");
|
|
125
141
|
}
|
|
142
|
+
catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
let pkg;
|
|
146
|
+
try {
|
|
147
|
+
pkg = JSON.parse(raw);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
if (typeof pkg !== "object" || pkg === null)
|
|
153
|
+
return null;
|
|
154
|
+
const record = pkg;
|
|
155
|
+
const plurnk = record.plurnk;
|
|
156
|
+
if (typeof plurnk !== "object" || plurnk === null)
|
|
157
|
+
return null;
|
|
158
|
+
const plurnkRec = plurnk;
|
|
159
|
+
if (plurnkRec.kind !== "exec")
|
|
160
|
+
return null;
|
|
161
|
+
return { packageName: typeof record.name === "string" ? record.name : "", plurnk: plurnkRec };
|
|
162
|
+
}
|
|
163
|
+
// Produce one ExecInfo per declared runtime tag — static `plurnk.runtimes[]`
|
|
164
|
+
// or a dynamic `plurnk.runtimesModule` hook. Returns [] when neither is
|
|
165
|
+
// declared.
|
|
166
|
+
static async #readExecInfos(dir, { packageName, plurnk }) {
|
|
167
|
+
// Package-level attribution, surfaced raw (plurnk-service#249); every tag
|
|
168
|
+
// of the package carries the same value. The consumer owns the policy.
|
|
169
|
+
const rawAttr = plurnk.attribution;
|
|
170
|
+
const attribution = typeof rawAttr === "string" || Array.isArray(rawAttr) ? rawAttr : undefined;
|
|
171
|
+
const infos = [];
|
|
172
|
+
for (const decl of await Discover.#runtimeDecls(dir, packageName, plurnk)) {
|
|
173
|
+
if (typeof decl !== "object" || decl === null)
|
|
174
|
+
continue;
|
|
175
|
+
const e = decl;
|
|
176
|
+
if (typeof e.name !== "string" || e.name === "")
|
|
177
|
+
continue;
|
|
178
|
+
// `docs/<tag>.md` is the documentation source of truth (the docs
|
|
179
|
+
// convention); the inline `documentation` field is the fallback.
|
|
180
|
+
const inlineDoc = typeof e.documentation === "string" ? e.documentation : "";
|
|
181
|
+
const documentation = await Discover.#readDocFile(dir, e.name) ?? inlineDoc;
|
|
182
|
+
infos.push({
|
|
183
|
+
runtime: e.name,
|
|
184
|
+
glyph: typeof e.glyph === "string" ? e.glyph : "",
|
|
185
|
+
example: typeof e.example === "string" ? e.example : "",
|
|
186
|
+
documentation,
|
|
187
|
+
packageName,
|
|
188
|
+
...(attribution !== undefined ? { attribution } : {}),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return infos;
|
|
192
|
+
}
|
|
193
|
+
// Resolve a package's runtime decls. Static `plurnk.runtimes[]` is the common
|
|
194
|
+
// case; `plurnk.runtimesModule` (a relative path) is the dynamic hook for
|
|
195
|
+
// per-deployment tags. Static wins if both are declared. Returns [] when
|
|
196
|
+
// neither is present.
|
|
197
|
+
static async #runtimeDecls(dir, packageName, plurnk) {
|
|
198
|
+
if (Array.isArray(plurnk.runtimes))
|
|
199
|
+
return plurnk.runtimes;
|
|
200
|
+
const mod = plurnk.runtimesModule;
|
|
201
|
+
if (typeof mod === "string" && mod !== "")
|
|
202
|
+
return Discover.#loadDynamicRuntimes(dir, packageName, mod);
|
|
203
|
+
return [];
|
|
126
204
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return null;
|
|
157
|
-
return { packageName: typeof record.name === "string" ? record.name : "", plurnk: plurnkRec };
|
|
158
|
-
}
|
|
159
|
-
// Produce one ExecInfo per declared runtime tag — static `plurnk.runtimes[]` or
|
|
160
|
-
// a dynamic `plurnk.runtimesModule` hook. Returns [] when neither is declared.
|
|
161
|
-
async function readExecInfos(dir, { packageName, plurnk }) {
|
|
162
|
-
// Package-level attribution, surfaced raw (plurnk-service#249); every tag of
|
|
163
|
-
// the package carries the same value. The consumer owns the policy.
|
|
164
|
-
const rawAttr = plurnk.attribution;
|
|
165
|
-
const attribution = typeof rawAttr === "string" || Array.isArray(rawAttr) ? rawAttr : undefined;
|
|
166
|
-
const infos = [];
|
|
167
|
-
for (const decl of await runtimeDecls(dir, packageName, plurnk)) {
|
|
168
|
-
if (typeof decl !== "object" || decl === null)
|
|
169
|
-
continue;
|
|
170
|
-
const e = decl;
|
|
171
|
-
if (typeof e.name !== "string" || e.name === "")
|
|
172
|
-
continue;
|
|
173
|
-
// `docs/<tag>.md` is the documentation source of truth (the docs
|
|
174
|
-
// convention); the inline `documentation` field is the fallback.
|
|
175
|
-
const inlineDoc = typeof e.documentation === "string" ? e.documentation : "";
|
|
176
|
-
const documentation = await readDocFile(dir, e.name) ?? inlineDoc;
|
|
177
|
-
infos.push({
|
|
178
|
-
runtime: e.name,
|
|
179
|
-
glyph: typeof e.glyph === "string" ? e.glyph : "",
|
|
180
|
-
example: typeof e.example === "string" ? e.example : "",
|
|
181
|
-
documentation,
|
|
182
|
-
packageName,
|
|
183
|
-
...(attribution !== undefined ? { attribution } : {}),
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
return infos;
|
|
187
|
-
}
|
|
188
|
-
// Resolve a package's runtime decls. Static `plurnk.runtimes[]` is the common
|
|
189
|
-
// case; `plurnk.runtimesModule` (a relative path) is the dynamic hook for
|
|
190
|
-
// per-deployment tags. Static wins if both are declared. Returns [] when
|
|
191
|
-
// neither is present.
|
|
192
|
-
async function runtimeDecls(dir, packageName, plurnk) {
|
|
193
|
-
if (Array.isArray(plurnk.runtimes))
|
|
194
|
-
return plurnk.runtimes;
|
|
195
|
-
const mod = plurnk.runtimesModule;
|
|
196
|
-
if (typeof mod === "string" && mod !== "")
|
|
197
|
-
return loadDynamicRuntimes(dir, packageName, mod);
|
|
198
|
-
return [];
|
|
199
|
-
}
|
|
200
|
-
// Import a trusted package's runtimes hook and call it. Fail-hard on every
|
|
201
|
-
// failure — an unloadable module, a missing/non-function export, or a
|
|
202
|
-
// non-array return is a contract violation by a trusted package (its own
|
|
203
|
-
// packaging or config), surfaced with the cause, never swallowed. The trust
|
|
204
|
-
// gate in discover() guarantees this only runs for trusted packages.
|
|
205
|
-
async function loadDynamicRuntimes(dir, packageName, rel) {
|
|
206
|
-
const href = pathToFileURL(path.join(dir, rel)).href;
|
|
207
|
-
let mod;
|
|
208
|
-
try {
|
|
209
|
-
mod = await import(__rewriteRelativeImportExtension(href));
|
|
210
|
-
}
|
|
211
|
-
catch (cause) {
|
|
212
|
-
throw new Error(`exec runtimes hook unloadable: ${packageName} -> ${rel}`, { cause });
|
|
213
|
-
}
|
|
214
|
-
const hook = mod.runtimes ?? mod.default;
|
|
215
|
-
if (typeof hook !== "function") {
|
|
216
|
-
throw new Error(`exec runtimes hook invalid: ${packageName} -> ${rel} must export 'runtimes' (or default) as a function`);
|
|
217
|
-
}
|
|
218
|
-
let decls;
|
|
219
|
-
try {
|
|
220
|
-
decls = await hook();
|
|
221
|
-
}
|
|
222
|
-
catch (cause) {
|
|
223
|
-
throw new Error(`exec runtimes hook threw: ${packageName} -> ${rel}`, { cause });
|
|
224
|
-
}
|
|
225
|
-
if (!Array.isArray(decls)) {
|
|
226
|
-
throw new Error(`exec runtimes hook returned a non-array: ${packageName} -> ${rel}`);
|
|
227
|
-
}
|
|
228
|
-
return decls;
|
|
229
|
-
}
|
|
230
|
-
// A tag's documentation file under the package's `docs/` folder — the docs
|
|
231
|
-
// convention's source of truth. Returns null when the package ships none.
|
|
232
|
-
async function readDocFile(dir, tag) {
|
|
233
|
-
try {
|
|
234
|
-
return await fs.readFile(path.join(dir, "docs", `${tag}.md`), "utf-8");
|
|
205
|
+
// Import a trusted package's runtimes hook and call it. Fail-hard on every
|
|
206
|
+
// failure — an unloadable module, a missing/non-function export, or a
|
|
207
|
+
// non-array return is a contract violation by a trusted package (its own
|
|
208
|
+
// packaging or config), surfaced with the cause, never swallowed. The trust
|
|
209
|
+
// gate in scan() guarantees this only runs for trusted packages.
|
|
210
|
+
static async #loadDynamicRuntimes(dir, packageName, rel) {
|
|
211
|
+
const href = pathToFileURL(path.join(dir, rel)).href;
|
|
212
|
+
let mod;
|
|
213
|
+
try {
|
|
214
|
+
mod = await import(__rewriteRelativeImportExtension(href));
|
|
215
|
+
}
|
|
216
|
+
catch (cause) {
|
|
217
|
+
throw new Error(`exec runtimes hook unloadable: ${packageName} -> ${rel}`, { cause });
|
|
218
|
+
}
|
|
219
|
+
const hook = mod.runtimes ?? mod.default;
|
|
220
|
+
if (typeof hook !== "function") {
|
|
221
|
+
throw new Error(`exec runtimes hook invalid: ${packageName} -> ${rel} must export 'runtimes' (or default) as a function`);
|
|
222
|
+
}
|
|
223
|
+
let decls;
|
|
224
|
+
try {
|
|
225
|
+
decls = await hook();
|
|
226
|
+
}
|
|
227
|
+
catch (cause) {
|
|
228
|
+
throw new Error(`exec runtimes hook threw: ${packageName} -> ${rel}`, { cause });
|
|
229
|
+
}
|
|
230
|
+
if (!Array.isArray(decls)) {
|
|
231
|
+
throw new Error(`exec runtimes hook returned a non-array: ${packageName} -> ${rel}`);
|
|
232
|
+
}
|
|
233
|
+
return decls;
|
|
235
234
|
}
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
// A tag's documentation file under the package's `docs/` folder — the docs
|
|
236
|
+
// convention's source of truth. Returns null when the package ships none.
|
|
237
|
+
static async #readDocFile(dir, tag) {
|
|
238
|
+
try {
|
|
239
|
+
return await fs.readFile(path.join(dir, "docs", `${tag}.md`), "utf-8");
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
238
244
|
}
|
|
239
245
|
}
|
|
240
246
|
//# sourceMappingURL=discover.js.map
|
package/dist/discover.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import Discover from "./discover.ts";
|
|
2
|
+
import Runtime from "./runtime.ts";
|
|
1
3
|
export { default as BaseExecutor } from "./BaseExecutor.ts";
|
|
2
4
|
export { default as SubprocessExecutor } from "./SubprocessExecutor.ts";
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
+
export declare const discover: typeof Discover.scan;
|
|
6
|
+
export declare const KNOWN_RUNTIMES: ReadonlySet<string>;
|
|
7
|
+
export declare const isKnownRuntime: typeof Runtime.isKnown;
|
|
8
|
+
export declare const resolveRuntime: typeof Runtime.resolve;
|
|
5
9
|
export type { ChannelState, ChannelDecl, ExecutorMetadata, ExecArgs, ExecResult, Effect, RuntimeAvailability, RuntimeDecl, RuntimesHook, ExecInfo, ExecRegistry, Discovery, DiscoverOptions, SpawnArgs, RuntimeResolver, } from "./types.ts";
|
|
6
10
|
export type { TelemetryEvent, ContentOffset, LogCoordinate } from "./TelemetryEvent.ts";
|
|
7
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,OAAO,MAAM,cAAc,CAAC;AAGnC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAKxE,eAAO,MAAM,QAAQ,sBAAgB,CAAC;AAKtC,eAAO,MAAM,cAAc,qBAAgB,CAAC;AAC5C,eAAO,MAAM,cAAc,wBAAkB,CAAC;AAC9C,eAAO,MAAM,cAAc,wBAAkB,CAAC;AAG9C,YAAY,EACR,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,QAAQ,EACR,UAAU,EACV,MAAM,EACN,mBAAmB,EACnB,WAAW,EACX,YAAY,EACZ,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,7 +1,16 @@
|
|
|
1
|
+
import Discover from "./discover.js";
|
|
2
|
+
import Runtime from "./runtime.js";
|
|
1
3
|
// Framework surface
|
|
2
4
|
export { default as BaseExecutor } from "./BaseExecutor.js";
|
|
3
5
|
export { default as SubprocessExecutor } from "./SubprocessExecutor.js";
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
|
|
6
|
+
// Discovery (SPEC §3). The behavior lives on the `Discover` class; the
|
|
7
|
+
// documented `discover()` entry is its `scan` static, re-exported here so the
|
|
8
|
+
// public contract and the consumer's import stay unchanged.
|
|
9
|
+
export const discover = Discover.scan;
|
|
10
|
+
// Runtime-tag → spawn-args helper (subprocess family; legacy scheme path,
|
|
11
|
+
// SPEC §4). Same shape: behavior on the `Runtime` class, the documented
|
|
12
|
+
// function/constant names re-exported over its statics.
|
|
13
|
+
export const KNOWN_RUNTIMES = Runtime.KNOWN;
|
|
14
|
+
export const isKnownRuntime = Runtime.isKnown;
|
|
15
|
+
export const resolveRuntime = Runtime.resolve;
|
|
7
16
|
//# 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":"AAAA,oBAAoB;AACpB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,oBAAoB;AACpB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAExE,uEAAuE;AACvE,8EAA8E;AAC9E,4DAA4D;AAC5D,MAAM,CAAC,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;AAEtC,0EAA0E;AAC1E,wEAAwE;AACxE,wDAAwD;AACxD,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC;AAC5C,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;AAC9C,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { SpawnArgs } from "./types.ts";
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
export default class Runtime {
|
|
3
|
+
static readonly KNOWN: ReadonlySet<string>;
|
|
4
|
+
static isKnown(runtime: string): boolean;
|
|
5
|
+
static resolve(runtime: string, command: string): SpawnArgs;
|
|
6
|
+
}
|
|
5
7
|
//# sourceMappingURL=runtime.d.ts.map
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,CAAC,OAAO,OAAO,OAAO;IAGxB,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAEvC;IAEH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIxC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS;CAe9D"}
|
package/dist/runtime.js
CHANGED
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
// Runtime tag → spawn-args dispatch. Hardcoded v0 multiplexer; plugin
|
|
2
2
|
// discovery (one runtime per `@plurnk/plurnk-execs-*` sibling) is the
|
|
3
|
-
// forward-spec path documented in SPEC.md.
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
// forward-spec path documented in SPEC.md. The public `KNOWN_RUNTIMES` /
|
|
4
|
+
// `isKnownRuntime` / `resolveRuntime` surface (SPEC §4) is re-exported from
|
|
5
|
+
// index.ts over these statics; cross-refs use the explicit `Runtime.` binding
|
|
6
|
+
// so a detached re-export stays callable.
|
|
7
|
+
export default class Runtime {
|
|
8
|
+
// Runtimes plurnk-service's `Exec` scheme accepts at v0. Unknown runtimes
|
|
9
|
+
// must return 501 from the scheme; `resolve` itself never throws.
|
|
10
|
+
static KNOWN = new Set([
|
|
11
|
+
"", "sh", "bash", "node", "python", "python3",
|
|
12
|
+
]);
|
|
13
|
+
static isKnown(runtime) {
|
|
14
|
+
return Runtime.KNOWN.has(runtime);
|
|
13
15
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
static resolve(runtime, command) {
|
|
17
|
+
if (runtime === "" || runtime === "sh" || runtime === "bash") {
|
|
18
|
+
return { cmd: command, args: [], useShell: true };
|
|
19
|
+
}
|
|
20
|
+
if (runtime === "node") {
|
|
21
|
+
return { cmd: "node", args: ["-e", command], useShell: false };
|
|
22
|
+
}
|
|
23
|
+
if (runtime === "python" || runtime === "python3") {
|
|
24
|
+
return { cmd: "python3", args: ["-c", command], useShell: false };
|
|
25
|
+
}
|
|
26
|
+
// Unknown runtime: conservative `<runtime> -c <command>` fallback.
|
|
27
|
+
// Schemes should gate this off with `isKnown` and return 501, but the
|
|
28
|
+
// resolver itself stays total.
|
|
29
|
+
return { cmd: runtime, args: ["-c", command], useShell: false };
|
|
16
30
|
}
|
|
17
|
-
|
|
18
|
-
return { cmd: "python3", args: ["-c", command], useShell: false };
|
|
19
|
-
}
|
|
20
|
-
// Unknown runtime: conservative `<runtime> -c <command>` fallback.
|
|
21
|
-
// Schemes should gate this off with `isKnownRuntime` and return 501,
|
|
22
|
-
// but the resolver itself stays total.
|
|
23
|
-
return { cmd: runtime, args: ["-c", command], useShell: false };
|
|
24
|
-
};
|
|
31
|
+
}
|
|
25
32
|
//# sourceMappingURL=runtime.js.map
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,sEAAsE;AACtE,
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,sEAAsE;AACtE,yEAAyE;AACzE,4EAA4E;AAC5E,8EAA8E;AAC9E,0CAA0C;AAI1C,MAAM,CAAC,OAAO,OAAO,OAAO;IACxB,0EAA0E;IAC1E,kEAAkE;IAClE,MAAM,CAAU,KAAK,GAAwB,IAAI,GAAG,CAAC;QACjD,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS;KAChD,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC,OAAe;QAC1B,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,OAAe,EAAE,OAAe;QAC3C,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YAC3D,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACtD,CAAC;QACD,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YACrB,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QACnE,CAAC;QACD,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAChD,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QACtE,CAAC;QACD,mEAAmE;QACnE,sEAAsE;QACtE,+BAA+B;QAC/B,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACpE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plurnk/plurnk-execs",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.20",
|
|
4
4
|
"description": "Framework + contract for the @plurnk/plurnk-execs-* runtime executor family.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"plurnk",
|
|
@@ -39,14 +39,14 @@
|
|
|
39
39
|
],
|
|
40
40
|
"scripts": {
|
|
41
41
|
"test:lint": "tsc --noEmit",
|
|
42
|
-
"test:unit": "node --test \"src/**/*.test.ts\"",
|
|
42
|
+
"test:unit": "node --test \"src/**/*.test.ts\" \"test/**/*.test.ts\"",
|
|
43
43
|
"test": "npm run test:lint && npm run test:unit",
|
|
44
44
|
"build:dist": "tsc -p tsconfig.build.json",
|
|
45
45
|
"build": "npm run build:dist",
|
|
46
46
|
"prepare": "npm run build"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@plurnk/plurnk-schemes": "^0.
|
|
49
|
+
"@plurnk/plurnk-schemes": "^0.31.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/node": "^26.0.0",
|