@plurnk/plurnk-execs 1.16.4 → 1.17.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/.env.defaults +6 -11
- package/README.md +31 -5
- package/SPEC.md +136 -47
- package/dist/BaseExecutor.d.ts +3 -1
- package/dist/BaseExecutor.d.ts.map +1 -1
- package/dist/BaseExecutor.js +8 -0
- package/dist/BaseExecutor.js.map +1 -1
- package/dist/DocFile.d.ts +5 -0
- package/dist/DocFile.d.ts.map +1 -0
- package/dist/DocFile.js +28 -0
- package/dist/DocFile.js.map +1 -0
- package/dist/InvocationMetadata.d.ts +22 -0
- package/dist/InvocationMetadata.d.ts.map +1 -0
- package/dist/InvocationMetadata.js +63 -0
- package/dist/InvocationMetadata.js.map +1 -0
- package/dist/RuntimeInvocation.d.ts.map +1 -1
- package/dist/RuntimeInvocation.js +13 -10
- package/dist/RuntimeInvocation.js.map +1 -1
- package/dist/RuntimeSummary.d.ts +0 -3
- package/dist/RuntimeSummary.d.ts.map +1 -1
- package/dist/RuntimeSummary.js +7 -13
- package/dist/RuntimeSummary.js.map +1 -1
- package/dist/SubprocessExecutor.d.ts +3 -2
- package/dist/SubprocessExecutor.d.ts.map +1 -1
- package/dist/SubprocessExecutor.js +30 -4
- package/dist/SubprocessExecutor.js.map +1 -1
- package/dist/SubprocessInput.d.ts +10 -0
- package/dist/SubprocessInput.d.ts.map +1 -0
- package/dist/SubprocessInput.js +86 -0
- package/dist/SubprocessInput.js.map +1 -0
- package/dist/discover.d.ts.map +1 -1
- package/dist/discover.js +2 -19
- package/dist/discover.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +4 -8
- package/dist/runtime.js.map +1 -1
- package/dist/types.d.ts +22 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/dist/advertise.d.ts +0 -13
- package/dist/advertise.d.ts.map +0 -1
- package/dist/advertise.js +0 -12
- package/dist/advertise.js.map +0 -1
package/.env.defaults
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
# is no force-enable verb. Unset ⇒ every discovered runtime is registered. This
|
|
4
|
-
# package sets no operative default; the comments below ARE the operator docs.
|
|
1
|
+
# @plurnk/plurnk-execs — installed runtime admission.
|
|
2
|
+
# These filters only remove registered runtimes; they cannot install or force-enable tools.
|
|
5
3
|
|
|
6
|
-
#
|
|
4
|
+
# Comma-separated allowlist; unset = all discovered runtimes.
|
|
7
5
|
# PLURNK_EXECS_ONLY=sh,jq
|
|
8
|
-
|
|
9
|
-
# Per-tag kill-switch (case-insensitive): set any registered tag to 0 to drop it.
|
|
10
|
-
# Absent ⇒ the runtime stays enabled. e.g.:
|
|
6
|
+
# Per-runtime switch, case-insensitive: 0 = disabled; absent = enabled.
|
|
11
7
|
# PLURNK_EXECS_PYTHON3=0
|
|
12
8
|
# PLURNK_EXECS_BC=0
|
|
13
|
-
|
|
14
|
-
# Maximum
|
|
15
|
-
# operation's model-facing Problem detail. Empty/unset leaves them unbounded.
|
|
9
|
+
# PLURNK_EXECS_QUESTION=0
|
|
10
|
+
# Maximum diagnostic characters in model-facing errors; empty/unset = unbounded.
|
|
16
11
|
PLURNK_EXECS_ERROR_DETAIL_LIMIT=512
|
package/README.md
CHANGED
|
@@ -51,10 +51,15 @@ One package may claim several tags; the consumer instantiates and probes each
|
|
|
51
51
|
tag independently. A name uses lowercase URI-scheme syntax
|
|
52
52
|
`[a-z][a-z0-9+.-]*`; `only` is reserved by runtime policy. `summary` is the
|
|
53
53
|
one-line capability description. `invocation` defines the body and optional
|
|
54
|
-
target buckets
|
|
55
|
-
generated `worker
|
|
54
|
+
target buckets used for dispatch enforcement and a canonical example for its
|
|
55
|
+
generated `worker:///_plurnk/plurnk/<tag>.md` document. A `docs/<tag>.md` file supplies
|
|
56
56
|
supplemental detail. See {§executor-runtime-declaration}.
|
|
57
57
|
|
|
58
|
+
For JSON inputs, supply `invocation.inputSchema` instead of an authored example
|
|
59
|
+
or signature. The shared renderer lists required top-level fields and links to
|
|
60
|
+
the complete raw schema and description; nested and optional inputs stay in
|
|
61
|
+
that on-demand document ({§executor-input-schema-preview}).
|
|
62
|
+
|
|
58
63
|
### Implement the executor
|
|
59
64
|
|
|
60
65
|
| Runtime shape | Base class | Author-owned hooks |
|
|
@@ -85,11 +90,33 @@ The EXEC `(target)` slot is runtime-specific:
|
|
|
85
90
|
The consumer supplies both `cwd` and a resolved `target`; the leaf maps them
|
|
86
91
|
to its tool rather than reconstructing filesystem or scheme policy.
|
|
87
92
|
|
|
93
|
+
### Own invocation metadata
|
|
94
|
+
|
|
95
|
+
`prepare(input)` validates the tool's raw header metadata before admission and
|
|
96
|
+
returns the effective cwd. `run(args)` receives that cwd and the original
|
|
97
|
+
metadata, separately from the unchanged body. Source acquisition never inherits
|
|
98
|
+
EXEC metadata. `BaseExecutor` supplies `[{"cwd": "..."}]`; `SubprocessExecutor` adds
|
|
99
|
+
literal script arguments with `[{"args": ["arg",...]}]`. Override preparation for
|
|
100
|
+
tool-specific options. See {§executor-metadata}.
|
|
101
|
+
|
|
102
|
+
### Receive live input
|
|
103
|
+
|
|
104
|
+
In-process executors may call `args.registerInput?.(async ({ body, metadata,
|
|
105
|
+
signal }) => result)` once during `run()`. Keep the receiver local to that
|
|
106
|
+
invocation, honor cancellation, and return a standard `SchemeResult` for each
|
|
107
|
+
delivery. The consumer routes SEND to the existing execution address and owns
|
|
108
|
+
ordering, deadlines, permissions, and proposals. This does not expose Worker
|
|
109
|
+
identity or grant access to stored output.
|
|
110
|
+
|
|
111
|
+
`SubprocessExecutor` supplies this receiver when launched with `[{"stdin": "open"}]`.
|
|
112
|
+
SEND writes exact UTF-8 input; `[{"eof": true}]` ends stdin. No option means ordinary
|
|
113
|
+
batch EOF. See [the live-input contract](SPEC.md#executor-live-input-invocation-local-input).
|
|
114
|
+
|
|
88
115
|
### Address output
|
|
89
116
|
|
|
90
117
|
The runtime tag is also the output scheme. A subprocess result is therefore
|
|
91
|
-
read at an address such as `sh:///
|
|
92
|
-
be `sqlite:///
|
|
118
|
+
read at an address such as `sh:///ab3d5678#stdout`, while a structured result may
|
|
119
|
+
be `sqlite:///f2c49a10#results`. `exec://` is not an output address. Executors only
|
|
93
120
|
produce channels; the consumer owns storage and every later READ/FIND. See
|
|
94
121
|
{§executor-output-address}.
|
|
95
122
|
|
|
@@ -116,7 +143,6 @@ Policy is subtractive; a downstream layer cannot restore a removed tag. See
|
|
|
116
143
|
|
|
117
144
|
- `BaseExecutor`, `SubprocessExecutor`, and `SpawnArgs`.
|
|
118
145
|
- `discover`, `Policy`, `RuntimeTag`, and runtime discovery types.
|
|
119
|
-
- `Advertise`, a deprecated frozen 1.x compatibility helper with no current service path.
|
|
120
146
|
- `ErrorDetail` and `PLURNK_EXECS_ERROR_DETAIL_LIMIT`.
|
|
121
147
|
- Executor arguments, channel, availability, and effect types.
|
|
122
148
|
- `Results`, result types, and runtime-neutral Notice types.
|
package/SPEC.md
CHANGED
|
@@ -39,6 +39,7 @@ abstract class BaseExecutor {
|
|
|
39
39
|
|
|
40
40
|
abstract get channels(): Readonly<Record<string, ChannelDecl>>;
|
|
41
41
|
get defaultChannel(): string;
|
|
42
|
+
prepare(input: ExecInput): Promise<ExecPreparation>;
|
|
42
43
|
abstract run(args: ExecArgs): Promise<ExecResult>;
|
|
43
44
|
probe(signal?: AbortSignal): Promise<RuntimeAvailability>;
|
|
44
45
|
effect(target: string | null): Effect;
|
|
@@ -55,8 +56,10 @@ interface ExecArgs {
|
|
|
55
56
|
body: string;
|
|
56
57
|
cwd: string | null;
|
|
57
58
|
target: string | null;
|
|
59
|
+
metadata: readonly string[] | null;
|
|
58
60
|
env?: NodeJS.ProcessEnv;
|
|
59
61
|
signal: AbortSignal;
|
|
62
|
+
registerInput?(receiver: ExecInputReceiver): void;
|
|
60
63
|
write(channel: string, chunk: string, mimetype?: string): void;
|
|
61
64
|
setState(channel: string, state: ChannelState): void;
|
|
62
65
|
emit(notice: Notice): void;
|
|
@@ -71,10 +74,9 @@ interface ExecArgs {
|
|
|
71
74
|
`ExecArgs` deliberately carries **no Worker identity**: an executor is a
|
|
72
75
|
worker-agnostic capability, and `run` may assume nothing about which Worker,
|
|
73
76
|
Loop, or workspace invoked it beyond the arguments given. A runtime whose
|
|
74
|
-
behavior depends on a
|
|
75
|
-
manager — is published per
|
|
76
|
-
identity at publication ({§functionality-model-projection}
|
|
77
|
-
specification; the MCP host is the precedent). Consumers must not smuggle
|
|
77
|
+
behavior depends on a workspace — an attached MCP server or Functionality
|
|
78
|
+
manager — is published per workspace by its module, closing over that
|
|
79
|
+
identity at publication ({§functionality-model-projection}). Consumers must not smuggle
|
|
78
80
|
identity through `env` or `body` conventions.
|
|
79
81
|
|
|
80
82
|
interface RuntimeAvailability {
|
|
@@ -101,8 +103,10 @@ surface.
|
|
|
101
103
|
| `body` | The authored EXEC body, interpreted according to the runtime's invocation declaration. |
|
|
102
104
|
| `cwd` | Consumer-selected project working directory, or `null` for a runtime that has none. |
|
|
103
105
|
| `target` | Consumer-realized optional EXEC target. Its representation and role come from the invocation declaration. |
|
|
106
|
+
| `metadata` | Exact ordered header blocks owned by the invoked executor, retained separately from the body and target. |
|
|
104
107
|
| `env` | Exact child environment when supplied. A subprocess must use it instead of reconstructing host policy. |
|
|
105
108
|
| `signal` | Consumer cancellation. Every executor must honor it at each cancellable boundary. |
|
|
109
|
+
| `registerInput` | Optionally register one live input receiver for this invocation under {§executor-live-input}. |
|
|
106
110
|
| `write` | Append to a declared channel. An optional mimetype replaces that channel's per-call output type. |
|
|
107
111
|
| `setState` | Move a declared channel from `active` to terminal `closed` or `errored`. |
|
|
108
112
|
| `emit` | Publish a transient, nonterminal Notice. |
|
|
@@ -113,6 +117,61 @@ The executor receives callbacks, never a database, subscription registry,
|
|
|
113
117
|
packet builder, or wake mechanism. Related lifecycle behavior remains on the
|
|
114
118
|
consumer side of {§executor-role}.
|
|
115
119
|
|
|
120
|
+
### §executor-metadata Invocation metadata ownership
|
|
121
|
+
|
|
122
|
+
The invoked executor owns its `[metadata]` for every target kind. The source
|
|
123
|
+
scheme supplies the program or data; it does not inherit the invoking tool's
|
|
124
|
+
options. An internal source READ therefore carries no EXEC metadata. An
|
|
125
|
+
authored READ retains its own source-scheme metadata contract.
|
|
126
|
+
|
|
127
|
+
| Stage | Contract |
|
|
128
|
+
| ----- | -------- |
|
|
129
|
+
| Preparation | Optional `prepare(input)` receives `runtime`, `body`, logical `target`, default `cwd`, and ordered raw `metadata`, before effect admission or source acquisition. It validates options without executing the program and returns `200` with a concrete `cwd` or `null`, or one universal failure. No hook means no metadata support. |
|
|
130
|
+
| Framework default | `BaseExecutor.prepare` accepts `[{"cwd": "<directory>"}]`. Relative directories resolve against the supplied default cwd; an absent override preserves it. Unknown fields, duplicates, malformed values, and nonexistent directories are refused. Tools can override preparation to own different metadata. |
|
|
131
|
+
| Subprocess options | `SubprocessExecutor` additionally accepts `[{"stdin": "open"}]` ({§executor-stdin}) and `[{"args": ["arg",...]}]`. The JSON array contains strings without NUL, preserves order and empty/whitespace-containing arguments, and appends directly to the spawn argument vector without shell parsing. Inline programs retain their interpreter's usual argument conventions. |
|
|
132
|
+
| Execution | `run()` receives the prepared cwd, realized target, unchanged body, and original metadata. The subprocess family uses the same option parser to obtain argv; cwd is already prepared and is not resolved a second time. |
|
|
133
|
+
| Evidence | Raw metadata follows the existing transient proposal handoff, never added to proposal attrs or emitted as receipt metadata. Expected preparation failures retain the tool's Problem; malformed preparation results are internal contract failures. |
|
|
134
|
+
|
|
135
|
+
Metadata does not turn inline programs or script stdin into JSON envelopes.
|
|
136
|
+
Executable references document advanced options on demand; no language-level
|
|
137
|
+
option names or hot-path teaching are required.
|
|
138
|
+
|
|
139
|
+
### §executor-live-input Invocation-local input
|
|
140
|
+
|
|
141
|
+
`ExecArgs.registerInput?(receiver)` binds one receiver to the current invocation.
|
|
142
|
+
The receiver accepts `{ body: string, metadata: readonly string[] | null,
|
|
143
|
+
signal: AbortSignal }` and resolves a universal `SchemeResult`. The body is exact
|
|
144
|
+
authored text; metadata belongs to the receiver. Registration is once per run,
|
|
145
|
+
never executor-instance state. An absent callback means the consumer cannot
|
|
146
|
+
deliver live input. A receiver must honor cancellation at each delivery boundary.
|
|
147
|
+
|
|
148
|
+
| Responsibility | Owner |
|
|
149
|
+
| --- | --- |
|
|
150
|
+
| Address, workspace admission, capability checks, proposals | Consumer, using the existing execution identity and effect. |
|
|
151
|
+
| Delivery ordering, bounded backpressure, lifetime | Consumer; serialize accepted deliveries, never replay an ambiguous write, retire on execution settlement/cancellation. |
|
|
152
|
+
| Input meaning, framing, EOF, delivery result | Receiver; acceptance does not imply consumption, command success, or execution completion. |
|
|
153
|
+
| Output, progress, completion | Existing `write`, `setState`, and `run` result; input introduces no second output or wake path. |
|
|
154
|
+
|
|
155
|
+
#### §executor-stdin Subprocess input
|
|
156
|
+
|
|
157
|
+
`SubprocessExecutor` accepts `[{"stdin": "open"}]` at invocation. The initial recipe
|
|
158
|
+
input precedes SEND bodies and stdin remains open; without this option, existing
|
|
159
|
+
batch input and EOF behavior is unchanged. The same input adapter serves `jq`.
|
|
160
|
+
|
|
161
|
+
| SEND input | Effect |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| Body, no metadata | Write its exact UTF-8 bytes, including authored newlines; no implicit newline. Empty input is a no-op, not EOF. |
|
|
164
|
+
| `[{"eof": true}]` with optional body | Write the body, then close stdin. Later SENDs return `410 input-closed`, including repeated EOF. |
|
|
165
|
+
| Other or duplicate metadata | `400`, before writing. |
|
|
166
|
+
| Pipe failure | Factual delivery failure with the native error code; no automatic retry. |
|
|
167
|
+
| Delivery cancellation | Stop the pending write and close stdin. The process retains its ordinary lifecycle. |
|
|
168
|
+
|
|
169
|
+
A successful receipt reports `bytesAccepted` and `inputClosed`, with those facts
|
|
170
|
+
in the ordinary model-visible `detail`. It acknowledges the writable pipe, not
|
|
171
|
+
application processing. Subprocess leaves inherit this
|
|
172
|
+
contract; logical executors need not offer a receiver. In particular, SQLite,
|
|
173
|
+
client-interaction tools, and MCP transports do not gain stdin through this API.
|
|
174
|
+
|
|
116
175
|
### §executor-channels Channels
|
|
117
176
|
|
|
118
177
|
The executor declares every channel it may write. The consumer seeds a stream
|
|
@@ -135,8 +194,10 @@ reformatting arbitrary source JSON read from an entry.
|
|
|
135
194
|
subprocess `exitCode`. A result with `status >= 400` carries exactly one RFC
|
|
136
195
|
9457 Problem whose status agrees with the result. Expected runtime failures
|
|
137
196
|
resolve as failure results and leave affected channels `errored`; they do not
|
|
138
|
-
throw.
|
|
139
|
-
|
|
197
|
+
throw. Rejection by an aborted execution's signal reason or an `AbortError`
|
|
198
|
+
is cancellation, not an executor defect; the consumer preserves its distinct
|
|
199
|
+
cancellation/deadline result. Other throws and invalid results become durable
|
|
200
|
+
contract failures before the consumer closes the stream.
|
|
140
201
|
|
|
141
202
|
A nonzero subprocess exit directs the caller only to inspect both stdout and
|
|
142
203
|
stderr because either may contain the useful diagnostic; it does not presume
|
|
@@ -202,27 +263,42 @@ no second scheme manifest.
|
|
|
202
263
|
|
|
203
264
|
| Output | Model-facing address |
|
|
204
265
|
| ------------------------- | ------------------------------------------------------------------ |
|
|
205
|
-
|
|
|
206
|
-
| Fragmentless read | `<tag>:///<
|
|
207
|
-
| Example subprocess stdout | `sh:///
|
|
208
|
-
| Example structured result | `sqlite:///
|
|
266
|
+
| Workspace execution stream | `<tag>:///<id>#<channel>` |
|
|
267
|
+
| Fragmentless read | `<tag>:///<id>` → the declared default channel |
|
|
268
|
+
| Example subprocess stdout | `sh:///ab3d5678#stdout` |
|
|
269
|
+
| Example structured result | `sqlite:///c2d45678#results` |
|
|
209
270
|
|
|
210
271
|
The executor only produces through `write` and `setState`. The consumer stores
|
|
211
272
|
the entry and serves every later READ/FIND through uniform entry machinery.
|
|
212
273
|
An executor does not implement a private read face, orientation receipt,
|
|
213
|
-
slicer, or index.
|
|
214
|
-
belong to core's {§
|
|
274
|
+
slicer, or index. Workspace-stable resource addresses and packet projection
|
|
275
|
+
belong to core's {§execution-output-identity} and {§exec-stream} contracts.
|
|
276
|
+
Address resolution binds the workspace without requiring an exact stored row:
|
|
277
|
+
FIND patterns and descendant resource paths participate in ordinary discovery;
|
|
278
|
+
an exact READ reports its own missing resource ({§entry-address-resolution}).
|
|
279
|
+
|
|
280
|
+
`publishedChannel` selects one declared channel for automatic stream observations;
|
|
281
|
+
absent/null selects all channels. Non-published channels remain READ-addressable.
|
|
282
|
+
This is the ordinary subscription publication selection, not another delivery path.
|
|
215
283
|
|
|
216
284
|
### §executor-entry-sink Optional materialization
|
|
217
285
|
|
|
218
|
-
`entry(path, content, {
|
|
219
|
-
executor access to storage.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
286
|
+
`entry(path, content, { mimetype?, name? })` is a consumer-implemented sink, not
|
|
287
|
+
executor access to storage. It returns the canonical address of an ordinary
|
|
288
|
+
resource; publication alone does not attach media or wake a Worker.
|
|
289
|
+
|
|
290
|
+
| Input | Meaning |
|
|
291
|
+
| --- | --- |
|
|
292
|
+
| Absolute resource URL | Materialize or update that resource through its scheme owner. |
|
|
293
|
+
| `path: null` | Publish beneath this invocation's output address, in `resources/`. Preserve `name` as one URI-encoded component; otherwise allocate an eight-character hexadecimal identifier. Duplicate names receive a hash suffix, never overwrite another publication. The returned address is workspace-stable and carries no Worker selector. |
|
|
294
|
+
| String content + mimetype | Supplied text; preserve its source layout. |
|
|
295
|
+
| `Uint8Array` content + mimetype | Supplied bytes, retained as bytes, not a JSON/base64 body. |
|
|
296
|
+
| `content: null` | Consumer-sourced acquisition from an absolute HTTP(S) URL. |
|
|
297
|
+
|
|
298
|
+
Core owns names, storage, publication evidence, and byte acquisition. Executors
|
|
299
|
+
publish returned addresses in their result. Rejection means materialization
|
|
300
|
+
failed, not that the upstream operation had no effect. An absent sink cannot
|
|
301
|
+
be reported as successful resource publication.
|
|
226
302
|
|
|
227
303
|
## §executor-discovery Discovery and registration
|
|
228
304
|
|
|
@@ -284,7 +360,7 @@ at boot; changing package membership or configuration requires a restart.
|
|
|
284
360
|
| ------------- | -------------------------------------------------------------------------------------------------- |
|
|
285
361
|
| `name` | Canonical runtime tag and derived output-scheme name, admitted below. |
|
|
286
362
|
| `glyph` | Optional presentation glyph. |
|
|
287
|
-
| `summary` | Required one-line description, or `{ from: "tools" }` for an exact family inventory.
|
|
363
|
+
| `summary` | Required one-line description, or `{ from: "tools", description?: string }` for an exact family inventory with an optional one-line purpose. |
|
|
288
364
|
| `invocation` | Required body and target contract, validated and normalized below. |
|
|
289
365
|
| `details` | Optional supplemental Markdown. `docs/<tag>.md` wins over the inline manifest field. |
|
|
290
366
|
| `attribution` | Published per-tag projection of the validated package declaration ({§plugin-attribution}). |
|
|
@@ -294,7 +370,11 @@ The framework validates and carries the summary source, invocation, and suppleme
|
|
|
294
370
|
details as separate facts. A `{ from: "tools" }` summary is valid only for a
|
|
295
371
|
runtime implementing {§executor-tool-registry}; the consumer resolves it from
|
|
296
372
|
the exact effective tool set, after capability attenuation, so a denied tool
|
|
297
|
-
cannot survive in the family orientation line. The
|
|
373
|
+
cannot survive in the family orientation line. The inventory renders as
|
|
374
|
+
one compact executable fence naming `runtime (target|...)`, with the optional
|
|
375
|
+
purpose as a trailing aside and body line breaks represented by literal `\n`;
|
|
376
|
+
an authored string remains a description, without expanding its tool inventory.
|
|
377
|
+
The consumer deterministically renders the
|
|
298
378
|
model-facing tool document from either the static invocation or the executor's exact
|
|
299
379
|
{§executor-tool-registry}; authors never duplicate Summary or Invocation in
|
|
300
380
|
prose. A
|
|
@@ -320,19 +400,20 @@ details; the generated tool document owns the one model-facing H1.
|
|
|
320
400
|
| `target.kind` | One of the structural realization modes below. |
|
|
321
401
|
| `exclusive` | Optional `true`: body and target are alternative inputs and supplying both is refused. |
|
|
322
402
|
| `example` | Concise executable witness with a one-line `body`, `target`, or both as the declared shape permits. |
|
|
323
|
-
| `signature` |
|
|
403
|
+
| `signature` | Authored one-line structural body signature when no JSON Schema defines the input. |
|
|
404
|
+
| `inputSchema` | Original JSON Schema object for the input; the common document renderer derives its preview. |
|
|
324
405
|
|
|
325
406
|
| Target kind | Consumer realization |
|
|
326
407
|
| ----------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
327
408
|
| `literal` | Preserve the complete authored target string. It is an executor identifier, never a scheme read or filesystem classification. |
|
|
328
409
|
| `path` | Accept only a local or `file://` path and pass that path directly. |
|
|
329
|
-
| `resource` | Pass a local/file path directly
|
|
410
|
+
| `resource` | Pass a local/file path directly. After acceptance, resolve a non-file data-scheme address through one exact READ; use its owner-supplied native file or a standalone temporary representation ({§exec-source-temporary}). |
|
|
330
411
|
| `script` | As `resource`, and the local path must be an existing file: a directory or an absent path is refused before anything spawns ({§exec-executor-slot}). |
|
|
331
412
|
|
|
332
413
|
Every EXEC must supply at least a body or target even when neither field is
|
|
333
414
|
independently required. A target's meaning never changes because the body is
|
|
334
|
-
empty or non-empty. `exclusive` requires a target declaration. Exactly one of `example
|
|
335
|
-
`signature` is present. An example must satisfy the same required, refused,
|
|
415
|
+
empty or non-empty. `exclusive` requires a target declaration. Exactly one of `example`,
|
|
416
|
+
`signature`, or `inputSchema` is present. An example must satisfy the same required, refused,
|
|
336
417
|
and exclusive buckets and parse as exactly one EXEC section for the runtime. A
|
|
337
418
|
signature is presentation, not an executable example; dispatch still enforces
|
|
338
419
|
the invocation's body and target declarations. An invocation declaration
|
|
@@ -377,19 +458,32 @@ I/O boundary rather than making packet assembly perform network discovery.
|
|
|
377
458
|
§executor-tool-document **Tool documents are the model-facing executor
|
|
378
459
|
directory.** A general runtime's document carries exact H2 `Summary` and
|
|
379
460
|
`Invocation` sections plus its executable witness. Its Summary is that compact
|
|
380
|
-
invocation witness in
|
|
381
|
-
operation
|
|
382
|
-
one-line body.
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
tool
|
|
387
|
-
|
|
461
|
+
invocation witness in plain text, with the authored description as an
|
|
462
|
+
operation aside on its invocation line and a literal `\n` before a
|
|
463
|
+
one-line body. The bundled subprocess interpreters declare concrete inline-program
|
|
464
|
+
examples; their catalog summaries include the program body without a script target.
|
|
465
|
+
An exact registry instead renders one compact family document whose Summary is
|
|
466
|
+
authored or derived from its effective tools. Its H2 `Tools` contains one
|
|
467
|
+
executable fence per tool, naming the runtime and exact target, with its aside
|
|
468
|
+
and input preview. A schema-backed invocation
|
|
469
|
+
links from its aside to a child document containing the full description and
|
|
470
|
+
original input JSON Schema. Non-schema invocations retain their authored witness
|
|
471
|
+
and supplemental details.
|
|
388
472
|
Supplemental `details` follows framework-owned sections and cannot own identity,
|
|
389
473
|
invocation, or admission. The consumer chooses resource addresses, materializes
|
|
390
474
|
the documents, and exposes each Summary through ordinary FIND metadata. No
|
|
391
475
|
executor table or executor-specific discovery protocol exists.
|
|
392
476
|
|
|
477
|
+
§executor-input-schema-preview Schema-backed previews list only explicitly
|
|
478
|
+
required top-level fields, with quoted names and declared broad JSON types.
|
|
479
|
+
Nested objects and arrays stay opaque; an undeclared type is `unknown`. Optional
|
|
480
|
+
fields, references, constraints, and conditional branches are not interpreted.
|
|
481
|
+
The preview is not a complete signature or validation promise. Its schema link
|
|
482
|
+
provides the complete original schema, including descriptions, definitions,
|
|
483
|
+
references, and constraints; repository-owned referenced schemas are included
|
|
484
|
+
unchanged alongside it. Documentation performs no network reference resolution.
|
|
485
|
+
Output schemas are not input teaching.
|
|
486
|
+
|
|
393
487
|
Runtime-name admission is one identity contract:
|
|
394
488
|
|
|
395
489
|
| Constraint | Contract |
|
|
@@ -429,7 +523,8 @@ swallowed.
|
|
|
429
523
|
|
|
430
524
|
### §executor-policy Subtractive runtime policy
|
|
431
525
|
|
|
432
|
-
|
|
526
|
+
Registration applies the daemon's policy to every tag, whether discovered from
|
|
527
|
+
a package or supplied by a daemon module, including workspace-scoped runtimes. The exported
|
|
433
528
|
`Policy` parser can apply the same grammar to additional consumer-owned layers.
|
|
434
529
|
|
|
435
530
|
| Variable | Enforced effect |
|
|
@@ -440,18 +535,11 @@ Discovery applies the daemon's registration policy to every tag. The exported
|
|
|
440
535
|
| `Policy.enabledAcross(tag, [a, b, ...])` | Keep the tag only when every supplied layer enables it. |
|
|
441
536
|
|
|
442
537
|
Policy is purely subtractive: no layer can re-enable a tag removed by another.
|
|
443
|
-
|
|
444
|
-
|
|
538
|
+
Disabled tags publish neither an executor nor its scheme or tool documents;
|
|
539
|
+
package discovery also returns them in `Discovery.disabled`.
|
|
540
|
+
Workspace and loop admission remain consumer concerns;
|
|
445
541
|
the framework does not define a second Active/Available state machine.
|
|
446
542
|
|
|
447
|
-
### §executor-advertise-compat Frozen `Advertise` compatibility
|
|
448
|
-
|
|
449
|
-
| Surface | 1.x contract |
|
|
450
|
-
|--------------------------------------|-------------------------------------------------------------------------------------------------------------|
|
|
451
|
-
| `Advertise.contribute(registry, fn)` | Filters the supplied registry; returns `NO_EXECS_NOTICE` only when the filtered result is empty. |
|
|
452
|
-
| Architectural ownership | None. It does not discover, probe, admit, dispatch, or render; the composed service never calls it. |
|
|
453
|
-
| Evolution | Frozen. New consumers compose discovery and `Policy` with their own presentation. Removal is SemVer-major. |
|
|
454
|
-
|
|
455
543
|
## §executor-default-inventory Current installed set
|
|
456
544
|
|
|
457
545
|
The default `@plurnk/plurnk-service` composition installs the following
|
|
@@ -490,9 +578,10 @@ interface SpawnArgs {
|
|
|
490
578
|
| `python3` | `python3 -c <body>`. |
|
|
491
579
|
| Other default-base runtime | `<runtime> -c <body>`; specialized leaves override this fallback. |
|
|
492
580
|
|
|
493
|
-
With a target, the target is the program and the body is its stdin.
|
|
581
|
+
With a target, the target is the program and the body is its stdin. Each leaf
|
|
582
|
+
uses its interpreter's file form (`awk -f <target>`, for example). The working
|
|
494
583
|
directory is the consumer's `cwd` — the project root, or the directory a
|
|
495
|
-
`{cwd
|
|
584
|
+
`[{"cwd": "<directory>"}]` block on the heading names ({§exec-executor-slot}); a
|
|
496
585
|
directory is never a target. Data runtimes define their own declared target
|
|
497
586
|
kind and role.
|
|
498
587
|
|
package/dist/BaseExecutor.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SchemeHandler, SchemeManifest } from "@plurnk/plurnk-schemes";
|
|
2
|
-
import type { ChannelDecl, Effect, ExecArgs, ExecResult, ExecutorMetadata, RuntimeAvailability } from "./types.ts";
|
|
2
|
+
import type { ChannelDecl, Effect, ExecArgs, ExecInput, ExecPreparation, ExecResult, ExecutorMetadata, RuntimeAvailability } from "./types.ts";
|
|
3
3
|
export default abstract class BaseExecutor implements SchemeHandler {
|
|
4
4
|
readonly runtime: string;
|
|
5
5
|
readonly glyph: string;
|
|
@@ -7,7 +7,9 @@ export default abstract class BaseExecutor implements SchemeHandler {
|
|
|
7
7
|
get manifest(): SchemeManifest;
|
|
8
8
|
get traits(): ReadonlyArray<string> | undefined;
|
|
9
9
|
get defaultChannel(): string;
|
|
10
|
+
get publishedChannel(): string | null;
|
|
10
11
|
abstract get channels(): Readonly<Record<string, ChannelDecl>>;
|
|
12
|
+
prepare(input: ExecInput): Promise<ExecPreparation>;
|
|
11
13
|
abstract run(args: ExecArgs): Promise<ExecResult>;
|
|
12
14
|
probe(_signal?: AbortSignal): Promise<RuntimeAvailability>;
|
|
13
15
|
effect(_target: string | null): Effect;
|
|
@@ -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;
|
|
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,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAY/I,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,YAAa,YAAW,aAAa;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,gBAAgB,EAG/C;IAaD,IAAI,QAAQ,IAAI,cAAc,CAU7B;IAGD,IAAI,MAAM,IAAI,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAE9C;IAID,IAAI,cAAc,IAAI,MAAM,CAE3B;IAGD,IAAI,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEpC;IAOD,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAE/D,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,eAAe,CAAC,CAElD;IAOD,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAmB5C,KAAK,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAE/D;IAQD,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAErC;CACJ"}
|
package/dist/BaseExecutor.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { OutputScheme } from "@plurnk/plurnk-schemes";
|
|
2
|
+
import InvocationMetadata from "./InvocationMetadata.js";
|
|
2
3
|
// Base class for runtime executors (parallel to plurnk-mimetypes' BaseHandler).
|
|
3
4
|
// A `@plurnk/plurnk-execs-*` sibling subclasses this and implements `run()`.
|
|
4
5
|
// The framework instantiates one executor per matched runtime tag, injecting
|
|
@@ -44,6 +45,13 @@ export default class BaseExecutor {
|
|
|
44
45
|
get defaultChannel() {
|
|
45
46
|
return Object.keys(this.channels)[0] ?? "";
|
|
46
47
|
}
|
|
48
|
+
// Select the existing stream-publication contract; null publishes every channel.
|
|
49
|
+
get publishedChannel() {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
prepare(input) {
|
|
53
|
+
return InvocationMetadata.prepare(input);
|
|
54
|
+
}
|
|
47
55
|
// Whether this runtime's execution environment is usable in the current
|
|
48
56
|
// deployment. Default: available (pure / in-process runtimes — e.g. node,
|
|
49
57
|
// sqlite, where the daemon itself satisfies the dependency). Subclasses
|
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;
|
|
1
|
+
{"version":3,"file":"BaseExecutor.js","sourceRoot":"","sources":["../src/BaseExecutor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGtD,OAAO,kBAAkB,MAAM,yBAAyB,CAAC;AAEzD,gFAAgF;AAChF,6EAA6E;AAC7E,6EAA6E;AAC7E,yEAAyE;AACzE,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;AAC7E,2EAA2E;AAC3E,4DAA4D;AAC5D,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,kEAAkE;IAClE,gCAAgC;IAChC,8EAA8E;IAC9E,8EAA8E;IAC9E,6EAA6E;IAC7E,yDAAyD;IACzD,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;YACnC,MAAM,EAAE,IAAI,CAAC,MAAM;SACtB,CAAC,CAAC;IACP,CAAC;IAED,+DAA+D;IAC/D,IAAI,MAAM;QACN,OAAO,SAAS,CAAC;IACrB,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;IAED,iFAAiF;IACjF,IAAI,gBAAgB;QAChB,OAAO,IAAI,CAAC;IAChB,CAAC;IASD,OAAO,CAAC,KAAgB;QACpB,OAAO,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;IASD,wEAAwE;IACxE,0EAA0E;IAC1E,wEAAwE;IACxE,iEAAiE;IACjE,EAAE;IACF,8EAA8E;IAC9E,yEAAyE;IACzE,2EAA2E;IAC3E,yEAAyE;IACzE,4DAA4D;IAC5D,EAAE;IACF,sEAAsE;IACtE,4EAA4E;IAC5E,yEAAyE;IACzE,kEAAkE;IAClE,6EAA6E;IAC7E,iBAAiB;IACjB,KAAK,CAAC,KAAK,CAAC,OAAqB;QAC7B,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IAED,4EAA4E;IAC5E,6EAA6E;IAC7E,8EAA8E;IAC9E,yEAAyE;IACzE,wEAAwE;IACxE,gEAAgE;IAChE,MAAM,CAAC,OAAsB;QACzB,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocFile.d.ts","sourceRoot":"","sources":["../src/DocFile.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,OAAO,OAAO,OAAO;IAExB,OAAa,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMlE;IAED,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAM/C;CACJ"}
|
package/dist/DocFile.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
// A package's `docs/<tag>.md` — the authored teaching carried beneath a generated tool
|
|
4
|
+
// document's header ({§executor-discovery}). Runtimes and Functionality families share this
|
|
5
|
+
// one rule: the file stays a valid standalone document whose exact authoring title `# <tag>`
|
|
6
|
+
// is removed, because the generated document owns the one model-facing H1.
|
|
7
|
+
export default class DocFile {
|
|
8
|
+
// The tag's supplemental detail file, or null when the package ships none.
|
|
9
|
+
static async read(dir, tag) {
|
|
10
|
+
try {
|
|
11
|
+
return DocFile.body(await fs.readFile(path.join(dir, "docs", `${tag}.md`), "utf-8"), tag);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
static body(source, tag) {
|
|
18
|
+
const title = `# ${tag}`;
|
|
19
|
+
if (source === title || source === `${title}\n`)
|
|
20
|
+
return "";
|
|
21
|
+
if (source.startsWith(`${title}\r\n`))
|
|
22
|
+
return source.slice(title.length + 2).replace(/^\r?\n/u, "");
|
|
23
|
+
if (source.startsWith(`${title}\n`))
|
|
24
|
+
return source.slice(title.length + 1).replace(/^\r?\n/u, "");
|
|
25
|
+
return source;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=DocFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocFile.js","sourceRoot":"","sources":["../src/DocFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,uFAAuF;AACvF,4FAA4F;AAC5F,6FAA6F;AAC7F,2EAA2E;AAC3E,MAAM,CAAC,OAAO,OAAO,OAAO;IACxB,2EAA2E;IAC3E,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAW,EAAE,GAAW;QACtC,IAAI,CAAC;YACD,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;QAC9F,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,MAAc,EAAE,GAAW;QACnC,MAAM,KAAK,GAAG,KAAK,GAAG,EAAE,CAAC;QACzB,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,GAAG,KAAK,IAAI;YAAE,OAAO,EAAE,CAAC;QAC3D,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,KAAK,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACpG,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,KAAK,IAAI,CAAC;YAAE,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAClG,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type SchemeResult } from "@plurnk/plurnk-schemes";
|
|
2
|
+
import type { ExecInput, ExecPreparation } from "./types.ts";
|
|
3
|
+
type Options = {
|
|
4
|
+
cwd?: string;
|
|
5
|
+
args: string[];
|
|
6
|
+
stdin?: "open";
|
|
7
|
+
};
|
|
8
|
+
type Accepted = {
|
|
9
|
+
args?: boolean;
|
|
10
|
+
stdin?: boolean;
|
|
11
|
+
};
|
|
12
|
+
type Parsed = {
|
|
13
|
+
options: Options;
|
|
14
|
+
} | {
|
|
15
|
+
failure: SchemeResult;
|
|
16
|
+
};
|
|
17
|
+
export default class InvocationMetadata {
|
|
18
|
+
static parse(input: ExecInput, accepted?: Accepted): Parsed;
|
|
19
|
+
static prepare(input: ExecInput, accepted?: Accepted): Promise<ExecPreparation>;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=InvocationMetadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvocationMetadata.d.ts","sourceRoot":"","sources":["../src/InvocationMetadata.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4B,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7D,KAAK,OAAO,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAChE,KAAK,QAAQ,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AACpD,KAAK,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,YAAY,CAAA;CAAE,CAAC;AAK/D,MAAM,CAAC,OAAO,OAAO,kBAAkB;IACnC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,GAAE,QAAa,GAAG,MAAM,CA6B9D;IAED,OAAa,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,GAAE,QAAa,GAAG,OAAO,CAAC,eAAe,CAAC,CAgBxF;CACJ"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { MetadataOptions, Results } from "@plurnk/plurnk-schemes";
|
|
4
|
+
// {§executor-metadata} The executor framework owns these options, not Core. The
|
|
5
|
+
// heading's `[metadata]` is one JSON array of option objects ({§scheme-metadata-modifier});
|
|
6
|
+
// the keys this framework knows are `cwd`, `args`, and `stdin`.
|
|
7
|
+
export default class InvocationMetadata {
|
|
8
|
+
static parse(input, accepted = {}) {
|
|
9
|
+
const fail = (code, detail) => ({
|
|
10
|
+
failure: Results.failure("executor:metadata", code, 400, detail, {}, {
|
|
11
|
+
runtime: input.runtime, retryable: false,
|
|
12
|
+
}),
|
|
13
|
+
});
|
|
14
|
+
const read = MetadataOptions.parse(input.metadata, "executor:metadata", { runtime: input.runtime });
|
|
15
|
+
if ("failure" in read)
|
|
16
|
+
return read;
|
|
17
|
+
const options = { args: [] };
|
|
18
|
+
for (const [field, value] of Object.entries(read.options)) {
|
|
19
|
+
if (field !== "cwd" && !(accepted.args && field === "args") && !(accepted.stdin && field === "stdin")) {
|
|
20
|
+
return fail("metadata-unsupported", `Executable tool '${input.runtime}' does not accept metadata field '${field}'.`);
|
|
21
|
+
}
|
|
22
|
+
if (field === "stdin") {
|
|
23
|
+
if (value !== "open")
|
|
24
|
+
return fail("invalid-stdin", 'Execution stdin accepts only "open".');
|
|
25
|
+
options.stdin = "open";
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (field === "cwd") {
|
|
29
|
+
if (typeof value !== "string" || value.length === 0 || value.includes("\0"))
|
|
30
|
+
return fail("invalid-cwd", "Execution cwd must be a nonempty directory path string without NUL.");
|
|
31
|
+
options.cwd = value;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (!Array.isArray(value) || !value.every((arg) => typeof arg === "string" && !arg.includes("\0"))) {
|
|
35
|
+
return fail("invalid-args", "Execution args must be a JSON array of strings without NUL.");
|
|
36
|
+
}
|
|
37
|
+
options.args = value;
|
|
38
|
+
}
|
|
39
|
+
return { options };
|
|
40
|
+
}
|
|
41
|
+
static async prepare(input, accepted = {}) {
|
|
42
|
+
const parsed = this.parse(input, accepted);
|
|
43
|
+
if ("failure" in parsed)
|
|
44
|
+
return parsed.failure;
|
|
45
|
+
const directory = parsed.options.cwd;
|
|
46
|
+
if (directory === undefined)
|
|
47
|
+
return { status: 200, cwd: input.cwd };
|
|
48
|
+
const cwd = resolve(input.cwd ?? process.cwd(), directory);
|
|
49
|
+
try {
|
|
50
|
+
if ((await stat(cwd)).isDirectory())
|
|
51
|
+
return { status: 200, cwd };
|
|
52
|
+
}
|
|
53
|
+
catch (cause) {
|
|
54
|
+
const code = cause.code;
|
|
55
|
+
if (code !== "ENOENT" && code !== "ENOTDIR")
|
|
56
|
+
throw cause;
|
|
57
|
+
}
|
|
58
|
+
return Results.failure("executor:metadata", "cwd-not-found", 400, `Execution cwd '${directory}' is not an existing directory.`, {}, {
|
|
59
|
+
runtime: input.runtime, retryable: false,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=InvocationMetadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvocationMetadata.js","sourceRoot":"","sources":["../src/InvocationMetadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuntimeInvocation.d.ts","sourceRoot":"","sources":["../src/RuntimeInvocation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGR,iBAAiB,IAAI,qBAAqB,EAE1C,mBAAmB,EAGtB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"RuntimeInvocation.d.ts","sourceRoot":"","sources":["../src/RuntimeInvocation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGR,iBAAiB,IAAI,qBAAqB,EAE1C,mBAAmB,EAGtB,MAAM,YAAY,CAAC;AAqEpB,MAAM,CAAC,OAAO,OAAO,iBAAiB;IAClC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAsFzF;IAED,MAAM,CAAC,kBAAkB,CACrB,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GAChB,mBAAmB,CA4CrB;CACJ"}
|