@zackbart/connecta 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +12 -5
- package/CHANGELOG.md +289 -0
- package/README.md +6 -1
- package/dist/catalog-service.d.ts +4 -0
- package/dist/catalog-service.js +49 -5
- package/dist/catalog.d.ts +11 -0
- package/dist/catalog.js +134 -12
- package/dist/errors.d.ts +28 -2
- package/dist/errors.js +1 -0
- package/dist/execute.d.ts +5 -0
- package/dist/execute.js +229 -161
- package/dist/invocation.js +3 -1
- package/dist/meta-tools.d.ts +4 -0
- package/dist/meta-tools.js +46 -14
- package/dist/operator-ui/generated.d.ts +1 -1
- package/dist/operator-ui/generated.js +1 -1
- package/dist/operator-ui/model.d.ts +3 -1
- package/dist/providers/cloudflare.js +13 -25
- package/dist/providers/mixpanel.d.ts +3 -5
- package/dist/providers/mixpanel.js +73 -5
- package/dist/providers/stripe.d.ts +2 -2
- package/dist/providers/stripe.js +13 -11
- package/dist/registry.d.ts +32 -9
- package/dist/registry.js +217 -33
- package/dist/routes/mcp.js +6 -0
- package/dist/skills.d.ts +4 -0
- package/dist/skills.js +157 -18
- package/dist/types.d.ts +14 -2
- package/dist/ui.js +4 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +7 -4
- package/documentation/cloudflare.md +40 -8
- package/documentation/code-first-exploration.md +2 -2
- package/documentation/code-mode.md +45 -53
- package/documentation/connector-guides.md +24 -19
- package/documentation/connectors.md +13 -1
- package/documentation/meta-tools.md +33 -18
- package/documentation/mixpanel.md +20 -0
- package/documentation/notion.md +7 -2
- package/documentation/operations.md +74 -29
- package/documentation/operator-ui.md +12 -2
- package/documentation/provider-audit.md +4 -4
- package/documentation/provider-conventions.md +68 -19
- package/documentation/stripe.md +45 -14
- package/documentation/upgrading.md +478 -0
- package/ethos.md +4 -4
- package/examples/worker/README.md +13 -6
- package/package.json +7 -2
- package/templates/node/AGENTS.md +5 -0
- package/templates/node/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -83,11 +83,18 @@ Two boundaries CI enforces that are not obvious from reading a file:
|
|
|
83
83
|
and fails otherwise. Need a Node API? It goes behind an explicit Node-only
|
|
84
84
|
subpath (`/node` or `/quickjs`), never the root.
|
|
85
85
|
- **The published surface.** Platform-specific storage adapters live in
|
|
86
|
-
`examples/`,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
`
|
|
90
|
-
|
|
86
|
+
`examples/worker/`, never in `src/` and never in the `exports` map. That
|
|
87
|
+
example does ship in the tarball, Cloudflare KV and D1 adapters included —
|
|
88
|
+
it is the Workers starting template a consumer copies, and copying it is the
|
|
89
|
+
point — but every `exports` target resolves into `dist/`, so those adapters
|
|
90
|
+
are readable reference source and not an importable subpath. What is
|
|
91
|
+
forbidden is a platform-bound adapter becoming importable from the package,
|
|
92
|
+
not a file appearing in the artifact. `@clerk/backend` and
|
|
93
|
+
`quickjs-emscripten` are optional peers behind the `./auth/clerk` and
|
|
94
|
+
`./quickjs` subpaths and must never become dependencies or install with
|
|
95
|
+
core. Enforced by `test/package-surface.test.ts` and
|
|
96
|
+
`scripts/check-package.mjs`. Anything heavyweight or platform-bound gets a
|
|
97
|
+
subpath and an optional peer.
|
|
91
98
|
|
|
92
99
|
## Where new tests go
|
|
93
100
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,295 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this package are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.17.0 — 2026-08-13
|
|
6
|
+
|
|
7
|
+
This minor release makes catalog discovery faster and its answers more exact.
|
|
8
|
+
Agent reads can use a verified stale catalog while one bounded refresh runs,
|
|
9
|
+
guide summaries now read Markdown as prose, compact schemas retain more declared
|
|
10
|
+
constraints, array projection distinguishes misses from genuine nulls, and
|
|
11
|
+
Mixpanel carries the conditional rules its live tools enforce. One construction
|
|
12
|
+
contract tightens: an explicit `usageGuide.summary` over 120 characters now
|
|
13
|
+
refuses to boot. Deployments whose summaries fit, or which let Connecta derive
|
|
14
|
+
them, need no configuration change. Operator catalog reads retain their blocking
|
|
15
|
+
freshness behavior. This release also makes the two code sandboxes' runtime
|
|
16
|
+
differences explicit. The shipped
|
|
17
|
+
Worker example is already loader-only; deployments that added executor
|
|
18
|
+
`bindings`, `modules`, or `globalOutbound` must remove them. Existing portable
|
|
19
|
+
`execute_code` programs keep their behavior. Programs can now classify a caught
|
|
20
|
+
Connecta failure without parsing its message.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- An explicit `usageGuide.summary` longer than 120 characters after whitespace
|
|
25
|
+
normalization now throws during registry construction. Exactly 120 remains
|
|
26
|
+
valid, and a blank explicit summary still falls back to derivation (#392).
|
|
27
|
+
|
|
28
|
+
- **Agent catalog reads now serve a verified stale entry while they refresh it.**
|
|
29
|
+
Search, describe, and code-mode calls no longer await a downstream listing
|
|
30
|
+
when the runtime already holds a complete catalog inside its stale window.
|
|
31
|
+
The inbound request still causes the refresh; there is no timer, warmup, or
|
|
32
|
+
credential probe. One bounded refresh per connector owns and closes a fresh
|
|
33
|
+
scope, while operator status stays blocking and shows whether the last agent
|
|
34
|
+
read in this runtime was fresh or stale (#396).
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- **Caught `execute_code` failures now keep their machine-readable type.**
|
|
39
|
+
Calls, connector shortcuts, discovery, emitted-output and UI validation,
|
|
40
|
+
batch validation, and host-call budgets still throw with the same human
|
|
41
|
+
message, but now expose `code`, `retryable`, and full `details`. Batch entries
|
|
42
|
+
use the same codes. A per-run authenticated frame prevents connector prose or
|
|
43
|
+
guest code from forging the host transport on either executor (#393).
|
|
44
|
+
|
|
45
|
+
- **`execute_code` now tells the truth about each shipped sandbox.** QuickJS
|
|
46
|
+
has no `fetch`, `process`, timers, `crypto`, or `WebSocket`, and blocks
|
|
47
|
+
imports. Loader-only Dynamic Workers deny outbound fetch, WebSocket,
|
|
48
|
+
`node:net`, and `node:tls`; leave DNS unresolved; expose no environment
|
|
49
|
+
bindings or filesystem/HTTP builtins; but retain local `data:` fetch,
|
|
50
|
+
runtime globals, and a non-contract builtin set that can drift. The example
|
|
51
|
+
pins the required loader-only construction, and agent guidance tells portable
|
|
52
|
+
programs to use none of that Dynamic-only authority (#390).
|
|
53
|
+
|
|
54
|
+
- **Clerk-authenticated operator pages now wait for ClerkJS before booting.**
|
|
55
|
+
The loader runs before the later inline operator bundle instead of deferring
|
|
56
|
+
until after parsing, so a fresh page no longer mistakes normal script order
|
|
57
|
+
for a network failure. Clerk's major-to-pinned version redirect remains
|
|
58
|
+
supported, and a real loader failure keeps the existing clear error (#403).
|
|
59
|
+
|
|
60
|
+
- **Stripe's guide now treats connector identity as routing intent, not account
|
|
61
|
+
proof.** One OAuth session may cover several accounts in one organization,
|
|
62
|
+
so agents resolve the intended account through the live tool schema and stop
|
|
63
|
+
when the target or selector is ambiguous. The guide also keeps organization
|
|
64
|
+
accounts separate from the restricted-key-only Stripe Connect path (#404).
|
|
65
|
+
|
|
66
|
+
- **The no-account-model constitution now matches provider-owned sessions.**
|
|
67
|
+
Connecta still has no account dimension: credentials, storage, admission,
|
|
68
|
+
and health remain connector-scoped. A provider may expose its own account
|
|
69
|
+
scope only through its live schema; metadata never proves identity, and an
|
|
70
|
+
ambiguous target or selector stops instead of becoming a guess (#410).
|
|
71
|
+
|
|
72
|
+
- **The reviewed Notion page contracts are current again.** Notion added
|
|
73
|
+
create-page template and placement options plus update-page locking,
|
|
74
|
+
template, and erase options. The existing parent, properties, Markdown,
|
|
75
|
+
children, emoji, and trash request subsets remain valid, so this release
|
|
76
|
+
records the two changed endpoint digests without adding the new capabilities.
|
|
77
|
+
Their product decisions remain in #408 and #409.
|
|
78
|
+
|
|
79
|
+
- **Array field misses now report what happened.** A path that misses every
|
|
80
|
+
element appears in `unmatchedFields` instead of returning a clean array of
|
|
81
|
+
false nulls. A heterogeneous array keeps its positional result and names the
|
|
82
|
+
path in `partialFields`, so genuine downstream nulls remain distinguishable.
|
|
83
|
+
Schema-backed misses keep the same bounded guidance through nested arrays;
|
|
84
|
+
schema-free projections still report their observed misses (#394).
|
|
85
|
+
- Derived guide summaries now join a hard-wrapped opening paragraph before
|
|
86
|
+
selecting a complete sentence or shortening at a clause or word boundary.
|
|
87
|
+
Frontmatter, fences, headings, rules, tables, and description fallbacks keep
|
|
88
|
+
their prior roles; multi-line HTML comments are now skipped whole (#392).
|
|
89
|
+
|
|
90
|
+
- **Compact schemas now carry declared numeric and string constraints.** Search
|
|
91
|
+
and compact describe show numeric bounds, multiples, string length bounds,
|
|
92
|
+
patterns, and formats beside the affected type. Search keeps its 1,024-byte
|
|
93
|
+
schema ceiling and 256-byte node budget: a constraint that does not fit is
|
|
94
|
+
dropped whole, and the existing truncation flag sends the caller to describe
|
|
95
|
+
for the complete shape (#391).
|
|
96
|
+
|
|
97
|
+
- **Carry Mixpanel's three enforced conditional-input rules in its maintained
|
|
98
|
+
guide.** A live read-only audit confirmed that `Get-Business-Context`,
|
|
99
|
+
`Get-Property-Values`, and `List-Properties` accept shapes in their advertised
|
|
100
|
+
schemas that their implementations reject. Connecta still preserves the
|
|
101
|
+
hosted schemas unchanged; the guide now prevents those rejected calls, the
|
|
102
|
+
vetted manifest records schema digests for all 63 tools, and the provider
|
|
103
|
+
defect is tracked upstream. The maintainer drift check also frames
|
|
104
|
+
Mixpanel's service account as its documented `Bearer Basic` value instead of
|
|
105
|
+
ordinary HTTP Basic (#395).
|
|
106
|
+
|
|
107
|
+
## 0.16.1 — 2026-08-13
|
|
108
|
+
|
|
109
|
+
This is the cleanup that follows 0.16.0 out the door: the packaging housekeeping
|
|
110
|
+
the pre-release smoke gauntlet turned up, one provider tool Cloudflare
|
|
111
|
+
deprecated out from under us, a discovery answer that told a plain lie, and the
|
|
112
|
+
upgrade runbook an existing deployment never had. Two things break, both on
|
|
113
|
+
Cloudflare and both named here rather than left to the section below:
|
|
114
|
+
`list_zone_settings` is gone from the `cloudflare()` named surface, and
|
|
115
|
+
Cloudflare's 404 arrives as `not_found` instead of `connector_call_failed`.
|
|
116
|
+
Nothing else does — no wire shape changes, no construction contract moves, no
|
|
117
|
+
other code reclassified, and the per-setting operations `list_zone_settings`
|
|
118
|
+
sat beside are the supported ones and are untouched. A deployment that writes
|
|
119
|
+
no `api()` connectors, branches on no error code, and never asked an agent for
|
|
120
|
+
a whole zone's settings in one call upgrades without reading further.
|
|
121
|
+
|
|
122
|
+
Three things are additions rather than repairs, and they are the reason this
|
|
123
|
+
release is worth reading rather than just installing: a new
|
|
124
|
+
`ConnectorCallErrorCode` member, `not_found`, with a rule for when a connector
|
|
125
|
+
may mint it; a `"./package.json"` entry in the `exports` map, so the installed
|
|
126
|
+
manifest resolves; and `@cloudflare/codemode` declared as an optional peer at
|
|
127
|
+
`^0.4.4 || ^0.5.0`. Strict semver would read those three as a minor, and would
|
|
128
|
+
read the two Cloudflare changes above as more than that. This ships as a patch
|
|
129
|
+
deliberately: every addition is opt-in at the point a deployment chooses to
|
|
130
|
+
read it, and the tool removal and the 404 reclassification ride along in the
|
|
131
|
+
same patch on purpose — both are scoped to one provider, both have a stated
|
|
132
|
+
replacement, and both carry a version boundary in
|
|
133
|
+
[`documentation/upgrading.md`](./documentation/upgrading.md). Holding them for
|
|
134
|
+
a minor would mean shipping a release that keeps calling an endpoint its
|
|
135
|
+
provider deprecated. The one install-time consequence is spelled out next.
|
|
136
|
+
|
|
137
|
+
One thing to check before upgrading a Worker: `@cloudflare/codemode` is now a
|
|
138
|
+
declared peer, so if your `package.json` holds it at a version outside
|
|
139
|
+
`^0.4.4 || ^0.5.0` — a `0.3.x`, or a `0.4` below `0.4.4` — npm stops the
|
|
140
|
+
upgrade with an `ERESOLVE` conflict rather than installing. Move it into the
|
|
141
|
+
range this release is tested against, or pass `--legacy-peer-deps` if you have
|
|
142
|
+
a reason to run outside it. A version already inside the range, and a range
|
|
143
|
+
loose enough for npm to pick one that is, both resolve exactly as before.
|
|
144
|
+
|
|
145
|
+
Alongside it, the upgrade path an existing deployment takes gets written down.
|
|
146
|
+
`connecta init` was the golden path for a new deployment and the whole story
|
|
147
|
+
for an old one, which is a gap with a shape: `init` refuses to merge into an
|
|
148
|
+
existing path — the guard that keeps an initializer from eating a connector
|
|
149
|
+
set — so an agent pointed at a deployment two releases behind had to
|
|
150
|
+
reconstruct the procedure from release prose written for the maintainer. Both
|
|
151
|
+
interesting failures there were silent too. It overwrites the configuration the
|
|
152
|
+
deployment exists for, or it "fixes" a construction throw by weakening a
|
|
153
|
+
fail-closed default and ships something quieter and wrong.
|
|
154
|
+
|
|
155
|
+
### Added
|
|
156
|
+
|
|
157
|
+
- **`not_found`, for a downstream that answered and had nothing to give.** A
|
|
158
|
+
hand-written connector meeting a 404 had exactly one honest code,
|
|
159
|
+
`connector_call_failed`, which also means "the call blew up" — so a program
|
|
160
|
+
inside `execute_code` could not tell a clean absence from a broken connector,
|
|
161
|
+
and a loop over ids had to abort where it should have skipped one. The new
|
|
162
|
+
code earns its place the way every code has to: it changes what the caller
|
|
163
|
+
does next. You do not wait, you do not go to `authorize_connector`, you do
|
|
164
|
+
not repair the arguments — you re-address. It is non-retryable, carries no
|
|
165
|
+
recovery envelope, derives no activity friction class, and is exported from
|
|
166
|
+
the root entry as part of `ConnectorCallErrorCode`.
|
|
167
|
+
|
|
168
|
+
The qualifier is the interesting half, and it is now written down in
|
|
169
|
+
[H11](./documentation/provider-conventions.md#h11--errors-are-mapped-to-what-the-caller-does-next):
|
|
170
|
+
map a status to `not_found` only where the provider tells absence apart from
|
|
171
|
+
a permission gap. Cloudflare does — a token that may not touch a resource is
|
|
172
|
+
refused with 401 or 403 — so its 404 is now `not_found` instead of
|
|
173
|
+
`connector_call_failed`. Notion does not: `object_not_found` means both "it
|
|
174
|
+
is gone" and "it was never shared with this integration", so it deliberately
|
|
175
|
+
stays generic with a message that says so. The hosted-MCP proxy path mints
|
|
176
|
+
the code never, because `P1` forbids re-shaping downstream framing and
|
|
177
|
+
provider prose is never parsed to invent a classification (#373).
|
|
178
|
+
|
|
179
|
+
- **An upgrade runbook for existing deployments.**
|
|
180
|
+
[`documentation/upgrading.md`](./documentation/upgrading.md) is written for
|
|
181
|
+
the agent sitting inside a generated deployment it did not create: read the
|
|
182
|
+
exact pin and the template generation it implies, regenerate that generation
|
|
183
|
+
with `npx @zackbart/connecta@<pin> init` to get a real merge base, three-way
|
|
184
|
+
reconcile the scaffolding against the current template while `src/index.ts`
|
|
185
|
+
stays the deployment's own, cross the version boundaries that break
|
|
186
|
+
construction, and finish where `init` finishes — typecheck, start,
|
|
187
|
+
`connecta doctor`, then a program that exercises the deployment's *own*
|
|
188
|
+
connectors, which doctor deliberately knows nothing about. The migration
|
|
189
|
+
notes are per boundary and derived from this file: the 0.16.0 `api()`
|
|
190
|
+
construction contract (with the one safe answer for an unannotated tool
|
|
191
|
+
written down — `readOnlyHint: false`, which is the routing it already had),
|
|
192
|
+
the `linear()`, `mixpanel()`, and Cloudflare provider changes, redirect
|
|
193
|
+
refusal and the response ceilings, and the fail-closed shipped defaults; then
|
|
194
|
+
0.14's annotation-precedence change, 0.13's rewritten guide summaries, the
|
|
195
|
+
0.11.0 executor requirement, 0.7.0's `verifyState` requirement and
|
|
196
|
+
core-owned routes for the pre-template deployments that still have to cross
|
|
197
|
+
them, and every removed option that throws with its migration. It closes with five refusals, because each is somebody's plausible
|
|
198
|
+
shortcut: no re-init over the top, no weakening a fail-closed default to get
|
|
199
|
+
green, no pinning back, no vendored internals, no second project shape.
|
|
200
|
+
Reachable from the README, from `operations.md`, and — absolutely, because
|
|
201
|
+
that reader has no copy of this repository — from the template's `AGENTS.md`
|
|
202
|
+
(#380).
|
|
203
|
+
- **A suite that keeps the guide honest.** `test/upgrade-guide.test.ts` pins
|
|
204
|
+
every claim its reader cannot check: the generated file inventory against
|
|
205
|
+
`templates/node/`, the seven tool names against the CLI's own list, each
|
|
206
|
+
named version boundary against a release that shipped, each removed option
|
|
207
|
+
against the release section that names its issue, the bump target against
|
|
208
|
+
this package's version, and the three places the guide is linked from. A template that gains a file now fails `npm run check` rather than
|
|
209
|
+
leaving an agent to guess which of the two is wrong (#380).
|
|
210
|
+
- **`@cloudflare/codemode` is a declared optional peer.** Every Workers
|
|
211
|
+
deployment installs the executor behind `execute_code` by hand, and until now
|
|
212
|
+
the only version range anywhere was a devDependency no consumer can read — a
|
|
213
|
+
fresh install resolved a minor ahead of what this repository tests, silently.
|
|
214
|
+
The manifest now publishes `^0.4.4 || ^0.5.0` for it, optional like
|
|
215
|
+
`@clerk/backend` and `quickjs-emscripten`, so a supported version installs in
|
|
216
|
+
silence and an unsupported one stops the install with something to act on
|
|
217
|
+
instead of becoming skew a Worker discovers in production. It still installs
|
|
218
|
+
with nothing: a default `npm install @zackbart/connecta` pulls no executor,
|
|
219
|
+
and the package smoke proves that, both halves of the range behavior, and
|
|
220
|
+
that the version this repository develops against stays inside the range it
|
|
221
|
+
publishes (#376).
|
|
222
|
+
|
|
223
|
+
### Changed
|
|
224
|
+
|
|
225
|
+
- **Cloudflare's 404 is `not_found`.** A deployment branching on
|
|
226
|
+
`connector_call_failed` to detect an unknown zone or account id should read
|
|
227
|
+
`not_found` instead; retryability, the message, and its pointer to
|
|
228
|
+
`list_zones` / `list_accounts` are unchanged (#373).
|
|
229
|
+
- `cloudflare()` no longer names a bulk zone-settings read.
|
|
230
|
+
`GET /zones/{zoneId}/settings` and its `PATCH` sibling are published as
|
|
231
|
+
`deprecated: true`, Cloudflare offers no bulk replacement, and the tool that
|
|
232
|
+
wrapped the read projected nothing — it took a zone id and grew the payload
|
|
233
|
+
by wrapping an unpaginated array in a page object. Read one setting with
|
|
234
|
+
`get_zone_setting` and write one with `update_zone_setting`, both on the
|
|
235
|
+
supported `/zones/{zoneId}/settings/{settingId}` operations. An operator who
|
|
236
|
+
still wants the whole set can name the deprecated path explicitly through
|
|
237
|
+
`cloudflare_api_get`. The named surface is 47 tools plus the three escape
|
|
238
|
+
hatches ([#361](https://github.com/zackbart/connecta/issues/361)).
|
|
239
|
+
- The Cloudflare touched-endpoint manifest drops the deprecated row with the
|
|
240
|
+
tool, so `npm run drift:check -- --specs` is quiet about zone settings
|
|
241
|
+
because nothing calls the endpoint, not because a maintainer signed off on
|
|
242
|
+
calling it anyway.
|
|
243
|
+
|
|
244
|
+
### Fixed
|
|
245
|
+
|
|
246
|
+
- **A search for a connector's own name stops claiming the deployment has no
|
|
247
|
+
such capability.** A connector's `id` — the address prefix an agent already
|
|
248
|
+
holds — and its `title` are displayed, never indexed, so `search_tools({
|
|
249
|
+
query: "inventory" })` against a connector called `inventory` matched no tool
|
|
250
|
+
and was answered with "No matching capability is configured in this
|
|
251
|
+
deployment", which was plainly false. Connector identity stays out of the
|
|
252
|
+
lexical index, because putting it in would move ranking for every query that
|
|
253
|
+
already matches tools; instead an unscoped miss whose terms name configured
|
|
254
|
+
connectors says so, names up to three of them by ID, and sends the caller to
|
|
255
|
+
a scoped browse. A term that matches nothing in the deployment still gets the
|
|
256
|
+
original sentence, unchanged. One `queryAnalysis.guidance` string differs; no
|
|
257
|
+
ranking, result, or field changed (#372).
|
|
258
|
+
- **Every relative link in the shipped Markdown resolves for the reader who
|
|
259
|
+
installed the package.** Ten of them pointed at `eval/`, `test/`, `scripts/`,
|
|
260
|
+
and the README hero — repository paths the tarball has never carried and, per
|
|
261
|
+
#346, should not start carrying. The link gate could not see any of them: it
|
|
262
|
+
read only `documentation/` targets, so the whole class was invisible and grew
|
|
263
|
+
with every trim. The policy is now stated once in the operations guide and
|
|
264
|
+
enforced over *every* relative link in packed Markdown: it either resolves
|
|
265
|
+
inside the tarball or it is cited as an absolute
|
|
266
|
+
`https://github.com/zackbart/connecta/blob/main/...` URL, which an outside
|
|
267
|
+
reader can follow and which `check:docs` resolves back to the checkout, so a
|
|
268
|
+
citation still fails when the file it names moves. The ten links were
|
|
269
|
+
rewritten that way, the README hero now loads from
|
|
270
|
+
`raw.githubusercontent.com` and still renders on npmjs.com, and the
|
|
271
|
+
repository reader loses no citation (#378).
|
|
272
|
+
- **`@zackbart/connecta/package.json` resolves.** The `exports` map listed
|
|
273
|
+
every code subpath and nothing else, so a bundler plugin, framework build
|
|
274
|
+
step, or version probe reaching for the installed manifest — a thing the
|
|
275
|
+
ecosystem broadly expects to work — got `ERR_PACKAGE_PATH_NOT_EXPORTED`
|
|
276
|
+
instead of the file. The manifest is now exported. It is a data file, so this
|
|
277
|
+
widens the published surface by exactly zero code paths: the root entry's
|
|
278
|
+
Workers purity boundary and the optional-peer subpaths are untouched. The
|
|
279
|
+
package-surface gate now asserts the whole subpath set, manifest included, so
|
|
280
|
+
neither this entry nor an unwanted one can arrive unnoticed (#374).
|
|
281
|
+
- **The published-surface rule says what it actually forbids.** `AGENTS.md`
|
|
282
|
+
claimed platform-specific storage adapters live in `examples/`, "not the
|
|
283
|
+
package", while the tarball has always carried `examples/worker` — Cloudflare
|
|
284
|
+
KV and D1 adapters included — because that example is the Workers starting
|
|
285
|
+
template a consumer copies. The invariant was never in danger: nothing under
|
|
286
|
+
`examples/` appears in the `exports` map, so those adapters are reference
|
|
287
|
+
source and not an importable subpath. The wording now draws the line where
|
|
288
|
+
the gates draw it — a platform-bound adapter must not reach `src/` or the
|
|
289
|
+
`exports` map — and says why the example ships, in `AGENTS.md`, the
|
|
290
|
+
operations guide, and the `scripts/check-package.mjs` comment. A new
|
|
291
|
+
assertion in `test/package-surface.test.ts` holds the instruction file and
|
|
292
|
+
the exports map to the same story (#377).
|
|
293
|
+
|
|
5
294
|
## 0.16.0 — 2026-08-12
|
|
6
295
|
|
|
7
296
|
This is the agent-efficiency refocus. One release, sixteen merges, and a single
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# connecta
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
5
|
One place for AI agents to connect to the tools you choose.
|
|
6
6
|
|
|
@@ -98,6 +98,11 @@ activity ship as commented configuration, each one a variable and an
|
|
|
98
98
|
uncommented block away. The generated `README.md` walks through all four, and
|
|
99
99
|
the [Worker example](./examples/worker/) does the same for KV and D1.
|
|
100
100
|
|
|
101
|
+
Already have a deployment on an older version? `init` deliberately refuses to
|
|
102
|
+
merge into it, so bringing one current is its own procedure:
|
|
103
|
+
[Upgrading an existing deployment](./documentation/upgrading.md) is the
|
|
104
|
+
runbook, written for the agent working inside that project.
|
|
105
|
+
|
|
101
106
|
The template refuses to merge into an existing directory, so initialization
|
|
102
107
|
cannot overwrite another project. Its generated programs have no filesystem,
|
|
103
108
|
environment, arbitrary network, imports, or timers; only explicitly read-only
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CallErrorDetails } from "./errors.js";
|
|
2
2
|
import type { ConnectorOperationOptions, RegistryView } from "./registry.js";
|
|
3
|
+
import type { DeferredWork } from "./connector-scope.js";
|
|
3
4
|
import type { Connector, ToolDef } from "./types.js";
|
|
4
5
|
export declare const DEFAULT_SEARCH_LIMIT = 8;
|
|
5
6
|
export declare const MAX_SEARCH_LIMIT = 100;
|
|
@@ -138,6 +139,7 @@ export declare class CatalogService {
|
|
|
138
139
|
private readonly probeTimeoutMs;
|
|
139
140
|
private readonly concurrency;
|
|
140
141
|
private readonly searchRoute;
|
|
142
|
+
private readonly readOptions;
|
|
141
143
|
private readonly loaded;
|
|
142
144
|
private readonly loading;
|
|
143
145
|
constructor(registry: RegistryView, baseUrl: string, options?: {
|
|
@@ -146,6 +148,8 @@ export declare class CatalogService {
|
|
|
146
148
|
concurrency?: number;
|
|
147
149
|
/** The discovery route recovery records name. Default `search_tools`. */
|
|
148
150
|
searchRoute?: SearchRoute;
|
|
151
|
+
/** Runtime-owned tail for stale-while-revalidate catalog reads. */
|
|
152
|
+
defer?: DeferredWork;
|
|
149
153
|
});
|
|
150
154
|
/**
|
|
151
155
|
* Send a caller back to discovery through the surface it can actually reach.
|
package/dist/catalog-service.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compactDiscoverySchema, compactSchema, lexicalCorpusStatistics, lexicalQueryTerms, lexicalSearchQuery, rankTools, schemaObjectKeys, summarizeDiscoveryDescription, summarizeDescription, } from "./catalog.js";
|
|
1
|
+
import { compactDiscoverySchema, compactSchema, lexicalCorpusStatistics, lexicalQueryTerms, lexicalSearchQuery, matchesLexicalTerm, rankTools, schemaObjectKeys, summarizeDiscoveryDescription, summarizeDescription, } from "./catalog.js";
|
|
2
2
|
import { mapSettledWithConcurrency, resolveDiscoveryConcurrency, } from "./concurrency.js";
|
|
3
3
|
import { boundedEchoText, classifyCallError, framingError, } from "./errors.js";
|
|
4
4
|
import { connectorGuide, connectorGuideRequired, connectorGuideSummary, connectorSkillName, } from "./skills.js";
|
|
@@ -10,6 +10,12 @@ export const MAX_DESCRIBE_ADDRESSES = 100;
|
|
|
10
10
|
export const MAX_DISCOVERY_RESULT_BYTES = 256_000;
|
|
11
11
|
const MAX_QUERY_TERMS = 8;
|
|
12
12
|
const MAX_QUERY_TERM_LENGTH = 64;
|
|
13
|
+
/**
|
|
14
|
+
* Connector IDs a no-match search will name back. Three is enough to point at
|
|
15
|
+
* the connector the query already named without turning a miss into a listing
|
|
16
|
+
* of the deployment.
|
|
17
|
+
*/
|
|
18
|
+
const MAX_IDENTITY_CONNECTORS = 3;
|
|
13
19
|
const encoder = new TextEncoder();
|
|
14
20
|
/** Clip one echoed query term without splitting a non-BMP code point. */
|
|
15
21
|
function boundedQueryTerm(term) {
|
|
@@ -161,6 +167,7 @@ export class CatalogService {
|
|
|
161
167
|
probeTimeoutMs;
|
|
162
168
|
concurrency;
|
|
163
169
|
searchRoute;
|
|
170
|
+
readOptions;
|
|
164
171
|
loaded = new Map();
|
|
165
172
|
loading = new Map();
|
|
166
173
|
constructor(registry, baseUrl, options = {}) {
|
|
@@ -171,6 +178,12 @@ export class CatalogService {
|
|
|
171
178
|
normalizeTimeoutMs(options.probeTimeoutMs) ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
172
179
|
this.concurrency = resolveDiscoveryConcurrency(options.concurrency);
|
|
173
180
|
this.searchRoute = options.searchRoute ?? "search_tools";
|
|
181
|
+
this.readOptions = options.defer
|
|
182
|
+
? {
|
|
183
|
+
defer: options.defer,
|
|
184
|
+
refreshTimeoutMs: this.probeTimeoutMs,
|
|
185
|
+
}
|
|
186
|
+
: undefined;
|
|
174
187
|
}
|
|
175
188
|
/**
|
|
176
189
|
* Send a caller back to discovery through the surface it can actually reach.
|
|
@@ -201,7 +214,7 @@ export class CatalogService {
|
|
|
201
214
|
if (inFlight)
|
|
202
215
|
return inFlight;
|
|
203
216
|
const loading = this.registry
|
|
204
|
-
.getTools(id, this.baseUrl, this.requestScope, callOptions)
|
|
217
|
+
.getTools(id, this.baseUrl, this.requestScope, callOptions, this.readOptions)
|
|
205
218
|
.then((tools) => {
|
|
206
219
|
this.loaded.set(id, tools);
|
|
207
220
|
return tools;
|
|
@@ -561,6 +574,36 @@ export class CatalogService {
|
|
|
561
574
|
required: connectorGuideRequired(scopedConnector),
|
|
562
575
|
}
|
|
563
576
|
: undefined;
|
|
577
|
+
// A connector's own id — the address prefix the caller already has — and
|
|
578
|
+
// the title it is displayed under are the most natural first query terms,
|
|
579
|
+
// and neither is a document in the lexical index. Indexing them would move
|
|
580
|
+
// ranking for every query that already matches tools, so instead a search
|
|
581
|
+
// that matched nothing asks the same lexical question of connector
|
|
582
|
+
// identity and corrects its own sentence: the deployment plainly has this
|
|
583
|
+
// capability, and one scoped browse away are its tools. Unscoped only —
|
|
584
|
+
// guidance for an explicit scope already names that connector rather than
|
|
585
|
+
// claiming the deployment has nothing.
|
|
586
|
+
const identityConnectorIds = matches.length === 0 && !isBrowse && !unsearchableQuery && !scopedConnector
|
|
587
|
+
? connectors
|
|
588
|
+
// The full query, not `analyzedTerms`: that cap exists to bound
|
|
589
|
+
// the serialized term fields, and ranking already reads every
|
|
590
|
+
// term. A ninth term is a real search term, and a search that
|
|
591
|
+
// ranked against it must not deny the connector it names.
|
|
592
|
+
.filter((connector) => queryTerms.some((term) => matchesLexicalTerm(connector.id, term) ||
|
|
593
|
+
(connector.title !== undefined &&
|
|
594
|
+
matchesLexicalTerm(connector.title, term))))
|
|
595
|
+
.map((connector) => connector.id)
|
|
596
|
+
: [];
|
|
597
|
+
const namedIdentityConnectors = identityConnectorIds
|
|
598
|
+
.slice(0, MAX_IDENTITY_CONNECTORS)
|
|
599
|
+
.map((id) => `"${id}"`)
|
|
600
|
+
.join(", ");
|
|
601
|
+
const unnamedIdentityConnectors = identityConnectorIds.length - MAX_IDENTITY_CONNECTORS;
|
|
602
|
+
const identityGuidance = identityConnectorIds.length === 0
|
|
603
|
+
? undefined
|
|
604
|
+
: `No matching ${safetyLabel}capability was found${unavailableCatalogs === 0 ? "" : " in the catalogs that answered"}, but the query names configured connector${identityConnectorIds.length === 1 ? "" : "s"} ${namedIdentityConnectors}${unnamedIdentityConnectors > 0
|
|
605
|
+
? ` and ${unnamedIdentityConnectors} more`
|
|
606
|
+
: ""}. Scope by connector and browse with an empty query to list the tools there.${filterRecovery}`;
|
|
564
607
|
// A scope that resolved to nothing is the same silence one step earlier in
|
|
565
608
|
// the lookup: no connector resolved, so no catalog was even attempted, so
|
|
566
609
|
// no catalog failed and the unavailable path below never fires. Echo only
|
|
@@ -604,9 +647,10 @@ export class CatalogService {
|
|
|
604
647
|
: scopedGuide?.required
|
|
605
648
|
? `No matching ${safetyLabel}capability was found on connector "${scopedConnector.id}". Fetch queryAnalysis.guide before calling, then refine terms or browse with an empty query.${filterRecovery}`
|
|
606
649
|
: `No matching ${safetyLabel}capability was found on connector "${scopedConnector.id}". Refine terms or browse it with an empty query.${filterRecovery}`
|
|
607
|
-
:
|
|
608
|
-
|
|
609
|
-
|
|
650
|
+
: (identityGuidance ??
|
|
651
|
+
(unavailableCatalogs === 0
|
|
652
|
+
? `No matching ${safetyLabel}capability is configured in this deployment. Refine terms, scope by connector, or browse with an empty query.${filterRecovery}`
|
|
653
|
+
: `No matching ${safetyLabel}capability was found in the catalogs that answered; ${unavailableCatalogs} connector catalog${unavailableCatalogs === 1 ? " was" : "s were"} unavailable. Refine terms, scope by connector, or browse with an empty query.${filterRecovery}`))))
|
|
610
654
|
: matchMode === "partial"
|
|
611
655
|
? scopedConnector
|
|
612
656
|
? `No single tool on connector "${scopedConnector.id}" matched every term. Split distinct intents into separate searches.`
|
package/dist/catalog.d.ts
CHANGED
|
@@ -18,6 +18,17 @@ export interface RankedTool {
|
|
|
18
18
|
exactName: boolean;
|
|
19
19
|
matchedTermCount: number;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Whether one query term matches a whole token of arbitrary text, under the
|
|
23
|
+
* same inflection rules the tool index uses.
|
|
24
|
+
*
|
|
25
|
+
* Connector identity — an `id` or a `title` — is deliberately not a document in
|
|
26
|
+
* that index: making it one would move ranking for every query that already
|
|
27
|
+
* matches tools. This lets a caller ask the index's question of a string that
|
|
28
|
+
* never became a document, which is what the no-match analysis needs to tell
|
|
29
|
+
* "nothing like this exists here" from "that word is a connector".
|
|
30
|
+
*/
|
|
31
|
+
export declare function matchesLexicalTerm(text: string, term: string): boolean;
|
|
21
32
|
export interface LexicalCorpusStatistics {
|
|
22
33
|
documentCount: number;
|
|
23
34
|
documentFrequency: ReadonlyMap<string, number>;
|