@plurnk/plurnk-execs 1.16.5 → 1.18.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.
Files changed (50) hide show
  1. package/.env.defaults +19 -11
  2. package/README.md +34 -8
  3. package/SPEC.md +152 -61
  4. package/dist/BaseExecutor.d.ts +3 -1
  5. package/dist/BaseExecutor.d.ts.map +1 -1
  6. package/dist/BaseExecutor.js +8 -0
  7. package/dist/BaseExecutor.js.map +1 -1
  8. package/dist/DocFile.d.ts +5 -0
  9. package/dist/DocFile.d.ts.map +1 -0
  10. package/dist/DocFile.js +28 -0
  11. package/dist/DocFile.js.map +1 -0
  12. package/dist/InvocationMetadata.d.ts +22 -0
  13. package/dist/InvocationMetadata.d.ts.map +1 -0
  14. package/dist/InvocationMetadata.js +63 -0
  15. package/dist/InvocationMetadata.js.map +1 -0
  16. package/dist/RuntimeInvocation.d.ts.map +1 -1
  17. package/dist/RuntimeInvocation.js +19 -14
  18. package/dist/RuntimeInvocation.js.map +1 -1
  19. package/dist/RuntimeSummary.d.ts +0 -3
  20. package/dist/RuntimeSummary.d.ts.map +1 -1
  21. package/dist/RuntimeSummary.js +7 -13
  22. package/dist/RuntimeSummary.js.map +1 -1
  23. package/dist/RuntimeTag.d.ts.map +1 -1
  24. package/dist/RuntimeTag.js +8 -1
  25. package/dist/RuntimeTag.js.map +1 -1
  26. package/dist/SubprocessExecutor.d.ts +3 -2
  27. package/dist/SubprocessExecutor.d.ts.map +1 -1
  28. package/dist/SubprocessExecutor.js +30 -4
  29. package/dist/SubprocessExecutor.js.map +1 -1
  30. package/dist/SubprocessInput.d.ts +10 -0
  31. package/dist/SubprocessInput.d.ts.map +1 -0
  32. package/dist/SubprocessInput.js +86 -0
  33. package/dist/SubprocessInput.js.map +1 -0
  34. package/dist/discover.d.ts.map +1 -1
  35. package/dist/discover.js +2 -19
  36. package/dist/discover.js.map +1 -1
  37. package/dist/index.d.ts +4 -2
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +3 -3
  40. package/dist/index.js.map +1 -1
  41. package/dist/runtime.d.ts.map +1 -1
  42. package/dist/runtime.js +4 -8
  43. package/dist/runtime.js.map +1 -1
  44. package/dist/types.d.ts +22 -2
  45. package/dist/types.d.ts.map +1 -1
  46. package/package.json +5 -4
  47. package/dist/advertise.d.ts +0 -13
  48. package/dist/advertise.d.ts.map +0 -1
  49. package/dist/advertise.js +0 -12
  50. package/dist/advertise.js.map +0 -1
package/.env.defaults CHANGED
@@ -1,16 +1,24 @@
1
- # --- @plurnk/plurnk-execs : runtime registration policy (SPEC §3.3) ---
2
- # Purely subtractive: these only ever REMOVE tags from the registered set — there
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
- # Allowlist: register ONLY these tags (comma-separated); every other tag is off.
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 source characters retained from third-party diagnostics in a failed
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
12
+
13
+ # Subprocess-common floors ({§operator-config-env-defaults}, {§exec-env-scoped}). The
14
+ # executor framework owns these because every subprocess runtime wants them and one owner
15
+ # per key is enforced at boot — each executor redeclaring them would crash the daemon.
16
+ # They are set-if-unset, so an operator who exports PAGER=less keeps theirs.
17
+ # A pager that waits for a keypress hangs a spawn that has no terminal.
18
+ PAGER=cat
19
+ # git consults its own pager variable first, so both are set.
20
+ GIT_PAGER=cat
21
+ # Colour escapes and progress spinners are noise in a captured channel.
22
+ NO_COLOR=1
23
+ # Non-interactive by construction: tools that branch on CI take the unattended path.
24
+ CI=1
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # plurnk-execs
2
2
 
3
3
  Lean framework and contract for `@plurnk/plurnk-execs-*` runtime packages. Core
4
- uses it to discover EXEC tags, admit calls, and stream each runtime's output
4
+ uses it to discover runtime tags, admit calls, and stream each runtime's output
5
5
  under its own tag-addressed scheme. The default service manifest, not this
6
6
  framework, owns the standard installed leaf set ({§bundled-set}).
7
7
 
@@ -18,7 +18,7 @@ framework or service.
18
18
  ## Documentation
19
19
 
20
20
  - [`SPEC.md`](./SPEC.md) — authoritative executor author and consumer contract.
21
- - [plurnk-contracts](https://github.com/plurnk/plurnk-service/tree/main/plurnk-contracts) — EXEC AST and shared runtime-neutral contracts.
21
+ - [plurnk-contracts](https://github.com/plurnk/plurnk-service/tree/main/plurnk-contracts) — the execution AST and shared runtime-neutral contracts.
22
22
  - [plurnk-schemes](https://github.com/plurnk/plurnk-service/tree/main/plurnk-schemes) — universal operation results and derived output-scheme contract.
23
23
 
24
24
  ## Write an executor
@@ -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 plus one canonical example used for dispatch enforcement and the
55
- generated `worker://~/_plurnk/tools/` document. A `docs/<tag>.md` file supplies
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 |
@@ -75,7 +80,7 @@ acceptance is not a same-turn result. See {§executor-effect}.
75
80
 
76
81
  ### Understand the target
77
82
 
78
- The EXEC `(target)` slot is runtime-specific:
83
+ The execution's `(target)` slot is runtime-specific:
79
84
 
80
85
  | Runtime family | Typical mapping |
81
86
  | -------------- | ----------------------------------------------------------------- |
@@ -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
+ execution 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:///1/2/3#stdout`, while a structured result may
92
- be `sqlite:///1/2/3#results`. `exec://` is not an output address. Executors only
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
@@ -6,7 +6,7 @@ the framework; executor leaves implement it.
6
6
  ## §executor-role Role and ownership
7
7
 
8
8
  An executor owns one declared runtime-specific invocation shape, its mapping
9
- from that EXEC body and realized target to work, declared output channels,
9
+ from that fence body and realized target to work, declared output channels,
10
10
  environment availability, and effect classification. The consumer owns
11
11
  dispatch, invocation-shape enforcement and target realization, proposal policy,
12
12
  storage, subscriptions, deadlines, polling, cancellation delivery, packet
@@ -17,7 +17,7 @@ flowchart LR
17
17
  Manifest["package runtime declarations"] --> Discover["framework discovery"]
18
18
  Discover --> Registry["runtime-tag registry"]
19
19
  Registry --> Probe["consumer instantiates and probes each tag"]
20
- Request["EXEC with runtime tag"] --> Effect["executor effect fact"]
20
+ Request["fence with runtime tag"] --> Effect["executor effect fact"]
21
21
  Effect --> Admission["consumer proposal policy"]
22
22
  Admission --> Stream["consumer creates tag-addressed stream"]
23
23
  Stream --> Run["executor run with consumer sinks"]
@@ -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,11 +74,12 @@ 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 Worker — an attached MCP server, a Worker Functionality
75
- manager — is published per Worker by its owning module, closing over that
76
- identity at publication ({§functionality-model-projection} in the core
77
- specification; the MCP host is the precedent). Consumers must not smuggle
78
- identity through `env` or `body` conventions.
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
80
+ identity through `env` or `body` conventions; a consumer that owns both a
81
+ runtime and the execution identity binds the two to each other outside these
82
+ arguments, at the operation.
79
83
 
80
84
  interface RuntimeAvailability {
81
85
  available: boolean;
@@ -90,7 +94,7 @@ The framework constructs one executor per matched runtime tag with
90
94
  `this.runtime`; it must not retain per-run state on the executor instance. The
91
95
  derived addressable runtime scheme retains `glyph` for client discovery
92
96
  ({§manifest-client-display}); runtime aliases remain excluded from scheme
93
- model-teaching because the EXEC invocation directory owns that hot-path
97
+ model-teaching because the execution invocation directory owns that hot-path
94
98
  surface.
95
99
 
96
100
  ### §executor-sinks Inputs and sinks
@@ -98,11 +102,13 @@ surface.
98
102
  | Field | Contract |
99
103
  | ---------- | ------------------------------------------------------------------------------------------------------- |
100
104
  | `runtime` | The matched tag. |
101
- | `body` | The authored EXEC body, interpreted according to the runtime's invocation declaration. |
105
+ | `body` | The authored fence body, interpreted according to the runtime's invocation declaration. |
102
106
  | `cwd` | Consumer-selected project working directory, or `null` for a runtime that has none. |
103
- | `target` | Consumer-realized optional EXEC target. Its representation and role come from the invocation declaration. |
107
+ | `target` | Consumer-realized optional execution target. Its representation and role come from the invocation declaration. |
108
+ | `metadata` | Exact ordered header blocks owned by the invoked executor, retained separately from the body and target. |
104
109
  | `env` | Exact child environment when supplied. A subprocess must use it instead of reconstructing host policy. |
105
110
  | `signal` | Consumer cancellation. Every executor must honor it at each cancellable boundary. |
111
+ | `registerInput` | Optionally register one live input receiver for this invocation under {§executor-live-input}. |
106
112
  | `write` | Append to a declared channel. An optional mimetype replaces that channel's per-call output type. |
107
113
  | `setState` | Move a declared channel from `active` to terminal `closed` or `errored`. |
108
114
  | `emit` | Publish a transient, nonterminal Notice. |
@@ -113,6 +119,61 @@ The executor receives callbacks, never a database, subscription registry,
113
119
  packet builder, or wake mechanism. Related lifecycle behavior remains on the
114
120
  consumer side of {§executor-role}.
115
121
 
122
+ ### §executor-metadata Invocation metadata ownership
123
+
124
+ The invoked executor owns its `[metadata]` for every target kind. The source
125
+ scheme supplies the program or data; it does not inherit the invoking tool's
126
+ options. An internal source READ therefore carries no execution metadata. An
127
+ authored READ retains its own source-scheme metadata contract.
128
+
129
+ | Stage | Contract |
130
+ | ----- | -------- |
131
+ | 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. |
132
+ | 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. |
133
+ | 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. |
134
+ | 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. |
135
+ | 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. |
136
+
137
+ Metadata does not turn inline programs or script stdin into JSON envelopes.
138
+ Executable references document advanced options on demand; no language-level
139
+ option names or hot-path teaching are required.
140
+
141
+ ### §executor-live-input Invocation-local input
142
+
143
+ `ExecArgs.registerInput?(receiver)` binds one receiver to the current invocation.
144
+ The receiver accepts `{ body: string, metadata: readonly string[] | null,
145
+ signal: AbortSignal }` and resolves a universal `SchemeResult`. The body is exact
146
+ authored text; metadata belongs to the receiver. Registration is once per run,
147
+ never executor-instance state. An absent callback means the consumer cannot
148
+ deliver live input. A receiver must honor cancellation at each delivery boundary.
149
+
150
+ | Responsibility | Owner |
151
+ | --- | --- |
152
+ | Address, workspace admission, capability checks, proposals | Consumer, using the existing execution identity and effect. |
153
+ | Delivery ordering, bounded backpressure, lifetime | Consumer; serialize accepted deliveries, never replay an ambiguous write, retire on execution settlement/cancellation. |
154
+ | Input meaning, framing, EOF, delivery result | Receiver; acceptance does not imply consumption, command success, or execution completion. |
155
+ | Output, progress, completion | Existing `write`, `setState`, and `run` result; input introduces no second output or wake path. |
156
+
157
+ #### §executor-stdin Subprocess input
158
+
159
+ `SubprocessExecutor` accepts `[{"stdin": "open"}]` at invocation. The initial recipe
160
+ input precedes SEND bodies and stdin remains open; without this option, existing
161
+ batch input and EOF behavior is unchanged. The same input adapter serves `jq`.
162
+
163
+ | SEND input | Effect |
164
+ | --- | --- |
165
+ | Body, no metadata | Write its exact UTF-8 bytes, including authored newlines; no implicit newline. Empty input is a no-op, not EOF. |
166
+ | `[{"eof": true}]` with optional body | Write the body, then close stdin. Later SENDs return `410 input-closed`, including repeated EOF. |
167
+ | Other or duplicate metadata | `400`, before writing. |
168
+ | Pipe failure | Factual delivery failure with the native error code; no automatic retry. |
169
+ | Delivery cancellation | Stop the pending write and close stdin. The process retains its ordinary lifecycle. |
170
+
171
+ A successful receipt reports `bytesAccepted` and `inputClosed`, with those facts
172
+ in the ordinary model-visible `detail`. It acknowledges the writable pipe, not
173
+ application processing. Subprocess leaves inherit this
174
+ contract; logical executors need not offer a receiver. In particular, SQLite,
175
+ client-interaction tools, and MCP transports do not gain stdin through this API.
176
+
116
177
  ### §executor-channels Channels
117
178
 
118
179
  The executor declares every channel it may write. The consumer seeds a stream
@@ -135,8 +196,10 @@ reformatting arbitrary source JSON read from an entry.
135
196
  subprocess `exitCode`. A result with `status >= 400` carries exactly one RFC
136
197
  9457 Problem whose status agrees with the result. Expected runtime failures
137
198
  resolve as failure results and leave affected channels `errored`; they do not
138
- throw. The consumer validates the boundary and converts a throw or invalid
139
- result into its own durable failure before closing the stream.
199
+ throw. Rejection by an aborted execution's signal reason or an `AbortError`
200
+ is cancellation, not an executor defect; the consumer preserves its distinct
201
+ cancellation/deadline result. Other throws and invalid results become durable
202
+ contract failures before the consumer closes the stream.
140
203
 
141
204
  A nonzero subprocess exit directs the caller only to inspect both stdout and
142
205
  stderr because either may contain the useful diagnostic; it does not presume
@@ -173,7 +236,7 @@ reclassifies the materialized path.
173
236
  | `pure` | Has no externally observable side effect. | Automatically accepted. |
174
237
 
175
238
  The classification controls admission policy and may be reused as operational
176
- metadata; it never changes within the invocation. After acceptance, every EXEC
239
+ metadata; it never changes within the invocation. After acceptance, every execution
177
240
  uses the same background stream path: output is not returned in the dispatching
178
241
  turn. Core owns that composed behavior in {§exec-host-proposes},
179
242
  {§exec-readpure-ungated}, and {§exec-stream}.
@@ -195,34 +258,49 @@ unavailable is a fail-hard boot error.
195
258
 
196
259
  ## §executor-output-address Tag-addressed output
197
260
 
198
- `exec` is the consumer's internal EXEC dispatcher; it is not a model-facing
261
+ `exec` is the consumer's internal execution dispatcher; it is not a model-facing
199
262
  output namespace. Every available runtime receives one derived read-only
200
263
  scheme face from its tag, channels, and default channel. The executor authors
201
264
  no second scheme manifest.
202
265
 
203
266
  | Output | Model-facing address |
204
267
  | ------------------------- | ------------------------------------------------------------------ |
205
- | Calling worker's stream | `<tag>:///<loop>/<turn>/<sequence>/EXEC#<channel>` |
206
- | Fragmentless read | `<tag>:///<loop>/<turn>/<sequence>/EXEC` → the declared default channel |
207
- | Example subprocess stdout | `sh:///1/2/3/EXEC#stdout` |
208
- | Example structured result | `sqlite:///1/2/3/EXEC#results` |
268
+ | Workspace execution stream | `<tag>:///<id>#<channel>` |
269
+ | Fragmentless read | `<tag>:///<id>` → the declared default channel |
270
+ | Example subprocess stdout | `sh:///ab3d5678#stdout` |
271
+ | Example structured result | `sqlite:///c2d45678#results` |
209
272
 
210
273
  The executor only produces through `write` and `setState`. The consumer stores
211
274
  the entry and serves every later READ/FIND through uniform entry machinery.
212
275
  An executor does not implement a private read face, orientation receipt,
213
- slicer, or index. Owner-qualified cross-worker addresses and packet projection
214
- belong to core's {§stream-owner-scoped} and {§exec-stream} contracts.
276
+ slicer, or index. Workspace-stable resource addresses and packet projection
277
+ belong to core's {§execution-output-identity} and {§exec-stream} contracts.
278
+ Address resolution binds the workspace without requiring an exact stored row:
279
+ FIND patterns and descendant resource paths participate in ordinary discovery;
280
+ an exact READ reports its own missing resource ({§entry-address-resolution}).
281
+
282
+ `publishedChannel` selects one declared channel for automatic stream observations;
283
+ absent/null selects all channels. Non-published channels remain READ-addressable.
284
+ This is the ordinary subscription publication selection, not another delivery path.
215
285
 
216
286
  ### §executor-entry-sink Optional materialization
217
287
 
218
- `entry(path, content, { tags, mimetype? })` is a consumer-implemented sink, not
219
- executor access to storage. The consumer materializes or updates an entry,
220
- uses the tags to classify its ordinary journal announcement, and resolves the
221
- canonical model-facing address. Tags never become resource metadata.
222
- `content === null` requests consumer-sourced
223
- acquisition. Rejection means only that this materialization failed; it does not
224
- invalidate the executor's upstream result. When the sink is absent, the
225
- executor preserves its result without inventing a materialization verdict.
288
+ `entry(path, content, { mimetype?, name? })` is a consumer-implemented sink, not
289
+ executor access to storage. It returns the canonical address of an ordinary
290
+ resource; publication alone does not attach media or wake a Worker.
291
+
292
+ | Input | Meaning |
293
+ | --- | --- |
294
+ | Absolute resource URL | Materialize or update that resource through its scheme owner. |
295
+ | `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. |
296
+ | String content + mimetype | Supplied text; preserve its source layout. |
297
+ | `Uint8Array` content + mimetype | Supplied bytes, retained as bytes, not a JSON/base64 body. |
298
+ | `content: null` | Consumer-sourced acquisition from an absolute HTTP(S) URL. |
299
+
300
+ Core owns names, storage, publication evidence, and byte acquisition. Executors
301
+ publish returned addresses in their result. Rejection means materialization
302
+ failed, not that the upstream operation had no effect. An absent sink cannot
303
+ be reported as successful resource publication.
226
304
 
227
305
  ## §executor-discovery Discovery and registration
228
306
 
@@ -284,7 +362,7 @@ at boot; changing package membership or configuration requires a restart.
284
362
  | ------------- | -------------------------------------------------------------------------------------------------- |
285
363
  | `name` | Canonical runtime tag and derived output-scheme name, admitted below. |
286
364
  | `glyph` | Optional presentation glyph. |
287
- | `summary` | Required one-line description, or `{ from: "tools" }` for an exact family inventory. |
365
+ | `summary` | Required one-line description, or `{ from: "tools", description?: string }` for an exact family inventory with an optional one-line purpose. |
288
366
  | `invocation` | Required body and target contract, validated and normalized below. |
289
367
  | `details` | Optional supplemental Markdown. `docs/<tag>.md` wins over the inline manifest field. |
290
368
  | `attribution` | Published per-tag projection of the validated package declaration ({§plugin-attribution}). |
@@ -294,7 +372,11 @@ The framework validates and carries the summary source, invocation, and suppleme
294
372
  details as separate facts. A `{ from: "tools" }` summary is valid only for a
295
373
  runtime implementing {§executor-tool-registry}; the consumer resolves it from
296
374
  the exact effective tool set, after capability attenuation, so a denied tool
297
- cannot survive in the family orientation line. The consumer deterministically renders the
375
+ cannot survive in the family orientation line. The inventory renders as
376
+ one compact executable fence naming `runtime (target|...)`, with the optional
377
+ purpose as a trailing aside and body line breaks represented by literal `\n`;
378
+ an authored string remains a description, without expanding its tool inventory.
379
+ The consumer deterministically renders the
298
380
  model-facing tool document from either the static invocation or the executor's exact
299
381
  {§executor-tool-registry}; authors never duplicate Summary or Invocation in
300
382
  prose. A
@@ -320,20 +402,21 @@ details; the generated tool document owns the one model-facing H1.
320
402
  | `target.kind` | One of the structural realization modes below. |
321
403
  | `exclusive` | Optional `true`: body and target are alternative inputs and supplying both is refused. |
322
404
  | `example` | Concise executable witness with a one-line `body`, `target`, or both as the declared shape permits. |
323
- | `signature` | One-line structural body signature for a schema-backed invocation; no fabricated argument values. |
405
+ | `signature` | Authored one-line structural body signature when no JSON Schema defines the input. |
406
+ | `inputSchema` | Original JSON Schema object for the input; the common document renderer derives its preview. |
324
407
 
325
408
  | Target kind | Consumer realization |
326
409
  | ----------- | ------------------------------------------------------------------------------------------------------------------------------ |
327
410
  | `literal` | Preserve the complete authored target string. It is an executor identifier, never a scheme read or filesystem classification. |
328
411
  | `path` | Accept only a local or `file://` path and pass that path directly. |
329
- | `resource` | Pass a local/file path directly; resolve a non-file data-scheme address through one exact READ and materialize its string representation to a temporary file. |
412
+ | `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
413
  | `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
414
 
332
- Every EXEC must supply at least a body or target even when neither field is
415
+ Every execution must supply at least a body or target even when neither field is
333
416
  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` or
335
- `signature` is present. An example must satisfy the same required, refused,
336
- and exclusive buckets and parse as exactly one EXEC section for the runtime. A
417
+ empty or non-empty. `exclusive` requires a target declaration. Exactly one of `example`,
418
+ `signature`, or `inputSchema` is present. An example must satisfy the same required, refused,
419
+ and exclusive buckets and parse as exactly one executor fence for the runtime. A
337
420
  signature is presentation, not an executable example; dispatch still enforces
338
421
  the invocation's body and target declarations. An invocation declaration
339
422
  with a missing field, unknown field, invalid combination, multiline role, or
@@ -377,25 +460,38 @@ I/O boundary rather than making packet assembly perform network discovery.
377
460
  §executor-tool-document **Tool documents are the model-facing executor
378
461
  directory.** A general runtime's document carries exact H2 `Summary` and
379
462
  `Invocation` sections plus its executable witness. Its Summary is that compact
380
- invocation witness in inline code, with the authored description as an
381
- operation annotation on its invocation line and a literal `\n` before a
382
- one-line body. An exact registry instead renders one compact family document
383
- whose Summary remains the family description and whose H2 `Invocation`
384
- contains one `example` fence with
385
- every exact annotated EXEC heading and signature, plus one child document per
386
- tool. Each child's Summary is its annotated invocation form; its H2 `Invocation`
387
- contains the literal target, signature, and supplemental input details.
463
+ invocation witness in plain text, with the authored description as an
464
+ operation aside on its invocation line and a literal `\n` before a
465
+ one-line body. The bundled subprocess interpreters declare concrete inline-program
466
+ examples; their catalog summaries include the program body without a script target.
467
+ An exact registry instead renders one compact family document whose Summary is
468
+ authored or derived from its effective tools. Its H2 `Tools` contains one
469
+ executable fence per tool, naming the runtime and exact target, with its aside
470
+ and input preview. A schema-backed invocation
471
+ links from its aside to a child document containing the full description and
472
+ original input JSON Schema. Non-schema invocations retain their authored witness
473
+ and supplemental details.
388
474
  Supplemental `details` follows framework-owned sections and cannot own identity,
389
475
  invocation, or admission. The consumer chooses resource addresses, materializes
390
476
  the documents, and exposes each Summary through ordinary FIND metadata. No
391
477
  executor table or executor-specific discovery protocol exists.
392
478
 
479
+ §executor-input-schema-preview Schema-backed previews list only explicitly
480
+ required top-level fields, with quoted names and declared broad JSON types.
481
+ Nested objects and arrays stay opaque; an undeclared type is `unknown`. Optional
482
+ fields, references, constraints, and conditional branches are not interpreted.
483
+ The preview is not a complete signature or validation promise. Its schema link
484
+ provides the complete original schema, including descriptions, definitions,
485
+ references, and constraints; repository-owned referenced schemas are included
486
+ unchanged alongside it. Documentation performs no network reference resolution.
487
+ Output schemas are not input teaching.
488
+
393
489
  Runtime-name admission is one identity contract:
394
490
 
395
491
  | Constraint | Contract |
396
492
  | ----------- | ------------------------------------------------------------------------------------------------------------- |
397
- | Syntax | `[a-z][a-z0-9+.-]*`: canonical lowercase RFC-scheme syntax that is also an admitted EXEC identifier. |
398
- | Identity | The exact name is the EXEC selector, registry key, tool-family identity, and output URI-scheme name. |
493
+ | Syntax | `[a-z][a-z0-9+.-]*`: canonical lowercase RFC-scheme syntax that is also an admitted execution identifier. |
494
+ | Identity | The exact name is the fence name, registry key, tool-family identity, and output URI-scheme name. |
399
495
  | Reservation | `only` is unavailable because `PLURNK_EXECS_ONLY` owns that case-insensitive configuration key. |
400
496
 
401
497
  Installed static declarations, trusted dynamic-hook declarations, and
@@ -429,7 +525,8 @@ swallowed.
429
525
 
430
526
  ### §executor-policy Subtractive runtime policy
431
527
 
432
- Discovery applies the daemon's registration policy to every tag. The exported
528
+ Registration applies the daemon's policy to every tag, whether discovered from
529
+ a package or supplied by a daemon module, including workspace-scoped runtimes. The exported
433
530
  `Policy` parser can apply the same grammar to additional consumer-owned layers.
434
531
 
435
532
  | Variable | Enforced effect |
@@ -440,18 +537,11 @@ Discovery applies the daemon's registration policy to every tag. The exported
440
537
  | `Policy.enabledAcross(tag, [a, b, ...])` | Keep the tag only when every supplied layer enables it. |
441
538
 
442
539
  Policy is purely subtractive: no layer can re-enable a tag removed by another.
443
- Boot-disabled tags are absent from the registry and returned in
444
- `Discovery.disabled`. Workspace and loop admission remain consumer concerns;
540
+ Disabled tags publish neither an executor nor its scheme or tool documents;
541
+ package discovery also returns them in `Discovery.disabled`.
542
+ Workspace and loop admission remain consumer concerns;
445
543
  the framework does not define a second Active/Available state machine.
446
544
 
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
545
  ## §executor-default-inventory Current installed set
456
546
 
457
547
  The default `@plurnk/plurnk-service` composition installs the following
@@ -490,9 +580,10 @@ interface SpawnArgs {
490
580
  | `python3` | `python3 -c <body>`. |
491
581
  | Other default-base runtime | `<runtime> -c <body>`; specialized leaves override this fallback. |
492
582
 
493
- With a target, the target is the program and the body is its stdin. The working
583
+ With a target, the target is the program and the body is its stdin. Each leaf
584
+ uses its interpreter's file form (`awk -f <target>`, for example). The working
494
585
  directory is the consumer's `cwd` — the project root, or the directory a
495
- `{cwd=<directory>}` block on the heading names ({§exec-executor-slot}); a
586
+ `[{"cwd": "<directory>"}]` block on the heading names ({§exec-executor-slot}); a
496
587
  directory is never a target. Data runtimes define their own declared target
497
588
  kind and role.
498
589
 
@@ -504,7 +595,7 @@ violations for the consumer to contain.
504
595
 
505
596
  ### §executor-cancellation Cancellation and consumer timing
506
597
 
507
- Executors know only the supplied `AbortSignal`. Core owns EXEC timeout and poll
598
+ Executors know only the supplied `AbortSignal`. Core owns execution timeout and poll
508
599
  syntax, timers, wakes, and loop lifetime in {§exec-timeout} and {§exec-poll}.
509
600
  Subprocess cancellation signals the process group: a caller-supplied kill code
510
601
  is delivered once; ordinary cancellation uses SIGHUP; loop-end housekeeping
@@ -516,7 +607,7 @@ The consumer:
516
607
 
517
608
  1. discovers declared tags, instantiates and probes each tag, and caches the verdict;
518
609
  2. registers a derived output scheme for every admitted, available tag;
519
- 3. resolves EXEC to exactly one tag and obtains its effect fact;
610
+ 3. resolves the fence name to exactly one tag and obtains its effect fact;
520
611
  4. applies proposal policy, creates the stream entry, and supplies sinks plus cancellation;
521
612
  5. validates the terminal result and closes every declared channel and subscription coherently; and
522
613
  6. projects stream observations and later reads without calling back into the executor.
@@ -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;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;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;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,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"}
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"}
@@ -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
@@ -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,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;IAgBD,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"}
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,5 @@
1
+ export default class DocFile {
2
+ static read(dir: string, tag: string): Promise<string | null>;
3
+ static body(source: string, tag: string): string;
4
+ }
5
+ //# sourceMappingURL=DocFile.d.ts.map
@@ -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"}
@@ -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"}