@zackbart/connecta 0.39.0 → 0.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/bin/connecta.mjs +4 -8
  3. package/bin/version.mjs +1 -1
  4. package/dist/access-tokens.js +6 -4
  5. package/dist/activity.d.ts +30 -4
  6. package/dist/activity.js +28 -2
  7. package/dist/agent-observation.js +24 -2
  8. package/dist/agent-routes.js +4 -41
  9. package/dist/auth/clerk.d.ts +6 -1
  10. package/dist/auth/clerk.js +16 -0
  11. package/dist/auth/cloudflare-access.js +49 -7
  12. package/dist/auth/downstream-oauth/consent.js +79 -29
  13. package/dist/auth/downstream-oauth/grant-store.js +58 -7
  14. package/dist/auth/downstream-oauth/refresh-records.js +6 -5
  15. package/dist/auth/downstream-oauth.js +12 -4
  16. package/dist/auth/native.js +10 -0
  17. package/dist/auth/oauth-request-not-sent.js +4 -0
  18. package/dist/auth/static-oauth.js +51 -21
  19. package/dist/catalog-cache.js +151 -37
  20. package/dist/catalog-freshness.js +13 -0
  21. package/dist/catalog-service.js +39 -12
  22. package/dist/catalog.js +103 -38
  23. package/dist/config.d.ts +10 -4
  24. package/dist/config.js +30 -7
  25. package/dist/connectors/remote-mcp/call.js +1 -1
  26. package/dist/connectors/remote-mcp/connection.js +52 -7
  27. package/dist/connectors/remote-mcp/oauth.js +6 -2
  28. package/dist/connectors/remote-mcp/resources.js +5 -2
  29. package/dist/connectors/remote-mcp/transport.js +37 -8
  30. package/dist/connectors/remote-mcp.js +8 -5
  31. package/dist/credential-contract.d.ts +3 -1
  32. package/dist/describe-config.d.ts +1 -0
  33. package/dist/describe-config.js +1 -0
  34. package/dist/downstream-input.js +11 -2
  35. package/dist/errors.d.ts +8 -1
  36. package/dist/errors.js +2 -0
  37. package/dist/execute.js +20 -7
  38. package/dist/executor-result.js +1 -1
  39. package/dist/executors/quickjs-child.js +1 -1
  40. package/dist/executors/quickjs-runtime.js +1 -1
  41. package/dist/executors/quickjs.js +1 -1
  42. package/dist/guarded-transport.js +2 -0
  43. package/dist/http/client.js +7 -0
  44. package/dist/http/hatch.js +2 -0
  45. package/dist/http/node-transport.js +110 -4
  46. package/dist/http/oauth.js +17 -6
  47. package/dist/index.js +10 -21
  48. package/dist/invocation-failure.js +28 -0
  49. package/dist/invocation.js +77 -35
  50. package/dist/membership.d.ts +1 -1
  51. package/dist/meta-tools.js +58 -36
  52. package/dist/module-contracts.d.ts +3 -1
  53. package/dist/native-tools.js +12 -5
  54. package/dist/node.d.ts +7 -0
  55. package/dist/node.js +82 -3
  56. package/dist/operation-activity.js +103 -0
  57. package/dist/operator-record.d.ts +8 -0
  58. package/dist/operator-record.js +15 -0
  59. package/dist/operator-ui/generated.js +2 -2
  60. package/dist/provider-call-facts.js +6 -2
  61. package/dist/provider.d.ts +1 -1
  62. package/dist/providers/_shared/google/workspace.d.ts +1 -1
  63. package/dist/providers/breeze/index.js +1 -1
  64. package/dist/providers/ccb/index.js +1 -1
  65. package/dist/providers/cloudflare/index.js +1 -1
  66. package/dist/providers/docs/index.js +1 -1
  67. package/dist/providers/drive/index.js +1 -1
  68. package/dist/providers/forms/index.js +1 -1
  69. package/dist/providers/github/index.js +1 -1
  70. package/dist/providers/gmail/index.js +1 -1
  71. package/dist/providers/granola/index.js +1 -1
  72. package/dist/providers/overflow/index.js +1 -1
  73. package/dist/providers/planning-center/index.js +1 -1
  74. package/dist/providers/planning-center/lib/constants.d.ts +1 -1
  75. package/dist/providers/quickbooks/api.js +28 -25
  76. package/dist/providers/quickbooks/index.js +1 -1
  77. package/dist/providers/quickbooks/lib/writes.js +55 -0
  78. package/dist/providers/quickbooks/safety.js +17 -5
  79. package/dist/providers/quickbooks/skill.generated.js +1 -1
  80. package/dist/providers/sheets/index.js +1 -1
  81. package/dist/providers/slides/index.js +1 -1
  82. package/dist/providers/stripe/index.js +2 -2
  83. package/dist/providers/tithely/index.js +1 -1
  84. package/dist/providers/vercel/api.js +1 -0
  85. package/dist/registry.js +16 -4
  86. package/dist/resource-read.js +21 -2
  87. package/dist/route-names.js +44 -0
  88. package/dist/routes/activity-context.js +1 -0
  89. package/dist/routes/activity-disclosure.js +26 -4
  90. package/dist/routes/activity.js +2 -1
  91. package/dist/routes/mcp.js +32 -13
  92. package/dist/routes/ui-config.js +1 -1
  93. package/dist/routes/ui-data.js +3 -2
  94. package/dist/runtime/native-storage.js +15 -0
  95. package/dist/runtime/request-reads.js +87 -10
  96. package/dist/runtime/request-scope.js +2 -1
  97. package/dist/skill-origin.js +16 -0
  98. package/dist/skills.js +132 -43
  99. package/dist/storage/d1-driver.js +33 -5
  100. package/dist/storage/keys.js +7 -1
  101. package/dist/storage/sql-native.js +85 -3
  102. package/dist/storage/sql.js +6 -0
  103. package/dist/timing-trace.js +84 -0
  104. package/dist/types.d.ts +5 -0
  105. package/dist/url-safety.js +38 -20
  106. package/dist/utility-recovery.js +33 -0
  107. package/dist/version.d.ts +1 -1
  108. package/dist/version.js +1 -1
  109. package/dist/worker.js +33 -8
  110. package/documentation/architecture.md +83 -2
  111. package/documentation/auth.md +132 -37
  112. package/documentation/code-mode.md +61 -46
  113. package/documentation/deploying.md +25 -1
  114. package/documentation/integrating.md +2 -2
  115. package/documentation/meta-tools.md +134 -15
  116. package/documentation/operating.md +86 -1
  117. package/documentation/operator-ui.md +51 -2
  118. package/documentation/providers.md +16 -14
  119. package/package.json +10 -8
  120. package/templates/node/package.json +1 -1
@@ -120,9 +120,11 @@ read-only endpoint nothing writes: `search_tools`, `connecta.search`, and
120
120
  `connecta.describe` omit write tools as if the connector lacked them, and
121
121
  every write call through `call_tool`, `call_destructive_tool`, or a program is
122
122
  refused before validation or dispatch with `read_only_endpoint`,
123
- `retryable: false`, and no `nextAction`. Connector guides are not filtered and
124
- may still name such a write. No route on that endpoint writes; the agent
125
- reports it. Connecta
123
+ `retryable: false`, and an explicit statement that no write route exists here.
124
+ Bootstrap instructions state the serving endpoint’s actual write policy. Connector
125
+ guides preserve their authored Markdown and prepend the effective read-only
126
+ endpoint or connection restriction: steps that change data will be refused.
127
+ The agent reports the limitation and can ask the operator for a writable connection. Connecta
126
128
  never pauses, replays, or approves a program.
127
129
 
128
130
  Both search routes return the flat page specified under
@@ -373,7 +375,7 @@ even when a connector has that id, whose guide stays at `connector:usage` or
373
375
  `Connector "<id>" has no usage guide.`; any other unknown name fails as an
374
376
  unknown skill. Names containing `:`, including URIs, never fall back to a bare
375
377
  id. MCP `skills/get` resolves names the same way; `resources/read` accepts only
376
- document URIs.
378
+ document URIs. Canonical names and document/root URIs take priority over compatibility aliases. An alias shared by multiple guides fails as ambiguous; use the canonical URI.
377
379
 
378
380
  A connector-scoped lexical miss keeps that connector's guide metadata under
379
381
  `queryAnalysis`. This matters for generic wrappers whose broad tool name
@@ -405,12 +407,16 @@ connector inventory, budgets, the endpoint's read-only setting, and whether any
405
407
  visible connector has a guide. No catalog outcome, call, authorization state,
406
408
  or other live status reaches `tools/list` or the instructions, so the
407
409
  always-loaded surface stays byte-stable for a client's prompt cache.
408
- The instructions are the same on every endpoint except one addition: at
410
+ Instructions reflect the surface and endpoint write policy, subject to connector
411
+ restrictions. When all admitted connectors are read-only, instructions state that
412
+ writes are unavailable. They also include pool scope: at
409
413
  `/mcp/<pool>` and `/agent/<pool>`, a pool that sets a
410
- [`description`](./auth.md#pools) has it appended after `This endpoint: `, so
414
+ [`description`](./auth.md#pools) has it placed first after `Use skills. `, so
411
415
  the model learns that endpoint's scope, for example
412
- `This endpoint: Team tier: shared tools only. For someone's own mail or files, ask them to message you one-on-one.`
413
- Plain `/mcp` never carries one. The description changes no tool or tool
416
+ `Use skills. Team tier: shared tools only. For someone's own mail or files, ask them to message you one-on-one.`
417
+ The guide pointer precedes the scope so both appear in the first 512 characters
418
+ for a description of up to 500 characters. The routing rules follow. Meta instructions use compact equivalent routing rules
419
+ when a scope is present. Plain `/mcp` never carries one. The description changes no tool or tool
414
420
  description, and `initialize` and `server/discover` stay `cacheScope: "private"`,
415
421
  so a client keeps what it learned per endpoint. Connector
416
422
  guides stay scoped to the deployment that listed them even when two deployments
@@ -419,17 +425,36 @@ the short conditional guide pointers in its tool definitions.
419
425
 
420
426
  ### Native Skills extension
421
427
 
428
+ The [Skills extension](https://github.com/modelcontextprotocol/ext-skills) is Beta under
429
+ [SEP-3392](https://modelcontextprotocol.io/seps/3392-extension-lifecycle): breaking
430
+ revisions can reuse its ID. The released settings define no `revision`; Connecta
431
+ refuses downstream declarations with an explicit revision rather than enabling
432
+ unknown semantics. Upward handlers remain Connecta-owned to preserve caller views.
433
+
422
434
  Connecta declares `resources: {}` and `io.modelcontextprotocol/skills`, then
423
435
  serves `skills/list`, `skills/get`, `resources/list` and `resources/read` from
424
436
  the same registry as `skills` and `connecta.skill`. These methods return
425
- `resultType: "complete"`, `ttlMs: 0` and `cacheScope: "private"`. Listing pages
437
+ `resultType: "complete"` and `cacheScope: "private"`. Local-only caller views
438
+ advertise `ttlMs: 300000` (five minutes); any visible downstream skill source
439
+ keeps `ttlMs: 0`, including reads of local guides on that view. Clients must key
440
+ private caches by endpoint and authenticated caller. No request-bound catalog or
441
+ digest promise is retained across requests. Listing pages
426
442
  contain at most five complete skills: usage first, required connector guides
427
443
  next, other connector guides, downstream skills, then the investigation guide.
428
444
  Subsequent pages use `cursor`/`nextCursor`. Local lookup works without listing.
429
445
 
430
446
  The local document URIs are `skill://connecta/usage/SKILL.md` and
431
447
  `skill://connecta/connectors/<slug>/SKILL.md`. A valid Agent Skills connector ID
432
- is its slug; other IDs use `connector-` followed by a stable SHA-256 prefix.
448
+ is its slug; other IDs use a readable normalized ID slug plus a 12-character
449
+ SHA-256 suffix. Generated slugs reserve every configured connector ID and append
450
+ a deterministic numeric suffix on collision. Avoid a connector ID equal to another
451
+ connector's generated name: allocation depends on the IDs a catalog can see, so
452
+ adding one moves the other guide to a suffixed name.
453
+ The former `connector-<48-character-hash>` names, roots and file URIs remain
454
+ resolvable aliases. Construction warns, without rejecting a guide, when its
455
+ summary has no English task verb or operation noun from the advisory heuristic
456
+ (for example, a credential-only scope statement). Set `usageGuide.summary`
457
+ to say when to load it; non-English prose may produce a false-positive warning.
433
458
  The suffix makes each
434
459
  document a valid Agent Skills file; the roots `skill://connecta/usage` and
435
460
  `skill://connecta/connectors/<connector-id>` also resolve. Provider guides are
@@ -459,6 +484,19 @@ from skill manifests; neither skill catalogs nor file bodies enter its response
459
484
  cache. A failed or malformed opted-in listing fails the entire skills catalog,
460
485
  with no partial cache. Known local guides remain readable during an outage.
461
486
 
487
+ On `skills` and program `connecta.skill` reads, downstream text is prefixed with
488
+ a fixed third-party origin sentence naming the connector (bounded to 128 ID
489
+ characters). This prefix has no closing delimiter. `skills` listings carry the
490
+ same sentence before each downstream description, collapsed to one line, in text
491
+ and structured output. Program `connecta.read` applies it to text contents whose
492
+ URI uses the `skill:` scheme or ends in `SKILL.md`; a downstream's other resources
493
+ are returned as ordinary data, and binary contents are not labeled. Maintained and
494
+ deployment guides remain unlabeled. Native `skills/get` metadata and `resources/read`
495
+ contents stay unchanged so original manifest digests remain verifiable; adding a
496
+ label there would break integrity checks. A native host must attach its own origin
497
+ label when it loads verified content into model context, as the Skills extension
498
+ requires.
499
+
462
500
  Downstream files are proxied byte-exact, including CRLF and binary supporting
463
501
  files, within 512 files and 16 MiB per skill. Catalog metadata is bounded to
464
502
  1,024 entries and 8 MiB. The existing request-scoped agent boundary redacts
@@ -905,6 +943,16 @@ fulfill downstream input.
905
943
 
906
944
  ## Authorization recovery
907
945
 
946
+ Every native pool lists `authorize_connector`, including pools without code.
947
+ If a connector’s tools are missing, use its id from that tool’s granted-connector
948
+ list to request a typed handoff. Give the URL and instructions to the operator;
949
+ after repair the host must refresh its tool list before it can call the repaired
950
+ tools (the cache hint is 300 seconds). A host that keeps its first list needs a
951
+ reconnect or a new conversation; on a pool with `execute_code`, a program can call
952
+ them by address without one.
953
+ Listing never creates a handoff. Authorization accepts only connectors already
954
+ granted to this request; it cannot enable a connector or expand pool scope.
955
+
908
956
  On MCP 2026-07-28, a host declaring `elicitation.url` receives
909
957
  `resultType: "input_required"` when an eligible call or program needs recoverable
910
958
  connector authentication and the admitted identity may manage that connector.
@@ -1119,11 +1167,47 @@ Activity records each of these refusals with the coarse `friction` class derived
1119
1167
  from its typed error code — `tool_not_found`, `schema_retry`,
1120
1168
  `destructive_reroute`, `auth_required` — and clamps the caller-authored
1121
1169
  `connectorId`, `toolName`, and `address` it keeps, both under
1122
- [code mode](./code-mode.md#activity)'s `V2` and `V3`. A `call_tool` result too
1170
+ [code mode](./code-mode.md#activity)'s `V2` and `V3`. Optional
1171
+ [operation history](./operator-ui.md#opt-in-to-operation-history) records
1172
+ search, skill and result reads with fixed names, without arguments or payloads;
1173
+ it is off by default and separate from downstream-call counts. A `call_tool` result too
1123
1174
  large to return inline is the one exception: it is friction
1124
1175
  (`result_too_large`) on a call whose `outcome` is still `"success"`, so it
1125
1176
  carries no `errorCode`.
1126
1177
 
1178
+ Recovery actions outside the tool namespace use `nextAction.action` and a
1179
+ `purpose`: `reconnect_host` repairs inbound HTTP authentication (separate from
1180
+ connector OAuth), `contact_operator` reports catalog or utility availability,
1181
+ `inspect_capabilities` requests a supporting client/operation, and
1182
+ `recover_result` requests a retained handle or an honest missing-output report.
1183
+ Unsupported task, Skills, and resource capabilities use the non-retryable
1184
+ `unsupported_capability` code with `inspect_capabilities`. Missing or expired handles have `code: not_found`; storage outages retain
1185
+ `code: unavailable`. Neither action authorizes anything or replays writes.
1186
+ Unknown skill names and connectors without a guide retain their local lookup
1187
+ diagnostic with `code: not_found` and a `nextAction` calling `skills` with no
1188
+ name to discover available names. They do not request service restoration.
1189
+ The search output schema describes action discriminators compactly; action
1190
+ advice is additive, while catalog error and authorization handoff fields retain
1191
+ their detailed contracts.
1192
+ A spent read continuation's fresh-call action takes precedence over generic
1193
+ retry advice, while auth and provider permission repair prerequisites and unknown-write reconciliation remain
1194
+ in force. HTTP 401/403 responses preserve the adapter status and challenge. JSON responses
1195
+ carry the host recovery envelope. Custom non-JSON responses preserve their body
1196
+ and lifetime, with the same typed facts in `Connecta-Error-Code`,
1197
+ `Connecta-Recovery`, and JSON-encoded `Connecta-Next-Action` headers (also exposed
1198
+ to cross-origin hosts).
1199
+
1200
+ ## Recovery limits
1201
+
1202
+ Typed `invalid_args` failures without validation findings point to scoped schema
1203
+ inspection. `not_found` asks the caller to verify the resource id, account and
1204
+ visibility. `unavailable` asks the operator to restore connector availability.
1205
+ These use `nextAction` for an executable action and `retry` for explicit limits.
1206
+ An uncertain write has no safe replay action: read its target to reconcile its
1207
+ outcome before deciding on any fresh operation. Host authentication requires
1208
+ reconnecting the host; downstream authorization handoffs repair credentials;
1209
+ provider permission denial requires the resource owner to grant access.
1210
+
1127
1211
  ## Argument recovery
1128
1212
 
1129
1213
  Standard API hatches refuse marker containment in request paths and query
@@ -1437,10 +1521,17 @@ pool's surface.
1437
1521
  | Each visible downstream tool | Named `<connector>__<tool>`; object input constraints and local references preserved; no `outputSchema`; `_meta["dev.connecta/address"]` is its address |
1438
1522
  | `execute_code` | Unless `executeCode: false`. Each downstream tool's description then ends with `Program address: <connector>.<tool>`, the address `connecta.call` takes |
1439
1523
  | `read_result` | Only with `executeCode: false`: `{ id, offset?, page?, maxBytes? }` pages a stashed result exactly as `connecta.result` does, with the same bindings and rechecks |
1524
+ | `authorize_connector` | Always; requests the existing typed authorization handoff for a granted connector |
1440
1525
  | `skills` | Always |
1441
1526
 
1442
- `search_tools`, `call_tool`, `call_destructive_tool`, and `authorize_connector`
1443
- are not listed. Auth failures still carry their handoff in the error envelope.
1527
+ `search_tools`, `call_tool`, and `call_destructive_tool` are not listed. Auth failures still carry their handoff in the error envelope.
1528
+
1529
+ Native tool descriptions append `Guide: skills <name>` when their connector has
1530
+ guidance. Call `skills` with `{name:"<name>"}` to read it. The name is the same
1531
+ allocated readable name listed by `skills`, including collision suffixes; a
1532
+ name reserved for a built-in guide uses its canonical connector skill URI. This
1533
+ compact pointer repeats on each tool so host search results retain it; connectors
1534
+ without guides add nothing. It depends only on the admitted connector roster.
1444
1535
 
1445
1536
  **Names.** A name is a pure function of the connector id and downstream tool
1446
1537
  name, so it survives catalog refreshes. It is `<connector>__<tool>` when the
@@ -1484,7 +1575,7 @@ window, a native `tools/list` carries a 300-second private cache hint, against
1484
1575
  an hour on meta endpoints. This hint does not guarantee that a host refreshes
1485
1576
  its cached annotations; the stale-approval race is accepted on writable pools.
1486
1577
 
1487
- **Listing.** `tools/list` is one page with no cursor (Eve 0.90 reads only the
1578
+ **Listing.** `tools/list` is one page with no cursor (Eve's MCP client reads only the
1488
1579
  first page). A pool listing more than 1,000 tools fails `tools/list` with a
1489
1580
  JSON-RPC error asking the operator to narrow the pool; nothing is silently
1490
1581
  dropped. A connector whose catalog cannot load is left out of that listing
@@ -1498,7 +1589,14 @@ reduced calls; write tools are absent and refused on a read-only endpoint;
1498
1589
  never repeat a write; page a truncated result as its notice says. A pool
1499
1590
  `description` is appended as on meta endpoints.
1500
1591
 
1501
- **Recovery.** Repair and validation fields retain the exact constraint details.
1592
+ **Recovery.** `authorize_connector` remains listed even when a catalog fails.
1593
+ Its description lists all granted connector ids independently of catalog health.
1594
+ Use it for a missing connector, then refresh the host tool list after repair.
1595
+ Endpoint instructions carry the same recovery rule for hosts that fetch them
1596
+ separately. A cached list retains the recovery tool; a refreshed list restores
1597
+ the repaired connector’s whole catalog.
1598
+
1599
+ Repair and validation fields retain the exact constraint details.
1502
1600
  Discovery `nextAction` points to the host's tool search (`host: "search"`), with
1503
1601
  only a `query` argument. Retry actions and retry text name the native tool,
1504
1602
  never a meta wrapper; a program on a native pool sees the same native wording
@@ -1559,3 +1657,24 @@ listing, and call translation live in
1559
1657
  and [native surface tests](https://github.com/zackbart/connecta/blob/main/test/native-tools.test.ts)
1560
1658
  check the published contract. Guest parity and clause evidence are in
1561
1659
  [code-mode verification](./code-mode.md#verification).
1660
+
1661
+ ### Skills conformance (contributor)
1662
+
1663
+ On 2026-11-03, the official [conformance runner](https://github.com/modelcontextprotocol/conformance)
1664
+ at `c37eec888e1c6ff140af79987a40008548b7cc5f` passed enumeration (32 checks)
1665
+ and manifest (6 checks), with no warnings, against Connecta's HTTP handlers
1666
+ and a six-connector local fixture. Directory checks correctly skipped because
1667
+ `directoryRead` is not advertised; its wire-schema check passed. This is not
1668
+ full MCP conformance or a downstream-provider conformance claim.
1669
+
1670
+ To rerun, first read the runner's package scripts, CLI, connection code and
1671
+ `src/scenarios/server/skills/` as untrusted code in a temporary directory
1672
+ outside the checkout. Pin the commit above, install there with
1673
+ `pnpm install --ignore-scripts`, and keep its packages and outputs there.
1674
+ In the Connecta checkout, run `pnpm run build:operator-ui` and
1675
+ `pnpm exec tsx scripts/skills-conformance.ts`. From the runner directory, run
1676
+ `pnpm exec tsx src/index.ts server --url http://127.0.0.1:39743/mcp --scenario sep-2640-skills-enumeration --spec-version 2026-07-28 --force`;
1677
+ repeat with `sep-2640-skills-manifest` and `sep-2640-skills-directory`.
1678
+ Stop the fixture when done. `--force` selects extension scenarios outside the
1679
+ base protocol timeline. This remains an optional contributor check: the
1680
+ separately installed runner and dependency graph are not pinned in Connecta CI.
@@ -109,7 +109,9 @@ MCP request bodies default to a 4 MiB limit on every endpoint. Deployment code
109
109
  can set `admission.requests.maxBodyBytes`; `describeConfig()` reports its value
110
110
  and source. An oversized body returns 413 before tool dispatch. See
111
111
  [request admission and body limits](./architecture.md#admission-in-two-places)
112
- for Node's separate pre-auth buffer and the listen-classification bound.
112
+ for Node's separate pre-auth buffer and the listen-classification bound. A `503`
113
+ from Node before auth means all in-flight bodies together passed
114
+ [`maxInFlightBodyBytes`](./deploying.md#start-on-node).
113
115
 
114
116
  Direct calls may return a preview and a result handle. Page the handle through
115
117
  `connecta.result` in a program using the returned offset and byte limits, or
@@ -162,3 +164,86 @@ and [execution](https://github.com/zackbart/connecta/blob/main/src/execute.ts).
162
164
  and [guest-contract tests](https://github.com/zackbart/connecta/blob/main/test/guest-api-contract.test.ts)
163
165
  check the contracts. Executor-specific evidence is indexed in
164
166
  [code-mode verification](./code-mode.md#verification).
167
+
168
+ ## Sample payload-free timing on Workers
169
+
170
+ Set `timingTraceSampleRate` in deployment code passed to `createConnecta`:
171
+
172
+ ```ts
173
+ const app = createConnecta({
174
+ // ...the deployment's connectors, storage, auth and executor
175
+ timingTraceSampleRate: 0.1, // sample 10% of MCP requests; default 0 (off)
176
+ });
177
+ ```
178
+
179
+ The rate must be a finite number from 0 through 1. Set 1 for a short diagnostic
180
+ window, then return it to 0. Sampling is independent of the caller's
181
+ `diagnostics` argument. Enable Workers observability logs in the deployment's
182
+ Wrangler configuration (`observability.logs.enabled: true`). Its own sampling
183
+ may reduce captured records further. The configured logger receives
184
+ `connecta.timing` and one structured object when the MCP response body closes;
185
+ `logger: "silent"` suppresses these records too. Consume or close streaming
186
+ responses to finish their trace. An isolate-first-request flag means the first
187
+ MCP request that reaches tracing in that isolate, including unsampled requests;
188
+ it does not measure module boot.
189
+
190
+ Each version-1 record contains elapsed request time, the first-request flag,
191
+ weak-reference availability and aggregate operation families. Each family has
192
+ `count`, `durationMs`, `bytes`, `statements`, `items` and `absent` totals.
193
+ `catalog.accepted` counts complete accepted catalogs, serialized bytes and tools. Invocation
194
+ `catalog`, `admission`, `connector` and `result` durations reuse the existing
195
+ `diagnostics` segments. `catalog.cache.lookup` counts cache probes; `catalog.cache.hit` counts accepted
196
+ unexpired entries. Lookups without hits can include misses, expiry, invalid
197
+ entries or interrupted reads; they are not proof of live relisting.
198
+ `catalog.validated.hit`/`miss` report immutable validation reuse.
199
+ `catalog.decode` counts JSON decodes and their UTF-8 input bytes;
200
+ `catalog.validate` and `catalog.intake` count those stages without timing them.
201
+ These three count-only families always have `durationMs: 0`.
202
+ `catalog.chunks` records accepted chunk bytes and counts. These counters do not
203
+ identify a connector, owner or private/public partition.
204
+ Concurrent spans can overlap; do not sum them as wall time.
205
+ `memo.hit`, `memo.miss` and `memo.fresh` describe the request-read memo
206
+ (`absent` counts null values, not cache failures). `d1.read`, `d1.write` and
207
+ `d1.batch` count physical native D1 trips and SQL statements, including
208
+ failed attempts. Batch count is one trip; statements is the batch length.
209
+ All native D1 work carrying the request context shares these totals, including
210
+ admission, credential and catalog work. Comparing them with `catalog` duration
211
+ (the diagnostics `catalogMs` segment) does not isolate catalog storage.
212
+ Returned D1 bytes measure serialized application results, not Cloudflare's wire
213
+ encoding. Memo bytes measure UTF-8 stored values. Result bytes use the existing
214
+ invocation measurement. No keys, tool names, owner identity, arguments, results,
215
+ credentials or error text enter the record. Records retain totals only.
216
+
217
+ On production Workers, `performance.now()` advances only across I/O. Durations
218
+ are I/O-spanning elapsed observations, not CPU attribution: zero is ambiguous,
219
+ and CPU work can appear in a later I/O interval. D1 durations are therefore not
220
+ pure storage latency. Use counts, sizes, cache outcomes and the isolate-first-request
221
+ flag to compare warm direct and one-call program requests with the same catalog.
222
+ For per-invocation CPU, use Workers' invocation telemetry field
223
+ [`$workers.cpuTimeMs`](https://developers.cloudflare.com/workers/observability/query-builder/).
224
+ Deeper attribution requires [CPU profiling](https://developers.cloudflare.com/workers/runtime-apis/performance/).
225
+
226
+ Only work carrying the MCP request's native context contributes D1 counters;
227
+ standalone operator/background or custom Promise adapter work is outside that
228
+ request trace. Sampling does not add reads, change TTLs, bypass generation or
229
+ credential fences, or start authorization.
230
+
231
+ For example, query a ten-minute window for a neutral Worker `assistant` (replace
232
+ the millisecond timestamps with the window you need):
233
+
234
+ ```sh
235
+ cf --profile assistant o11y telemetry query \
236
+ --query-id 00000000-0000-4000-8000-000000000001 \
237
+ --view events --limit 100 \
238
+ --timeframe-from 1793700000000 --timeframe-to 1793700600000 \
239
+ --parameters-order-by-value count --parameters-order-by-order desc \
240
+ --parameters-calculations '[{"operator":"count","alias":"count"}]' \
241
+ --parameters-filters '[{"key":"$workers.scriptName","operation":"eq","type":"string","value":"assistant"}]'
242
+ ```
243
+
244
+ Select `connecta.timing` messages in the returned events and inspect their
245
+ structured operation totals. Use the profile belonging to your deployment.
246
+ The example reads telemetry only; it changes no Worker settings.
247
+
248
+ The example passes CLI dry-run validation; server acceptance has not been verified.
249
+ Use `--dry-run` to validate the request locally without querying telemetry.
@@ -287,7 +287,7 @@ stack each row into a card.
287
287
 
288
288
  ### Activity
289
289
 
290
- Counts for the loaded history (calls, failed, tools, catalog changes), also
290
+ Counts for the loaded history (calls, failed, tools, catalog changes, and opt-in operations), also
291
291
  in its accessible summary, and a strip of calls over time with failures in
292
292
  red when the calls span more than a minute.
293
293
 
@@ -304,7 +304,9 @@ red when the calls span more than a minute.
304
304
  row lists what was recorded: result, how it ran, classification, exact
305
305
  duration and size, caller, stable caller id, request id, client, and
306
306
  connecta version. Unrecorded fields are left out. Catalog changes are rows
307
- with added, removed and changed counts.
307
+ with added, removed and changed counts. Opt-in operation rows use fixed names
308
+ (Search, Describe, Result page, Skill read, Program) and an Operation detail;
309
+ they do not count as calls, failed calls, friction, tools or last calls.
308
310
  - **Empty.** "No calls yet" with Refresh, or "No matches" with Clear filters.
309
311
 
310
312
  ### Navigation, gates and recovery
@@ -767,6 +769,53 @@ names, descriptions or schemas enter the event. Private catalog changes require
767
769
  a matching principal owner even when the connector uses shared auth. Empty credential declarations
768
770
  report `credential_required` before running a connector status or catalog probe.
769
771
 
772
+ ### Opt in to operation history
773
+
774
+ Set `operations: true` on the existing activity module, for example
775
+ `activity: activityHistory({ store, operations: true })`, where `store` is the
776
+ configured platform activity store. The default is off: existing deployments
777
+ emit no operation rows. Each admitted search, describe, result page, skill read
778
+ and whole program adds one event through the existing detached sink. Workers
779
+ attach its promise to `waitUntil`; Node does not await it in the response path.
780
+ This adds storage writes and retention cleanup work for every operation.
781
+
782
+ Rows use `kind: "operation"`, `source: "execute_code"`, and a fixed operation
783
+ name. They contain duration, outcome, a checked error code, returned page
784
+ byte count when already measured, and host-call counts for a program. No query, tool
785
+ address supplied by a caller, skill name, result ID, code, arguments, result
786
+ contents or raw error text enters the row. Custom history readers must exclude
787
+ operation rows from call/friction counts. The public kind union adds
788
+ `"operation"`; exhaustive consumers may need a new case even when their
789
+ runtime configuration leaves recording off.
790
+
791
+ Operation disclosure is deliberately conservative:
792
+
793
+ - The existing maintainer permission and optional `readGate` still apply.
794
+ - Scope means every connector visible to the admitted endpoint, rather than
795
+ just the connectors named by a particular argument. A single-connector scope
796
+ uses that connector ID; other scopes use a reserved operation ID internally.
797
+ - Every connector in that scope must still be visible through a whole-connector
798
+ grant to both the reader and the recorded pool. Address-only grants do not
799
+ disclose operations. Removed pools/connectors or invalid scope metadata
800
+ withhold the entire row.
801
+ - All human operations are owner-only. Scopes containing personal auth,
802
+ caller-bound auth or a dynamically discovered catalog are also owner-only,
803
+ since static configuration cannot prove the catalog public. Owner-only rows
804
+ require the recorded principal basis and an exact match to the reader's
805
+ admitted principal ID and namespace. An agent without a provable admitted
806
+ human owner has those rows withheld.
807
+ - Shared machine operations over statically declared catalogs are visible to
808
+ maintainers only when the complete scope passes those checks. This policy
809
+ can withhold single-connector work performed on a mixed endpoint.
810
+
811
+ Existing D1 and SQLite activity tables need no new columns. The existing
812
+ kind-tagged metadata text slot stores the checked operation scope and counts;
813
+ legacy tool and catalog-change rows keep their format. The timeline shows
814
+ operations separately and excludes them from call totals, friction, tool
815
+ counts, call strips and last-call overlays.
816
+
817
+ ### Activity actor labels
818
+
770
819
  Activity label resolvers receive an optional `AbortSignal`. Pass it to user-directory
771
820
  fetches and stop work when it aborts: the reader has left or the label lookup
772
821
  budget has expired. Clerk label lookups follow the same lifetime and discard
@@ -275,12 +275,12 @@ discovery for your deployment's catalog.
275
275
  </details>
276
276
 
277
277
  <details>
278
- <summary>QuickBooks Online (10 tools)</summary>
278
+ <summary>QuickBooks Online (11 tools)</summary>
279
279
 
280
280
  [Setup](#quickbooks-online). **API source:** Hand-authored endpoint contracts. No vendored OpenAPI document.
281
281
 
282
282
  - **Named reads:** `get_company_info`, `get_record`, `get_report`, `search_records`.
283
- - **Named writes:** `create_customer`, `create_invoice`, `update_customer`.
283
+ - **Named writes:** `create_customer`, `create_invoice`, `update_customer`, `update_unsent_invoice`.
284
284
  - **API reads:** `quickbooks_api_details`, `quickbooks_api_read`, `quickbooks_api_search`.
285
285
  - **API writes:** None.
286
286
 
@@ -1520,18 +1520,20 @@ Creation fixes EmailStatus to `NotSet` and IPN/online/card/ACH/PayPal/Affirm
1520
1520
  payment flags to false, accepts no email fields, and never calls a send endpoint.
1521
1521
  Intuit's documented autosend path requires company opt-in, enabled online
1522
1522
  payments and `NeedToSend` with BillEmail; the fixed creation body withholds
1523
- those request conditions. Invoice updates remain unavailable because retaining
1524
- an existing send-ready state is not established safe, and resetting that state
1525
- would change existing payment settings. Deletes, voids, delivery, payment
1526
- execution, batch and other accounting writes remain unavailable. The API hatch
1527
- refuses POSTs even when named writes are enabled.
1528
-
1529
- Sparse field preservation, a current SyncToken and requestid do not establish
1530
- that an invoice update cannot send email. For example, changing only DueDate
1531
- on an invoice with NeedToSend and enabled card/ACH payments retains those
1532
- settings; omitting email fields does not disable them. Do not reset delivery or
1533
- payment settings to work around the unavailable update, or replace the invoice
1534
- with a new one. No unsent-only update tool is currently exposed either.
1523
+ those request conditions.
1524
+
1525
+ `update_unsent_invoice` changes only DocNumber. Supply caller-observed Id and
1526
+ SyncToken and an explicit docNumber. It reads the US company and invoice,
1527
+ requires USD, explicit NotSet, no DeliveryInfo and every IPN/online/card/ACH/
1528
+ PayPal/Affirm payment flag explicitly false. Unknown state, send-ready or
1529
+ delivered state and stale versions fail before POST; no newer version is
1530
+ substituted. The sparse body preserves omitted delivery/payment fields.
1531
+ No date edits are exposed. Applying autosend prerequisites to updates is an
1532
+ inference, not an update-specific Intuit no-email guarantee. NotSet and absent
1533
+ delivery information cannot prove there was never historical delivery.
1534
+ Do not reset state to qualify or replace an invoice to bypass a refusal.
1535
+ Deletes, voids, delivery, payment execution, batch and other accounting writes
1536
+ remain unavailable. The API hatch refuses POSTs even when named writes are enabled.
1535
1537
 
1536
1538
  Each write requires `requestId`, a stable identifier for the exact intent,
1537
1539
  unique across all requests/tools for this company: 1–50 ASCII letters, digits,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zackbart/connecta",
3
- "version": "0.39.0",
3
+ "version": "0.41.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 six meta-tools.",
@@ -173,8 +173,8 @@
173
173
  "build:operator-ui": "node scripts/build-operator-ui.mjs",
174
174
  "check:operator-ui": "node scripts/build-operator-ui.mjs --check",
175
175
  "check:clerk-sdk": "node scripts/build-clerk-sdk.mjs --check",
176
- "build": "pnpm run providers:generate && pnpm run clean && tsc -p tsconfig.build.json && node scripts/prune-declarations.mjs",
177
- "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.operator-ui.json --noEmit",
176
+ "build": "node scripts/eval-runtime.mjs --build",
177
+ "typecheck": "node node_modules/typescript-native/bin/tsc -p tsconfig.json --noEmit && node node_modules/typescript-native/bin/tsc -p tsconfig.operator-ui.json --noEmit",
178
178
  "test": "vitest run",
179
179
  "test:browser:install": "playwright install chromium",
180
180
  "test:browser": "playwright test",
@@ -182,19 +182,20 @@
182
182
  "pretest:browser:snapshots": "pnpm run build:operator-ui",
183
183
  "test:node": "vitest run --config vitest.config.node.ts",
184
184
  "test:workers": "vitest run --project workers",
185
+ "check:node-shards": "node scripts/check-node-shards.mjs",
185
186
  "check:docs": "node scripts/check-doc-links.mjs",
186
187
  "check:lint": "oxlint -D correctness --report-unused-disable-directives .",
187
188
  "check:unused": "knip --include dependencies,unlisted,exports,nsExports,types,nsTypes",
188
- "check:examples": "tsc -p tsconfig.template.node.json && tsc -p tsconfig.examples.worker.json",
189
+ "check:examples": "node node_modules/typescript/bin/tsc -p tsconfig.template.node.json && node node_modules/typescript/bin/tsc -p tsconfig.examples.worker.json",
189
190
  "check:security": "pnpm audit --prod --audit-level moderate",
190
191
  "check:package": "node scripts/check-package.mjs",
191
192
  "check:declarations": "node scripts/check-declarations.mjs --dist .",
192
193
  "check:bundle": "node scripts/bundle-size.mjs",
193
194
  "providers:check": "tsx scripts/drift-check.mjs --specs --manual",
194
- "eval:selftest": "tsx eval/selftest.ts",
195
- "eval:agent": "tsx eval/run-agent.ts",
196
- "eval:smoke": "tsx eval/run-smoke.ts",
197
- "eval:outcomes": "tsx eval/run-outcomes.ts",
195
+ "eval:selftest": "node --import tsx scripts/eval-runtime.mjs selftest",
196
+ "eval:agent": "node --import tsx scripts/eval-runtime.mjs run-agent",
197
+ "eval:smoke": "node --import tsx scripts/eval-runtime.mjs run-smoke",
198
+ "eval:outcomes": "node --import tsx scripts/eval-runtime.mjs run-outcomes",
198
199
  "preeval:outcomes": "node scripts/generate-version.mjs && pnpm run build:operator-ui",
199
200
  "eval:perf": "tsx eval/run-perf.ts",
200
201
  "eval:report": "tsx eval/report.ts",
@@ -279,6 +280,7 @@
279
280
  "react-dom": "^19.3.1",
280
281
  "tsx": "^4.23.15",
281
282
  "typescript": "^6.0.3",
283
+ "typescript-native": "npm:typescript@7.0.2",
282
284
  "undici": "6.29.1",
283
285
  "vite": "^8.3.4",
284
286
  "vitest": "^5.0.4",
@@ -18,7 +18,7 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@clerk/backend": "^3.12.0",
21
- "@zackbart/connecta": "0.39.0",
21
+ "@zackbart/connecta": "0.41.0",
22
22
  "quickjs-emscripten": "0.32.0",
23
23
  "undici": "6.29.1"
24
24
  },