@plurnk/plurnk-mcp 1.16.5 → 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 CHANGED
@@ -1,46 +1,42 @@
1
- # --- @plurnk/plurnk-mcp : current MCP host module ---
1
+ # @plurnk/plurnk-mcp — Worker MCP attachments.
2
+ # Alias blocks make servers available; ENABLED selects initial attachments.
3
+ # A Worker can add/enable/disable/remove attachments through its Functionality controls.
2
4
 
3
- # Bound only connection and protocol discovery. Individual MCP operations use
4
- # the request timeout below and remain cancellable through their Plurnk run.
5
+ # Connection and protocol-discovery deadline, positive ms.
5
6
  PLURNK_MCP_CONNECT_TIMEOUT=30000
7
+ # Individual operation deadline, positive ms; caller cancellation still applies.
6
8
  PLURNK_MCP_REQUEST_TIMEOUT=86400000
7
-
8
- # Configured servers are available to clients. Only this exact JSON-array
9
- # subset connects and becomes model-visible by default; workspaces may override it.
9
+ # Initially enabled aliases, JSON array; [] = none.
10
10
  PLURNK_MCP_ENABLED=[]
11
-
12
- # Turn 0 surveys enabled tool FAMILIES (one row per server, summary = its
13
- # one-liner). Servers named here also expand their complete tool tree into
14
- # the turn-0 survey:
11
+ # Expand these servers' tool lists in turn 0; otherwise show one row per server.
15
12
  # PLURNK_MCP_EXPANDED=[]
16
13
 
17
- # Each configured server contributes its enabled `[server] (tool)` rows and server:// resources.
18
- #
19
- # Streamable HTTP:
20
- # PLURNK_MCP_github=https://example.test/mcp
21
- # PLURNK_MCP_github_BEARER=${GITHUB_TOKEN}
22
- # PLURNK_MCP_github_TOOLS=["issue_read","issue_search"]
23
- # PLURNK_MCP_github_READ=["issue_read","issue_search"]
24
- #
25
- # stdio: the target is one exact executable path/name, including whitespace.
26
- # Arguments are a JSON array so Plurnk does not invent or interpret a shell.
27
- # PLURNK_MCP_atlas=node
28
- # PLURNK_MCP_atlas_ARGS=["/absolute/path/to/atlas-server.mjs"]
29
- # PLURNK_MCP_atlas_CWD=/absolute/working/directory
30
- # PLURNK_MCP_atlas_ENV={"TOKEN":"${ATLAS_TOKEN}"}
31
- #
32
- # npx (installed-on-demand executables) — the documented Brave Search fixture,
33
- # demo-tier only; credentials stay one ${NAME} reference in the operator env:
34
- # PLURNK_MCP_BRAVE=npx
35
- # PLURNK_MCP_BRAVE_ARGS=["-y","@brave/brave-search-mcp-server@2.1.0"]
36
- # PLURNK_MCP_BRAVE_ENV={"BRAVE_API_KEY":"${BRAVE_API_KEY}"}
37
- # PLURNK_MCP_BRAVE_TOOLS=["brave_web_search","brave_news_search"]
38
- # PLURNK_MCP_BRAVE_READ=["brave_web_search","brave_news_search"]
39
- #
40
- # _SUMMARY companions are fallbacks only — declare one when the server's own
41
- # summary metadata is missing, confusing, or garbage. The family row can carry
42
- # its flagship invocation form directly:
43
- # PLURNK_MCP_BRAVE_SUMMARY=EXEC [brave] (brave_web_search) <!-- Retrieve web results -->
44
- # PLURNK_MCP_BRAVE_BRAVE_WEB_SEARCH_SUMMARY=General web search.
45
- #
46
- # Then list it above to make it model-visible, e.g. PLURNK_MCP_ENABLED=["brave"].
14
+ # --- HTTP target ---
15
+ # URL, optional bearer reference, optional headers (string-valued JSON object).
16
+ # PLURNK_MCP_forge=https://example.test/mcp
17
+ # PLURNK_MCP_forge_BEARER=${FORGE_TOKEN}
18
+ # PLURNK_MCP_forge_HEADERS={"X-Tenant":"${FORGE_TENANT}"}
19
+
20
+ # --- stdio target ---
21
+ # One exact executable (not a shell command); ARGS is a literal JSON array.
22
+ # CWD is optional; ENV overlays the subprocess environment, resolving ${NAME} references.
23
+ # PLURNK_MCP_browser=node
24
+ # PLURNK_MCP_browser_ARGS=["/absolute/path/to/browser-server.mjs"]
25
+ # PLURNK_MCP_browser_CWD=/absolute/working/directory
26
+ # PLURNK_MCP_browser_ENV={"TOKEN":"${BROWSER_TOKEN}"}
27
+
28
+ # --- Tool admission and orientation ---
29
+ # Optional tool allowlist; omitted = all server tools. READ marks tools as read-only for admission.
30
+ # PLURNK_MCP_forge_TOOLS=["issue_read","issue_search"]
31
+ # PLURNK_MCP_forge_READ=["issue_read","issue_search"]
32
+ # Summary fallbacks when server metadata is inadequate; per-server or per-tool.
33
+ # PLURNK_MCP_forge_SUMMARY=```forge (issue_read) <!-- Read forge issues -->```
34
+ # PLURNK_MCP_forge_issue_read_SUMMARY=Read one issue.
35
+
36
+ # --- Optional Brave Search ---
37
+ # PLURNK_MCP_brave=npx
38
+ # PLURNK_MCP_brave_ARGS=["-y","@brave/brave-search-mcp-server@2.1.0"]
39
+ # PLURNK_MCP_brave_ENV={"BRAVE_API_KEY":"${BRAVE_API_KEY}"}
40
+ # PLURNK_MCP_brave_TOOLS=["brave_web_search","brave_news_search"]
41
+ # PLURNK_MCP_brave_READ=["brave_web_search","brave_news_search"]
42
+ # PLURNK_MCP_ENABLED=["brave"]
package/README.md CHANGED
@@ -13,11 +13,11 @@ serves its standard surface at its own negotiated revision. Plurnk does not
13
13
  downgrade its own extension wire, but it does not reject an older supported
14
14
  revision.
15
15
 
16
- ## Manage Worker servers
16
+ ## Manage workspace servers
17
17
 
18
- Service environment variables provide available servers for every Worker;
18
+ Service environment variables provide available servers for every workspace;
19
19
  `PLURNK_MCP_ENABLED` selects the exact cold-enabled subset. Users can add,
20
- enable, disable, or remove one Worker's servers without restarting the daemon. An
20
+ enable, disable, or remove a workspace's servers without restarting the daemon. An
21
21
  existing AG-UI connection sends the ordinary management-action form under
22
22
  `forwardedProps.plurnk.action`:
23
23
 
@@ -27,7 +27,7 @@ existing AG-UI connection sends the ordinary management-action form under
27
27
  "plurnk": {
28
28
  "workspace": "example",
29
29
  "action": {
30
- "kind": "worker.mcp.add",
30
+ "kind": "workspace.mcp.add",
31
31
  "alias": "project",
32
32
  "definition": {
33
33
  "name": "project",
@@ -45,22 +45,29 @@ existing AG-UI connection sends the ordinary management-action form under
45
45
  ```
46
46
 
47
47
  The standard `plurnk.action.result` event reports success or exact RFC 9457
48
- Problem Details. The definition is durable and Worker-private; symbolic
48
+ Problem Details. The definition is durable and workspace-shared; symbolic
49
49
  environment references remain unexpanded at rest.
50
50
 
51
- MCP is one family of Worker Functionality; the common lifecycle actions are
51
+ MCP is one family of workspace Functionality; the common lifecycle actions are
52
52
  published by the coordinator and the two continuations by this module:
53
53
 
54
54
  | Action | Parameters |
55
55
  |---|---|
56
- | `worker.mcp.list` | — |
57
- | `worker.mcp.discover` | optional `query`, `source` (URL or command line), `configuration` (a client's `PLURNK_MCP_*` overlay) |
58
- | `worker.mcp.add` | optional `alias` (must equal the definition's `name`), `definition: McpServerDefinition` |
59
- | `worker.mcp.enable` / `disable` / `remove` | `alias` |
60
- | `worker.mcp.oauth.complete` | `alias`, complete `callbackUrl` |
61
- | `worker.mcp.complete` | `server`, completion `ref` and `argument`; optional `context` |
62
-
63
- The model manages the same family through `EXEC [mcp] (list|discover|add|enable|disable|remove)`.
56
+ | `workspace.mcp.list` | — |
57
+ | `workspace.mcp.discover` | optional `query`, `source` (URL or command line), `configuration` (a client's `PLURNK_MCP_*` overlay) |
58
+ | `workspace.mcp.add` | optional `alias` (must equal the definition's `name`), `definition: McpServerDefinition` |
59
+ | `workspace.mcp.enable` / `disable` / `remove` | `alias` |
60
+ | `workspace.mcp.oauth.complete` | `alias`, complete `callbackUrl` |
61
+ | `workspace.mcp.complete` | `server`, completion `ref` and `argument`; optional `context` |
62
+
63
+ The model manages the same family through ```` ```mcp (list|discover|add|enable|disable|remove) ````.
64
+
65
+ Tool discovery uses ordinary `FIND (worker:///_plurnk/tools/*.md)` and READ.
66
+ Each server's document lists enabled EXEC calls with required-field previews
67
+ and links to full input schemas under `tools/<server>/<encoded-tool>.md`.
68
+ The manager uses the same layout under `plurnk/mcp.md` and `plurnk/mcp/`;
69
+ schema documents preserve descriptions and constraints without adding them to
70
+ the initial survey ({§tools-resource-discovery}).
64
71
 
65
72
  The owning [specification](./SPEC.md) defines the complete action and server
66
73
  definition contracts.
@@ -80,9 +87,11 @@ PLURNK_MCP_GITEA_ARGS=["plurnk_pk"]
80
87
 
81
88
  The client carries its raw declarations while listing and enabling. Listing is
82
89
  inert. `/mcp enable gitea` (or `plurnk mcp enable gitea` in a bound conversation)
83
- composes service, durable worker, client, and optional command-file fields
90
+ composes service, durable workspace, client, and optional command-file fields
84
91
  in that order, prepares the connection, then persists the complete unexpanded
85
- worker specialization. Arrays and maps replace rather than append or merge.
92
+ workspace definition. Arrays and maps replace rather than append or merge.
93
+ Reapplying an identical definition is idempotent. A different definition for
94
+ the same workspace alias requires explicit removal before replacement.
86
95
 
87
96
  ## Demo fixtures
88
97
 
@@ -156,18 +165,24 @@ Portable timeouts and complete examples live in [`.env.defaults`](./.env.default
156
165
 
157
166
  | MCP surface | Plurnk surface |
158
167
  |---|---|
159
- | Server tools | `worker://~/_plurnk/tools/<server>.md` family summary |
160
- | Enabled tool | Exact `worker://~/_plurnk/tools/<server>/<encoded-tool>.md` document and `### EXEC0 [server] (tool)` |
168
+ | Server tools | `worker:///_plurnk/tools/<server>.md` family summary |
169
+ | Enabled tool | Exact `worker:///_plurnk/tools/<server>/<encoded-tool>.md` document and ```` ```server (tool) ```` |
161
170
  | Resource catalog | `server:///` or `server:///resources` |
162
171
  | Resource | `server:///resources/<encoded-uri>` through ordinary `FIND` and `READ` |
163
172
  | Prompt catalog | `server:///prompts` |
164
173
  | Prompt retrieval | `server:///prompts/<encoded-name>?argument=value` through ordinary `READ` |
165
- | Completion | Client-owned `worker.mcp.complete` action |
174
+ | Completion | Client-owned `workspace.mcp.complete` action |
175
+ | Tool image/audio or embedded resource | A named resource beneath the invocation's `resources/`; eight hexadecimal characters when unnamed |
176
+ | Exact tool-result evidence | The invocation's `#json` channel, retrieved on demand |
166
177
 
167
178
  Tool results, resource bodies, prompt messages, and failures become ordinary
168
179
  Plurnk entries and channels. Disabled tools appear in neither teaching nor
169
180
  admission. There is no MCP-specific model discovery grammar.
170
181
 
182
+ Results link to media rather than dumping base64. An ordinary `READ` delivers
183
+ supported images natively; other content and unsupported models retain the
184
+ text/byte view. Listing the resource alone does not attach it.
185
+
171
186
  Current pagination, cache hints, unified subscriptions, progress,
172
187
  cancellation, multi-round-trip input, elicitation, and negotiated Tasks remain
173
188
  inside the owning operation. Client input uses the standard AG-UI interrupt and
@@ -180,7 +195,7 @@ HTTP definitions support bearer references, client credentials, and
180
195
  interactive OAuth. Stdio never receives OAuth. Interactive add or enable returns
181
196
  `{ "status": 202, "authorization": { "url": "..." } }` without publishing a
182
197
  partial server. After the user completes that URL, the client submits its
183
- complete callback URL through `worker.mcp.oauth.complete`. PKCE, issuer and
198
+ complete callback URL through `workspace.mcp.oauth.complete`. PKCE, issuer and
184
199
  resource validation, refresh, scope escalation, and credentials remain inside
185
200
  the host connection.
186
201
 
package/SPEC.md CHANGED
@@ -45,7 +45,7 @@ matrix rows cite.
45
45
  | Resources | Negotiated server capability: `resources/list`, `resources/templates/list`, `resources/read` | Publish catalogs, templates, and materialized contents through the server's resource authority |
46
46
  | Prompts | Negotiated server capability: `prompts/list`, `prompts/get` | Publish prompt definitions and retrieve prompt messages through the same server authority |
47
47
  | Completion | Negotiated server capability: `completion/complete` | Make prompt and resource-template completion available to the host interaction that owns the argument |
48
- | Pagination | Opaque cursors on list methods | Drain every page with a finite non-convergence guard; never publish a partial catalog as complete |
48
+ | Pagination | Opaque cursors on list methods | Drain every page with a finite non-convergence guard; never publish a partial catalog as complete ({§mcp-catalog-convergence}) |
49
49
  | Caching | `server/discover`, list methods, and `resources/read` carry `ttlMs` and `cacheScope` | Honor freshness and notification invalidation; partition private entries by authorization context |
50
50
  | Subscriptions | `subscriptions/listen` plus acknowledged filters and correlated notifications | Keep one current filter for list changes, resource URIs read into cache, and active Task IDs; overlap filter replacement, re-listen after loss, and never use the removed resource subscription methods |
51
51
  | Progress | Request-scoped `notifications/progress` | Project progress onto the owning Plurnk operation without creating an independent protocol lifecycle |
@@ -54,6 +54,16 @@ matrix rows cite.
54
54
  | Elicitation | Active client capability carried through MRTR | Advertise supported form/URL modes and route the request through Plurnk's client-owned interaction lifecycle |
55
55
  | Authorization | OAuth profile for HTTP transports | Require validated protected-resource and authorization-server metadata; never infer endpoints; use PKCE, issuer validation, resource indicators, refresh, and bounded scope escalation; never apply OAuth to stdio |
56
56
 
57
+ §mcp-catalog-convergence **A catalog is complete or it is an error.** The pinned SDK's aggregating
58
+ list walk (`listTools`, `listResources`, `listResourceTemplates`, `listPrompts`) stops silently when
59
+ a server returns a cursor it already returned, drops `nextCursor`, and caches the partial aggregate
60
+ as if it were whole; only its page cap (`listMaxPages`) throws. The host's client watches the pages
61
+ the SDK requests and refuses the page that repeats a cursor with `CatalogNonConvergenceError`
62
+ (method and cursor named), so the listing fails and nothing partial is published or cached.
63
+ Pagination, caching, and the cap remain the SDK's; a converging server's pages aggregate exactly as
64
+ before. This is a host guard over an upstream behavior, not a second paginator; the upstream
65
+ report is #601's to file.
66
+
57
67
  ## §mcp-tasks Tasks extension
58
68
 
59
69
  Tasks is the optional `io.modelcontextprotocol/tasks` extension, never core
@@ -85,7 +95,7 @@ nothing task-shaped is written to SQLite and no MCP sidecar lifecycle exists.
85
95
  |---|---|
86
96
  | Client disconnect | The daemon-owned operation and its task keep running; the client reattaches to the operation, not the task. |
87
97
  | Daemon restart | The connection and every in-flight task handle die with it; the tool call fails like any interrupted operation, the loop re-runs, and the tool call creates a fresh task. |
88
- | Worker reactivation | The attachment reconstructs from its durable definition; in-flight tasks on the replaced connection are abandoned, not resumed. |
98
+ | Workspace reactivation | The attachment reconstructs from its durable definition; in-flight tasks on the replaced connection are abandoned, not resumed. |
89
99
  | Expiry | The owning operation deadline bounds polling; a non-converging task fails at the standard round bound and is cancelled. |
90
100
  | Cancellation | Owner abort cancels the task before settling; the handle is then terminal. |
91
101
  | Already terminal | Terminal results and errors are consumed by the drive loop; a completed or failed task is never re-polled or re-resumed. |
@@ -164,17 +174,17 @@ originating distinction in its canonical Problem/result path.
164
174
 
165
175
  ## §mcp-configuration Configuration
166
176
 
167
- Service configuration and worker state produce one available set and one
168
- enabled subset per worker. Every `PLURNK_MCP_<server>` declares an available
177
+ Service configuration and workspace state produce one available set and one
178
+ enabled subset per workspace. Every `PLURNK_MCP_<server>` declares an available
169
179
  service-owned definition. `PLURNK_MCP_ENABLED` names the exact subset enabled
170
- when a worker has no override. Worker state may positively override a
180
+ when a workspace has no override. Workspace state may positively override a
171
181
  service definition's enabledness or own an added definition and its enabledness.
172
182
  Disabled definitions remain client-visible but contribute no connection,
173
183
  Registry, documentation, or resource authority.
174
184
 
175
185
  §mcp-activation-isolation **Cold endpoint failure is capability-local.** Invalid
176
186
  service configuration or durable state fails admission, but an enabled server
177
- that cannot connect or complete discovery during worker activation remains
187
+ that cannot connect or complete discovery during workspace activation remains
178
188
  enabled and client-visible as `unavailable`. It publishes no runtime, tools,
179
189
  resources, or documentation and cannot prevent other capabilities or the daemon
180
190
  from starting or serving dormant workers. Enabling that already-enabled alias is an explicit reconnect
@@ -195,7 +205,7 @@ unavailable candidate without changing durable state.
195
205
  | `PLURNK_MCP_<server>_SUMMARY` | Authored one-line server orientation ({§mcp-summary-derivation}) |
196
206
  | `PLURNK_MCP_<server>_<tool>_SUMMARY` | Authored one-line tool orientation; tool names fold the same way and may contain underscores |
197
207
  | `PLURNK_MCP_ENABLED` | JSON array of exact configured server aliases enabled by default; absent or `[]` enables none |
198
- | `PLURNK_MCP_EXPANDED` | JSON array subset of enabled servers whose every tool is surveyed at turn 0 — one FIND row per `### EXEC0` heading of the family document, with annotation and signature ({§tools-resource-materialization}); never a document delivered unasked; absent or `[]` expands none |
208
+ | `PLURNK_MCP_EXPANDED` | JSON array subset of enabled servers whose every tool is surveyed at turn 0 — one FIND row per executable block of the family document, with aside and signature ({§tools-resource-materialization}); never a document delivered unasked; absent or `[]` expands none |
199
209
  | `PLURNK_MCP_CONNECT_TIMEOUT` | Positive integer milliseconds |
200
210
  | `PLURNK_MCP_REQUEST_TIMEOUT` | Positive integer milliseconds |
201
211
 
@@ -218,7 +228,7 @@ resolves: its `_<server>_<tool>_SUMMARY` companion, `annotations.title`, the
218
228
  first sentence of its `description` (capped), then the tool name. The family
219
229
  doc's Summary section and the survey row carry the server one-liner; the tool
220
230
  doc's Summary section IS the invocation form
221
- `EXEC [server] (tool) <!-- one-liner -->`, so the discovery row teaches the
231
+ ```` ```server (tool) <!-- one-liner --> ````, so the discovery row teaches the
222
232
  call ({§tools-resource-materialization}). Summary companions expand `${NAME}`
223
233
  references like every other companion.
224
234
 
@@ -253,22 +263,22 @@ stdio executable) and its options (`args`, `cwd`, `env`, `headers`,
253
263
  transport-inapplicable options before any connection work.
254
264
 
255
265
  §mcp-configuration-cascade MCP server configuration has one field-wise
256
- precedence order: service environment, then the Worker's durable definition.
266
+ precedence order: service environment, then the workspace's durable definition.
257
267
  Arrays and maps replace their lower value instead of appending or merging.
258
268
  Client configuration is not a live layer: the contracts-owned
259
269
  `{§mcp-configuration-overlay}` enters only as the `configuration` of a
260
270
  `discover` query, is parsed by the same owner and path as service environment
261
271
  declarations, and yields inert candidates with client-configuration provenance
262
272
  ({§mcp-discovery}); adding one persists a complete, normalized, unexpanded
263
- Worker definition. Thus later enablement needs neither the originating client
273
+ workspace definition. Thus later enablement needs neither the originating client
264
274
  nor its configuration file, and symbolic credentials remain resolvable only by
265
275
  the service at connection preparation.
266
276
 
267
277
  ### §mcp-module The MCP family beneath the coordinator
268
278
 
269
- §mcp-management-actions MCP is one family of Worker Functionality
270
- ({§functionality-coordinator}): the coordinator publishes `worker.mcp.list |
271
- discover | add | enable | disable | remove` and the model's `EXEC [mcp]`
279
+ §mcp-management-actions MCP is one family of workspace Functionality
280
+ ({§functionality-coordinator}): the coordinator publishes `workspace.mcp.list |
281
+ discover | add | enable | disable | remove` and the model's `mcp` executable fence
272
282
  family with the common semantics, durable state, and publication; this module
273
283
  registers the family adapter and owns protocol truth beneath it. `available`
274
284
  is the service environment with its `PLURNK_MCP_ENABLED` defaults; `admit`
@@ -281,13 +291,13 @@ exact Problem, or `authorization-required` with its URL), and a two-phase
281
291
  snapshot: `commit` closes connections the new set no longer uses and records
282
292
  pending authorizations; `abort` closes only what the attempt opened.
283
293
 
284
- Two protocol continuations remain MCP-registered worker actions beneath the
294
+ Two protocol continuations remain MCP-registered workspace actions beneath the
285
295
  common grammar:
286
296
 
287
297
  | Action | Parameters | Result / effect |
288
298
  |---|---|---|
289
- | `worker.mcp.oauth.complete` | `alias`, `callbackUrl` | State- and issuer-validates one pending interactive callback through the SDK, completes connection preparation, and re-enables the alias through the coordinator ({§oauth-continuation}); the result is the common mutation result. |
290
- | `worker.mcp.complete` | `server`, `ref`, `argument`; optional `context` | Requests negotiated prompt/resource-template argument completion for a client-owned interaction. |
299
+ | `workspace.mcp.oauth.complete` | `alias`, `callbackUrl` | State- and issuer-validates one pending interactive callback through the SDK, completes connection preparation, and re-enables the alias through the coordinator ({§oauth-continuation}); the result is the common mutation result. |
300
+ | `workspace.mcp.complete` | `server`, `ref`, `argument`; optional `context` | Requests negotiated prompt/resource-template argument completion for a client-owned interaction. |
291
301
 
292
302
  §mcp-discovery Discovery is inert. `configuration` (a client's own
293
303
  `PLURNK_MCP_*` overlay) becomes candidates without connecting; `source` — an
@@ -314,8 +324,8 @@ in daemon diagnostics. No MCP resource Problem admits an unbounded SDK message.
314
324
 
315
325
  §oauth-continuation Interactive preparation publishes the alias as enabled and
316
326
  `authorization-required` with its URL; it publishes no runtime. The adapter
317
- retains one pending candidate per `(worker, alias)` holding the challenged
318
- connection and one Worker residency lease; a new challenge for the alias
327
+ retains one pending candidate per `(workspace, alias)` holding the challenged
328
+ connection and one workspace residency lease; a new challenge for the alias
319
329
  supersedes and releases the previous one ({§oauth-lifetime}).
320
330
  `oauth.complete` accepts the complete callback URL so state, `code`, and
321
331
  `iss` remain one parsing unit; it finishes the pending connection's
@@ -332,25 +342,25 @@ error text.
332
342
  Interactive OAuth state is deliberately ephemeral and process-memory: client
333
343
  registration data, access and refresh tokens, the PKCE verifier, and pending
334
344
  state live only in the owning connection or pending candidate. Nothing
335
- OAuth-secret is written to SQLite; the durable worker state holds only the
345
+ OAuth-secret is written to SQLite; the durable workspace state holds only the
336
346
  unexpanded definition ({§mcp-configuration}). There is no callback HTTP
337
347
  listener, authority-root resource, or daemon-side browser side channel: the
338
- client returns the complete callback URL through `worker.mcp.oauth.complete`
348
+ client returns the complete callback URL through `workspace.mcp.oauth.complete`
339
349
  so `state`, `code`, and `iss` remain one parsing unit. Reauthorization after a
340
350
  daemon restart is the intended journey, documented here rather than presented
341
351
  as an accidental failure.
342
352
 
343
353
  | Journey point | Behaviour |
344
354
  |---|---|
345
- | Pending authorization | One pending candidate per `(worker, alias)`; a new add or customized enable cancels and replaces it. A callback from a superseded attempt fails state validation instead of cross-completing. |
355
+ | Pending authorization | One pending candidate per `(workspace, alias)`; a new add or customized enable cancels and replaces it. A callback from a superseded attempt fails state validation instead of cross-completing. |
346
356
  | Client disconnect | Does not touch the pending candidate; it can still be completed, or replaced by a fresh request. |
347
357
  | Daemon restart during pending | The candidate is lost: nothing was durable, no attachment publishes, and `oauth.complete` answers `404 oauth-not-pending`. Start authorization again. |
348
358
  | Daemon restart after authorization | The durable definition rehydrates but tokens are gone; the attachment publishes `authorization-required` and enable returns a fresh `{ status: 202, authorization: { url } }`. The operator reauthorizes. |
349
359
  | Token expiry | An expired access token surfaces as one unauthorized response; the SDK re-acquires via `refresh_token` when one was issued, otherwise re-enters interactive authorization. |
350
360
  | Refresh | Happens only against the issuer bound during the original authorization; the refreshed token replaces the in-memory token. |
351
- | Worker disable/remove | Closes the attachment and clears its pending candidate; no durable secret deletion is needed because nothing secret is durable. |
361
+ | Workspace disable/remove | Closes the attachment and clears its pending candidate; no durable secret deletion is needed because nothing secret is durable. |
352
362
  | Server replacement | Completion compares the pending candidate's expected definition with the current one; drift of the same server fails `409 oauth-target-conflict` instead of replaying a stale snapshot. |
353
- | Cross-authorization protection | Candidates are keyed by `(worker, alias)`; callback state, PKCE, and issuer are validated by the SDK against the attempt that created them, so no other worker, alias, or attempt can complete this authorization. |
363
+ | Cross-authorization protection | Candidates are keyed by `(workspace, alias)`; callback state, PKCE, and issuer are validated by the SDK against the attempt that created them, so no other workspace, alias, or attempt can complete this authorization. |
354
364
 
355
365
  ## §oauth-client-credentials Client-credentials grant adoption
356
366
 
@@ -402,32 +412,32 @@ decision on durable identity material is ratified.
402
412
 
403
413
  ## §mcp-setup Atomic lifecycle
404
414
 
405
- When a cold worker is demanded, activation resolves service defaults and durable positive
406
- worker state, opens and discovers only enabled connections,
415
+ When a cold workspace is demanded, activation resolves service defaults and durable positive
416
+ workspace state, opens and discovers only enabled connections,
407
417
  lists the negotiated catalogs, applies enabled/effect policy, builds each exact
408
418
  tool Registry and resource facet, and submits one complete owner snapshot to
409
- {§module-worker-capabilities}. A configured tool absent from the server, a
419
+ {§module-workspace-capabilities}. A configured tool absent from the server, a
410
420
  duplicate remote name, an enabled name not representable as a Plurnk target,
411
- or a `read` name outside the enabled set fails that worker activation. No
421
+ or a `read` name outside the enabled set fails that workspace activation. No
412
422
  partial namespace is published and every acquired candidate closes.
413
423
 
414
424
  - §mcp-catalog-refresh-in-place **A catalog change refreshes in place.** When a server announces a changed catalog, the alias is dirty and its executor is rebuilt on the next preparation — on the connection the alias already holds, never by spawning a second server: with an unchanged definition and a live connection, preparation re-lists the catalog over that connection, so neither an aborted attempt nor a commit has anything of the alias to close, and a failed re-listing leaves the current catalog in service. (#429's root: the SDK's negotiated connect probes a stdio server on a disposable sibling process before the real connect, so every stdio connect starts the server twice and the sibling exits on its own schedule — a test that reads "any exit" as "the committed server was closed" flakes under load. The committed server is the last one started; the refresh-in-place rule keeps it so.) Covered: `Module.test.ts` — one process ever, no close marker across the refresh.
415
425
 
416
- MCP participates in core Functionality residency ({§module-worker-residency}).
417
- Every tool call and Task retains the worker from executor entry through its
426
+ MCP participates in core Functionality residency ({§module-workspace-residency}).
427
+ Every tool call and Task retains the workspace from executor entry through its
418
428
  terminal result; an interactive OAuth candidate retains it until completion,
419
429
  replacement, cancellation, or module shutdown. Catalog refresh timers are
420
430
  infrastructure, not residency owners: cooling serializes behind a refresh
421
431
  already running and cancels any timer not yet begun. At a lease-free quiescent
422
- boundary, deactivation removes the worker snapshot and closes all of its
432
+ boundary, deactivation removes the workspace snapshot and closes all of its
423
433
  connections. Core separately withdraws the executor/scheme publication while
424
434
  preserving durable MCP state and generated reference entries for transparent
425
435
  reactivation.
426
436
 
427
437
  Add and enable prepare the candidate while the old snapshot remains
428
- authoritative, then commit only at {§module-worker-quiescence}. Disable and
438
+ authoritative, then commit only at {§module-workspace-quiescence}. Disable and
429
439
  remove commit the complete reduced snapshot at the same boundary. The
430
- old connection rejects replacement while it owns an active protocol request,
440
+ old connection rejects replacement with `409 server-busy` while it owns an active protocol request,
431
441
  MRTR exchange, or Task. Cache/list-change watches are infrastructure and close
432
442
  with the old connection after the new snapshot commits. A failed candidate or
433
443
  commit leaves the durable definition, connection, Registry, docs, and resource
@@ -446,7 +456,7 @@ cancellation.
446
456
 
447
457
  One `ServerConnection` owns negotiation, SDK caches, authorization partition,
448
458
  subscriptions, active request controllers, MRTR rounds, and Tasks for one
449
- worker attachment. The host does not reproduce SDK protocol machinery.
459
+ workspace attachment. The host does not reproduce SDK protocol machinery.
450
460
 
451
461
  | Protocol event | Plurnk composition |
452
462
  |---|---|
@@ -479,18 +489,34 @@ effect occurred.
479
489
 
480
490
  ## §mcp-result-content Passive result content
481
491
 
482
- The EXEC channel carries the tool's RESULT, never the transport envelope
483
- (`_meta`, `content`): text parts are written as text with their own newlines
484
- — `application/json` when the text is a JSON document, else `text/plain`;
492
+ The default output channel carries the tool's result, not its transport envelope:
493
+ text parts are written as text with their own newlines
494
+ — whitespace-formatted `application/json` when the text is a complete JSON document,
495
+ else unchanged `text/plain` ({§json-document-presentation});
485
496
  several text parts join with newlines; an empty content with
486
497
  `structuredContent` writes it pretty-printed — so the page rule and a scoped
487
- READ mean what they say and nothing reaches the model double-escaped. A result
488
- holding any non-text variant — image, audio, resource links, embedded
489
- text/blob resources — is preserved losslessly as one JSON value of the whole
490
- result ({§json-result-rendering}), the durable evidence path. Plurnk does not claim
491
- first-class client rendering of non-text variants and adds no MCP-only media
492
- envelopes: presentation is a client concern over ordinary typed
493
- entries/resources, and a text-only client degrades by rendering the JSON. A
498
+ READ mean what they say and nothing reaches the model double-escaped. The
499
+ complete result, including metadata and annotations, remains available in
500
+ `#json` as protocol evidence. The default body preserves content order:
501
+
502
+ | Content | Model-facing projection |
503
+ | --- | --- |
504
+ | Text | Its text. |
505
+ | Inline image/audio | Link to an invocation-owned typed byte resource, published through {§executor-entry-sink}. |
506
+ | Embedded text/blob resource | Link to a typed resource snapshot; use the supplied URI's filename when present. |
507
+ | Resource link | Link to the existing MCP resource address; acquisition occurs on READ, not on listing. |
508
+
509
+ Unnamed resources receive eight-character hexadecimal identifiers, not ordinal
510
+ labels. No binary base64 is copied into the default result body. Listing a
511
+ resource creates no native model attachment; READ uses {§packet-attachment-parts},
512
+ including scoped byte reads, supported modalities, and single-request delivery.
513
+ Resource publication is passive; completion of the originating execution retains
514
+ its ordinary wake semantics. A single `resources/read` content item becomes the
515
+ resource's typed body; multiple items become named children under its `resources/`
516
+ folder and a directory of links. Each response retains its complete `#json` evidence;
517
+ reconstructing the same collection preserves child paths ({§resource-publication-names}).
518
+ Generated catalogs and prompt documents use two-space
519
+ JSON indentation; individual text resources preserve their source layout. A
494
520
  standalone `blob` content block is not a modern `tools/call` content member
495
521
  (blobs ride inside embedded blob resources) and is rejected as
496
522
  protocol-invalid. Size limits and MIME trust remain ordinary channel and
@@ -516,25 +542,32 @@ even then the capability would be per-client-advertised, never daemon-wide.
516
542
 
517
543
  | MCP surface | Plurnk surface |
518
544
  |---|---|
519
- | Server | One registered executor family, `worker://~/_plurnk/tools/<server>.md`, and matching resource scheme |
520
- | Enabled tool | One annotated call in the compact family document plus one exact `worker://~/_plurnk/tools/<server>/<encoded-tool>.md` input-contract document |
545
+ | Server | One registered executor family, `worker:///_plurnk/tools/<server>.md`, and matching resource scheme |
546
+ | Enabled tool | One annotated call in the compact family document plus one exact `worker:///_plurnk/tools/<server>/<encoded-tool>.md` input-contract document |
521
547
  | Tool survey | Ordinary FIND summary metadata from the standard executable-tool resource tree |
522
548
  | Resource catalog | `<server>:///` and `<server>:///resources` |
523
549
  | Resources | `<server>:///resources` and encoded resource-URI descendants |
524
550
  | Prompts | `<server>:///prompts` and encoded prompt-name descendants |
525
551
 
552
+ Qualified `<server>://<worker>/…` resources, prompts, and catalogs follow
553
+ {§runtime-resource-binding}: the qualifier selects the stored projection, not
554
+ a private attachment. Acquisition uses the workspace attachment; the requesting
555
+ operation retains its policy and client interactions.
556
+ Returned Plurnk resource links retain that qualifier; MCP protocol URIs remain
557
+ unchanged on the wire.
558
+
526
559
  §mcp-tool-presentation One canonical enabled-tool snapshot owns every
527
560
  model-facing and executable consequence. Each enabled remote tool becomes one
528
561
  exact target in {§executor-tool-registry}. Its standard
529
- {§executor-tool-document} carries the normalized remote description as Summary,
530
- requiredness derived from the input schema, and a deterministic one-line
531
- JSON-shaped invocation signature: quoted property names, `?` on optional
532
- properties, primitive type words, and literal unions—never fabricated argument
533
- data. The compact family document projects those same facts into annotated,
534
- copyable EXEC headings; each exact child additionally projects property-level
535
- input descriptions and standard constraints such as defaults, formats, ranges,
536
- lengths, and patterns. A missing remote description receives a deterministic
537
- server-and-tool summary rather than an invented capability claim. Output schemas
562
+ {§executor-tool-document} carries a compact summary, requiredness derived from
563
+ the input schema, and the original schema itself. The common renderer owns
564
+ {§executor-input-schema-preview}, not an MCP-specific schema interpreter.
565
+ The compact family document contains annotated, copyable tool invocations with
566
+ shallow required-field previews and alias-scoped schema links. Each linked child
567
+ preserves the complete remote description and raw input schema, without
568
+ reconstructing property tables or expanding nested constraints into the preview.
569
+ A missing remote description falls back to the tool name rather than an invented
570
+ capability claim. Output schemas
538
571
  do not enter model teaching; the returned value remains ordinary evidence. Disabled names
539
572
  appear in neither discovery nor admission, and there is no MCP-specific FIND,
540
573
  READ, authority-root, or other model discovery mechanism for tools.
@@ -1,22 +1,19 @@
1
1
  import { BaseExecutor } from "@plurnk/plurnk-execs";
2
2
  import type { ChannelDecl, Effect, ExecArgs, ExecResult, RuntimeAvailability, RuntimeDecl, RuntimeSummaryDecl, RuntimeToolRegistry } from "@plurnk/plurnk-execs";
3
3
  import ServerConnection, { type ServerCatalog } from "./client.ts";
4
+ import type { ContentBlock } from "@modelcontextprotocol/client";
4
5
  import type { ToolPolicy } from "./config.ts";
5
6
  export declare const serverSummary: (name: string, catalog: ServerCatalog | undefined, override: string | undefined) => string;
6
7
  export declare const runtimeServerSummary: (name: string, catalog: ServerCatalog | undefined, override: string | undefined) => RuntimeSummaryDecl;
7
8
  export type ToolResultShape = {
8
- readonly content?: ReadonlyArray<{
9
- readonly type: string;
10
- readonly text?: string;
11
- readonly [field: string]: unknown;
12
- }>;
9
+ readonly content?: readonly ContentBlock[];
13
10
  readonly structuredContent?: unknown;
14
11
  readonly isError?: boolean;
15
12
  };
16
- export declare const toolResultBody: (result: ToolResultShape) => {
13
+ export declare const toolResultBody: (result: ToolResultShape, runtime: string, entry?: ExecArgs["entry"]) => Promise<{
17
14
  content: string;
18
15
  mimetype: string;
19
- };
16
+ }>;
20
17
  export declare const runtimeDecl: (name: string, summary: RuntimeSummaryDecl, expandTools: boolean) => RuntimeDecl;
21
18
  export default class McpExecutor extends BaseExecutor {
22
19
  #private;
@@ -24,55 +21,13 @@ export default class McpExecutor extends BaseExecutor {
24
21
  runtime: string;
25
22
  glyph: string;
26
23
  }, connection: ServerConnection, retainWorkspace: () => () => void, policy?: Partial<ToolPolicy>, toolSummaries?: ReadonlyMap<string, string>);
27
- get manifest(): {
28
- name: string;
29
- authority?: import("@plurnk/plurnk-schemes").SchemeAuthority;
30
- channels: Record<string, string>;
31
- defaultChannel: string;
32
- writableBy: ReadonlyArray<import("@plurnk/plurnk-schemes").WriterTier>;
33
- volatile: boolean;
34
- modelVisible: boolean;
35
- folderScopes?: boolean;
36
- textEditScopes?: boolean;
37
- metadataModifier?: boolean;
38
- lineAnchors?: boolean;
39
- foldedByDefault?: boolean;
40
- traits?: ReadonlyArray<string>;
41
- documentation?: string;
42
- glyph?: string;
43
- storedScheme?: string;
44
- category: "data";
45
- entryOwner: import("@plurnk/plurnk-schemes").SchemeEntryOwner;
46
- inherit: import("@plurnk/plurnk-schemes").SchemeEntryInheritance;
47
- example: string;
48
- } | {
49
- name: string;
50
- authority?: import("@plurnk/plurnk-schemes").SchemeAuthority;
51
- channels: Record<string, string>;
52
- defaultChannel: string;
53
- writableBy: ReadonlyArray<import("@plurnk/plurnk-schemes").WriterTier>;
54
- volatile: boolean;
55
- modelVisible: boolean;
56
- folderScopes?: boolean;
57
- textEditScopes?: boolean;
58
- metadataModifier?: boolean;
59
- lineAnchors?: boolean;
60
- foldedByDefault?: boolean;
61
- traits?: ReadonlyArray<string>;
62
- documentation?: string;
63
- glyph?: string;
64
- storedScheme?: string;
65
- category: "logging" | "control";
66
- entryOwner?: never;
67
- inherit?: never;
68
- example: string;
69
- };
70
24
  get channels(): Readonly<Record<string, ChannelDecl>>;
71
25
  effect(target: string | null): Effect;
26
+ get publishedChannel(): string;
72
27
  toolRegistry(): RuntimeToolRegistry;
73
28
  get catalog(): ServerCatalog;
74
29
  probe(signal?: AbortSignal): Promise<RuntimeAvailability>;
75
30
  requireAvailable(signal?: AbortSignal): Promise<RuntimeAvailability>;
76
- run({ runtime, body, target, signal, write, setState, emit, interact, }: ExecArgs): Promise<ExecResult>;
31
+ run({ runtime, body, target, signal, write, setState, emit, interact, entry, }: ExecArgs): Promise<ExecResult>;
77
32
  }
78
33
  //# sourceMappingURL=McpExecutor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpExecutor.d.ts","sourceRoot":"","sources":["../src/McpExecutor.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,YAAY,EAMf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EACR,WAAW,EACX,MAAM,EACN,QAAQ,EACR,UAAU,EAEV,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,gBAAgB,EAAE,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAiC9C,eAAO,MAAM,aAAa,SAChB,MAAM,WACH,aAAa,GAAG,SAAS,YACxB,MAAM,GAAG,SAAS,KAC7B,MAOF,CAAC;AAIF,eAAO,MAAM,oBAAoB,SACvB,MAAM,WACH,aAAa,GAAG,SAAS,YACxB,MAAM,GAAG,SAAS,KAC7B,kBAIF,CAAC;AAMF,MAAM,MAAM,eAAe,GAAG;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IACvH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF,eAAO,MAAM,cAAc,WAAY,eAAe,KAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAU3F,CAAC;AAaF,eAAO,MAAM,WAAW,SAAU,MAAM,WAAW,kBAAkB,eAAe,OAAO,KAAG,WAc5F,CAAC;AAuBH,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,YAAY;;IASjD,YACI,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAC5C,UAAU,EAAE,gBAAgB,EAC5B,eAAe,EAAE,MAAM,MAAM,IAAI,EACjC,MAAM,GAAE,OAAO,CAAC,UAAU,CAAM,EAChC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAQ9C;IAED,IAAa,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAKpB;IAED,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAMpD;IAEQ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAK7C;IAgCD,YAAY,IAAI,mBAAmB,CAKlC;IAED,IAAI,OAAO,IAAI,aAAa,CAK3B;IAEc,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAgBvE;IAEK,gBAAgB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAqBzE;IAEK,GAAG,CAAC,EACN,OAAO,EACP,IAAI,EACJ,MAAM,EACN,MAAM,EACN,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,QAAQ,GACX,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAyHhC;CACJ"}
1
+ {"version":3,"file":"McpExecutor.d.ts","sourceRoot":"","sources":["../src/McpExecutor.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,YAAY,EAKf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EACR,WAAW,EACX,MAAM,EACN,QAAQ,EACR,UAAU,EAEV,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,gBAAgB,EAAE,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,8BAA8B,CAAC;AAGjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAiC9C,eAAO,MAAM,aAAa,SAChB,MAAM,WACH,aAAa,GAAG,SAAS,YACxB,MAAM,GAAG,SAAS,KAC7B,MAOF,CAAC;AAIF,eAAO,MAAM,oBAAoB,SACvB,MAAM,WACH,aAAa,GAAG,SAAS,YACxB,MAAM,GAAG,SAAS,KAC7B,kBAIF,CAAC;AAMF,MAAM,MAAM,eAAe,GAAG;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF,eAAO,MAAM,cAAc,WAAkB,eAAe,WAAW,MAAM,UAAU,QAAQ,CAAC,OAAO,CAAC,KAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAyBvJ,CAAC;AAEF,eAAO,MAAM,WAAW,SAAU,MAAM,WAAW,kBAAkB,eAAe,OAAO,KAAG,WAc5F,CAAC;AAuBH,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,YAAY;;IASjD,YACI,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAC5C,UAAU,EAAE,gBAAgB,EAC5B,eAAe,EAAE,MAAM,MAAM,IAAI,EACjC,MAAM,GAAE,OAAO,CAAC,UAAU,CAAM,EAChC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAQ9C;IAED,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAOpD;IAEQ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAK7C;IAED,IAAa,gBAAgB,IAAI,MAAM,CAEtC;IAgCD,YAAY,IAAI,mBAAmB,CAKlC;IAED,IAAI,OAAO,IAAI,aAAa,CAK3B;IAEc,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAgBvE;IAEK,gBAAgB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAqBzE;IAEK,GAAG,CAAC,EACN,OAAO,EACP,IAAI,EACJ,MAAM,EACN,MAAM,EACN,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,KAAK,GACR,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CA2HhC;CACJ"}