@zackbart/connecta 0.24.4 → 0.26.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 (155) hide show
  1. package/AGENTS.md +43 -12
  2. package/CHANGELOG.md +524 -0
  3. package/README.md +32 -15
  4. package/SECURITY.md +6 -5
  5. package/bin/connecta.mjs +5 -1
  6. package/dist/activity.d.ts +10 -3
  7. package/dist/activity.js +10 -1
  8. package/dist/advertised-schema.js +53 -0
  9. package/dist/artifacts/connector.d.ts +55 -0
  10. package/dist/artifacts/connector.js +724 -0
  11. package/dist/artifacts/document.js +76 -0
  12. package/dist/artifacts/guide.js +140 -0
  13. package/dist/artifacts/html-scan.js +329 -0
  14. package/dist/artifacts/json.js +68 -0
  15. package/dist/artifacts/kv-store.d.ts +20 -0
  16. package/dist/artifacts/kv-store.js +140 -0
  17. package/dist/artifacts/markdown.js +449 -0
  18. package/dist/artifacts/module.d.ts +37 -0
  19. package/dist/artifacts/module.js +60 -0
  20. package/dist/artifacts/operations.d.ts +195 -0
  21. package/dist/artifacts/operations.js +944 -0
  22. package/dist/artifacts/refresh.d.ts +53 -0
  23. package/dist/artifacts/refresh.js +235 -0
  24. package/dist/artifacts/routes.js +194 -0
  25. package/dist/artifacts/types.d.ts +214 -0
  26. package/dist/artifacts/types.js +22 -0
  27. package/dist/artifacts/validate.d.ts +62 -0
  28. package/dist/artifacts/validate.js +652 -0
  29. package/dist/artifacts.d.ts +6 -0
  30. package/dist/artifacts.js +9 -0
  31. package/dist/auth/downstream-oauth.js +490 -106
  32. package/dist/call-admission.js +139 -113
  33. package/dist/catalog-service.js +152 -106
  34. package/dist/catalog.js +297 -38
  35. package/dist/concurrency.js +24 -23
  36. package/dist/connector-access.d.ts +18 -4
  37. package/dist/connector-access.js +65 -20
  38. package/dist/connector-caller.d.ts +8 -0
  39. package/dist/connector-caller.js +19 -0
  40. package/dist/connector-scope.js +6 -37
  41. package/dist/connectors/api.d.ts +2 -2
  42. package/dist/connectors/remote-mcp.d.ts +6 -5
  43. package/dist/connectors/remote-mcp.js +330 -240
  44. package/dist/credential-contract.d.ts +9 -0
  45. package/dist/credential-rules.js +2 -2
  46. package/dist/credentials.d.ts +6 -1
  47. package/dist/credentials.js +45 -3
  48. package/dist/errors.d.ts +16 -1
  49. package/dist/errors.js +28 -0
  50. package/dist/execute.js +745 -282
  51. package/dist/executor-admission.d.ts +11 -1
  52. package/dist/executor-admission.js +145 -63
  53. package/dist/executors/quickjs-runtime.js +4 -2
  54. package/dist/executors/quickjs.js +255 -212
  55. package/dist/fix-prompt.js +37 -0
  56. package/dist/index.d.ts +72 -7
  57. package/dist/index.js +281 -26
  58. package/dist/invocation.js +371 -286
  59. package/dist/meta-tools.js +213 -94
  60. package/dist/module-contracts.d.ts +21 -1
  61. package/dist/oauth-callback-outcome.js +94 -0
  62. package/dist/oauth-sealing.js +29 -0
  63. package/dist/operator-ui/fix-prompts.js +87 -0
  64. package/dist/operator-ui/generated.js +2 -2
  65. package/dist/operator-ui/model.d.ts +103 -1
  66. package/dist/operator-ui/setup-commands.js +53 -0
  67. package/dist/operator-ui/view.js +128 -3
  68. package/dist/program-source.js +321 -0
  69. package/dist/providers/notion.js +2 -2
  70. package/dist/providers/revenuecat.js +32 -5
  71. package/dist/providers/stripe.d.ts +3 -2
  72. package/dist/providers/vercel.js +1 -1
  73. package/dist/registry.d.ts +43 -7
  74. package/dist/registry.js +434 -288
  75. package/dist/resumable.js +1291 -0
  76. package/dist/routes/activity.js +74 -154
  77. package/dist/routes/actor-labels.js +114 -0
  78. package/dist/routes/credentials.js +196 -163
  79. package/dist/routes/mcp.js +228 -112
  80. package/dist/routes/oauth-management.js +73 -71
  81. package/dist/routes/oauth.js +44 -16
  82. package/dist/routes/operator.js +83 -0
  83. package/dist/routes/shared.d.ts +25 -1
  84. package/dist/routes/shared.js +20 -2
  85. package/dist/routes/ui-data.js +211 -0
  86. package/dist/routes/ui.js +76 -35
  87. package/dist/run-journal.js +347 -0
  88. package/dist/runtime/admission.js +43 -0
  89. package/dist/runtime/call-admission.js +67 -0
  90. package/dist/runtime/connector-scope.js +72 -0
  91. package/dist/runtime/run.js +174 -0
  92. package/dist/runtime/services.js +130 -0
  93. package/dist/runtime/shared-read.js +106 -0
  94. package/dist/runtime/storage.js +66 -0
  95. package/dist/server.js +137 -89
  96. package/dist/skills.js +28 -9
  97. package/dist/storage/file.js +39 -2
  98. package/dist/storage/memory.js +28 -16
  99. package/dist/timeout.js +39 -43
  100. package/dist/tool-safety.d.ts +27 -1
  101. package/dist/tool-safety.js +31 -0
  102. package/dist/types.d.ts +45 -7
  103. package/dist/ui.d.ts +25 -4
  104. package/dist/ui.js +77 -167
  105. package/dist/url-safety.js +157 -0
  106. package/dist/version.d.ts +1 -1
  107. package/dist/version.js +1 -1
  108. package/documentation/architecture.md +367 -16
  109. package/documentation/auth.md +163 -2
  110. package/documentation/code-mode.md +274 -56
  111. package/documentation/meta-tools.md +200 -44
  112. package/ethos.md +46 -47
  113. package/examples/worker/AGENTS.md +6 -0
  114. package/examples/worker/README.md +224 -14
  115. package/examples/worker/src/d1-activity-row.ts +14 -2
  116. package/examples/worker/src/d1-activity.ts +4 -2
  117. package/examples/worker/src/d1-storage.ts +116 -0
  118. package/examples/worker/src/index.ts +42 -7
  119. package/examples/worker/src/r2-artifact-blobs.ts +29 -0
  120. package/examples/worker/wrangler.jsonc +21 -5
  121. package/package.json +16 -4
  122. package/templates/node/AGENTS.md +9 -2
  123. package/templates/node/README.md +31 -3
  124. package/templates/node/package.json +1 -1
  125. package/templates/node/src/index.ts +27 -0
  126. package/dist/auth/downstream-oauth.d.ts +0 -200
  127. package/dist/catalog-fingerprint.d.ts +0 -19
  128. package/dist/catalog-limits.d.ts +0 -9
  129. package/dist/catalog-service.d.ts +0 -263
  130. package/dist/catalog.d.ts +0 -87
  131. package/dist/concurrency.d.ts +0 -3
  132. package/dist/connectors/guarded-fetch.d.ts +0 -96
  133. package/dist/credential-rules.d.ts +0 -85
  134. package/dist/execute.d.ts +0 -154
  135. package/dist/executor-result.d.ts +0 -10
  136. package/dist/executors/quickjs-child.d.ts +0 -1
  137. package/dist/executors/quickjs-protocol.d.ts +0 -67
  138. package/dist/favicon.d.ts +0 -1
  139. package/dist/identity.d.ts +0 -4
  140. package/dist/invocation.d.ts +0 -74
  141. package/dist/mcp-result.d.ts +0 -8
  142. package/dist/meta-tools.d.ts +0 -129
  143. package/dist/operator-ui/generated.d.ts +0 -2
  144. package/dist/operator-ui/view.d.ts +0 -188
  145. package/dist/result-shapes.d.ts +0 -13
  146. package/dist/retired-toolkits.d.ts +0 -2
  147. package/dist/routes/activity.d.ts +0 -2
  148. package/dist/routes/credentials.d.ts +0 -2
  149. package/dist/routes/mcp.d.ts +0 -10
  150. package/dist/routes/oauth-management.d.ts +0 -2
  151. package/dist/routes/oauth.d.ts +0 -2
  152. package/dist/routes/ui.d.ts +0 -2
  153. package/dist/server.d.ts +0 -9
  154. package/dist/skills.d.ts +0 -44
  155. package/dist/timeout.d.ts +0 -21
package/README.md CHANGED
@@ -10,16 +10,19 @@ writing code instead of loading a thousand tool definitions.
10
10
  You ask your agent a question that touches a service — Linear, Stripe, an
11
11
  internal API, anything you have connected. Here is what happens:
12
12
 
13
- 1. The agent talks to one endpoint, yours, and sees seven tools. Always seven,
13
+ 1. The agent talks to one endpoint, yours, and sees eight tools. Always eight,
14
14
  no matter how many services sit behind it.
15
15
  2. It writes a short JavaScript program. Connecta runs it in a sandbox next to
16
16
  your integrations. The program can search for tools, call them, chain the
17
17
  calls, and shape the result.
18
18
  3. Only the answer comes back into the agent's context — not raw pages of
19
19
  API output.
20
- 4. If the agent wants to change something — create, update, delete — it
21
- cannot do that from a program. It makes one explicit call, and your MCP
22
- client can put that call in front of you first.
20
+ 4. If the program wants to change something — create, update, delete — it
21
+ stops right there, before anything is sent, and hands the agent the exact
22
+ write. The agent repeats it through `resume_execution`, which your MCP
23
+ client can put in front of you first. Approve it and the program picks up
24
+ where it stopped, without re-reading what it already read. A single write
25
+ can also go straight through `call_destructive_tool`.
23
26
 
24
27
  Credentials never leave the server. The program never sees them, and neither
25
28
  does the agent.
@@ -28,9 +31,9 @@ does the agent.
28
31
  flowchart TB
29
32
  Client["Your MCP client<br/>Claude, Cursor, …"]
30
33
 
31
- subgraph Connecta["Connecta — one endpoint, seven tools, your credentials"]
32
- Sandbox["execute_code<br/>the agent's program runs here<br/>read-only tools only"]
33
- Explicit["call_destructive_tool<br/>one visible call per write<br/>your client can ask you first"]
34
+ subgraph Connecta["Connecta — one endpoint, eight tools, your credentials"]
35
+ Sandbox["execute_code<br/>the agent's program runs here<br/>reads run, writes pause"]
36
+ Explicit["resume_execution · call_destructive_tool<br/>the exact write, visible<br/>your client can ask you first"]
34
37
  end
35
38
 
36
39
  Integrations["The integrations you chose<br/>Linear · Stripe · Notion · Vercel · your HTTP API · any MCP server"]
@@ -38,6 +41,7 @@ flowchart TB
38
41
  Client -->|"one connection"| Sandbox
39
42
  Client --> Explicit
40
43
  Sandbox -->|"reads"| Integrations
44
+ Sandbox -.->|"paused write"| Explicit
41
45
  Explicit -->|"writes"| Integrations
42
46
  ```
43
47
 
@@ -73,22 +77,35 @@ Fifty issues in, one small object out. Your context window notices.
73
77
  retain field names and broad types in bounded runtime memory, never scalar
74
78
  values, so later programs can project a remote MCP result its provider never
75
79
  documented.
76
- - **Keep writes deliberate.** Only tools marked read-only run in a program.
77
- Everything else is a separate, visible call your client can gate.
78
- - **Run it where you like.** Node, a Docker container, or a Cloudflare Worker,
79
- from the same small deployment file.
80
+ - **Keep large results usable.** Oversized direct calls return a bounded
81
+ preview with a handle for paging through the rest. For read-only work, the
82
+ notice also points the agent to reduce or search the result inside a
83
+ program. Discovery can show compact schemas, exact JSON Schema, or a
84
+ TypeScript signature to read while writing JavaScript.
85
+ - **Keep writes deliberate.** Only tools marked read-only run in a program
86
+ unasked. Any other call pauses the program with the exact write, and it
87
+ runs only once `resume_execution` repeats it — a visible call your client
88
+ can gate. A paused run is a journal in storage, not a held program, so it
89
+ survives a restart; it expires, and a write whose outcome is unknown is
90
+ never sent twice. Config — and only config — can exempt a cheap,
91
+ reversible write from asking, per tool or per connector.
92
+ - **Run it on Node or Cloudflare Workers.** The core is shared; each deployment
93
+ supplies its platform's executor and storage. The Node template also runs
94
+ unchanged in Docker.
80
95
 
81
96
  Deployments explicitly compose optional features: `operatorUi()` from
82
97
  `@zackbart/connecta/ui`, `encryptedCredentialVault()` from `/credentials`,
83
- `activityHistory()` from `/activity`, and inbound authentication adapters from
84
- `/auth/*`. Omit a module and its implementation does no runtime work. Core
98
+ `activityHistory()` from `/activity`, `artifacts()` from `/artifacts`, and
99
+ inbound authentication adapters from `/auth/*`. Omit a module and its implementation does no runtime work. Core
85
100
  keeps connector discovery, execution, invocation, and enforcement together.
86
101
 
87
102
  The optional UI shows each person's connections and effective permissions.
88
103
  Authentication controls live inside each connection, with optional activity
89
104
  history. The configured connection list loads before downstream checks finish;
90
105
  a slow provider does not hold up the page. Connector selection and access rules
91
- remain in deployment code.
106
+ remain in deployment code. It also explains which tools can run in programs or
107
+ need approval, offers a fixed repair prompt for classified failures, and shows
108
+ client setup commands for the endpoints the signed-in person can use.
92
109
 
93
110
  One deployment may serve several authenticated people inside the same tenant.
94
111
  Cloudflare Access supplies Worker identity; Node can use Clerk or the optional
@@ -105,7 +122,7 @@ and why.
105
122
 
106
123
  Setup is written for an agent. Point yours at [`AGENTS.md`](./AGENTS.md) and
107
124
  ask it to set up a Connecta deployment; the
108
- [documentation](./documentation/) covers the architecture, the seven tools,
125
+ [documentation](./documentation/) covers the architecture, the eight tools,
109
126
  code mode, and inbound auth if you want to go deeper. When upgrading an
110
127
  existing deployment, each [changelog](./CHANGELOG.md) release opens with what
111
128
  breaks and what a deployment can ignore.
package/SECURITY.md CHANGED
@@ -16,8 +16,9 @@ CI blocks moderate, high, and critical production dependency advisories. Lower
16
16
  findings are reviewed for reachability and recorded when an upstream package has
17
17
  not yet released a compatible fix.
18
18
 
19
- The MCP TypeScript SDK 2.x packages are exact-pinned. The split client and
20
- server packages no longer install Hono or `@hono/node-server`, so the temporary
21
- root-project override used with SDK 1.x is gone. A dependency bump must pass
22
- both `npm run release:check` and the Node/Workers runtime suites before the pin
23
- moves.
19
+ The MCP TypeScript SDK 2.x packages and Effect are exact-pinned. Effect is the
20
+ runtime core, and its unstable modules can break in a minor release, so its pin
21
+ moves in a dedicated upgrade. The split client and server packages no longer
22
+ install Hono or `@hono/node-server`, so the temporary root-project override
23
+ used with SDK 1.x is gone. A dependency bump must pass `npm run release:check`
24
+ and the Node/Workers runtime suites before a pin moves.
package/bin/connecta.mjs CHANGED
@@ -249,6 +249,7 @@ async function doctor() {
249
249
  "call_tool",
250
250
  "execute_code",
251
251
  "get_result",
252
+ "resume_execution",
252
253
  "search_tools",
253
254
  "skills",
254
255
  ];
@@ -301,7 +302,10 @@ async function doctor() {
301
302
  console.log(
302
303
  `Connecta doctor passed: ${health.connectors} connector(s), ` +
303
304
  `${executorName ? `${executorName} executed` : "code executed"}, ` +
304
- "prescribed seven-tool surface" +
305
+ "prescribed eight-tool surface" +
306
+ // resume_execution is listed either way; whether programs can write is
307
+ // what an operator cannot tell from the tool list, so say when not.
308
+ (health.resumableWrites === false ? ", resumable writes off" : "") +
305
309
  (drifted.length > 0
306
310
  ? `, catalog drift on ${drifted.length} connector(s).`
307
311
  : "."),
@@ -1,7 +1,9 @@
1
1
  import type { ActivityModule } from "./module-contracts.js";
2
2
  import type { CatalogDriftCounts, Logger } from "./types.js";
3
- export type ActivityCallSource = "call_tool" | "call_destructive_tool" | "batch_call" | "execute_code";
4
- export type ActivityOutcome = "success" | "error" | "timeout" | "cancelled";
3
+ export type ActivityCallSource = "call_tool" | "call_destructive_tool" | "batch_call" | "execute_code" | "resume_execution";
4
+ export type ActivityOutcome = "success" | "error" | "timeout" | "cancelled" | "paused" | "approved";
5
+ /** How much one `resume_execution` approved: this call, or this tool for the run. */
6
+ export type ActivityApproval = "call" | "tool";
5
7
  export type AgentFriction = "tool_not_found" | "schema_retry" | "destructive_reroute" | "auth_required" | "result_too_large";
6
8
  export { agentFrictionForCode } from "./activity-friction.js";
7
9
  /**
@@ -47,6 +49,11 @@ export interface ToolCallActivityEvent {
47
49
  * agent while remaining an `outcome: "success"` call with no error code.
48
50
  */
49
51
  friction?: AgentFriction;
52
+ /**
53
+ * Set only on an `approved` event: the scope the approval covered. An enum,
54
+ * like everything else here — the approved arguments are never recorded.
55
+ */
56
+ approval?: ActivityApproval;
50
57
  serverName: string;
51
58
  serverVersion: string;
52
59
  deploymentId?: string;
@@ -142,7 +149,7 @@ export interface ActivityRequestContext {
142
149
  defer?: (promise: Promise<unknown>) => void;
143
150
  logger: Logger;
144
151
  }
145
- export type ActivityEventInput = Pick<ToolCallActivityEvent, "connectorId" | "toolName" | "address" | "source" | "outcome" | "durationMs" | "attempts" | "errorCode" | "friction">;
152
+ export type ActivityEventInput = Pick<ToolCallActivityEvent, "connectorId" | "toolName" | "address" | "source" | "outcome" | "durationMs" | "attempts" | "errorCode" | "friction" | "approval">;
146
153
  /**
147
154
  * Best-effort by design: activity storage can never change a tool result.
148
155
  * Workers attach async sinks to waitUntil; synchronous sinks such as Analytics
package/dist/activity.js CHANGED
@@ -49,9 +49,18 @@ export function recordToolActivity(context, input) {
49
49
  source: input.source,
50
50
  outcome: input.outcome,
51
51
  durationMs: Math.max(0, Math.trunc(input.durationMs)),
52
- attempts: Math.max(1, Math.trunc(input.attempts)),
52
+ // A pause and an approval reach nothing downstream, so they are the two
53
+ // events that honestly carry zero attempts. Every other outcome keeps its
54
+ // floor of one, as it always has.
55
+ attempts: input.outcome === "paused" || input.outcome === "approved"
56
+ ? 0
57
+ : Math.max(1, Math.trunc(input.attempts)),
53
58
  ...(input.errorCode ? { errorCode: input.errorCode } : {}),
54
59
  ...(friction ? { friction } : {}),
60
+ ...(input.outcome === "approved" &&
61
+ (input.approval === "call" || input.approval === "tool")
62
+ ? { approval: input.approval }
63
+ : {}),
55
64
  serverName: context.serverInfo.name,
56
65
  serverVersion: context.serverInfo.version,
57
66
  ...(context.deploymentId
@@ -0,0 +1,53 @@
1
+ function deepFreeze(value) {
2
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
3
+ Object.freeze(value);
4
+ for (const child of Object.values(value))
5
+ deepFreeze(child);
6
+ }
7
+ return value;
8
+ }
9
+ /**
10
+ * A meta-tool input schema whose JSON Schema rendering is derived once per
11
+ * process, not once per request.
12
+ *
13
+ * Every `/mcp` request builds a fresh `McpServer` (stateless per request), and
14
+ * the SDK renders each registered tool's input schema through
15
+ * `~standard.jsonSchema` at registration and again for `tools/list`. Zod
16
+ * re-walks the whole schema on every one of those calls, which made the
17
+ * rendering most of a `tools/list` request's CPU. The schemas themselves are
18
+ * module constants — no deployment option, identity, or scoped view reaches
19
+ * them; what does vary (descriptions) is a string computed per registration
20
+ * and never passes through here — so the rendering is immutable data that can
21
+ * outlive a request without being request-bound.
22
+ *
23
+ * This is the SDK's own `StandardSchemaWithJSON` contract, not a patch of it:
24
+ * validation delegates to zod unchanged, so a tool call is checked exactly as
25
+ * before, and the JSON Schema is zod's own output for the same target,
26
+ * memoized and deep-frozen so no request can alter what the next one sees.
27
+ * Conversions with library options are passed through uncached; nothing in
28
+ * the SDK sends them.
29
+ */
30
+ export function advertisedSchema(schema) {
31
+ const standard = schema["~standard"];
32
+ const rendered = new Map();
33
+ const convert = (io) => (options) => {
34
+ if (options.libraryOptions !== undefined) {
35
+ return standard.jsonSchema[io](options);
36
+ }
37
+ const key = `${io}:${options.target}`;
38
+ let json = rendered.get(key);
39
+ if (json === undefined) {
40
+ json = deepFreeze(standard.jsonSchema[io](options));
41
+ rendered.set(key, json);
42
+ }
43
+ return json;
44
+ };
45
+ return {
46
+ "~standard": {
47
+ version: 1,
48
+ vendor: standard.vendor,
49
+ validate: (value) => standard.validate(value),
50
+ jsonSchema: { input: convert("input"), output: convert("output") },
51
+ },
52
+ };
53
+ }
@@ -0,0 +1,55 @@
1
+ import type { Connector } from "../types.js";
2
+ import { type ArtifactOperations } from "./operations.js";
3
+ import { type ArtifactRefreshService } from "./refresh.js";
4
+ import type { ArtifactAllowlist, ArtifactIssue, ArtifactKind, ArtifactLimits } from "./types.js";
5
+ /** What a deployment's render check is handed: exactly what the viewer loads. */
6
+ export interface ArtifactRenderCheckInput {
7
+ /** The complete frame document, data injected. */
8
+ document: string;
9
+ /** The Content-Security-Policy the viewer serves it under. */
10
+ csp: string;
11
+ kind: ArtifactKind;
12
+ /** Aborted when the check's 20-second deadline or the call's own passes. */
13
+ signal: AbortSignal;
14
+ }
15
+ export type ArtifactRenderCheckResult = {
16
+ ok: true;
17
+ warnings?: string[];
18
+ } | {
19
+ ok: false;
20
+ errors: string[];
21
+ };
22
+ /**
23
+ * A real render check — a headless browser, say — run on `validate_artifact`
24
+ * and on every write that changes what a page renders. It must answer within
25
+ * 20 seconds; a throw or a timeout fails the write as retryable `unavailable`
26
+ * and saves nothing.
27
+ */
28
+ export type ArtifactRenderCheck = (input: ArtifactRenderCheckInput) => Promise<ArtifactRenderCheckResult>;
29
+ type RenderVerdict = {
30
+ ok: true;
31
+ warnings: ArtifactIssue[];
32
+ } | {
33
+ ok: false;
34
+ errors: ArtifactIssue[];
35
+ } | {
36
+ ok: false;
37
+ unavailable: string;
38
+ };
39
+ /** Run a hook under its 20-second deadline and the call's own signal. Never throws. */
40
+ export declare function runRenderCheck(hook: ArtifactRenderCheck, input: {
41
+ document: string;
42
+ csp: string;
43
+ kind: ArtifactKind;
44
+ }, callSignal: AbortSignal | undefined): Promise<RenderVerdict>;
45
+ export interface ArtifactsConnectorOptions {
46
+ operations: ArtifactOperations;
47
+ refresh: ArtifactRefreshService;
48
+ allowlist: ArtifactAllowlist;
49
+ limits: ArtifactLimits;
50
+ renderCheck?: ArtifactRenderCheck;
51
+ /** Where pages are served, when not the deployment's own origin. */
52
+ origin?: string;
53
+ }
54
+ export declare function artifactsConnector(options: ArtifactsConnectorOptions): Connector;
55
+ export {};