@zackbart/connecta 0.22.3 → 0.23.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/CHANGELOG.md +42 -0
- package/README.md +1 -1
- package/dist/catalog-service.d.ts +1 -6
- package/dist/catalog-service.js +3 -53
- package/dist/errors.d.ts +1 -1
- package/dist/execute.d.ts +5 -52
- package/dist/execute.js +40 -347
- package/dist/executors/quickjs-protocol.d.ts +0 -7
- package/dist/executors/quickjs-protocol.js +2 -10
- package/dist/executors/quickjs.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/invocation.d.ts +0 -33
- package/dist/invocation.js +54 -121
- package/dist/meta-tools.d.ts +3 -6
- package/dist/meta-tools.js +6 -17
- package/dist/registry.js +4 -0
- package/dist/routes/mcp.js +0 -48
- package/dist/server.d.ts +1 -2
- package/dist/server.js +1 -19
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +55 -19
- package/dist/types.d.ts +1 -15
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +7 -11
- package/documentation/auth.md +4 -5
- package/documentation/call-admission.md +10 -11
- package/documentation/code-mode.md +65 -260
- package/documentation/connectors.md +7 -5
- package/documentation/meta-tools.md +31 -14
- package/documentation/operations.md +7 -9
- package/documentation/provider-conventions.md +2 -2
- package/documentation/upgrading.md +58 -8
- package/ethos.md +14 -13
- package/package.json +1 -1
- package/templates/node/package.json +1 -1
- package/dist/apps-shell.d.ts +0 -37
- package/dist/apps-shell.js +0 -174
|
@@ -8,9 +8,8 @@ annotations, and `get_result` pages bounded results.
|
|
|
8
8
|
|
|
9
9
|
Every deployment requires an executor and `tools/list` is exactly seven:
|
|
10
10
|
`execute_code`, `search_tools`, `call_tool`, `call_destructive_tool`,
|
|
11
|
-
`authorize_connector`, `get_result`, and `skills`. Discovery
|
|
12
|
-
|
|
13
|
-
inside a program ([#273](https://github.com/zackbart/connecta/issues/273)).
|
|
11
|
+
`authorize_connector`, `get_result`, and `skills`. Discovery uses `connecta.search` and `connecta.describe`; programs compose
|
|
12
|
+
calls with JavaScript promises ([#273](https://github.com/zackbart/connecta/issues/273)).
|
|
14
13
|
|
|
15
14
|
Code-first is what a model sees. Read-only work has two routes: `call_tool` for
|
|
16
15
|
one known address, and `execute_code` when discovery or any wider work is
|
|
@@ -21,8 +20,11 @@ The [guest API contract](./code-mode.md) is what a program is promised.
|
|
|
21
20
|
|
|
22
21
|
The route is chosen before discovery. An unknown address, a result that will be
|
|
23
22
|
reduced, a call whose arguments depend on an earlier result, or work with
|
|
24
|
-
multiple operations starts with
|
|
25
|
-
|
|
23
|
+
multiple operations starts with `execute_code` and keeps discovery, calls, and reduction inside it
|
|
24
|
+
when the schemas and result shapes suffice. An unfamiliar provider result may
|
|
25
|
+
return a small sample for inspection before continuing in another call. This
|
|
26
|
+
exception avoids repeated guesses at text formats or collection roots; it does
|
|
27
|
+
not restore a mandatory discovery-only round trip. Distinct operations get distinct short
|
|
26
28
|
`connecta.search` queries in that program. A known address needs only
|
|
27
29
|
`call_tool`.
|
|
28
30
|
|
|
@@ -41,11 +43,13 @@ The measurements never contain program source, arguments, values, addresses,
|
|
|
41
43
|
credentials, logs, or raw error text.
|
|
42
44
|
|
|
43
45
|
Nothing became unreachable. `connecta.describe` takes the same addresses and
|
|
44
|
-
formats as the internal catalog service,
|
|
45
|
-
|
|
46
|
+
formats as the internal catalog service, ordinary promises compose read-only
|
|
47
|
+
calls, and an unfiltered
|
|
46
48
|
`connecta.search({})` browses every catalog a program can reach. Live connector
|
|
47
49
|
probing is an operator concern: the operator pages and `/health` own it.
|
|
48
50
|
|
|
51
|
+
Program search includes a bounded `connectorTitle` on each tool when configured, so choosing an account or environment does not require a provider read. It is context, not a ranking input or proof of live access.
|
|
52
|
+
|
|
49
53
|
The three discovery routes use deliberately different envelopes. These are
|
|
50
54
|
their smallest successful one-tool shapes:
|
|
51
55
|
|
|
@@ -62,7 +66,7 @@ their smallest successful one-tool shapes:
|
|
|
62
66
|
|
|
63
67
|
The deployment-derived `execute_code` description includes a live connector
|
|
64
68
|
inventory before any catalog search. It preserves registry order and uses each
|
|
65
|
-
canonical id
|
|
69
|
+
canonical id and a distinct configured title without generating a second name for programs. Titles normalize whitespace and are capped at 48 UTF-8 bytes, so account and environment hints cannot consume the entire inventory.
|
|
66
70
|
The complete inventory line is capped at 256 UTF-8 bytes. Entries stay whole,
|
|
67
71
|
and a truncated line ends with the exact `+N more` count. This reads only the
|
|
68
72
|
configured registry: it loads no catalog, probes no credential, grants no
|
|
@@ -177,6 +181,22 @@ This split avoids two normative copies while preserving a valid first program
|
|
|
177
181
|
for clients that never fetch the skill. Deployments without connector guides
|
|
178
182
|
receive none of the short conditional guide pointers in their definitions.
|
|
179
183
|
|
|
184
|
+
## Task guidance
|
|
185
|
+
|
|
186
|
+
`skills({ name: "investigate" })` provides on-demand guidance for purchase
|
|
187
|
+
verification, experiment checks, and customer or deployment investigations.
|
|
188
|
+
The execute description points to it when planning is unclear; routine reads need no additional guide fetch. It explains how to
|
|
189
|
+
resolve app/account/environment, follow evidence across services, establish
|
|
190
|
+
capability limits, and stop with a clear answer or a specific gap. It is shared
|
|
191
|
+
guidance, not a saved workflow or a source of deployment-specific ids. Existing
|
|
192
|
+
connector titles, purposes, and guides still own those distinctions.
|
|
193
|
+
|
|
194
|
+
The usage skill keeps the executable mechanics. Its dependent-call example
|
|
195
|
+
searches each operation separately, uses the page's `tools` array and canonical
|
|
196
|
+
addresses, and reports unresolved evidence instead of inventing an address or
|
|
197
|
+
querying another account. Its source runs against local fixtures in the QuickJS
|
|
198
|
+
suite, including missing and approval-required evidence.
|
|
199
|
+
|
|
180
200
|
## Result representation
|
|
181
201
|
|
|
182
202
|
For object results, `structuredContent` is the canonical full-fidelity value.
|
|
@@ -338,8 +358,7 @@ That route echoes the caller's own arguments back only while they fit a
|
|
|
338
358
|
512-byte budget, and then whole — never clipped. An error envelope is not
|
|
339
359
|
size-guarded the way a result is, so an unbounded echo would let a large
|
|
340
360
|
argument object produce a refusal many times the deployment's result cap, on
|
|
341
|
-
both `call_tool` and
|
|
342
|
-
`connecta.batch`. Over budget, `args` is absent and the `purpose` says to
|
|
361
|
+
both `call_tool` and program calls through `connecta.call`. Over budget, `args` is absent and the `purpose` says to
|
|
343
362
|
re-send what was just sent: the agent already holds its own arguments, and half
|
|
344
363
|
of them would describe a call nobody made.
|
|
345
364
|
|
|
@@ -352,9 +371,7 @@ recovery query, each of which lands in both the text content and
|
|
|
352
371
|
the address is the thing being corrected, a clipped one still identifies the
|
|
353
372
|
mistake, and a short one — every real one — comes back exact and untagged.
|
|
354
373
|
|
|
355
|
-
|
|
356
|
-
address and points at `connecta.call`; the program or model must still choose
|
|
357
|
-
which one matches the user's intent. `call_destructive_tool` accepts an optional
|
|
374
|
+
`call_destructive_tool` accepts an optional
|
|
358
375
|
`reason` of at most 500 characters for the host's human approval view. It is
|
|
359
376
|
outer-call context only: Connecta neither treats it as authority nor passes it
|
|
360
377
|
to the downstream connector, and an empty or whitespace-only one is read as no
|
|
@@ -395,7 +412,7 @@ about the mistake as all 40,000 would.
|
|
|
395
412
|
A remote MCP tool's advertised `inputSchema` is checked in the shared
|
|
396
413
|
invocation path before admission and provider dispatch. A mismatch is the
|
|
397
414
|
non-retryable `invalid_args`, consistently across `call_tool`,
|
|
398
|
-
`call_destructive_tool`,
|
|
415
|
+
`call_destructive_tool`, generated-code failures, and rejected promises. The error
|
|
399
416
|
names the connector and operation and carries bounded `validation.issues`:
|
|
400
417
|
JSON Pointer `path`, schema-keyword `code`, and expected shape. Submitted
|
|
401
418
|
values are never copied into those findings.
|
|
@@ -99,7 +99,7 @@ optional.
|
|
|
99
99
|
| `discovery.persistCatalog?` | true | persist serializable catalogs as a manifest plus revision-addressed chunks |
|
|
100
100
|
| `discovery.staleCatalogSeconds?` | 3600 | how long a complete expired catalog stays usable for agent SWR and as a refresh-failure fallback |
|
|
101
101
|
| `discovery.probeTimeoutMs?` | 30_000 | per-connector deadline for catalog fan-out; a timed-out connector degrades alone. Not a tool-call deadline |
|
|
102
|
-
| `calls.defaultTimeoutMs?` | **unset (opt-in)** | deadline for calls that pass no `timeoutMs`.
|
|
102
|
+
| `calls.defaultTimeoutMs?` | **unset (opt-in)** | deadline for calls that pass no `timeoutMs`. Each admitted call makes one attempt |
|
|
103
103
|
| `calls.maxResultBytes?` | 50_000 | inline result cap before truncation and `get_result` paging; a connector may override it. Invalid values warn and fall back |
|
|
104
104
|
| `execute.maxEmittedBytes?` | 4_000_000 | aggregate `connecta.emit` bytes per run — a transport bound, not a context bound |
|
|
105
105
|
| `execute.maxEmittedBlocks?` | 32 | content blocks `connecta.emit` accepts per run |
|
|
@@ -240,19 +240,18 @@ in.
|
|
|
240
240
|
| `clerk.test.ts` | protected-resource metadata, the browser sign-in config, OAuth and session tokens, cached best-effort activity labels with their caps, the hand-applied `azp` rejection, and the `allowedDomains` allowlist including every lookalike that must not be repaired into a match |
|
|
241
241
|
| `cloudflare-access-auth.test.ts` | trusted `ctx.access` human and service identities, absent/error fail-closed behavior, service-token MCP admission without operator mutation, human same-origin mutation, and the Clerk-to-ambient shell switch |
|
|
242
242
|
| `cloudflare-provider.test.ts` | `cloudflare()` API and MCP construction, the code-mode safety manifest, API tool surface, current R2 and KV jurisdictions, useful output declarations, request building, projections including additive provider fields, typed failures, and credential test |
|
|
243
|
-
| `code-first-surface.test.ts` | the seven-tool surface itself — an executor required, every removed option and top-level tool refused, compact always-loaded routing pinned below 1,000 characters, complete on-demand usage served, and
|
|
243
|
+
| `code-first-surface.test.ts` | the seven-tool surface itself — an executor required, every removed option and top-level tool refused, compact always-loaded routing pinned below 1,000 characters, complete on-demand usage served, and no rendering instructions |
|
|
244
244
|
| `codemode-compat.test.ts` | the `Executor` seam staying structurally compatible with `@cloudflare/codemode`'s `DynamicWorkerExecutor`, enforced by `tsc` |
|
|
245
245
|
| `config.test.ts` | the grouped `ConnectaConfig` boundary — each group forwarding to its internals, malformed admission bounds failing construction, and unknown own-properties rejected by their complete path before construction does work |
|
|
246
246
|
| `credentials.test.ts` | the pure stored-shape classifier (containment, not equality) and the AES-GCM vault: round-trip, ciphertext bound to its connector id, named field sets, masked metadata, wrong-key rejection, deletion, coexistence with OAuth keys |
|
|
247
247
|
| `d1-activity-example.test.ts` | the Worker example's deployment-owned D1 activity store: actor namespace round-trip, payload-free friction reconstructed from the persisted code, and agreement with the package's friction table |
|
|
248
248
|
| `downstream-oauth.test.ts` | `KvOAuthProvider` round-trips and generation races, runtime-local rotating-token refresh coordination across request scopes, refresh failure/retry, `auth_required` versus `error`, `startAuth`/`finishAuth`, callback refusal equality, bounded diagnostics, and HTML escaping |
|
|
249
249
|
| `errors.test.ts` | `ConnectorCallError` codes, retryable defaults and overrides, `retryAfterMs` round-trip, typed-over-heuristic classification, `AbortError` as a retryable timeout, and framing errors |
|
|
250
|
-
| `execute.test.ts` | the code-mode host bridge: identifier sanitization, MCP-result unwrapping, sandbox provider construction, authenticated thrown-failure framing, fail-closed filtering of destructive and unannotated tools, MCP/code-mode invocation parity, and payload-free describe diagnostics |
|
|
250
|
+
| `execute.test.ts` | the code-mode host bridge: identifier sanitization, account titles in program discovery, MCP-result unwrapping, sandbox provider construction, authenticated thrown-failure framing, fail-closed filtering of destructive and unannotated tools, MCP/code-mode invocation parity, and payload-free describe diagnostics |
|
|
251
251
|
| `execute-emit.test.ts` | `connecta.emit` (M1–M10) — block validation, budgets, the provider, delivery after the result envelope on success only, and the defaults |
|
|
252
|
-
| `execute-ui.test.ts` | display-only `connecta.ui` (U1–U13) — one-string validation, multiplicity and budget, the provider, `_meta` delivery, shell isolation, and the absence of a payload-to-host call path |
|
|
253
252
|
| `executor-admission.test.ts` | the portable bounded FIFO both pools use: active and queue ceilings, stable retryable overload, queue timeout, cancellation removal, idempotent release, shutdown |
|
|
254
253
|
| `guarded-fetch.test.ts` | the guarded transport — construction, request building, destination confinement, and response handling |
|
|
255
|
-
| `guest-api-contract.test.ts` | the shared guest contract on the Dynamic Worker, including caught call, typed inline describe recovery, discovery, utility,
|
|
254
|
+
| `guest-api-contract.test.ts` | the shared guest contract on the Dynamic Worker, including caught call, typed inline describe recovery, discovery, utility, parallel-call, and budget failure codes; plus the real authority boundary — local `data:` fetch, denied egress, unresolved DNS, empty environment paths, unavailable filesystem/HTTP builtins, and present runtime globals |
|
|
256
255
|
| `identity-scope.test.ts` | identity-derived connector visibility, personal credential isolation, shared-auth operator control, and personal OAuth callback ownership |
|
|
257
256
|
| `linear-provider.test.ts` | the Linear proxy's construction, guide, plan-aware catalog superset, and current workspace, template, and issue-sharing classifications |
|
|
258
257
|
| `meta-tools-call.test.ts` | registry-backed calls: structured errors, truncation and `get_result`, per-connector result bounds, JSON representation failures, MCP content bounds, and offset alignment |
|
|
@@ -271,8 +270,8 @@ in.
|
|
|
271
270
|
| `request-admission.test.ts` | `/mcp` bounded before auth, the stable 503 and `Retry-After`, health and operator responsiveness under saturation, payload-free counters, queued cancellation, shutdown rejection while active work drains, and the separate fallback code pool |
|
|
272
271
|
| `result-shapes.test.ts` | passive output-shape learning: value-free bounded inference, merging, 256-entry LRU eviction, 24-hour expiry, runtime isolation, read-only admission, declared-schema precedence, definition-change invalidation, discovery provenance, and failure isolation |
|
|
273
272
|
| `revenuecat-provider.test.ts` | the RevenueCat proxy's per-project key scoping and account-wide OAuth guides, its purpose-bearing summary, the refund-preference read and argued borderline verdicts in its digest-free manifest, and the deliberately unclassified `render-paywall-screenshot` |
|
|
274
|
-
| `server.test.ts` | end-to-end `/mcp` (401 → compact initialize instructions → seven compact definitions with bounded connector inventory
|
|
275
|
-
| `server-route-contracts.test.ts` | the route contracts `server.ts` must keep byte-identical:
|
|
273
|
+
| `server.test.ts` | end-to-end `/mcp` (401 → compact initialize instructions → seven compact definitions with bounded connector inventory, account titles, on-demand investigation guidance, and no Apps metadata or resource capability → complete usage skill → `call_tool`), conditional guide pointers, open routes, Clerk `.well-known` metadata without network, code mode, removed connector HTTP hooks rejected at construction, and deferred catalog reads through both discovery surfaces |
|
|
274
|
+
| `server-route-contracts.test.ts` | the route contracts `server.ts` must keep byte-identical: built-in routes and unknown-path 404s inside the security wrapper, open data-free shells with framing denied, per-route auth and same-origin requirements with exact 401/403/405 bodies, and OAuth `verifyState`-before-`finishAuth` ordering |
|
|
276
275
|
| `startup-warnings.test.ts` | every construction-time `logger.warn` and, as importantly, the conditions that must *not* trigger one: open mode with a credential or OAuth connector, `publicUrl` unset beside OAuth, dropped branding and `uiAuth` URLs, a missing `verifyState`, a credential test-hook mismatch, and an unusable `calls.maxResultBytes` |
|
|
277
276
|
| `stripe-provider.test.ts` | the Stripe proxy's mixed-mode OAuth and fixed-mode header contracts, current eleven-tool classifications, admission, exact account selectors, and no-guess rule |
|
|
278
277
|
| `operator-view.test.ts` | the app's pure state rules from `view.ts`: filtering, page routing, capability states, activity summaries, drift display, and identity reset |
|
|
@@ -300,7 +299,7 @@ justification for *not* re-running it in workerd, so "it was easier" is not one.
|
|
|
300
299
|
| `purity.test.ts` | the import-graph guardrail ([architecture](./architecture.md#import-graph-purity)) — the core stays Workers-clean | walks the source import graph with Node filesystem APIs |
|
|
301
300
|
| `quickjs-child-entry.test.ts` | a missing QuickJS child entry failing before `fork()`, with the expected path and the bundler-externalization constraint | mocks Node child-process and filesystem APIs |
|
|
302
301
|
| `quickjs-child-stderr.test.ts` | the QuickJS child-process boundary: an explicitly empty environment despite parent secrets and `NODE_OPTIONS`, plus abnormal exits retaining only an 8 KiB stderr tail in the parent-side diagnostic | mocks Node child-process streams |
|
|
303
|
-
| `quickjs-executor.test.ts` | the child-process sandbox — code normalization,
|
|
302
|
+
| `quickjs-executor.test.ts` | executable usage example with dependent, missing, and approval-required evidence; the child-process sandbox — code normalization, provider bridges and canonical connector calls, bounded IPC, separate guest-CPU and wall budgets, saturation, cancellation and shutdown, crash and OOM recovery, host-call hangs, stalled-promise detection | runs the Node QuickJS child-process executor |
|
|
304
303
|
| `quickjs-log-limits.test.ts` | bounded `console.*` capture — per-entry cut, cumulative character and transport budgets, escape-heavy floods preserving the guest result | runs the Node QuickJS child-process executor |
|
|
305
304
|
| `suite-partition.test.ts` | this partition, including itself: every `*.test.ts` in exactly one list, stale entries and empty reasons refused | walks the test directory to guard the partition |
|
|
306
305
|
| `template-file-activity.test.ts` | the Node template's own activity store — persistence across restart, torn-line repair, newest-first paging, and compaction past the slack window | runs it against real files |
|
|
@@ -312,7 +311,6 @@ justification for *not* re-running it in workerd, so "it was easier" is not one.
|
|
|
312
311
|
| Suite | Covers |
|
|
313
312
|
| --- | --- |
|
|
314
313
|
| `browser/operator-ui.spec.ts` | the operator wiring in a real browser: Clerk loader order across its version redirect and a real load failure, the shell staying open until authentication, credential and access-token and OAuth flows end to end, drift shown without naming a tool, and every failure and empty state |
|
|
315
|
-
| `browser/program-ui.spec.ts` | the display-only Apps shell in a real browser: local payload JavaScript runs, `connecta` stays absent, and forged payload messages never become host tool calls |
|
|
316
314
|
|
|
317
315
|
**The `_transportFactory` seam.** `RemoteMcpOptions._transportFactory` is
|
|
318
316
|
internal, not public API: when set, `remoteMcp()` uses that `Transport` instead
|
|
@@ -237,8 +237,8 @@ not send the agent to `authorize_connector`, you do not repair the argument
|
|
|
237
237
|
object. You re-address — look the id up again, or accept the absence and carry
|
|
238
238
|
on — and a program looping over ids inside `execute_code` can continue past
|
|
239
239
|
`not_found` where `connector_call_failed` would have to abort the run, reading
|
|
240
|
-
the code
|
|
241
|
-
|
|
240
|
+
the code from a caught error or a rejected promise. The guest bridge preserves
|
|
241
|
+
the typed classification. That
|
|
242
242
|
control-flow difference is the H11 test being met; it is not a label for the
|
|
243
243
|
cause.
|
|
244
244
|
|
|
@@ -17,6 +17,51 @@ the release notes broke, and prove it with `connecta doctor`.
|
|
|
17
17
|
Work on a branch. Every step below is reversible until you delete the old
|
|
18
18
|
lockfile, and you want the diff reviewable by whoever owns this deployment.
|
|
19
19
|
|
|
20
|
+
## 0.23.0 program API pruning
|
|
21
|
+
|
|
22
|
+
This update removes MCP Apps rendering, connector shortcut globals,
|
|
23
|
+
`connecta.batch`, automatic direct-call retries, and connector-owned HTTP routes. Refresh the client's MCP
|
|
24
|
+
instructions and tool definitions after upgrading. The seven top-level tools,
|
|
25
|
+
operator pages, credentials, result paging, and media emission remain.
|
|
26
|
+
|
|
27
|
+
| Before | After |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| Connector `handleRequest(request, ctx)` | Move custom HTTP routes into the existing deployment fetch handler |
|
|
30
|
+
| `await tracker.list_issues(args)` | `await connecta.call("tracker.list_issues", args)` using the exact address from discovery |
|
|
31
|
+
| `await connecta.batch(calls)` | `Promise.all` over `connecta.call`, or `Promise.allSettled` to keep failures alongside successes |
|
|
32
|
+
| `await connecta.ui(html)` | Return the data the client needs to render its own view |
|
|
33
|
+
| `call_tool` or `call_destructive_tool` with `maxRetries` | Omit the removed argument; each call makes one attempt and returns typed failures with provider retry hints |
|
|
34
|
+
|
|
35
|
+
A connector that still declares `handleRequest` refuses construction. Handle
|
|
36
|
+
custom routes in the existing Node or Worker deployment before delegating other
|
|
37
|
+
requests to `connecta.fetch`. The deployment owns authentication and security
|
|
38
|
+
headers for its custom responses. Connecta returns 404 for unknown paths.
|
|
39
|
+
Cloudflare Global API Key authentication and multi-field credentials remain
|
|
40
|
+
supported; they need no migration.
|
|
41
|
+
|
|
42
|
+
The direct-call schemas reject unknown arguments, including `maxRetries`, before
|
|
43
|
+
invocation. Review stored programs and deployment-owned usage guides for the
|
|
44
|
+
removed guest functions. Canonical addresses preserve punctuation; do not copy
|
|
45
|
+
the old sanitized shortcut into the address string.
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
async () => {
|
|
49
|
+
const outcomes = await Promise.allSettled([
|
|
50
|
+
connecta.call("tracker.list_issues", { state: "started" }),
|
|
51
|
+
connecta.call("tracker.list_projects", {}),
|
|
52
|
+
]);
|
|
53
|
+
return outcomes.map((outcome) => outcome.status === "fulfilled"
|
|
54
|
+
? { ok: true, data: outcome.value }
|
|
55
|
+
: { ok: false, code: outcome.reason.code, message: outcome.reason.message });
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Reduce large successful values before returning. Promise rejection reasons are
|
|
60
|
+
Error objects; explicitly select their fields for JSON output. Every call still
|
|
61
|
+
passes through the existing read-only checks, admission limits, deadlines, and
|
|
62
|
+
20-call program budget. Rate-limited calls return `retryAfterMs` without waiting;
|
|
63
|
+
the client can reissue after that delay. No storage migration is required.
|
|
64
|
+
|
|
20
65
|
## Read what you have first
|
|
21
66
|
|
|
22
67
|
Three questions, in order. Answer all three before editing anything — the
|
|
@@ -57,7 +102,7 @@ exist so far:
|
|
|
57
102
|
| --- | --- | --- |
|
|
58
103
|
| **pre-template** | before 0.10.2 | no `connecta init` existed; hand-written, or copied from the retired `examples/node` |
|
|
59
104
|
| **A** | 0.10.2 – 0.15.1 | `.env.example`, `.gitignore`, `AGENTS.md`, `CLAUDE.md`, `README.md`, `package.json`, `src/index.ts`, `tsconfig.json` |
|
|
60
|
-
| **B** | 0.16.0 – 0.
|
|
105
|
+
| **B** | 0.16.0 – 0.23.0 | adds `.dockerignore`, `Dockerfile`, `docker-compose.yml`, and `src/file-activity.ts`; `src/index.ts` grows the four commented operator blocks; `.env.example` ships `CONNECTA_TOKEN=` empty |
|
|
61
106
|
|
|
62
107
|
Generation A is a decade in template years and identifying it precisely does
|
|
63
108
|
not matter, because you are about to reconstruct it exactly rather than guess
|
|
@@ -106,7 +151,7 @@ know what to preserve, once to know what to re-verify at the end.
|
|
|
106
151
|
### Bump the pin and install
|
|
107
152
|
|
|
108
153
|
```sh
|
|
109
|
-
npm pkg set dependencies.@zackbart/connecta=0.
|
|
154
|
+
npm pkg set dependencies.@zackbart/connecta=0.23.0
|
|
110
155
|
npm install
|
|
111
156
|
```
|
|
112
157
|
|
|
@@ -130,7 +175,7 @@ Generate the *current* template beside the base you already made, into the same
|
|
|
130
175
|
`$SCRATCH`:
|
|
131
176
|
|
|
132
177
|
```sh
|
|
133
|
-
(cd "$SCRATCH" && npx @zackbart/connecta@0.
|
|
178
|
+
(cd "$SCRATCH" && npx @zackbart/connecta@0.23.0 init current)
|
|
134
179
|
```
|
|
135
180
|
|
|
136
181
|
You now have a three-way merge with a real base: `$SCRATCH/base` is what this
|
|
@@ -186,7 +231,7 @@ A deployment older than 0.10.2 has no base to diff against. Do not try to
|
|
|
186
231
|
manufacture one. Instead:
|
|
187
232
|
|
|
188
233
|
1. `SCRATCH=$(mktemp -d)`, then
|
|
189
|
-
`(cd "$SCRATCH" && npx @zackbart/connecta@0.
|
|
234
|
+
`(cd "$SCRATCH" && npx @zackbart/connecta@0.23.0 init current)` — there is no
|
|
190
235
|
`base` leg here, only the current template to read from.
|
|
191
236
|
2. Copy `$SCRATCH/current` into the deployment file by file, **skipping
|
|
192
237
|
`src/index.ts`**.
|
|
@@ -207,6 +252,13 @@ first, so cross them bottom-up: start at the oldest one still above this
|
|
|
207
252
|
deployment's pin and work back up the page, because each boundary assumes the
|
|
208
253
|
older ones are already done.
|
|
209
254
|
|
|
255
|
+
### 0.22.3 → 0.23.0
|
|
256
|
+
|
|
257
|
+
Migrate stored programs and custom connector routes using the
|
|
258
|
+
[0.23.0 migration](#0230-program-api-pruning). Refresh client instructions
|
|
259
|
+
and tool definitions so account titles and the revised discovery guidance take
|
|
260
|
+
effect. No storage migration is required.
|
|
261
|
+
|
|
210
262
|
### 0.21.2 → 0.22.3
|
|
211
263
|
|
|
212
264
|
Connector and user policy remain config-as-code. If `identity.connectorAccess`
|
|
@@ -572,10 +624,8 @@ all, so this is not a hook to stub out with `() => true`.
|
|
|
572
624
|
previously fell through to connector `handleRequest` and then to a 404, so a
|
|
573
625
|
connector that served any of the three is now shadowed without warning. `GET /`
|
|
574
626
|
returns the operator shell where 0.6.1 returned 404, and a non-GET on those
|
|
575
|
-
routes or on `/ui` returns 405 instead of falling through.
|
|
576
|
-
|
|
577
|
-
built-in routes miss, so it can add a route and never shadow one
|
|
578
|
-
([architecture](./architecture.md)).
|
|
627
|
+
routes or on `/ui` returns 405 instead of falling through. For the current release, move custom handlers into the deployment: connector
|
|
628
|
+
`handleRequest` is now removed. See the [current migration](#0230-program-api-pruning).
|
|
579
629
|
|
|
580
630
|
### Removed options that throw
|
|
581
631
|
|
package/ethos.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# connecta — ethos
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
preserve. A contradiction needs a design decision, not a drive-by edit.
|
|
3
|
+
Connecta’s scope, refusals, and invariants. Contradictions require a design decision.
|
|
5
4
|
|
|
6
5
|
## What this is
|
|
7
6
|
|
|
@@ -40,9 +39,8 @@ preserve. A contradiction needs a design decision, not a drive-by edit.
|
|
|
40
39
|
|
|
41
40
|
## Decisions
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
CHANGELOG, not here.
|
|
42
|
+
Revisiting a verdict requires a new argument. Accepted designs live in
|
|
43
|
+
subsystem guides and the CHANGELOG.
|
|
46
44
|
|
|
47
45
|
| Decision | Verdict | Why |
|
|
48
46
|
| --- | --- | --- |
|
|
@@ -53,7 +51,7 @@ CHANGELOG, not here.
|
|
|
53
51
|
| Provider registry / marketplace | refused | prebuilt connections are imports; discovery happens in docs ([#297](https://github.com/zackbart/connecta/issues/297)) |
|
|
54
52
|
| Expanded Notion page create/update options | refused | different workflows, not missing fields; use `api()` ([#408](https://github.com/zackbart/connecta/issues/408)) |
|
|
55
53
|
| Protocol sessions & server push | refused | stateless per request |
|
|
56
|
-
| Resources & prompts aggregation | refused | tools only;
|
|
54
|
+
| Resources & prompts aggregation | refused | tools only; clients own presentation ([#266](https://github.com/zackbart/connecta/issues/266)) |
|
|
57
55
|
| Elicitation passthrough | refused | no route through a stateless aggregator |
|
|
58
56
|
| Repository formatter | refused | style is authored, not enforced |
|
|
59
57
|
| Host-side projection of program results | refused | a program projects; a heuristic drops fields invisibly ([#223](https://github.com/zackbart/connecta/issues/223)) |
|
|
@@ -67,6 +65,11 @@ CHANGELOG, not here.
|
|
|
67
65
|
| Legacy embedded `UIResource` delivery | refused | superseded upstream, rendered by no client we face ([#266](https://github.com/zackbart/connecta/issues/266)) |
|
|
68
66
|
| Effect as the core effect system | refused | −4% of the core for +75 KB gzip and a second async paradigm; re-measure at v4 stable ([#470](https://github.com/zackbart/connecta/issues/470)) |
|
|
69
67
|
| Shared bounded queue under both admission controllers | refused | built and measured −17 lines for a hook-parameterised abstraction ([#453](https://github.com/zackbart/connecta/issues/453)) |
|
|
68
|
+
| MCP Apps rendering and `connecta.ui` | removed | clients render returned data |
|
|
69
|
+
| Connector shortcut globals | removed | canonical addresses need no sanitization |
|
|
70
|
+
| `connecta.batch` | removed | JavaScript promises suffice |
|
|
71
|
+
| Automatic direct-call retries | removed | callers own retry timing |
|
|
72
|
+
| Connector HTTP routes | removed | deployments own custom routes |
|
|
70
73
|
| Caller-selected toolkits | removed | only config may derive an identity's connector view ([#178](https://github.com/zackbart/connecta/issues/178)) |
|
|
71
74
|
| Proactive credential liveness | removed | fail-at-use is enough ([#179](https://github.com/zackbart/connecta/issues/179)) |
|
|
72
75
|
| Classic (executor-free) surface | removed | an executor is mandatory ([#273](https://github.com/zackbart/connecta/issues/273)) |
|
|
@@ -75,14 +78,14 @@ CHANGELOG, not here.
|
|
|
75
78
|
| Semantic tool search | gated | keyword search has not been shown to fail ([#27](https://github.com/zackbart/connecta/issues/27)) |
|
|
76
79
|
| MRTR / `input_required` passthrough | gated | relayable statelessly; no host or downstream emits it yet ([#176](https://github.com/zackbart/connecta/issues/176)) |
|
|
77
80
|
| Downstream `ttlMs` cache hints | gated | needs refresh-churn evidence ([#206](https://github.com/zackbart/connecta/issues/206)) |
|
|
78
|
-
| Downstream MCP Apps template passthrough |
|
|
81
|
+
| Downstream MCP Apps template passthrough | refused | clients own presentation; Connecta serves tools and data |
|
|
79
82
|
| Worker Access inbound auth | provisional | Managed OAuth and Clerk migration need production evidence ([#506](https://github.com/zackbart/connecta/issues/506)) |
|
|
80
|
-
| Program UI tool calls | removed |
|
|
83
|
+
| Program UI tool calls | removed | duplicated calls without improving retrieval ([#287](https://github.com/zackbart/connecta/issues/287), [#484](https://github.com/zackbart/connecta/issues/484)) |
|
|
81
84
|
|
|
82
85
|
## Invariants
|
|
83
86
|
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
Tests beside subsystem documentation enforce these invariants. Breaking one
|
|
88
|
+
requires a design decision.
|
|
86
89
|
|
|
87
90
|
- **Fail-closed read-only.** A missing, false, or contradictory annotation never gets the benefit of the doubt.
|
|
88
91
|
- **Generated code cannot mint capabilities.** Admission, credentials, and classification are enforced below the sandbox.
|
|
@@ -97,6 +100,4 @@ Breaking one is a design change wearing a disguise.
|
|
|
97
100
|
- **Human routes manage auth, never capability.** Signed-in humans manage auth for visible connectors; operators also manage tokens and global activity.
|
|
98
101
|
- **Structural mistakes throw at construction.** Booting into the wrong shape is worse than not booting.
|
|
99
102
|
|
|
100
|
-
Connecta
|
|
101
|
-
[executor](https://github.com/UsefulSoftwareCo/executor); this file is the
|
|
102
|
-
record of that simplification holding.
|
|
103
|
+
Connecta simplifies [executor](https://github.com/UsefulSoftwareCo/executor).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zackbart/connecta",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "One MCP to rule them all — a single MCP endpoint aggregating many downstream connectors behind a code-first surface of seven meta-tools.",
|
package/dist/apps-shell.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The one MCP Apps template connecta serves (`U5`, `U6`).
|
|
3
|
-
*
|
|
4
|
-
* A build-time string constant, not a file read at startup: the core is
|
|
5
|
-
* Web-API-only so it runs unchanged on Workers, and the same bytes have to
|
|
6
|
-
* serve everywhere. The shell is display-only: it renders whatever HTML a
|
|
7
|
-
* program handed `connecta.ui` inside a nested `srcdoc` frame and forwards no
|
|
8
|
-
* channel back from that frame to the host, so program-authored markup is
|
|
9
|
-
* inert beyond its own pixels.
|
|
10
|
-
*
|
|
11
|
-
* The address carries a version segment because hosts are permitted to
|
|
12
|
-
* prefetch and cache templates by URI: change these bytes, bump the version.
|
|
13
|
-
*/
|
|
14
|
-
/** The only `ui://` URI in the system. No program input reaches it. */
|
|
15
|
-
export declare const PROGRAM_UI_RESOURCE_URI = "ui://connecta/program-ui/v3";
|
|
16
|
-
/** The mimeType the Apps spec requires of an HTML template. */
|
|
17
|
-
export declare const PROGRAM_UI_MIME_TYPE = "text/html;profile=mcp-app";
|
|
18
|
-
/**
|
|
19
|
-
* The result `_meta` key carrying the payload (`U3`). A plain single-label
|
|
20
|
-
* prefix rather than the reverse-DNS form MCP's SHOULD prefers: connecta has
|
|
21
|
-
* no domain to reverse, and fabricating one to satisfy a SHOULD is a worse
|
|
22
|
-
* answer than the shape the key format's MUST already permits.
|
|
23
|
-
*/
|
|
24
|
-
export declare const PROGRAM_UI_META_KEY = "connecta/ui";
|
|
25
|
-
/** The one extension identifier connecta advertises (`U11`). */
|
|
26
|
-
export declare const MCP_APPS_EXTENSION = "io.modelcontextprotocol/ui";
|
|
27
|
-
/**
|
|
28
|
-
* The shell document. Dependency-free and deliberately small: it speaks the
|
|
29
|
-
* Apps postMessage dialect (`ui/initialize`, `ui/notifications/initialized`,
|
|
30
|
-
* `ui/notifications/tool-result`, `ui/notifications/size-changed`,
|
|
31
|
-
* `ui/resource-teardown`), lifts `_meta["connecta/ui"].html` out of the
|
|
32
|
-
* delivered tool result, and puts it in a frame. It declares no CSP domains,
|
|
33
|
-
* so the host applies its restrictive default and the `srcdoc` frame inherits
|
|
34
|
-
* `default-src 'none'`. The payload gets scripts and local interactivity, and
|
|
35
|
-
* no network.
|
|
36
|
-
*/
|
|
37
|
-
export declare const PROGRAM_UI_SHELL_HTML = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>connecta program view</title>\n <style>\n html,\n body {\n margin: 0;\n padding: 0;\n background: transparent;\n }\n #program-view {\n display: block;\n width: 100%;\n min-height: 480px;\n border: 0;\n }\n </style>\n </head>\n <body>\n <iframe\n id=\"program-view\"\n title=\"Program-rendered view\"\n sandbox=\"allow-scripts\"\n srcdoc=\"\"\n ></iframe>\n <script>\n (function () {\n \"use strict\";\n // The host frame is the only peer this shell speaks to, in either\n // direction. The payload frame below is sandboxed to scripts alone,\n // with no same-origin escape, and is never handed a reply path:\n // anything it posts fails the source check and is dropped. There is\n // no bridge from program HTML to the host, by construction rather\n // than by validation.\n var host = window.parent;\n var view = document.getElementById(\"program-view\");\n var initializeId = \"connecta-ui-initialize\";\n var lastWidth = 0;\n var lastHeight = 0;\n\n function send(message) {\n if (!host || host === window) return;\n host.postMessage(message, \"*\");\n }\n\n function notify(method, params) {\n send({ jsonrpc: \"2.0\", method: method, params: params });\n }\n\n // Program views are fixed-height by construction. The shell has no\n // bridge to the payload frame \u2014 that is the security posture, not an\n // omission \u2014 so it can never learn the payload's content height, and\n // what it reports here is its own box: the min-height above, unless\n // the host has given it more. Taller content scrolls inside the inner\n // frame rather than growing the view. Raising the min-height is the\n // only lever; a content-height signal would cost the isolation.\n function reportSize() {\n var width = Math.ceil(document.documentElement.clientWidth);\n var height = Math.ceil(document.documentElement.scrollHeight);\n if (width === lastWidth && height === lastHeight) return;\n lastWidth = width;\n lastHeight = height;\n notify(\"ui/notifications/size-changed\", {\n width: width,\n height: height\n });\n }\n\n function payloadHtml(result) {\n if (!result || typeof result !== \"object\") return null;\n var meta = result._meta;\n if (!meta || typeof meta !== \"object\") return null;\n var payload = meta[\"connecta/ui\"];\n if (!payload || typeof payload !== \"object\") return null;\n var html = payload.html;\n return typeof html === \"string\" && html.length > 0 ? html : null;\n }\n\n function render(params) {\n var html =\n payloadHtml(params) ||\n payloadHtml(params && params.result) ||\n payloadHtml(params && params.toolResult);\n if (html === null) return;\n view.srcdoc = html;\n reportSize();\n }\n\n window.addEventListener(\"message\", function (event) {\n if (event.source !== host) return;\n var message = event.data;\n if (!message || message.jsonrpc !== \"2.0\") return;\n if (message.method === \"ui/notifications/tool-result\") {\n render(message.params);\n return;\n }\n if (message.method === \"ui/resource-teardown\") {\n // A host->view request, not a notification: the host waits for\n // this reply before it tears the view down. There is nothing to\n // release, so answer immediately rather than make it time out.\n if (message.id !== undefined && message.id !== null) {\n send({ jsonrpc: \"2.0\", id: message.id, result: {} });\n }\n return;\n }\n // Only a completed handshake earns \"initialized\". A JSON-RPC error\n // response carries the same id, and announcing initialization on one\n // would assert a handshake that never happened.\n if (message.id === initializeId && message.result !== undefined) {\n notify(\"ui/notifications/initialized\", {});\n }\n });\n\n window.addEventListener(\"resize\", reportSize);\n view.addEventListener(\"load\", reportSize);\n\n // Every field here is required by the Apps initialize schema, and a\n // conforming host rejects the request outright when one is missing \u2014\n // which would strand the shell before any tool result arrives.\n send({\n jsonrpc: \"2.0\",\n id: initializeId,\n method: \"ui/initialize\",\n params: {\n appInfo: { name: \"connecta program view\", version: \"1\" },\n appCapabilities: {},\n protocolVersion: \"2026-01-26\"\n }\n });\n reportSize();\n })();\n </script>\n </body>\n</html>\n";
|
package/dist/apps-shell.js
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The one MCP Apps template connecta serves (`U5`, `U6`).
|
|
3
|
-
*
|
|
4
|
-
* A build-time string constant, not a file read at startup: the core is
|
|
5
|
-
* Web-API-only so it runs unchanged on Workers, and the same bytes have to
|
|
6
|
-
* serve everywhere. The shell is display-only: it renders whatever HTML a
|
|
7
|
-
* program handed `connecta.ui` inside a nested `srcdoc` frame and forwards no
|
|
8
|
-
* channel back from that frame to the host, so program-authored markup is
|
|
9
|
-
* inert beyond its own pixels.
|
|
10
|
-
*
|
|
11
|
-
* The address carries a version segment because hosts are permitted to
|
|
12
|
-
* prefetch and cache templates by URI: change these bytes, bump the version.
|
|
13
|
-
*/
|
|
14
|
-
/** The only `ui://` URI in the system. No program input reaches it. */
|
|
15
|
-
export const PROGRAM_UI_RESOURCE_URI = "ui://connecta/program-ui/v3";
|
|
16
|
-
/** The mimeType the Apps spec requires of an HTML template. */
|
|
17
|
-
export const PROGRAM_UI_MIME_TYPE = "text/html;profile=mcp-app";
|
|
18
|
-
/**
|
|
19
|
-
* The result `_meta` key carrying the payload (`U3`). A plain single-label
|
|
20
|
-
* prefix rather than the reverse-DNS form MCP's SHOULD prefers: connecta has
|
|
21
|
-
* no domain to reverse, and fabricating one to satisfy a SHOULD is a worse
|
|
22
|
-
* answer than the shape the key format's MUST already permits.
|
|
23
|
-
*/
|
|
24
|
-
export const PROGRAM_UI_META_KEY = "connecta/ui";
|
|
25
|
-
/** The one extension identifier connecta advertises (`U11`). */
|
|
26
|
-
export const MCP_APPS_EXTENSION = "io.modelcontextprotocol/ui";
|
|
27
|
-
/**
|
|
28
|
-
* The shell document. Dependency-free and deliberately small: it speaks the
|
|
29
|
-
* Apps postMessage dialect (`ui/initialize`, `ui/notifications/initialized`,
|
|
30
|
-
* `ui/notifications/tool-result`, `ui/notifications/size-changed`,
|
|
31
|
-
* `ui/resource-teardown`), lifts `_meta["connecta/ui"].html` out of the
|
|
32
|
-
* delivered tool result, and puts it in a frame. It declares no CSP domains,
|
|
33
|
-
* so the host applies its restrictive default and the `srcdoc` frame inherits
|
|
34
|
-
* `default-src 'none'`. The payload gets scripts and local interactivity, and
|
|
35
|
-
* no network.
|
|
36
|
-
*/
|
|
37
|
-
export const PROGRAM_UI_SHELL_HTML = `<!doctype html>
|
|
38
|
-
<html lang="en">
|
|
39
|
-
<head>
|
|
40
|
-
<meta charset="utf-8" />
|
|
41
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
42
|
-
<title>connecta program view</title>
|
|
43
|
-
<style>
|
|
44
|
-
html,
|
|
45
|
-
body {
|
|
46
|
-
margin: 0;
|
|
47
|
-
padding: 0;
|
|
48
|
-
background: transparent;
|
|
49
|
-
}
|
|
50
|
-
#program-view {
|
|
51
|
-
display: block;
|
|
52
|
-
width: 100%;
|
|
53
|
-
min-height: 480px;
|
|
54
|
-
border: 0;
|
|
55
|
-
}
|
|
56
|
-
</style>
|
|
57
|
-
</head>
|
|
58
|
-
<body>
|
|
59
|
-
<iframe
|
|
60
|
-
id="program-view"
|
|
61
|
-
title="Program-rendered view"
|
|
62
|
-
sandbox="allow-scripts"
|
|
63
|
-
srcdoc=""
|
|
64
|
-
></iframe>
|
|
65
|
-
<script>
|
|
66
|
-
(function () {
|
|
67
|
-
"use strict";
|
|
68
|
-
// The host frame is the only peer this shell speaks to, in either
|
|
69
|
-
// direction. The payload frame below is sandboxed to scripts alone,
|
|
70
|
-
// with no same-origin escape, and is never handed a reply path:
|
|
71
|
-
// anything it posts fails the source check and is dropped. There is
|
|
72
|
-
// no bridge from program HTML to the host, by construction rather
|
|
73
|
-
// than by validation.
|
|
74
|
-
var host = window.parent;
|
|
75
|
-
var view = document.getElementById("program-view");
|
|
76
|
-
var initializeId = "connecta-ui-initialize";
|
|
77
|
-
var lastWidth = 0;
|
|
78
|
-
var lastHeight = 0;
|
|
79
|
-
|
|
80
|
-
function send(message) {
|
|
81
|
-
if (!host || host === window) return;
|
|
82
|
-
host.postMessage(message, "*");
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function notify(method, params) {
|
|
86
|
-
send({ jsonrpc: "2.0", method: method, params: params });
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Program views are fixed-height by construction. The shell has no
|
|
90
|
-
// bridge to the payload frame — that is the security posture, not an
|
|
91
|
-
// omission — so it can never learn the payload's content height, and
|
|
92
|
-
// what it reports here is its own box: the min-height above, unless
|
|
93
|
-
// the host has given it more. Taller content scrolls inside the inner
|
|
94
|
-
// frame rather than growing the view. Raising the min-height is the
|
|
95
|
-
// only lever; a content-height signal would cost the isolation.
|
|
96
|
-
function reportSize() {
|
|
97
|
-
var width = Math.ceil(document.documentElement.clientWidth);
|
|
98
|
-
var height = Math.ceil(document.documentElement.scrollHeight);
|
|
99
|
-
if (width === lastWidth && height === lastHeight) return;
|
|
100
|
-
lastWidth = width;
|
|
101
|
-
lastHeight = height;
|
|
102
|
-
notify("ui/notifications/size-changed", {
|
|
103
|
-
width: width,
|
|
104
|
-
height: height
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function payloadHtml(result) {
|
|
109
|
-
if (!result || typeof result !== "object") return null;
|
|
110
|
-
var meta = result._meta;
|
|
111
|
-
if (!meta || typeof meta !== "object") return null;
|
|
112
|
-
var payload = meta["connecta/ui"];
|
|
113
|
-
if (!payload || typeof payload !== "object") return null;
|
|
114
|
-
var html = payload.html;
|
|
115
|
-
return typeof html === "string" && html.length > 0 ? html : null;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function render(params) {
|
|
119
|
-
var html =
|
|
120
|
-
payloadHtml(params) ||
|
|
121
|
-
payloadHtml(params && params.result) ||
|
|
122
|
-
payloadHtml(params && params.toolResult);
|
|
123
|
-
if (html === null) return;
|
|
124
|
-
view.srcdoc = html;
|
|
125
|
-
reportSize();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
window.addEventListener("message", function (event) {
|
|
129
|
-
if (event.source !== host) return;
|
|
130
|
-
var message = event.data;
|
|
131
|
-
if (!message || message.jsonrpc !== "2.0") return;
|
|
132
|
-
if (message.method === "ui/notifications/tool-result") {
|
|
133
|
-
render(message.params);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (message.method === "ui/resource-teardown") {
|
|
137
|
-
// A host->view request, not a notification: the host waits for
|
|
138
|
-
// this reply before it tears the view down. There is nothing to
|
|
139
|
-
// release, so answer immediately rather than make it time out.
|
|
140
|
-
if (message.id !== undefined && message.id !== null) {
|
|
141
|
-
send({ jsonrpc: "2.0", id: message.id, result: {} });
|
|
142
|
-
}
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
// Only a completed handshake earns "initialized". A JSON-RPC error
|
|
146
|
-
// response carries the same id, and announcing initialization on one
|
|
147
|
-
// would assert a handshake that never happened.
|
|
148
|
-
if (message.id === initializeId && message.result !== undefined) {
|
|
149
|
-
notify("ui/notifications/initialized", {});
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
window.addEventListener("resize", reportSize);
|
|
154
|
-
view.addEventListener("load", reportSize);
|
|
155
|
-
|
|
156
|
-
// Every field here is required by the Apps initialize schema, and a
|
|
157
|
-
// conforming host rejects the request outright when one is missing —
|
|
158
|
-
// which would strand the shell before any tool result arrives.
|
|
159
|
-
send({
|
|
160
|
-
jsonrpc: "2.0",
|
|
161
|
-
id: initializeId,
|
|
162
|
-
method: "ui/initialize",
|
|
163
|
-
params: {
|
|
164
|
-
appInfo: { name: "connecta program view", version: "1" },
|
|
165
|
-
appCapabilities: {},
|
|
166
|
-
protocolVersion: "2026-01-26"
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
reportSize();
|
|
170
|
-
})();
|
|
171
|
-
</script>
|
|
172
|
-
</body>
|
|
173
|
-
</html>
|
|
174
|
-
`;
|