@zackbart/connecta 0.32.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +98 -0
- package/README.md +95 -116
- package/SECURITY.md +1 -1
- package/bin/connecta.mjs +24 -6
- package/bin/version.mjs +1 -1
- package/dist/access-tokens.d.ts +167 -23
- package/dist/access-tokens.js +676 -140
- package/dist/activity.d.ts +3 -0
- package/dist/agent-identity.js +47 -0
- package/dist/auth/cloudflare-access.js +13 -5
- package/dist/branding.d.ts +7 -0
- package/dist/branding.js +76 -9
- package/dist/call-admission-context.js +15 -0
- package/dist/call-admission.js +30 -43
- package/dist/call-recovery.js +6 -2
- package/dist/catalog-service.js +15 -1
- package/dist/config-value-sources.js +16 -9
- package/dist/config.d.ts +48 -75
- package/dist/config.js +144 -36
- package/dist/connector-access.d.ts +4 -34
- package/dist/connector-access.js +15 -99
- package/dist/connector-caller.d.ts +7 -1
- package/dist/connector-caller.js +4 -2
- package/dist/connectors/api-connector.d.ts +27 -4
- package/dist/connectors/api-connector.js +2 -0
- package/dist/connectors/remote-mcp.js +2 -0
- package/dist/describe-config.d.ts +31 -7
- package/dist/describe-config.js +8 -17
- package/dist/execute.js +1 -11
- package/dist/fix-prompt.js +2 -2
- package/dist/index.d.ts +4 -3
- package/dist/index.js +30 -10
- package/dist/invocation.js +5 -3
- package/dist/membership.d.ts +53 -0
- package/dist/membership.js +121 -0
- package/dist/module-contracts.d.ts +23 -6
- package/dist/oauth-callback-outcome.js +2 -2
- package/dist/operator-record.d.ts +2 -2
- package/dist/operator-record.js +2 -4
- package/dist/operator-ui/agents.d.ts +74 -0
- package/dist/operator-ui/agents.js +104 -0
- package/dist/operator-ui/config-summary.js +562 -0
- package/dist/operator-ui/connection-map.js +375 -0
- package/dist/operator-ui/contract.d.ts +149 -28
- package/dist/operator-ui/endpoints.js +221 -0
- package/dist/operator-ui/fix-prompts.js +5 -5
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/member-page.js +97 -0
- package/dist/operator-ui/model.d.ts +14 -6
- package/dist/operator-ui/overview.js +134 -0
- package/dist/operator-ui/view.d.ts +107 -37
- package/dist/operator-ui/view.js +163 -86
- package/dist/page-styles.js +5 -3
- package/dist/provider.d.ts +61 -8
- package/dist/provider.js +46 -7
- package/dist/providers/_shared/google/workspace.d.ts +56 -17
- package/dist/providers/_shared/google/workspace.js +34 -8
- package/dist/providers/_shared/rest/tools.js +2 -2
- package/dist/providers/_shared/rest/value-safety.d.ts +50 -0
- package/dist/providers/_shared/rest/value-safety.js +699 -7
- package/dist/providers/ccb/index.js +2 -2
- package/dist/providers/cloudflare/index.js +3 -3
- package/dist/providers/cloudflare/rest.js +25 -3
- package/dist/providers/cloudflare/skill.generated.js +1 -1
- package/dist/providers/cloudflare/value-safety.js +32 -0
- package/dist/providers/docs/index.js +4 -4
- package/dist/providers/docs/skill.generated.js +2 -2
- package/dist/providers/drive/index.js +4 -4
- package/dist/providers/drive/skill.generated.js +2 -2
- package/dist/providers/forms/index.js +4 -4
- package/dist/providers/forms/skill.generated.js +2 -2
- package/dist/providers/gmail/index.js +11 -9
- package/dist/providers/gmail/skill.generated.js +2 -2
- package/dist/providers/mixpanel/index.js +1 -1
- package/dist/providers/mixpanel/skill.generated.js +3 -3
- package/dist/providers/notion/index.d.ts +7 -0
- package/dist/providers/notion/index.js +100 -11
- package/dist/providers/notion/rest.js +45 -5
- package/dist/providers/notion/skill.generated.js +2 -2
- package/dist/providers/notion/value-safety.js +30 -5
- package/dist/providers/overflow/index.js +2 -2
- package/dist/providers/overflow/skill.generated.js +2 -2
- package/dist/providers/planning-center/index.js +2 -2
- package/dist/providers/planning-center/skill.generated.js +4 -4
- package/dist/providers/revenuecat/skill.generated.js +2 -2
- package/dist/providers/sheets/index.d.ts +3 -0
- package/dist/providers/sheets/index.js +7 -4
- package/dist/providers/sheets/skill.generated.js +2 -2
- package/dist/providers/slides/index.js +4 -4
- package/dist/providers/slides/skill.generated.js +2 -2
- package/dist/providers/stripe/rest.js +9 -2
- package/dist/providers/stripe/skill.generated.js +1 -1
- package/dist/providers/stripe/value-safety.js +22 -0
- package/dist/providers/tithely/index.js +1 -1
- package/dist/providers/vercel/index.js +1 -1
- package/dist/providers/vercel/rest.js +20 -2
- package/dist/providers/vercel/skill.generated.js +2 -2
- package/dist/providers/vercel/value-safety.js +22 -0
- package/dist/registry.d.ts +2 -3
- package/dist/registry.js +23 -9
- package/dist/routes/access-tokens.js +82 -75
- package/dist/routes/activity-disclosure.js +17 -18
- package/dist/routes/activity.js +34 -54
- package/dist/routes/actor-labels.js +33 -4
- package/dist/routes/agent-path.js +43 -0
- package/dist/routes/connect.js +16 -12
- package/dist/routes/credentials.js +16 -40
- package/dist/routes/mcp.js +161 -104
- package/dist/routes/oauth-management.js +11 -5
- package/dist/routes/oauth.js +5 -11
- package/dist/routes/operator.js +24 -23
- package/dist/routes/shared.d.ts +60 -20
- package/dist/routes/shared.js +187 -96
- package/dist/routes/ui-config.js +437 -97
- package/dist/routes/ui-data.js +2 -2
- package/dist/routes/ui.js +9 -16
- package/dist/runtime/call-admission.js +9 -0
- package/dist/server.js +5 -0
- package/dist/skills.js +10 -0
- package/dist/storage/keys.js +9 -1
- package/dist/storage/sql.js +5 -1
- package/dist/types.d.ts +29 -7
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +23 -16
- package/dist/usage-guide.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace-address.js +9 -0
- package/dist/workspace-subject.js +23 -0
- package/documentation/README.md +47 -23
- package/documentation/architecture.md +371 -61
- package/documentation/auth.md +897 -249
- package/documentation/code-mode.md +37 -16
- package/documentation/deploying.md +126 -25
- package/documentation/integrating.md +97 -23
- package/documentation/meta-tools.md +50 -31
- package/documentation/migration-0.33.md +352 -0
- package/documentation/migration-0.34.md +67 -0
- package/documentation/operating.md +3 -1
- package/documentation/operator-tests.md +147 -34
- package/documentation/operator-ui.md +519 -64
- package/documentation/provider-auth-migration.md +37 -23
- package/documentation/provider-migration-0.29.md +2 -2
- package/examples/worker/AGENTS.md +37 -9
- package/examples/worker/README.md +127 -61
- package/examples/worker/src/connecta.config.ts +40 -23
- package/examples/worker/wrangler.jsonc +4 -1
- package/package.json +19 -18
- package/templates/node/.env.example +3 -0
- package/templates/node/AGENTS.md +33 -6
- package/templates/node/Dockerfile +2 -2
- package/templates/node/README.md +80 -52
- package/templates/node/docker-compose.yml +3 -2
- package/templates/node/package.json +4 -3
- package/templates/node/src/adopt-token.ts +23 -0
- package/templates/node/src/connecta.config.ts +28 -12
- package/templates/node/src/rotate-token.ts +17 -0
- package/templates/node/src/provision-token.ts +0 -17
package/dist/routes/ui-data.js
CHANGED
|
@@ -137,8 +137,8 @@ export function uiData(registry, baseUrl, options) {
|
|
|
137
137
|
const fields = credentialFields();
|
|
138
138
|
return Effect.succeed({
|
|
139
139
|
...card,
|
|
140
|
-
...(fields?.length ? { fields } : {}),
|
|
141
|
-
configured:
|
|
140
|
+
...(fields?.length ? { fields: fields.map((field) => ({ ...field, configured: null })) } : {}),
|
|
141
|
+
configured: null,
|
|
142
142
|
removable: true,
|
|
143
143
|
testable: testRule.mode !== null,
|
|
144
144
|
error: "Stored credential could not be read.",
|
package/dist/routes/ui.js
CHANGED
|
@@ -9,7 +9,7 @@ import { CONNECTA_VERSION } from "../version.js";
|
|
|
9
9
|
import { CONNECTA_FAVICON_ICO } from "../favicon.js";
|
|
10
10
|
import { CONNECTA_FAVICON_SVG, operatorPageForPath, renderUiHtml } from "../ui.js";
|
|
11
11
|
import { authorized, refuse, scopeFor, serveOperator, visibleRegistry, } from "./operator.js";
|
|
12
|
-
import { mayManageConnector, privateJson } from "./shared.js";
|
|
12
|
+
import { managesAgentTokens, mayManageConnector, privateJson, readsActivity } from "./shared.js";
|
|
13
13
|
import { routeUiConfig } from "./ui-config.js";
|
|
14
14
|
import { uiData } from "./ui-data.js";
|
|
15
15
|
/**
|
|
@@ -84,7 +84,8 @@ export async function routeUi(context) {
|
|
|
84
84
|
? opts.config.auth.find((provider) => provider.uiAuth?.kind === "cloudflare-access")?.uiAuth
|
|
85
85
|
: undefined;
|
|
86
86
|
const uiAuth = ambient ??
|
|
87
|
-
opts.config.auth.find((provider) => provider.uiAuth && provider.uiAuth.kind !== "cloudflare-access")?.uiAuth
|
|
87
|
+
opts.config.auth.find((provider) => provider.uiAuth && provider.uiAuth.kind !== "cloudflare-access")?.uiAuth ??
|
|
88
|
+
opts.config.auth.find((provider) => provider.uiAuth?.kind === "cloudflare-access")?.uiAuth;
|
|
88
89
|
const mcpUrl = new URL("/mcp", baseUrl).toString();
|
|
89
90
|
const clerkOrigin = uiAuth?.kind === "clerk" && isSafeHttpsUrl(uiAuth.frontendApiUrl)
|
|
90
91
|
? new URL(uiAuth.frontendApiUrl).origin
|
|
@@ -115,14 +116,14 @@ function operatorView({ opts }, authz, registry) {
|
|
|
115
116
|
const visible = registry.listConnectors();
|
|
116
117
|
const mayManage = (id) => {
|
|
117
118
|
const connector = registry.getConnector(id);
|
|
118
|
-
return Boolean(connector && mayManageConnector(authz, connector));
|
|
119
|
+
return Boolean(connector && mayManageConnector(opts, authz, connector));
|
|
119
120
|
};
|
|
120
121
|
const permissions = (connector) => ({
|
|
121
122
|
use: true,
|
|
122
123
|
manageSharedAuth: connector.authScope !== "personal" && mayManage(connector.id),
|
|
123
124
|
connectPersonal: connector.authScope === "personal" && mayManage(connector.id),
|
|
124
125
|
});
|
|
125
|
-
const activityEnabled = Boolean(opts.config.activity?.store.list) && authz
|
|
126
|
+
const activityEnabled = Boolean(opts.config.activity?.store.list) && readsActivity(opts, authz);
|
|
126
127
|
const credentialManagement = visible.some((c) => c.credential && mayManage(c.id))
|
|
127
128
|
? opts.config.vault
|
|
128
129
|
? "available"
|
|
@@ -169,17 +170,9 @@ function summary(context) {
|
|
|
169
170
|
const authz = yield* authorized(context);
|
|
170
171
|
const registry = yield* visibleRegistry(context, authz);
|
|
171
172
|
const { visible, mayManage, permissions, activityEnabled, credentialManagement } = operatorView(context, authz, registry);
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
const pools = [];
|
|
176
|
-
for (const [name, pool] of opts.pools ?? []) {
|
|
177
|
-
const granted = yield* Effect.tryPromise(async () => (await pool.grant(authz.identity)) === true).pipe(
|
|
178
|
-
// A throwing grant is a refusal at the endpoint, and so a refusal here.
|
|
179
|
-
Effect.orElseSucceed(() => false));
|
|
180
|
-
if (granted)
|
|
181
|
-
pools.push(name);
|
|
182
|
-
}
|
|
173
|
+
// Only maintainers reach here (#837); setup commands are offered for every
|
|
174
|
+
// declared pool, since they administer them all.
|
|
175
|
+
const pools = [...opts.pools.keys()];
|
|
183
176
|
return privateJson({
|
|
184
177
|
...(pools.length ? { pools } : {}),
|
|
185
178
|
serverInfo: opts.config.serverInfo,
|
|
@@ -187,7 +180,7 @@ function summary(context) {
|
|
|
187
180
|
activityEnabled,
|
|
188
181
|
...(opts.config.accessTokens
|
|
189
182
|
? {
|
|
190
|
-
accessTokenManagement:
|
|
183
|
+
accessTokenManagement: managesAgentTokens(opts, authz) ? "available" : "requires_operator",
|
|
191
184
|
}
|
|
192
185
|
: {}),
|
|
193
186
|
credentialManagement,
|
|
@@ -12,6 +12,15 @@
|
|
|
12
12
|
// shared queue between them was refused.
|
|
13
13
|
import { Effect } from "effect";
|
|
14
14
|
let program;
|
|
15
|
+
const budgetCharges = new WeakMap();
|
|
16
|
+
/** Bind budget-only admission to the partition already owned by this permit. */
|
|
17
|
+
export function provideCallBudgetCharge(permit, charge) {
|
|
18
|
+
budgetCharges.set(permit, charge);
|
|
19
|
+
}
|
|
20
|
+
/** Charge an internal request without acquiring another concurrency permit. */
|
|
21
|
+
export function chargeCallBudget(permit, signal) {
|
|
22
|
+
return Effect.clockWith((clock) => budgetCharges.get(permit)?.(clock.currentTimeMillisUnsafe(), signal) ?? Effect.void);
|
|
23
|
+
}
|
|
15
24
|
// What the live Clock reads, looked up on every call rather than bound once,
|
|
16
25
|
// so a Date faked after a caller queued (vitest's setSystemTime) still counts.
|
|
17
26
|
const liveNow = () => Date.now();
|
package/dist/server.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { notFoundResponse } from "./branding.js";
|
|
3
3
|
import { aggregateCallAdmissionSnapshots } from "./call-admission.js";
|
|
4
4
|
import { isAdmittingExecutor } from "./executor-admission.js";
|
|
5
|
+
import { isAgentPath } from "./routes/agent-path.js";
|
|
5
6
|
import { createMcpRoute, MCP_CORS_HEADERS } from "./routes/mcp.js";
|
|
6
7
|
import { routeOAuthCallback } from "./routes/oauth.js";
|
|
7
8
|
import { routeOAuthClientMetadata } from "./routes/oauth-client-metadata.js";
|
|
@@ -59,6 +60,10 @@ export function createFetchHandler(opts) {
|
|
|
59
60
|
};
|
|
60
61
|
const route = (context) => Effect.gen(function* () {
|
|
61
62
|
const { request, path, baseUrl } = context;
|
|
63
|
+
// The agent namespace is routed before anything else, so no path
|
|
64
|
+
// Cloudflare Access bypasses as `/agent/*` can reach a human route.
|
|
65
|
+
if (isAgentPath(path))
|
|
66
|
+
return (yield* routeMcp.handle(context)) ?? notFoundResponse(request, opts.config);
|
|
62
67
|
const clientMetadata = routeOAuthClientMetadata(context);
|
|
63
68
|
if (clientMetadata)
|
|
64
69
|
return clientMetadata;
|
package/dist/skills.js
CHANGED
|
@@ -13,6 +13,16 @@ const RECOVERY = 'When an auth error includes a handoff, give it to the user or
|
|
|
13
13
|
* and describe and refuses every write call. Guides may still name them.
|
|
14
14
|
*/
|
|
15
15
|
export const CONNECTA_INSTRUCTIONS = `${ROUTE} On a writable endpoint, programs and call_destructive_tool may write. On a read-only endpoint, search omits write tools and every write call is refused; guides may still name them. The execute_code description says which this endpoint is. Never repeat a write to recover its output. ${RECOVERY}`;
|
|
16
|
+
/**
|
|
17
|
+
* The instructions one endpoint serves: {@link CONNECTA_INSTRUCTIONS}, then
|
|
18
|
+
* the admitted pool's `description` after a fixed lead-in. Plain `/mcp` and a
|
|
19
|
+
* pool without a description serve the constant unchanged. The description
|
|
20
|
+
* comes from deployment config for the pool the request was admitted through;
|
|
21
|
+
* nothing a request sends reaches it.
|
|
22
|
+
*/
|
|
23
|
+
export function endpointInstructions(description) {
|
|
24
|
+
return description === undefined ? CONNECTA_INSTRUCTIONS : `${CONNECTA_INSTRUCTIONS} This endpoint: ${description}`;
|
|
25
|
+
}
|
|
16
26
|
export { USAGE_SKILL } from "./usage-guide.js";
|
|
17
27
|
/** True when at least one of `connectors` carries a usage guide. */
|
|
18
28
|
export function hasConnectorGuides(connectors) {
|
package/dist/storage/keys.js
CHANGED
|
@@ -164,7 +164,12 @@ export const oauthHandoffKeys = {
|
|
|
164
164
|
},
|
|
165
165
|
handoff: (connectorId, stateHash) => validateStorageKey(`oauth-handoff:v1:${connectorId}:${stateHash}`),
|
|
166
166
|
};
|
|
167
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* Connecta-issued `cta_` access tokens: token records, digest lookups, one
|
|
169
|
+
* slot per declared agent naming its live record, and a never-deleted claim per
|
|
170
|
+
* legacy record an adoption has taken. `active` is the capacity
|
|
171
|
+
* ledger releases before 0.33 wrote; nothing writes it now.
|
|
172
|
+
*/
|
|
168
173
|
export const accessTokenKeys = {
|
|
169
174
|
family: {
|
|
170
175
|
name: "access-token",
|
|
@@ -178,6 +183,9 @@ export const accessTokenKeys = {
|
|
|
178
183
|
recordPrefix: "access-token:v1:record:",
|
|
179
184
|
record: (id) => validateStorageKey(`access-token:v1:record:${id}`),
|
|
180
185
|
lookup: (tokenHash) => validateStorageKey(`access-token:v1:lookup:${tokenHash}`),
|
|
186
|
+
agent: (name) => validateStorageKey(`access-token:v1:agent:${name}`),
|
|
187
|
+
/** Write-once claim that a legacy token record has been taken by one agent's adoption. */
|
|
188
|
+
adopted: (legacyRecordId) => validateStorageKey(`access-token:v1:adopted:${legacyRecordId}`),
|
|
181
189
|
active: "access-token:v1:active",
|
|
182
190
|
};
|
|
183
191
|
/**
|
package/dist/storage/sql.js
CHANGED
|
@@ -492,7 +492,11 @@ export function sqlActivityStore(driver, kind, options = {}) {
|
|
|
492
492
|
}
|
|
493
493
|
});
|
|
494
494
|
return {
|
|
495
|
-
describe: () => ({
|
|
495
|
+
describe: () => ({
|
|
496
|
+
kind,
|
|
497
|
+
retentionDays,
|
|
498
|
+
optionSources: { retentionDays: options.retentionDays === undefined ? "default" : "config" },
|
|
499
|
+
}),
|
|
496
500
|
async record(event) {
|
|
497
501
|
await ensure();
|
|
498
502
|
const occurredAtMs = Date.parse(event.occurredAt);
|
package/dist/types.d.ts
CHANGED
|
@@ -727,6 +727,11 @@ export type AuthResult = {
|
|
|
727
727
|
sessionCookies?: readonly string[];
|
|
728
728
|
/** Human owner represented by a non-interactive access credential. */
|
|
729
729
|
principal?: IdentityReference;
|
|
730
|
+
/**
|
|
731
|
+
* Declared agent name. Only the built-in `accessTokens()` adapter may
|
|
732
|
+
* set it; a result from any other provider that carries it is refused.
|
|
733
|
+
*/
|
|
734
|
+
agent?: string;
|
|
730
735
|
} | {
|
|
731
736
|
ok: false;
|
|
732
737
|
response: Response;
|
|
@@ -747,6 +752,12 @@ export interface AuthenticatedIdentity {
|
|
|
747
752
|
subject?: IdentityReference;
|
|
748
753
|
/** Human owner of personal connector authentication. */
|
|
749
754
|
principal?: IdentityReference;
|
|
755
|
+
/**
|
|
756
|
+
* Name of the code-declared agent this caller is, from `agents`. Set only
|
|
757
|
+
* when the built-in access-token adapter admitted a `cta_` token bound to
|
|
758
|
+
* a currently declared agent; an agent never has a `principal`.
|
|
759
|
+
*/
|
|
760
|
+
agent?: string;
|
|
750
761
|
interactive: boolean;
|
|
751
762
|
}
|
|
752
763
|
/** Public browser-auth configuration exposed to connecta's status UI. */
|
|
@@ -811,7 +822,7 @@ export interface ConnectaBranding {
|
|
|
811
822
|
description?: string;
|
|
812
823
|
/**
|
|
813
824
|
* Browser tab title and page meta name. Defaults to
|
|
814
|
-
* `"<productName>
|
|
825
|
+
* `"<productName> · <ownerName>"`, or just `productName` when no owner is set.
|
|
815
826
|
*/
|
|
816
827
|
pageTitle?: string;
|
|
817
828
|
/**
|
|
@@ -821,14 +832,18 @@ export interface ConnectaBranding {
|
|
|
821
832
|
* elsewhere (it replaces the `/favicon.svg` link in the page head; the
|
|
822
833
|
* `/favicon.*` routes still serve whatever `svg`/`ico` provide). `href` must
|
|
823
834
|
* be an absolute `http(s)` URL or a root-relative path; anything else falls
|
|
824
|
-
* back to the default mark.
|
|
835
|
+
* back to the default mark. With `svg` set, the top bar shows it beside the
|
|
836
|
+
* name; the drawn mark shows only when no branding is set.
|
|
825
837
|
*/
|
|
826
838
|
favicon?: {
|
|
827
839
|
svg?: string;
|
|
828
840
|
ico?: Uint8Array;
|
|
829
841
|
href?: string;
|
|
830
842
|
};
|
|
831
|
-
/**
|
|
843
|
+
/**
|
|
844
|
+
* `theme-color` meta value. Unset, pages follow the page background:
|
|
845
|
+
* `#f6f4ef` in light and `#12110f` in dark.
|
|
846
|
+
*/
|
|
832
847
|
themeColor?: string;
|
|
833
848
|
/**
|
|
834
849
|
* Operator-page appearance. Every field is optional, and a rejected value
|
|
@@ -849,18 +864,25 @@ export interface ConnectaBranding {
|
|
|
849
864
|
export interface ConnectaTheme {
|
|
850
865
|
/**
|
|
851
866
|
* The brand color: links, focus rings, primary actions, the active nav item.
|
|
852
|
-
* Hex only (`#rgb`, `#rrggbb`, or `#rrggbbaa`). Defaults to `#
|
|
867
|
+
* Hex only (`#rgb`, `#rrggbb`, or `#rrggbbaa`). Defaults to `#4c44e0`
|
|
868
|
+
* (`#8c86ff` in dark). Text on it and accent text in dark derive from it.
|
|
853
869
|
*/
|
|
854
870
|
accent?: string;
|
|
855
871
|
/**
|
|
856
872
|
* Corner rounding for cards, inputs, and buttons. A CSS length (`10px`,
|
|
857
873
|
* `0.5rem`) or a bare number read as pixels. `0` restores square corners.
|
|
858
|
-
* Defaults to `
|
|
874
|
+
* Defaults to `14px`.
|
|
859
875
|
*/
|
|
860
876
|
radius?: string | number;
|
|
861
|
-
/**
|
|
877
|
+
/**
|
|
878
|
+
* Body font stack. A plain CSS font-family list. Defaults to Hanken
|
|
879
|
+
* Grotesk, served with the operator UI, then a system stack.
|
|
880
|
+
*/
|
|
862
881
|
fontFamily?: string;
|
|
863
|
-
/**
|
|
882
|
+
/**
|
|
883
|
+
* Monospace font stack for addresses, ids, and the endpoint URL. Defaults
|
|
884
|
+
* to JetBrains Mono, served with the operator UI, then a system stack.
|
|
885
|
+
*/
|
|
864
886
|
monoFamily?: string;
|
|
865
887
|
/**
|
|
866
888
|
* `"system"` (the default) follows the operator's OS setting; `"light"` and
|
package/dist/ui.d.ts
CHANGED
|
@@ -49,4 +49,4 @@ _nonce?: string, page?: OperatorPage): string;
|
|
|
49
49
|
export declare function operatorUi(options?: {
|
|
50
50
|
branding?: ConnectaBranding;
|
|
51
51
|
}): OperatorSurface;
|
|
52
|
-
export type { OperatorUiContract,
|
|
52
|
+
export type { OperatorUiContract, OperatorUiContractV2, OperatorRole, OperatorMember, OperatorPoolV2, OperatorRootEndpoint, OperatorMemberConnector, OperatorMemberManage, OperatorAgent, OperatorSharedSource, OperatorRunsAs, OperatorConnectorPoolCell, OperatorConnectorOverlay, OperatorTool, OperatorGrant, OperatorLastCall, } from "./operator-ui/contract.js";
|
package/dist/ui.js
CHANGED
|
@@ -4,33 +4,34 @@ import { routeCredentials } from "./routes/credentials.js";
|
|
|
4
4
|
import { routeOAuthManagement } from "./routes/oauth-management.js";
|
|
5
5
|
import { uiData } from "./routes/ui-data.js";
|
|
6
6
|
import { runEdge } from "./runtime/run.js";
|
|
7
|
-
import { OPERATOR_UI_STYLE_PATH, OPERATOR_UI_SCRIPT_PATH, OPERATOR_UI_NOTICES_PATH } from "./operator-ui/generated.js";
|
|
7
|
+
import { OPERATOR_UI_STYLE_PATH, OPERATOR_UI_SCHEME_PATH, OPERATOR_UI_SCRIPT_PATH, OPERATOR_UI_NOTICES_PATH, } from "./operator-ui/generated.js";
|
|
8
8
|
export { filterUiConnectors, } from "./operator-ui/model.js";
|
|
9
|
-
import { escapeHtml, isSafeHttpsUrl, renderPage, resolveBranding } from "./branding.js";
|
|
9
|
+
import { brandMark, escapeHtml, isSafeHttpsUrl, renderPage, resolveBranding } from "./branding.js";
|
|
10
10
|
export { CONNECTA_FAVICON_SVG, resolveBranding, isSafeHttpUrl, isSafeHttpsUrl, isSafeIconHref } from "./branding.js";
|
|
11
11
|
const OPERATOR_PAGE_LABELS = {
|
|
12
12
|
overview: "Overview",
|
|
13
|
+
endpoints: "Endpoints",
|
|
13
14
|
connections: "Connectors",
|
|
14
15
|
connector: "Connector",
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
config: "Config",
|
|
18
|
-
tokens: "Access tokens",
|
|
16
|
+
settings: "Settings",
|
|
17
|
+
tokens: "Tokens",
|
|
19
18
|
activity: "Activity",
|
|
20
19
|
};
|
|
21
20
|
export function operatorPageForPath(path) {
|
|
22
21
|
if (path === "/")
|
|
23
22
|
return "overview";
|
|
23
|
+
if (path === "/endpoints")
|
|
24
|
+
return "endpoints";
|
|
24
25
|
if (path === "/connectors")
|
|
25
26
|
return "connections";
|
|
26
27
|
if (/^\/connectors\/[a-z0-9_-]+$/.test(path))
|
|
27
28
|
return "connector";
|
|
28
29
|
if (path === "/tools")
|
|
29
|
-
return "
|
|
30
|
+
return "connections";
|
|
30
31
|
if (path === "/access")
|
|
31
|
-
return "
|
|
32
|
-
if (path === "/config")
|
|
33
|
-
return "
|
|
32
|
+
return "endpoints";
|
|
33
|
+
if (path === "/config" || path === "/settings")
|
|
34
|
+
return "settings";
|
|
34
35
|
if (path === "/tokens")
|
|
35
36
|
return "tokens";
|
|
36
37
|
if (path === "/activity")
|
|
@@ -38,7 +39,7 @@ export function operatorPageForPath(path) {
|
|
|
38
39
|
return undefined;
|
|
39
40
|
}
|
|
40
41
|
export function operatorPageTitle(page, configuredTitle) {
|
|
41
|
-
return `${OPERATOR_PAGE_LABELS[page]}
|
|
42
|
+
return `${OPERATOR_PAGE_LABELS[page]} · ${configuredTitle}`;
|
|
42
43
|
}
|
|
43
44
|
/** Report the verdict the registry stored, independent of whether an endpoint is read-only. */
|
|
44
45
|
export function uiToolSafety(definition) {
|
|
@@ -101,7 +102,7 @@ function jsonForInlineScript(value) {
|
|
|
101
102
|
*/
|
|
102
103
|
export function renderUiHtml(uiAuth, mcpUrl = "/mcp", branding,
|
|
103
104
|
/** @deprecated Scripts load from same-origin assets; ignored. */
|
|
104
|
-
_nonce, page = "
|
|
105
|
+
_nonce, page = "endpoints") {
|
|
105
106
|
const clerk = uiAuth?.kind === "clerk" ? uiAuth : undefined;
|
|
106
107
|
// The Clerk loader's origin. A value that fails the gate is dropped rather
|
|
107
108
|
// than escaped into the page: the loader tag is simply not emitted, the gate
|
|
@@ -130,13 +131,15 @@ _nonce, page = "overview") {
|
|
|
130
131
|
: "";
|
|
131
132
|
// The shared layout owns the head, scheme, theme, and masthead; the shell
|
|
132
133
|
// adds its own bundle (which already imports the shared tokens), the nav
|
|
133
|
-
// mount, and the app.
|
|
134
|
+
// mount, and the app. The scheme initializer blocks, ahead of the
|
|
135
|
+
// stylesheet, so a saved color scheme holds from the first paint.
|
|
134
136
|
return renderPage(branding, {
|
|
135
137
|
title: operatorPageTitle(page, brand.pageTitle),
|
|
136
138
|
uiMounted: true,
|
|
137
139
|
operatorShell: true,
|
|
138
140
|
styles: "",
|
|
139
|
-
head: `<
|
|
141
|
+
head: `<script src="${OPERATOR_UI_SCHEME_PATH}"></script>` +
|
|
142
|
+
`<link rel="stylesheet" href="${OPERATOR_UI_STYLE_PATH}"><link rel="license" href="${OPERATOR_UI_NOTICES_PATH}">` +
|
|
140
143
|
clerkScript,
|
|
141
144
|
skipTo: { id: "operatorContent", label: "Skip to operator page" },
|
|
142
145
|
mastheadEnd: '<div id="operatorNav"></div>',
|
|
@@ -146,8 +149,8 @@ _nonce, page = "overview") {
|
|
|
146
149
|
<h1>${OPERATOR_PAGE_LABELS[page]}</h1>
|
|
147
150
|
<div class="lead-copy">
|
|
148
151
|
<p>${escapeHtml(brand.description)}</p>
|
|
149
|
-
<noscript><p class="msg">
|
|
150
|
-
|
|
152
|
+
<noscript><p class="msg">Operator pages need JavaScript. Agents connect at
|
|
153
|
+
<span class="mono">/mcp</span>.</p></noscript>
|
|
151
154
|
</div>
|
|
152
155
|
</div>
|
|
153
156
|
</main>
|
|
@@ -156,8 +159,10 @@ _nonce, page = "overview") {
|
|
|
156
159
|
auth,
|
|
157
160
|
mcpUrl,
|
|
158
161
|
initialPage: page,
|
|
162
|
+
schemePinned: brand.theme.colorScheme !== "system",
|
|
159
163
|
titleSuffix: brand.pageTitle,
|
|
160
164
|
productName: brand.productName,
|
|
165
|
+
brandMark: brandMark(branding, true),
|
|
161
166
|
productDescription: brand.description,
|
|
162
167
|
productOperatorLabel: brand.productName + " operator",
|
|
163
168
|
})}</script><script defer src="${OPERATOR_UI_SCRIPT_PATH}"></script>`,
|
|
@@ -181,11 +186,13 @@ export function operatorUi(options = {}) {
|
|
|
181
186
|
options = assertKnownOptions(options, "operatorUi()", OPERATOR_UI_OPTIONS);
|
|
182
187
|
const reservedPaths = [
|
|
183
188
|
"/",
|
|
189
|
+
"/endpoints",
|
|
184
190
|
"/connectors",
|
|
185
191
|
"/connectors/*",
|
|
186
192
|
"/tools",
|
|
187
193
|
"/access",
|
|
188
194
|
"/config",
|
|
195
|
+
"/settings",
|
|
189
196
|
"/ui",
|
|
190
197
|
"/ui/*",
|
|
191
198
|
"/favicon.svg",
|
package/dist/usage-guide.js
CHANGED
|
@@ -77,7 +77,7 @@ async () => {
|
|
|
77
77
|
|
|
78
78
|
Host-call budget exhaustion ends the run with budget_exceeded. Catch and
|
|
79
79
|
allSettled cannot recover it or return partial output. Bound batches before
|
|
80
|
-
starting them;
|
|
80
|
+
starting them; every guest call except emit spends host calls.
|
|
81
81
|
Split remaining reads. Never replay writes for their output.
|
|
82
82
|
|
|
83
83
|
## Per-connector guides
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CONNECTA_VERSION = "0.
|
|
1
|
+
export declare const CONNECTA_VERSION = "0.34.0";
|
package/dist/version.js
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// The one rule for a Google Workspace address, shared by the Workspace
|
|
2
|
+
// providers' fixed `subject` and a pool's `owner` (#837, decisions/0006), so
|
|
3
|
+
// config accepts exactly the addresses a delegated token can be minted for.
|
|
4
|
+
/** A plausible mailbox: one `@`, no whitespace or control characters. */
|
|
5
|
+
const ADDRESS = /^[^\s@<>()",;:\\[\]]+@[^\s@<>()",;:\\[\]]+\.[^\s@<>()",;:\\[\]]+$/;
|
|
6
|
+
/** Whether `value`, already trimmed, is a Workspace email address. */
|
|
7
|
+
export function isWorkspaceAddress(value) {
|
|
8
|
+
return typeof value === "string" && ADDRESS.test(value);
|
|
9
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Whose account a Google Workspace connector acts as, for the operator
|
|
2
|
+
// matrix (#837, decisions/0006). The Workspace providers tag the connector
|
|
3
|
+
// they build; nothing else can, and nothing a request sends reaches this.
|
|
4
|
+
// Read only by the operator contract, which never shows a mapping function.
|
|
5
|
+
const tagged = new WeakMap();
|
|
6
|
+
/** Tag a Workspace connector with its subject kind, returning it unchanged. */
|
|
7
|
+
export function tagWorkspaceSubject(connector, subject) {
|
|
8
|
+
tagged.set(connector, typeof subject === "string" ? { kind: "fixed", subject } : { kind: "mapping" });
|
|
9
|
+
return connector;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The subject kind of a tagged connector, or undefined for any other. Walks
|
|
13
|
+
* the prototype chain, since provider construction may wrap a connector it
|
|
14
|
+
* cannot restamp in an object that inherits from it.
|
|
15
|
+
*/
|
|
16
|
+
export function workspaceSubjectOf(connector) {
|
|
17
|
+
for (let current = connector; current; current = Object.getPrototypeOf(current)) {
|
|
18
|
+
const subject = tagged.get(current);
|
|
19
|
+
if (subject)
|
|
20
|
+
return subject;
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
package/documentation/README.md
CHANGED
|
@@ -1,34 +1,58 @@
|
|
|
1
1
|
# Agent documentation
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Start here when operating a deployment installed with `@zackbart/connecta`.
|
|
4
|
+
All operator procedures below are available in the installed package; paths in
|
|
5
|
+
this directory are relative to `node_modules/@zackbart/connecta/documentation/`.
|
|
6
|
+
For an existing endpoint, start with [Operating an endpoint](./operating.md).
|
|
7
|
+
For a new deployment, start with [Deploying Connecta](./deploying.md).
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
|
10
|
-
|
|
|
11
|
-
| Add
|
|
12
|
-
|
|
|
9
|
+
## Operator tasks
|
|
10
|
+
|
|
11
|
+
| Task | Self-contained procedure |
|
|
12
|
+
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
13
|
+
| Add or remove a connector | [Change the connector roster](./integrating.md#add-or-remove-a-connector) |
|
|
14
|
+
| Organize an agent's pools and tiers | [Organizing an agent's pools](./auth.md#organizing-an-agents-pools) |
|
|
15
|
+
| Add a person (maintainer or pool member) | [Add a person](./auth.md#add-a-person), [member page](./operator-ui.md#use-the-member-page) |
|
|
16
|
+
| Connect a shared credential | [Connect a shared credential](./auth.md#connect-a-shared-credential) |
|
|
17
|
+
| Issue, rotate, or revoke an agent token | [Manage an agent token](./auth.md#issue-rotate-or-revoke-an-agent-token) |
|
|
18
|
+
| Upgrade between versions | [Upgrade an existing deployment](./deploying.md#upgrade-an-existing-deployment), including [migration to 0.33](./migration-0.33.md) |
|
|
19
|
+
| Diagnose with `connecta doctor` | [Verify and diagnose](./deploying.md#verify-and-diagnose) |
|
|
20
|
+
|
|
21
|
+
## Audience rule
|
|
22
|
+
|
|
23
|
+
Shipped docs (`documentation/`, `templates/`, `examples/worker/`, and the root
|
|
24
|
+
`README.md`) are written first for an agent operating a deployment from the
|
|
25
|
+
installed package. Operator conventions must be self-contained rules plus a
|
|
26
|
+
neutral example. Decision records and issues explain why; no operator task
|
|
27
|
+
requires them, `spec/`, `.claude/`, or the Connecta source checkout. Those
|
|
28
|
+
three directories do not ship. Contributor source maps, INV citations, and
|
|
29
|
+
implementation/test evidence belong under clearly labeled contributor
|
|
30
|
+
headings and are optional for operators. Use `assistant`, `alice`, `bob`,
|
|
31
|
+
`crm`, `tickets`, `notes_alice`, and `alice@example.com` in examples; never
|
|
32
|
+
real deployment, client, person, or organization names. Maintained provider
|
|
33
|
+
product names stay.
|
|
13
34
|
|
|
14
35
|
## Contract reference
|
|
15
36
|
|
|
16
|
-
| Guide
|
|
17
|
-
|
|
|
18
|
-
| [Meta-tools](./meta-tools.md)
|
|
19
|
-
| [Code mode](./code-mode.md)
|
|
20
|
-
| [Auth](./auth.md)
|
|
21
|
-
| [Architecture](./architecture.md)
|
|
22
|
-
| [Operator UI](./operator-ui.md)
|
|
23
|
-
| [Operator UI tests](./operator-tests.md)
|
|
24
|
-
| [
|
|
25
|
-
| [Provider
|
|
37
|
+
| Guide | Owns |
|
|
38
|
+
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
39
|
+
| [Meta-tools](./meta-tools.md) | Six top-level tools, discovery, direct-call results, paging, skills, and recovery |
|
|
40
|
+
| [Code mode](./code-mode.md) | JavaScript guest API, executor requirements, output, retries, cancellation, limits, and writes |
|
|
41
|
+
| [Auth](./auth.md) | Inbound identity, maintainers, pools and members, agents, credential ownership, and downstream OAuth |
|
|
42
|
+
| [Architecture (contributor reference)](./architecture.md) | Request lifetimes, routes, storage, configuration, import boundaries, and Effect implementation |
|
|
43
|
+
| [Operator UI](./operator-ui.md) | Optional UI setup, scoped configuration and live-data contract, activity disclosure, and UI implementation |
|
|
44
|
+
| [Operator UI tests (contributor reference)](./operator-tests.md) | Browser state matrix, real-server flows, and snapshot maintenance |
|
|
45
|
+
| [Migration to 0.33](./migration-0.33.md) | Upgrade actions from 0.32 options to maintainers, members, agents, agent endpoints, and pool owners |
|
|
46
|
+
| [Provider migration for 0.29](./provider-migration-0.29.md) | Upgrade actions for Notion, Vercel, and Cloudflare; provider reconciliation tables supply exact name mappings |
|
|
47
|
+
| [Provider auth migration](./provider-auth-migration.md) | Upgrade actions when `auth` selects hosted MCP or Connecta's REST connector, Stripe and Vercel |
|
|
26
48
|
|
|
27
49
|
Each long contract starts with task routes. Follow those section links before
|
|
28
|
-
reading the whole guide.
|
|
29
|
-
|
|
50
|
+
reading the whole guide. Contributor references at the end are optional
|
|
51
|
+
implementation evidence.
|
|
52
|
+
|
|
53
|
+
## Contributor reference
|
|
30
54
|
|
|
31
|
-
|
|
55
|
+
### Documentation ownership
|
|
32
56
|
|
|
33
57
|
The root [README](../README.md) explains the product for people. It owns what
|
|
34
58
|
Connecta offers, how the pieces connect, deployment choices, and the setup
|
|
@@ -47,7 +71,7 @@ own scoped change procedures. Each [provider folder](https://github.com/zackbart
|
|
|
47
71
|
owns its maintained `SKILL.md`, options, tests, fixtures, and review data.
|
|
48
72
|
Use those details instead of copying provider catalogs into general guides.
|
|
49
73
|
The provider list in the human README is generated; preserve its marker pair
|
|
50
|
-
and run `
|
|
74
|
+
and run `pnpm run check:providers-generated` after edits.
|
|
51
75
|
|
|
52
76
|
When changing behavior, update its owning contract and task guide in the same
|
|
53
77
|
change. Check examples against current source and point to the tests that
|