@tangle-network/agent-runtime 0.349.0 → 0.352.1
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/dist/{activation-wBipBkCf.d.ts → activation-BidzGkUQ.d.ts} +2 -24
- package/dist/{activation-tNGW73Y9.js → activation-C6zNC2kx.js} +12 -14
- package/dist/{activation-tNGW73Y9.js.map → activation-C6zNC2kx.js.map} +1 -1
- package/dist/agent.d.ts +8 -12
- package/dist/agent.js +9 -12
- package/dist/agent.js.map +1 -1
- package/dist/{analyst-loop-DZw5QWT9.js → analyst-loop-BZvXCDKy.js} +2 -3
- package/dist/{analyst-loop-DZw5QWT9.js.map → analyst-loop-BZvXCDKy.js.map} +1 -1
- package/dist/analyst-loop.d.ts +3 -5
- package/dist/analyst-loop.js +1 -2
- package/dist/{bundle-1xaJEgjq.js → bundle-DeDkJbsr.js} +3 -4
- package/dist/{bundle-1xaJEgjq.js.map → bundle-DeDkJbsr.js.map} +1 -1
- package/dist/candidate-execution/index.d.ts +13 -33
- package/dist/candidate-execution/index.js +16 -18
- package/dist/candidate-execution/index.js.map +1 -1
- package/dist/chat-turn.d.ts +2 -0
- package/dist/chat-turn.js +1 -0
- package/dist/{coordination-manager-B2Z_MmL9.js → coordination-manager-B7QadgrI.js} +101 -132
- package/dist/{coordination-manager-B2Z_MmL9.js.map → coordination-manager-B7QadgrI.js.map} +1 -1
- package/dist/{delegate-Dr-63jFl.js → delegate-CoscoyEo.js} +19 -21
- package/dist/delegate-CoscoyEo.js.map +1 -0
- package/dist/durable.d.ts +16 -149
- package/dist/durable.js +57 -980
- package/dist/durable.js.map +1 -1
- package/dist/{errors-DodWX-cb.js → errors-AzSuGI23.js} +5 -3
- package/dist/errors-AzSuGI23.js.map +1 -0
- package/dist/execution-handle-Bd2_nUB6.js +167 -0
- package/dist/execution-handle-Bd2_nUB6.js.map +1 -0
- package/dist/execution-handle-CujvqgCn.d.ts +130 -0
- package/dist/{graph-DPejYB3C.js → graph-mojMML8e.js} +192 -14
- package/dist/graph-mojMML8e.js.map +1 -0
- package/dist/{improve-DwSahPi1.js → improve-Dm5ZE8mr.js} +36 -53
- package/dist/{improve-DwSahPi1.js.map → improve-Dm5ZE8mr.js.map} +1 -1
- package/dist/{improvement-adapter-sIthWkcN.d.ts → improvement-adapter-D5GRU1eY.d.ts} +2 -6
- package/dist/index.d.ts +41 -89
- package/dist/index.js +45 -61
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +39 -59
- package/dist/intelligence.js +24 -33
- package/dist/intelligence.js.map +1 -1
- package/dist/journal-store-BJPMUydp.js +3925 -0
- package/dist/journal-store-BJPMUydp.js.map +1 -0
- package/dist/kernel.d.ts +5 -5
- package/dist/kernel.js +12 -11
- package/dist/{loop-runner-CP6MfO1b.js → loop-runner-5cL_vZi0.js} +5 -6
- package/dist/{loop-runner-CP6MfO1b.js.map → loop-runner-5cL_vZi0.js.map} +1 -1
- package/dist/{loop-runner-C6pGq-2l.d.ts → loop-runner-DyLD-aNb.d.ts} +3 -5
- package/dist/loop-runner-bin.d.ts +5 -8
- package/dist/loop-runner-bin.js +2 -3
- package/dist/mcp/bin.js +6 -8
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +8 -18
- package/dist/mcp/index.js +17 -25
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/memory-bin.js +4 -6
- package/dist/mcp/memory-bin.js.map +1 -1
- package/dist/{model-policy-CyCUwHed.js → model-policy-C-RGAUW4.js} +11 -13
- package/dist/{model-policy-CyCUwHed.js.map → model-policy-C-RGAUW4.js.map} +1 -1
- package/dist/placement.d.ts +12 -14
- package/dist/placement.js +1 -2
- package/dist/platform.d.ts +7 -13
- package/dist/platform.js +3 -6
- package/dist/platform.js.map +1 -1
- package/dist/{prepare-B9wWffjO.js → prepare-XWwsOh8O.js} +50 -69
- package/dist/{prepare-B9wWffjO.js.map → prepare-XWwsOh8O.js.map} +1 -1
- package/dist/{profile-JLJd2wFG.js → profile-C01SQZKa.js} +58 -92
- package/dist/profile-C01SQZKa.js.map +1 -0
- package/dist/{profile-materialization-bPm0gGLO.d.ts → profile-materialization-BRY22Oh8.d.ts} +1 -3
- package/dist/profiles.d.ts +25 -12
- package/dist/profiles.js +52 -11
- package/dist/profiles.js.map +1 -1
- package/dist/{protected-model-port-DVVh-hEk.d.ts → protected-model-port-IKqhTypD.d.ts} +2 -14
- package/dist/{protected-redaction-DFCeo4vg.js → protected-redaction-DilFZch5.js} +2 -3
- package/dist/{protected-redaction-DFCeo4vg.js.map → protected-redaction-DilFZch5.js.map} +1 -1
- package/dist/{provision-supervisor-C4v2vqDo.js → provision-supervisor-D9pO-iPl.js} +11 -15
- package/dist/{provision-supervisor-C4v2vqDo.js.map → provision-supervisor-D9pO-iPl.js.map} +1 -1
- package/dist/{run-cancellation-CzFhQGMa.js → run-cancellation-CoJRKvih.js} +6 -7
- package/dist/{run-cancellation-CzFhQGMa.js.map → run-cancellation-CoJRKvih.js.map} +1 -1
- package/dist/{runtime-CsvGCQpl.js → runtime-BJPXHWbc.js} +652 -215
- package/dist/runtime-BJPXHWbc.js.map +1 -0
- package/dist/{runtime-hooks-tXpAarhW.js → runtime-hooks-CsW2pfFk.js} +2 -3
- package/dist/{runtime-hooks-tXpAarhW.js.map → runtime-hooks-CsW2pfFk.js.map} +1 -1
- package/dist/{runtime-hooks-nsqxSUFL.d.ts → runtime-hooks-ZQqPw-0g.d.ts} +1 -3
- package/dist/{sandbox-profile-compat-DtuJWFrM.js → sandbox-profile-compat-CXjozdWL.js} +52 -653
- package/dist/sandbox-profile-compat-CXjozdWL.js.map +1 -0
- package/dist/{search-executor-CCb82Umc.js → search-executor-CQEHMXoT.js} +12 -15
- package/dist/{search-executor-CCb82Umc.js.map → search-executor-CQEHMXoT.js.map} +1 -1
- package/dist/{server-CKPwZU-I.js → server-U9NGgudQ.js} +19 -30
- package/dist/{server-CKPwZU-I.js.map → server-U9NGgudQ.js.map} +1 -1
- package/dist/{structural-rollout-DylC_fwU.js → structural-rollout-wMSxE7bn.js} +71 -70
- package/dist/structural-rollout-wMSxE7bn.js.map +1 -0
- package/dist/{substrate-CGDFTSRh.js → substrate-Db2pp6y3.js} +2 -3
- package/dist/{substrate-CGDFTSRh.js.map → substrate-Db2pp6y3.js.map} +1 -1
- package/dist/{supervise-BGfm2GlY.js → supervise-CNNhX0ab.js} +460 -195
- package/dist/supervise-CNNhX0ab.js.map +1 -0
- package/dist/supervision-discovery-CewADdEs.js +772 -0
- package/dist/supervision-discovery-CewADdEs.js.map +1 -0
- package/dist/{supervisor-wS9Ehz_x.js → supervisor-rK5Y8en6.js} +521 -4320
- package/dist/supervisor-rK5Y8en6.js.map +1 -0
- package/dist/{task-queue-0fKkoweu.d.ts → task-queue-kefGy79U.d.ts} +1 -3
- package/dist/task-queue.d.ts +1 -1
- package/dist/task-queue.js +1 -2
- package/dist/testing.d.ts +7 -15
- package/dist/testing.js +241 -244
- package/dist/testing.js.map +1 -1
- package/dist/tool-loop.d.ts +16 -19
- package/dist/tool-loop.js +2 -3
- package/dist/{tool-server-XV4aJwoQ.js → tool-server-CZWd_Opp.js} +3 -4
- package/dist/{tool-server-XV4aJwoQ.js.map → tool-server-CZWd_Opp.js.map} +1 -1
- package/dist/{top-snapshot-CflmaDgk.js → top-snapshot-DcV7VG4m.js} +179 -163
- package/dist/top-snapshot-DcV7VG4m.js.map +1 -0
- package/dist/tui/bin.js +50 -81
- package/dist/tui/bin.js.map +1 -1
- package/dist/tui/index.d.ts +27 -58
- package/dist/tui/index.js +2 -2
- package/dist/{types-C8BGOCBn.d.ts → types-0uzVKtFW.d.ts} +388 -484
- package/dist/{types-Cwrea-bU.d.ts → types-qsqfyQoY.d.ts} +1 -3
- package/dist/util-ebWMWzY0.js +624 -0
- package/dist/util-ebWMWzY0.js.map +1 -0
- package/dist/workspace-store/index.d.ts +12 -22
- package/dist/workspace-store/index.js +13 -10
- package/dist/workspace-store/index.js.map +1 -1
- package/dist/{workspace-streams-BiS4ABah.d.ts → workspace-streams-Dq2Fzk3c.d.ts} +1 -11
- package/package.json +31 -26
- package/skills/agent-graphs/SKILL.md +17 -4
- package/skills/be-ambitious/SKILL.md +46 -0
- package/skills/graph-designer/SKILL.md +9 -2
- package/dist/delegate-Dr-63jFl.js.map +0 -1
- package/dist/errors-DodWX-cb.js.map +0 -1
- package/dist/graph-DPejYB3C.js.map +0 -1
- package/dist/profile-JLJd2wFG.js.map +0 -1
- package/dist/record-events-D93DkpAx.js +0 -263
- package/dist/record-events-D93DkpAx.js.map +0 -1
- package/dist/runtime-CsvGCQpl.js.map +0 -1
- package/dist/sandbox-profile-compat-DtuJWFrM.js.map +0 -1
- package/dist/structural-rollout-DylC_fwU.js.map +0 -1
- package/dist/supervise-BGfm2GlY.js.map +0 -1
- package/dist/supervisor-wS9Ehz_x.js.map +0 -1
- package/dist/top-snapshot-CflmaDgk.js.map +0 -1
package/dist/platform.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isRecord } from "@tangle-network/agent-core";
|
|
2
|
-
|
|
2
|
+
// src/platform/auth.ts
|
|
3
3
|
/**
|
|
4
4
|
* Server-side client for the Tangle platform's cross-site SSO bridge.
|
|
5
5
|
*
|
|
@@ -101,8 +101,7 @@ var PlatformAuthClient = class {
|
|
|
101
101
|
return parseExchangeResult(body, res.status);
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
|
-
|
|
105
|
-
//#region src/platform/integrations.ts
|
|
104
|
+
// src/platform/integrations.ts
|
|
106
105
|
/** Thrown when a `PlatformHubClient` request returns a non-success status. */
|
|
107
106
|
var PlatformHubError = class extends Error {
|
|
108
107
|
status;
|
|
@@ -230,8 +229,7 @@ var PlatformHubClient = class {
|
|
|
230
229
|
return parsed.data;
|
|
231
230
|
}
|
|
232
231
|
};
|
|
233
|
-
|
|
234
|
-
//#region src/platform/oidc.ts
|
|
232
|
+
// src/platform/oidc.ts
|
|
235
233
|
/**
|
|
236
234
|
* OpenID Connect client for the Tangle authorization server. Identity tokens
|
|
237
235
|
* are not platform API keys. Resource scopes and audiences must be registered
|
|
@@ -476,7 +474,6 @@ var PlatformOidcClient = class {
|
|
|
476
474
|
});
|
|
477
475
|
}
|
|
478
476
|
};
|
|
479
|
-
//#endregion
|
|
480
477
|
export { PlatformAuthClient, PlatformAuthError, PlatformHubClient, PlatformHubError, PlatformOidcClient, createPkcePair };
|
|
481
478
|
|
|
482
479
|
//# sourceMappingURL=platform.js.map
|
package/dist/platform.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.js","names":["isNonemptyString"],"sources":["../src/platform/auth.ts","../src/platform/integrations.ts","../src/platform/oidc.ts"],"sourcesContent":["/**\n * Server-side client for the Tangle platform's cross-site SSO bridge.\n *\n * Consumer apps (gtm-agent, tax-agent, legal-agent, creative-agent, …)\n * use this to:\n * 1. Build an /authorize URL that lands the user on id.tangle.tools\n * and brings them back with a single-use code.\n * 2. Exchange that code for an API key + the user's identity.\n *\n * The platform endpoint contract is documented in\n * the cross-site route in agent-container's platform API. This client only\n * speaks HTTP — no SDK weight, no transitive deps.\n */\n\nimport { isRecord } from '@tangle-network/agent-core'\n\nexport interface PlatformAuthClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** App id as registered in the platform's TRUSTED_APPS registry. */\n appId: string\n /** Override the global fetch (useful for tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\nexport interface AuthorizeUrlOptions {\n /** Required CSRF token; the consumer verifies it on the callback. */\n state: string\n /**\n * Final redirect URI. Must be one of the URIs registered for `appId`\n * on the platform. Omit to use the first registered URI.\n */\n redirectUri?: string\n /** Force the login screen even if a session is already active. */\n prompt?: 'login'\n /** Pre-fill the email field on the login screen. */\n email?: string\n}\n\nexport interface ExchangeCodeResult {\n apiKey: string\n emailVerified: true\n user: {\n id: string\n email: string\n name?: string | null\n }\n /** Null when the platform could not provide a subscription. This is not a paid-access grant. */\n plan: {\n tier: string\n } | null\n}\n\n/** Thrown when a `PlatformAuthClient` request returns a non-success status. */\nexport class PlatformAuthError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformAuthError'\n }\n}\n\nfunction isNonemptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0\n}\n\n/** Validate the platform's verified identity before consumers create a local session. */\nfunction parseExchangeResult(body: unknown, status: number): ExchangeCodeResult {\n const invalid = (): never => {\n // A successful but malformed response can contain the one-time API secret.\n throw new PlatformAuthError(\n 'Platform exchange response has no valid verified identity',\n status,\n { code: 'INVALID_EXCHANGE_RESPONSE' },\n )\n }\n if (\n !isRecord(body) ||\n !isNonemptyString(body.apiKey) ||\n body.emailVerified !== true ||\n !isRecord(body.user)\n )\n return invalid()\n const user = body.user\n if (!isNonemptyString(user.id) || !isNonemptyString(user.email)) return invalid()\n const email = user.email.trim()\n if (\n email.length > 320 ||\n !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email) ||\n /(?:@users\\.noreply\\.tangle\\.tools$|^0x[a-f0-9]{40}@tangle\\.tools$)/i.test(email)\n )\n return invalid()\n if (user.name !== undefined && user.name !== null && typeof user.name !== 'string')\n return invalid()\n let plan: ExchangeCodeResult['plan'] = null\n if (body.subscription !== undefined) {\n if (!isRecord(body.subscription) || !isNonemptyString(body.subscription.plan)) return invalid()\n plan = { tier: body.subscription.plan }\n }\n return {\n apiKey: body.apiKey,\n emailVerified: true,\n user: { id: user.id, email, ...(user.name !== undefined ? { name: user.name } : {}) },\n plan,\n }\n}\n\n/** HTTP client for the Tangle Platform SSO: builds authorize URLs and exchanges auth codes for API keys. */\nexport class PlatformAuthClient {\n private readonly baseUrl: string\n private readonly appId: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformAuthClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformAuthClient: baseUrl is required')\n if (!options.appId) throw new Error('PlatformAuthClient: appId is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.appId = options.appId\n this.fetchImpl =\n options.fetchImpl ??\n ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => fetch(url, init))\n }\n\n /**\n * Build the URL the user is redirected to in order to start SSO.\n * The platform redirects back to one of `appId`'s registered\n * `redirectUris` with `?code=...&app=...&state=...`.\n */\n authorizeUrl(options: AuthorizeUrlOptions): string {\n if (!options.state) {\n throw new Error('PlatformAuthClient.authorizeUrl: state is required for CSRF')\n }\n const url = new URL('/cross-site/authorize', this.baseUrl)\n url.searchParams.set('app', this.appId)\n url.searchParams.set('state', options.state)\n if (options.redirectUri) url.searchParams.set('redirect', options.redirectUri)\n if (options.prompt) url.searchParams.set('prompt', options.prompt)\n if (options.email) url.searchParams.set('email', options.email)\n return url.toString()\n }\n\n /**\n * Exchange a single-use auth code (delivered to the consumer's\n * callback by the platform) for an API key + the user's identity.\n * Codes are single-use and expire ~5 minutes after issue.\n */\n async exchange(code: string): Promise<ExchangeCodeResult> {\n if (!code) throw new Error('PlatformAuthClient.exchange: code is required')\n const res = await this.fetchImpl(`${this.baseUrl}/cross-site/exchange`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ code, app: this.appId }),\n })\n const body = await res.json().catch(() => null)\n if (!res.ok) {\n const message =\n body && typeof body === 'object' && 'error' in body && typeof body.error === 'string'\n ? body.error\n : `Platform exchange failed (${res.status})`\n throw new PlatformAuthError(message, res.status, body)\n }\n return parseExchangeResult(body, res.status)\n }\n}\n","/**\n * Server-side client for the Tangle platform's integration hub\n * (`/v1/hub/*`). Consumer apps use this instead of rolling their own\n * OAuth + connection tables.\n *\n * Auth: the caller supplies a bearer (either the user's API key from\n * cross-site exchange, or a platform service token) on construction.\n *\n * Endpoint contract (authoritative): the platform API's hub contract\n * and hub route (both in agent-container's platform API). The platform wraps every response in\n * `{ success, data }`; non-2xx or `success:false` surfaces as `PlatformHubError`\n * carrying the real upstream status.\n */\n\nexport interface PlatformHubClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** Bearer credential — user API key or service token. */\n bearer: string\n /** Override fetch (tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\n/** A live integration connection, as returned by `/v1/hub/connections`. */\nexport interface PlatformConnection {\n id: string\n providerId: string\n displayName: string\n accountDisplay: string | null\n scopes: string[]\n status: 'active' | 'revoked' | 'unhealthy' | 'reconnect_required' | (string & {})\n health: 'unknown' | 'healthy' | 'unhealthy' | 'rate_limited' | (string & {})\n createdAt: string\n updatedAt: string\n lastUsedAt: string | null\n}\n\n/** A connectable provider in the catalog (`/v1/hub/providers`). */\nexport interface PlatformCatalogProvider {\n providerId: string\n title?: string\n authKind?: string\n category?: string\n scopes?: string[]\n capabilityCount?: number\n native?: boolean\n /** Whether the OAuth app's credentials are wired — the UI offers Connect\n * only when true. */\n configured?: boolean\n [k: string]: unknown\n}\n\nexport interface CatalogResult {\n providers: PlatformCatalogProvider[]\n /** Count of substrate-bundled connectors behind the catalog. */\n substrateBundled?: number\n [k: string]: unknown\n}\n\nexport interface StartAuthInput {\n /** The provider to connect (goes in the URL path). */\n providerId: string\n /** Accepted for interface compatibility; the platform's start endpoint is\n * provider-level and does not consume a connector id. */\n connectorId?: string\n /** Where the platform redirects the user back to after OAuth. */\n returnUrl: string\n /** Accepted for interface compatibility; not consumed by the start endpoint. */\n requestedScopes?: string[]\n /** CLI flow flag — affects the platform's post-auth redirect handling. */\n cli?: boolean\n}\n\nexport interface StartAuthResult {\n /** The URL to send the user to. Normalized across the platform's two start\n * branches: github returns `authorizationUrl`, substrate returns\n * `redirectUrl`. */\n authorizationUrl: string\n state: string\n expiresAt?: string\n scopes?: string[]\n}\n\nexport interface ConnectionHealth {\n status: 'unknown' | 'healthy' | 'unhealthy' | 'rate_limited' | (string & {})\n checkedAt: string\n error?: { code: string; message: string }\n}\n\nexport interface ConnectionHealthResult {\n connection: PlatformConnection\n health: ConnectionHealth\n}\n\n/** Last-known health for a connection, derived from the connection row. */\nexport interface HealthCheck {\n connectionId: string\n providerId: string\n /** Mirrors `PlatformConnection.health`. */\n status: ConnectionHealth['status']\n checkedAt?: string\n}\n\nexport interface MintTokenInput {\n /** The hub action the token authorizes (e.g. `slack.chat.postMessage`). */\n actionPath: string\n /** Bind to a specific connection, or … */\n connectionId?: string\n /** … resolve the connection by provider for the calling user. */\n provider?: string\n}\n\nexport interface MintTokenResult {\n tokenId: string\n token: string\n expiresAt: string\n}\n\nexport interface ExecInput {\n /** The hub action path to execute. */\n path: string\n input?: unknown\n connectionId?: string\n}\n\nexport interface PlatformHubStatus {\n contract?: unknown\n principal: { kind: string; userId: string; [k: string]: unknown }\n connections: { connectedProviderCount: number; unhealthyProviderCount: number }\n}\n\n/** Thrown when a `PlatformHubClient` request returns a non-success status. */\nexport class PlatformHubError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code: string | undefined,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformHubError'\n }\n}\n\ninterface PlatformEnvelope<T> {\n success: boolean\n data?: T\n error?: { code?: string; message?: string } | string\n}\n\n/** HTTP client for the Tangle Platform Hub API: provider catalog, connection flow, and status. */\nexport class PlatformHubClient {\n private readonly baseUrl: string\n private readonly bearer: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformHubClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformHubClient: baseUrl is required')\n if (!options.bearer) throw new Error('PlatformHubClient: bearer is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.bearer = options.bearer\n this.fetchImpl =\n options.fetchImpl ??\n ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => fetch(url, init))\n }\n\n /** GET /v1/hub/providers — the connectable provider catalog. */\n catalog(): Promise<CatalogResult> {\n return this.request('GET', '/v1/hub/providers')\n }\n\n /** GET /v1/hub/connections — the calling user's live connections. */\n async listConnections(): Promise<PlatformConnection[]> {\n const data = await this.request<{ connections: PlatformConnection[] }>(\n 'GET',\n '/v1/hub/connections',\n )\n return data.connections\n }\n\n /** DELETE /v1/hub/connections/:connectionId — revoke + disable a connection. */\n revokeConnection(connectionId: string): Promise<{ connection: PlatformConnection }> {\n return this.request('DELETE', `/v1/hub/connections/${encodeURIComponent(connectionId)}`)\n }\n\n /**\n * POST /v1/hub/connections/:provider/start — begin OAuth/grant. The provider\n * is taken from the URL; the body carries `returnUrl` (+ `cli`). The platform's\n * two start branches name the URL field differently (github → `authorizationUrl`,\n * substrate → `redirectUrl`); this normalizes to `authorizationUrl`.\n */\n async startAuth(input: StartAuthInput): Promise<StartAuthResult> {\n const body: { returnUrl: string; cli?: boolean } = { returnUrl: input.returnUrl }\n if (input.cli !== undefined) body.cli = input.cli\n const data = await this.request<{\n authorizationUrl?: string\n redirectUrl?: string\n state: string\n expiresAt?: string\n scopes?: string[]\n }>('POST', `/v1/hub/connections/${encodeURIComponent(input.providerId)}/start`, body)\n const authorizationUrl = data.authorizationUrl ?? data.redirectUrl\n if (!authorizationUrl) {\n throw new PlatformHubError(\n 'Platform hub start response missing an authorization URL',\n 502,\n 'HUB_INVALID_START_RESPONSE',\n data,\n )\n }\n return { authorizationUrl, state: data.state, expiresAt: data.expiresAt, scopes: data.scopes }\n }\n\n /**\n * Last-known health for every connection. The platform has no global\n * healthcheck listing — health rides on each connection row — so this derives\n * the list from `listConnections()` (one request, no extra round-trips).\n */\n async listHealthchecks(): Promise<HealthCheck[]> {\n const connections = await this.listConnections()\n return connections.map((c) => ({\n connectionId: c.id,\n providerId: c.providerId,\n status: c.health,\n checkedAt: c.updatedAt,\n }))\n }\n\n /**\n * POST /v1/hub/connections/:connectionId/health — trigger a fresh health\n * probe for one connection and return its updated state.\n */\n checkConnectionHealth(connectionId: string): Promise<ConnectionHealthResult> {\n return this.request('POST', `/v1/hub/connections/${encodeURIComponent(connectionId)}/health`)\n }\n\n /**\n * Trigger a fresh health probe across all of the user's connections. The\n * platform exposes health per-connection only, so this fans out over\n * `listConnections()`. `scheduled` is the number of probes dispatched.\n */\n async runHealthchecks(): Promise<{ scheduled: number }> {\n const connections = await this.listConnections()\n await Promise.allSettled(connections.map((c) => this.checkConnectionHealth(c.id)))\n return { scheduled: connections.length }\n }\n\n /** GET /v1/hub/status — principal + aggregate connection counts. */\n status(): Promise<PlatformHubStatus> {\n return this.request('GET', '/v1/hub/status')\n }\n\n /**\n * POST /v1/hub/tokens — mint a short-lived, action-scoped capability token a\n * sandbox can use to invoke one hub action on the user's behalf without\n * seeing the underlying provider credential.\n */\n mintToken(input: MintTokenInput): Promise<MintTokenResult> {\n return this.request('POST', '/v1/hub/tokens', input)\n }\n\n /** POST /v1/hub/exec — execute a hub action and return its result. */\n async exec(input: ExecInput): Promise<unknown> {\n const data = await this.request<{ result: unknown }>('POST', '/v1/hub/exec', input)\n return data.result\n }\n\n private async request<T>(\n method: 'GET' | 'POST' | 'DELETE' | 'PUT',\n path: string,\n body?: unknown,\n ): Promise<T> {\n const headers: Record<string, string> = {\n authorization: `Bearer ${this.bearer}`,\n accept: 'application/json',\n }\n if (body !== undefined) headers['content-type'] = 'application/json'\n\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n const text = await res.text()\n let parsed: PlatformEnvelope<T> | null = null\n if (text) {\n try {\n parsed = JSON.parse(text)\n } catch {\n // fall through to error handling below\n }\n }\n if (!res.ok || (parsed && parsed.success === false)) {\n const code = parsed?.error && typeof parsed.error === 'object' ? parsed.error.code : undefined\n const message =\n (parsed?.error && typeof parsed.error === 'object' && parsed.error.message) ||\n (typeof parsed?.error === 'string' ? parsed.error : `Platform hub error (${res.status})`)\n throw new PlatformHubError(message, res.status, code, parsed ?? text)\n }\n if (!parsed) {\n throw new PlatformHubError(\n `Platform hub returned non-JSON success (${res.status})`,\n res.status,\n undefined,\n text,\n )\n }\n if (parsed.data === undefined) {\n throw new PlatformHubError(\n 'Platform hub envelope missing `data`',\n res.status,\n undefined,\n parsed,\n )\n }\n return parsed.data\n }\n}\n","/**\n * OpenID Connect client for the Tangle authorization server. Identity tokens\n * are not platform API keys. Resource scopes and audiences must be registered\n * by the provider before a consumer can use these tokens at a paid API.\n */\n\nimport { isRecord } from '@tangle-network/agent-core'\nimport { PlatformAuthError } from './auth.js'\n\nexport interface PlatformOidcClientOptions {\n baseUrl: string\n clientId: string\n /** Omit only for clients registered with token_endpoint_auth_method=none. */\n clientSecret?: string\n /** Required for authorization code; not required for the device grant. */\n redirectUri?: string\n scope?: string\n /** RFC 8707 resource identifiers registered at the authorization server. */\n resources?: readonly string[]\n fetchImpl?: typeof fetch\n}\n\nexport interface OidcAuthorizeUrlOptions {\n state: string\n codeChallenge: string\n /** Only supply a nonce when the consumer also validates the ID token. */\n nonce?: string\n prompt?: 'login' | 'consent' | 'none'\n loginHint?: string\n}\n\nexport interface OidcTokens {\n accessToken: string\n tokenType: string\n expiresIn?: number\n refreshToken?: string\n idToken?: string\n scope?: string\n}\n\nexport interface OidcUser {\n id: string\n email: string\n emailVerified: true\n name?: string\n}\n\nexport interface OidcExchangeResult {\n tokens: OidcTokens\n user: OidcUser\n}\n\n/** Keep deviceCode secret. Only userCode and the verification URLs are displayed. */\nexport interface OidcDeviceAuthorization {\n deviceCode: string\n userCode: string\n verificationUri: string\n verificationUriComplete?: string\n expiresIn: number\n /** Absolute deadline preserves expiry when a polling process resumes. */\n expiresAt: number\n interval: number\n}\n\nconst DEFAULT_SCOPE = 'openid profile email offline_access'\nconst DEVICE_GRANT = 'urn:ietf:params:oauth:grant-type:device_code'\n\nfunction isNonemptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0\n}\n\nfunction base64url(bytes: Uint8Array): string {\n let binary = ''\n for (const byte of bytes) binary += String.fromCharCode(byte)\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\n/** Create an RFC 7636 verifier and its S256 challenge with Web Crypto. */\nexport async function createPkcePair(): Promise<{ verifier: string; challenge: string }> {\n const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)))\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier))\n return { verifier, challenge: base64url(new Uint8Array(digest)) }\n}\n\nfunction oauthError(body: unknown, fallback: string): string {\n if (!isRecord(body)) return fallback\n if (isNonemptyString(body.error_description)) return body.error_description\n if (isNonemptyString(body.error)) return body.error\n return fallback\n}\n\nfunction parseTokens(body: unknown, status: number): OidcTokens {\n if (!isRecord(body) || !isNonemptyString(body.access_token)) {\n throw new PlatformAuthError('Platform token response is malformed', status, {\n code: 'INVALID_TOKEN_RESPONSE',\n })\n }\n return {\n accessToken: body.access_token,\n tokenType: isNonemptyString(body.token_type) ? body.token_type : 'Bearer',\n ...(typeof body.expires_in === 'number' ? { expiresIn: body.expires_in } : {}),\n ...(isNonemptyString(body.refresh_token) ? { refreshToken: body.refresh_token } : {}),\n ...(isNonemptyString(body.id_token) ? { idToken: body.id_token } : {}),\n ...(isNonemptyString(body.scope) ? { scope: body.scope } : {}),\n }\n}\n\nfunction formComponent(value: string): string {\n return new URLSearchParams({ v: value }).toString().slice(2)\n}\n\nfunction pause(ms: number, signal?: AbortSignal): Promise<void> {\n signal?.throwIfAborted()\n return new Promise((resolve, reject) => {\n const finish = () => {\n signal?.removeEventListener('abort', abort)\n resolve()\n }\n const timer = setTimeout(finish, ms)\n const abort = () => {\n clearTimeout(timer)\n signal?.removeEventListener('abort', abort)\n reject(signal?.reason ?? new Error('Device authorization cancelled'))\n }\n signal?.addEventListener('abort', abort, { once: true })\n })\n}\n\n/** OIDC code + PKCE, refresh/revoke and discovery-bound RFC 8628 device grants. */\nexport class PlatformOidcClient {\n private readonly baseUrl: string\n private readonly clientId: string\n private readonly clientSecret: string | undefined\n private readonly redirectUri: string | undefined\n private readonly scope: string\n private readonly resources: readonly string[]\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformOidcClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformOidcClient: baseUrl is required')\n if (!options.clientId) throw new Error('PlatformOidcClient: clientId is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.clientId = options.clientId\n this.clientSecret = options.clientSecret || undefined\n this.redirectUri = options.redirectUri\n this.scope = options.scope ?? DEFAULT_SCOPE\n this.resources = [...new Set(options.resources ?? [])]\n for (const resource of this.resources) {\n const url = new URL(resource)\n if (url.hash || url.username || url.password) {\n throw new Error('PlatformOidcClient: resource must not contain a fragment or credentials')\n }\n }\n this.fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init))\n }\n\n authorizeUrl(options: OidcAuthorizeUrlOptions): string {\n if (!this.redirectUri)\n throw new Error('PlatformOidcClient: redirectUri is required for authorization code')\n if (!options.state)\n throw new Error('PlatformOidcClient.authorizeUrl: state is required for CSRF')\n if (!options.codeChallenge)\n throw new Error('PlatformOidcClient.authorizeUrl: codeChallenge is required for PKCE')\n const url = new URL('/api/auth/oauth2/authorize', this.baseUrl)\n url.searchParams.set('client_id', this.clientId)\n url.searchParams.set('redirect_uri', this.redirectUri)\n url.searchParams.set('response_type', 'code')\n url.searchParams.set('scope', this.scope)\n url.searchParams.set('state', options.state)\n url.searchParams.set('code_challenge', options.codeChallenge)\n url.searchParams.set('code_challenge_method', 'S256')\n for (const resource of this.resources) url.searchParams.append('resource', resource)\n if (options.nonce) url.searchParams.set('nonce', options.nonce)\n if (options.prompt) url.searchParams.set('prompt', options.prompt)\n if (options.loginHint) url.searchParams.set('login_hint', options.loginHint)\n return url.toString()\n }\n\n async exchange(code: string, codeVerifier: string): Promise<OidcExchangeResult> {\n if (!this.redirectUri)\n throw new Error('PlatformOidcClient: redirectUri is required for authorization code')\n if (!code) throw new Error('PlatformOidcClient.exchange: code is required')\n if (!codeVerifier)\n throw new Error('PlatformOidcClient.exchange: codeVerifier is required for PKCE')\n const tokens = await this.token({\n grant_type: 'authorization_code',\n code,\n redirect_uri: this.redirectUri,\n code_verifier: codeVerifier,\n })\n return { tokens, user: await this.userinfo(tokens.accessToken) }\n }\n\n /** Save the replacement refresh token. Never retry an old token as a new grant. */\n async refresh(refreshToken: string): Promise<OidcTokens> {\n if (!refreshToken) throw new Error('PlatformOidcClient.refresh: refreshToken is required')\n return this.token({ grant_type: 'refresh_token', refresh_token: refreshToken })\n }\n\n async userinfo(accessToken: string): Promise<OidcUser> {\n if (!accessToken) throw new Error('PlatformOidcClient.userinfo: accessToken is required')\n const res = await this.fetchImpl(`${this.baseUrl}/api/auth/oauth2/userinfo`, {\n headers: { authorization: `Bearer ${accessToken}` },\n redirect: 'error',\n })\n const body: unknown = await res.json().catch(() => null)\n if (!res.ok)\n throw new PlatformAuthError(\n oauthError(body, `Platform userinfo failed (${res.status})`),\n res.status,\n body,\n )\n if (\n !isRecord(body) ||\n !isNonemptyString(body.sub) ||\n !isNonemptyString(body.email) ||\n body.email_verified !== true\n ) {\n throw new PlatformAuthError('Platform userinfo has no verified identity', res.status, {\n code: 'INVALID_USERINFO_RESPONSE',\n })\n }\n return {\n id: body.sub,\n email: body.email,\n emailVerified: true,\n ...(isNonemptyString(body.name) ? { name: body.name } : {}),\n }\n }\n\n /** RFC 7009. A local logout alone is not a provider disconnect. */\n async revoke(token: string, tokenTypeHint?: 'access_token' | 'refresh_token'): Promise<void> {\n if (!token) throw new Error('PlatformOidcClient.revoke: token is required')\n const res = await this.post(\n `${this.baseUrl}/api/auth/oauth2/revoke`,\n {\n token,\n ...(tokenTypeHint ? { token_type_hint: tokenTypeHint } : {}),\n },\n undefined,\n false,\n )\n if (!res.ok) {\n const body: unknown = await res.json().catch(() => null)\n throw new PlatformAuthError(\n oauthError(body, `Platform revoke failed (${res.status})`),\n res.status,\n body,\n )\n }\n }\n\n /**\n * Start a device grant only when this issuer advertises the OAuth-integrated\n * device endpoint. No fallback to /cross-site/device or a standalone session\n * device endpoint: those issue different credentials.\n */\n async deviceAuthorize(options: { signal?: AbortSignal } = {}): Promise<OidcDeviceAuthorization> {\n const discovery = await this.fetchImpl(\n `${this.baseUrl}/api/auth/.well-known/openid-configuration`,\n {\n redirect: 'error',\n signal: options.signal,\n },\n )\n const metadata: unknown = await discovery.json().catch(() => null)\n const issuer = `${this.baseUrl}/api/auth`\n if (\n !discovery.ok ||\n !isRecord(metadata) ||\n metadata.issuer !== issuer ||\n metadata.token_endpoint !== `${issuer}/oauth2/token` ||\n !Array.isArray(metadata.grant_types_supported) ||\n !metadata.grant_types_supported.includes(DEVICE_GRANT) ||\n !isNonemptyString(metadata.device_authorization_endpoint)\n ) {\n throw new PlatformAuthError(\n 'Issuer does not advertise an OAuth device grant',\n discovery.status,\n { code: 'OAUTH_DEVICE_GRANT_UNAVAILABLE' },\n )\n }\n const endpoint = new URL(metadata.device_authorization_endpoint)\n const origin = new URL(this.baseUrl).origin\n if (endpoint.origin !== origin || endpoint.username || endpoint.password || endpoint.hash) {\n throw new PlatformAuthError('Device endpoint is outside the configured issuer', 400, {\n code: 'INVALID_DEVICE_ENDPOINT',\n })\n }\n const startedAt = Date.now()\n const res = await this.post(endpoint.href, { scope: this.scope }, options.signal)\n const body: unknown = await res.json().catch(() => null)\n if (!res.ok)\n throw new PlatformAuthError(\n oauthError(body, `Device authorization failed (${res.status})`),\n res.status,\n body,\n )\n if (\n !isRecord(body) ||\n !isNonemptyString(body.device_code) ||\n !isNonemptyString(body.user_code) ||\n !isNonemptyString(body.verification_uri) ||\n typeof body.expires_in !== 'number' ||\n !Number.isSafeInteger(body.expires_in) ||\n body.expires_in <= 0 ||\n (body.interval !== undefined &&\n (typeof body.interval !== 'number' ||\n !Number.isSafeInteger(body.interval) ||\n body.interval <= 0))\n ) {\n throw new PlatformAuthError('Malformed device authorization response', res.status, {\n code: 'INVALID_DEVICE_RESPONSE',\n })\n }\n for (const value of [body.verification_uri, body.verification_uri_complete]) {\n if (value === undefined) continue\n if (!isNonemptyString(value))\n throw new PlatformAuthError('Invalid device verification URI', 400, {\n code: 'INVALID_DEVICE_RESPONSE',\n })\n const uri = new URL(value)\n if (uri.origin !== origin || uri.username || uri.password || uri.hash) {\n throw new PlatformAuthError('Device verification URI is outside the issuer', 400, {\n code: 'INVALID_DEVICE_RESPONSE',\n })\n }\n }\n return {\n deviceCode: body.device_code,\n userCode: body.user_code,\n verificationUri: body.verification_uri,\n ...(isNonemptyString(body.verification_uri_complete)\n ? { verificationUriComplete: body.verification_uri_complete }\n : {}),\n expiresIn: body.expires_in,\n expiresAt: startedAt + body.expires_in * 1000,\n interval: typeof body.interval === 'number' ? body.interval : 5,\n }\n }\n\n /** RFC 8628 pending/slow_down handling, expiry, cancellation and timeout backoff. */\n async pollDeviceAuthorization(\n grant: OidcDeviceAuthorization,\n options: { signal?: AbortSignal } = {},\n ): Promise<OidcTokens> {\n if (\n !grant.deviceCode ||\n !Number.isFinite(grant.expiresAt) ||\n !Number.isFinite(grant.interval) ||\n grant.interval <= 0\n ) {\n throw new Error('PlatformOidcClient.pollDeviceAuthorization: invalid device grant')\n }\n let intervalMs = grant.interval * 1000\n while (Date.now() < grant.expiresAt) {\n options.signal?.throwIfAborted()\n await pause(Math.min(intervalMs, Math.max(0, grant.expiresAt - Date.now())), options.signal)\n const remaining = grant.expiresAt - Date.now()\n if (remaining <= 0) break\n const timeout = AbortSignal.timeout(Math.max(1, Math.min(30_000, Math.floor(remaining))))\n const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout\n try {\n return await this.token({ grant_type: DEVICE_GRANT, device_code: grant.deviceCode }, signal)\n } catch (error) {\n options.signal?.throwIfAborted()\n if (timeout.aborted) {\n intervalMs *= 2\n continue\n }\n if (!(error instanceof PlatformAuthError) || !isRecord(error.body)) throw error\n if (error.body.error === 'authorization_pending') continue\n if (error.body.error === 'slow_down') {\n intervalMs += 5_000\n continue\n }\n throw error\n }\n }\n throw new PlatformAuthError('Device authorization expired', 400, { error: 'expired_token' })\n }\n\n private async token(params: Record<string, string>, signal?: AbortSignal): Promise<OidcTokens> {\n const res = await this.post(`${this.baseUrl}/api/auth/oauth2/token`, params, signal)\n const body: unknown = await res.json().catch(() => null)\n if (!res.ok)\n throw new PlatformAuthError(\n oauthError(body, `Platform token request failed (${res.status})`),\n res.status,\n body,\n )\n return parseTokens(body, res.status)\n }\n\n private post(\n url: string,\n params: Record<string, string>,\n signal?: AbortSignal,\n includeResources = true,\n ): Promise<Response> {\n const body = new URLSearchParams(params)\n const headers: Record<string, string> = { 'content-type': 'application/x-www-form-urlencoded' }\n if (this.clientSecret) {\n // RFC 6749 section 2.3.1: form-encode each component before HTTP Basic.\n headers.authorization = `Basic ${btoa(`${formComponent(this.clientId)}:${formComponent(this.clientSecret)}`)}`\n } else body.set('client_id', this.clientId)\n if (includeResources) for (const resource of this.resources) body.append('resource', resource)\n return this.fetchImpl(url, { method: 'POST', headers, body, redirect: 'error', signal })\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAsDA,IAAa,oBAAb,cAAuC,MAAM;CAGzB;CACA;CAHlB,YACE,SACA,QACA,MACA;EACA,MAAM,OAAO;EAHG,KAAA,SAAA;EACA,KAAA,OAAA;EAGhB,KAAK,OAAO;CACd;AACF;AAEA,SAASA,mBAAiB,OAAiC;CACzD,OAAO,OAAO,UAAU,YAAY,MAAM,KAAK,CAAC,CAAC,SAAS;AAC5D;;AAGA,SAAS,oBAAoB,MAAe,QAAoC;CAC9E,MAAM,gBAAuB;EAE3B,MAAM,IAAI,kBACR,6DACA,QACA,EAAE,MAAM,4BAA4B,CACtC;CACF;CACA,IACE,CAAC,SAAS,IAAI,KACd,CAACA,mBAAiB,KAAK,MAAM,KAC7B,KAAK,kBAAkB,QACvB,CAAC,SAAS,KAAK,IAAI,GAEnB,OAAO,QAAQ;CACjB,MAAM,OAAO,KAAK;CAClB,IAAI,CAACA,mBAAiB,KAAK,EAAE,KAAK,CAACA,mBAAiB,KAAK,KAAK,GAAG,OAAO,QAAQ;CAChF,MAAM,QAAQ,KAAK,MAAM,KAAK;CAC9B,IACE,MAAM,SAAS,OACf,CAAC,6BAA6B,KAAK,KAAK,KACxC,sEAAsE,KAAK,KAAK,GAEhF,OAAO,QAAQ;CACjB,IAAI,KAAK,SAAS,KAAA,KAAa,KAAK,SAAS,QAAQ,OAAO,KAAK,SAAS,UACxE,OAAO,QAAQ;CACjB,IAAI,OAAmC;CACvC,IAAI,KAAK,iBAAiB,KAAA,GAAW;EACnC,IAAI,CAAC,SAAS,KAAK,YAAY,KAAK,CAACA,mBAAiB,KAAK,aAAa,IAAI,GAAG,OAAO,QAAQ;EAC9F,OAAO,EAAE,MAAM,KAAK,aAAa,KAAK;CACxC;CACA,OAAO;EACL,QAAQ,KAAK;EACb,eAAe;EACf,MAAM;GAAE,IAAI,KAAK;GAAI;GAAO,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EAAG;EACpF;CACF;AACF;;AAGA,IAAa,qBAAb,MAAgC;CAC9B;CACA;CACA;CAEA,YAAY,SAAoC;EAC9C,IAAI,CAAC,QAAQ,SAAS,MAAM,IAAI,MAAM,yCAAyC;EAC/E,IAAI,CAAC,QAAQ,OAAO,MAAM,IAAI,MAAM,uCAAuC;EAC3E,KAAK,UAAU,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;EACjD,KAAK,QAAQ,QAAQ;EACrB,KAAK,YACH,QAAQ,eACN,KAAkC,SAAuC,MAAM,KAAK,IAAI;CAC9F;;;;;;CAOA,aAAa,SAAsC;EACjD,IAAI,CAAC,QAAQ,OACX,MAAM,IAAI,MAAM,6DAA6D;EAE/E,MAAM,MAAM,IAAI,IAAI,yBAAyB,KAAK,OAAO;EACzD,IAAI,aAAa,IAAI,OAAO,KAAK,KAAK;EACtC,IAAI,aAAa,IAAI,SAAS,QAAQ,KAAK;EAC3C,IAAI,QAAQ,aAAa,IAAI,aAAa,IAAI,YAAY,QAAQ,WAAW;EAC7E,IAAI,QAAQ,QAAQ,IAAI,aAAa,IAAI,UAAU,QAAQ,MAAM;EACjE,IAAI,QAAQ,OAAO,IAAI,aAAa,IAAI,SAAS,QAAQ,KAAK;EAC9D,OAAO,IAAI,SAAS;CACtB;;;;;;CAOA,MAAM,SAAS,MAA2C;EACxD,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,+CAA+C;EAC1E,MAAM,MAAM,MAAM,KAAK,UAAU,GAAG,KAAK,QAAQ,uBAAuB;GACtE,QAAQ;GACR,SAAS,EAAE,gBAAgB,mBAAmB;GAC9C,MAAM,KAAK,UAAU;IAAE;IAAM,KAAK,KAAK;GAAM,CAAC;EAChD,CAAC;EACD,MAAM,OAAO,MAAM,IAAI,KAAK,CAAC,CAAC,YAAY,IAAI;EAC9C,IAAI,CAAC,IAAI,IAKP,MAAM,IAAI,kBAHR,QAAQ,OAAO,SAAS,YAAY,WAAW,QAAQ,OAAO,KAAK,UAAU,WACzE,KAAK,QACL,6BAA6B,IAAI,OAAO,IACT,IAAI,QAAQ,IAAI;EAEvD,OAAO,oBAAoB,MAAM,IAAI,MAAM;CAC7C;AACF;;;;AClCA,IAAa,mBAAb,cAAsC,MAAM;CAGxB;CACA;CACA;CAJlB,YACE,SACA,QACA,MACA,MACA;EACA,MAAM,OAAO;EAJG,KAAA,SAAA;EACA,KAAA,OAAA;EACA,KAAA,OAAA;EAGhB,KAAK,OAAO;CACd;AACF;;AASA,IAAa,oBAAb,MAA+B;CAC7B;CACA;CACA;CAEA,YAAY,SAAmC;EAC7C,IAAI,CAAC,QAAQ,SAAS,MAAM,IAAI,MAAM,wCAAwC;EAC9E,IAAI,CAAC,QAAQ,QAAQ,MAAM,IAAI,MAAM,uCAAuC;EAC5E,KAAK,UAAU,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;EACjD,KAAK,SAAS,QAAQ;EACtB,KAAK,YACH,QAAQ,eACN,KAAkC,SAAuC,MAAM,KAAK,IAAI;CAC9F;;CAGA,UAAkC;EAChC,OAAO,KAAK,QAAQ,OAAO,mBAAmB;CAChD;;CAGA,MAAM,kBAAiD;EAKrD,QAAO,MAJY,KAAK,QACtB,OACA,qBACF,EAAA,CACY;CACd;;CAGA,iBAAiB,cAAmE;EAClF,OAAO,KAAK,QAAQ,UAAU,uBAAuB,mBAAmB,YAAY,GAAG;CACzF;;;;;;;CAQA,MAAM,UAAU,OAAiD;EAC/D,MAAM,OAA6C,EAAE,WAAW,MAAM,UAAU;EAChF,IAAI,MAAM,QAAQ,KAAA,GAAW,KAAK,MAAM,MAAM;EAC9C,MAAM,OAAO,MAAM,KAAK,QAMrB,QAAQ,uBAAuB,mBAAmB,MAAM,UAAU,EAAE,SAAS,IAAI;EACpF,MAAM,mBAAmB,KAAK,oBAAoB,KAAK;EACvD,IAAI,CAAC,kBACH,MAAM,IAAI,iBACR,4DACA,KACA,8BACA,IACF;EAEF,OAAO;GAAE;GAAkB,OAAO,KAAK;GAAO,WAAW,KAAK;GAAW,QAAQ,KAAK;EAAO;CAC/F;;;;;;CAOA,MAAM,mBAA2C;EAE/C,QAAO,MADmB,KAAK,gBAAgB,EAAA,CAC5B,KAAK,OAAO;GAC7B,cAAc,EAAE;GAChB,YAAY,EAAE;GACd,QAAQ,EAAE;GACV,WAAW,EAAE;EACf,EAAE;CACJ;;;;;CAMA,sBAAsB,cAAuD;EAC3E,OAAO,KAAK,QAAQ,QAAQ,uBAAuB,mBAAmB,YAAY,EAAE,QAAQ;CAC9F;;;;;;CAOA,MAAM,kBAAkD;EACtD,MAAM,cAAc,MAAM,KAAK,gBAAgB;EAC/C,MAAM,QAAQ,WAAW,YAAY,KAAK,MAAM,KAAK,sBAAsB,EAAE,EAAE,CAAC,CAAC;EACjF,OAAO,EAAE,WAAW,YAAY,OAAO;CACzC;;CAGA,SAAqC;EACnC,OAAO,KAAK,QAAQ,OAAO,gBAAgB;CAC7C;;;;;;CAOA,UAAU,OAAiD;EACzD,OAAO,KAAK,QAAQ,QAAQ,kBAAkB,KAAK;CACrD;;CAGA,MAAM,KAAK,OAAoC;EAE7C,QAAO,MADY,KAAK,QAA6B,QAAQ,gBAAgB,KAAK,EAAA,CACtE;CACd;CAEA,MAAc,QACZ,QACA,MACA,MACY;EACZ,MAAM,UAAkC;GACtC,eAAe,UAAU,KAAK;GAC9B,QAAQ;EACV;EACA,IAAI,SAAS,KAAA,GAAW,QAAQ,kBAAkB;EAElD,MAAM,MAAM,MAAM,KAAK,UAAU,GAAG,KAAK,UAAU,QAAQ;GACzD;GACA;GACA,MAAM,SAAS,KAAA,IAAY,KAAK,UAAU,IAAI,IAAI,KAAA;EACpD,CAAC;EACD,MAAM,OAAO,MAAM,IAAI,KAAK;EAC5B,IAAI,SAAqC;EACzC,IAAI,MACF,IAAI;GACF,SAAS,KAAK,MAAM,IAAI;EAC1B,QAAQ,CAER;EAEF,IAAI,CAAC,IAAI,MAAO,UAAU,OAAO,YAAY,OAAQ;GACnD,MAAM,OAAO,QAAQ,SAAS,OAAO,OAAO,UAAU,WAAW,OAAO,MAAM,OAAO,KAAA;GAIrF,MAAM,IAAI,iBAFP,QAAQ,SAAS,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,YAClE,OAAO,QAAQ,UAAU,WAAW,OAAO,QAAQ,uBAAuB,IAAI,OAAO,KACpD,IAAI,QAAQ,MAAM,UAAU,IAAI;EACtE;EACA,IAAI,CAAC,QACH,MAAM,IAAI,iBACR,2CAA2C,IAAI,OAAO,IACtD,IAAI,QACJ,KAAA,GACA,IACF;EAEF,IAAI,OAAO,SAAS,KAAA,GAClB,MAAM,IAAI,iBACR,wCACA,IAAI,QACJ,KAAA,GACA,MACF;EAEF,OAAO,OAAO;CAChB;AACF;;;;;;;;AC7PA,MAAM,gBAAgB;AACtB,MAAM,eAAe;AAErB,SAAS,iBAAiB,OAAiC;CACzD,OAAO,OAAO,UAAU,YAAY,MAAM,KAAK,CAAC,CAAC,SAAS;AAC5D;AAEA,SAAS,UAAU,OAA2B;CAC5C,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,OAAO,UAAU,OAAO,aAAa,IAAI;CAC5D,OAAO,KAAK,MAAM,CAAC,CAAC,QAAQ,OAAO,GAAG,CAAC,CAAC,QAAQ,OAAO,GAAG,CAAC,CAAC,QAAQ,OAAO,EAAE;AAC/E;;AAGA,eAAsB,iBAAmE;CACvF,MAAM,WAAW,UAAU,OAAO,gCAAgB,IAAI,WAAW,EAAE,CAAC,CAAC;CACrE,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,QAAQ,CAAC;CACvF,OAAO;EAAE;EAAU,WAAW,UAAU,IAAI,WAAW,MAAM,CAAC;CAAE;AAClE;AAEA,SAAS,WAAW,MAAe,UAA0B;CAC3D,IAAI,CAAC,SAAS,IAAI,GAAG,OAAO;CAC5B,IAAI,iBAAiB,KAAK,iBAAiB,GAAG,OAAO,KAAK;CAC1D,IAAI,iBAAiB,KAAK,KAAK,GAAG,OAAO,KAAK;CAC9C,OAAO;AACT;AAEA,SAAS,YAAY,MAAe,QAA4B;CAC9D,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,iBAAiB,KAAK,YAAY,GACxD,MAAM,IAAI,kBAAkB,wCAAwC,QAAQ,EAC1E,MAAM,yBACR,CAAC;CAEH,OAAO;EACL,aAAa,KAAK;EAClB,WAAW,iBAAiB,KAAK,UAAU,IAAI,KAAK,aAAa;EACjE,GAAI,OAAO,KAAK,eAAe,WAAW,EAAE,WAAW,KAAK,WAAW,IAAI,CAAC;EAC5E,GAAI,iBAAiB,KAAK,aAAa,IAAI,EAAE,cAAc,KAAK,cAAc,IAAI,CAAC;EACnF,GAAI,iBAAiB,KAAK,QAAQ,IAAI,EAAE,SAAS,KAAK,SAAS,IAAI,CAAC;EACpE,GAAI,iBAAiB,KAAK,KAAK,IAAI,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;CAC9D;AACF;AAEA,SAAS,cAAc,OAAuB;CAC5C,OAAO,IAAI,gBAAgB,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;AAC7D;AAEA,SAAS,MAAM,IAAY,QAAqC;CAC9D,QAAQ,eAAe;CACvB,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,eAAe;GACnB,QAAQ,oBAAoB,SAAS,KAAK;GAC1C,QAAQ;EACV;EACA,MAAM,QAAQ,WAAW,QAAQ,EAAE;EACnC,MAAM,cAAc;GAClB,aAAa,KAAK;GAClB,QAAQ,oBAAoB,SAAS,KAAK;GAC1C,OAAO,QAAQ,0BAAU,IAAI,MAAM,gCAAgC,CAAC;EACtE;EACA,QAAQ,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;CACzD,CAAC;AACH;;AAGA,IAAa,qBAAb,MAAgC;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,SAAoC;EAC9C,IAAI,CAAC,QAAQ,SAAS,MAAM,IAAI,MAAM,yCAAyC;EAC/E,IAAI,CAAC,QAAQ,UAAU,MAAM,IAAI,MAAM,0CAA0C;EACjF,KAAK,UAAU,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;EACjD,KAAK,WAAW,QAAQ;EACxB,KAAK,eAAe,QAAQ,gBAAgB,KAAA;EAC5C,KAAK,cAAc,QAAQ;EAC3B,KAAK,QAAQ,QAAQ,SAAS;EAC9B,KAAK,YAAY,CAAC,GAAG,IAAI,IAAI,QAAQ,aAAa,CAAC,CAAC,CAAC;EACrD,KAAK,MAAM,YAAY,KAAK,WAAW;GACrC,MAAM,MAAM,IAAI,IAAI,QAAQ;GAC5B,IAAI,IAAI,QAAQ,IAAI,YAAY,IAAI,UAClC,MAAM,IAAI,MAAM,yEAAyE;EAE7F;EACA,KAAK,YAAY,QAAQ,eAAe,OAAO,SAAS,MAAM,OAAO,IAAI;CAC3E;CAEA,aAAa,SAA0C;EACrD,IAAI,CAAC,KAAK,aACR,MAAM,IAAI,MAAM,oEAAoE;EACtF,IAAI,CAAC,QAAQ,OACX,MAAM,IAAI,MAAM,6DAA6D;EAC/E,IAAI,CAAC,QAAQ,eACX,MAAM,IAAI,MAAM,qEAAqE;EACvF,MAAM,MAAM,IAAI,IAAI,8BAA8B,KAAK,OAAO;EAC9D,IAAI,aAAa,IAAI,aAAa,KAAK,QAAQ;EAC/C,IAAI,aAAa,IAAI,gBAAgB,KAAK,WAAW;EACrD,IAAI,aAAa,IAAI,iBAAiB,MAAM;EAC5C,IAAI,aAAa,IAAI,SAAS,KAAK,KAAK;EACxC,IAAI,aAAa,IAAI,SAAS,QAAQ,KAAK;EAC3C,IAAI,aAAa,IAAI,kBAAkB,QAAQ,aAAa;EAC5D,IAAI,aAAa,IAAI,yBAAyB,MAAM;EACpD,KAAK,MAAM,YAAY,KAAK,WAAW,IAAI,aAAa,OAAO,YAAY,QAAQ;EACnF,IAAI,QAAQ,OAAO,IAAI,aAAa,IAAI,SAAS,QAAQ,KAAK;EAC9D,IAAI,QAAQ,QAAQ,IAAI,aAAa,IAAI,UAAU,QAAQ,MAAM;EACjE,IAAI,QAAQ,WAAW,IAAI,aAAa,IAAI,cAAc,QAAQ,SAAS;EAC3E,OAAO,IAAI,SAAS;CACtB;CAEA,MAAM,SAAS,MAAc,cAAmD;EAC9E,IAAI,CAAC,KAAK,aACR,MAAM,IAAI,MAAM,oEAAoE;EACtF,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,+CAA+C;EAC1E,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,gEAAgE;EAClF,MAAM,SAAS,MAAM,KAAK,MAAM;GAC9B,YAAY;GACZ;GACA,cAAc,KAAK;GACnB,eAAe;EACjB,CAAC;EACD,OAAO;GAAE;GAAQ,MAAM,MAAM,KAAK,SAAS,OAAO,WAAW;EAAE;CACjE;;CAGA,MAAM,QAAQ,cAA2C;EACvD,IAAI,CAAC,cAAc,MAAM,IAAI,MAAM,sDAAsD;EACzF,OAAO,KAAK,MAAM;GAAE,YAAY;GAAiB,eAAe;EAAa,CAAC;CAChF;CAEA,MAAM,SAAS,aAAwC;EACrD,IAAI,CAAC,aAAa,MAAM,IAAI,MAAM,sDAAsD;EACxF,MAAM,MAAM,MAAM,KAAK,UAAU,GAAG,KAAK,QAAQ,4BAA4B;GAC3E,SAAS,EAAE,eAAe,UAAU,cAAc;GAClD,UAAU;EACZ,CAAC;EACD,MAAM,OAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,YAAY,IAAI;EACvD,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,kBACR,WAAW,MAAM,6BAA6B,IAAI,OAAO,EAAE,GAC3D,IAAI,QACJ,IACF;EACF,IACE,CAAC,SAAS,IAAI,KACd,CAAC,iBAAiB,KAAK,GAAG,KAC1B,CAAC,iBAAiB,KAAK,KAAK,KAC5B,KAAK,mBAAmB,MAExB,MAAM,IAAI,kBAAkB,8CAA8C,IAAI,QAAQ,EACpF,MAAM,4BACR,CAAC;EAEH,OAAO;GACL,IAAI,KAAK;GACT,OAAO,KAAK;GACZ,eAAe;GACf,GAAI,iBAAiB,KAAK,IAAI,IAAI,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EAC3D;CACF;;CAGA,MAAM,OAAO,OAAe,eAAiE;EAC3F,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,8CAA8C;EAC1E,MAAM,MAAM,MAAM,KAAK,KACrB,GAAG,KAAK,QAAQ,0BAChB;GACE;GACA,GAAI,gBAAgB,EAAE,iBAAiB,cAAc,IAAI,CAAC;EAC5D,GACA,KAAA,GACA,KACF;EACA,IAAI,CAAC,IAAI,IAAI;GACX,MAAM,OAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,YAAY,IAAI;GACvD,MAAM,IAAI,kBACR,WAAW,MAAM,2BAA2B,IAAI,OAAO,EAAE,GACzD,IAAI,QACJ,IACF;EACF;CACF;;;;;;CAOA,MAAM,gBAAgB,UAAoC,CAAC,GAAqC;EAC9F,MAAM,YAAY,MAAM,KAAK,UAC3B,GAAG,KAAK,QAAQ,6CAChB;GACE,UAAU;GACV,QAAQ,QAAQ;EAClB,CACF;EACA,MAAM,WAAoB,MAAM,UAAU,KAAK,CAAC,CAAC,YAAY,IAAI;EACjE,MAAM,SAAS,GAAG,KAAK,QAAQ;EAC/B,IACE,CAAC,UAAU,MACX,CAAC,SAAS,QAAQ,KAClB,SAAS,WAAW,UACpB,SAAS,mBAAmB,GAAG,OAAO,kBACtC,CAAC,MAAM,QAAQ,SAAS,qBAAqB,KAC7C,CAAC,SAAS,sBAAsB,SAAS,YAAY,KACrD,CAAC,iBAAiB,SAAS,6BAA6B,GAExD,MAAM,IAAI,kBACR,mDACA,UAAU,QACV,EAAE,MAAM,iCAAiC,CAC3C;EAEF,MAAM,WAAW,IAAI,IAAI,SAAS,6BAA6B;EAC/D,MAAM,SAAS,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC;EACrC,IAAI,SAAS,WAAW,UAAU,SAAS,YAAY,SAAS,YAAY,SAAS,MACnF,MAAM,IAAI,kBAAkB,oDAAoD,KAAK,EACnF,MAAM,0BACR,CAAC;EAEH,MAAM,YAAY,KAAK,IAAI;EAC3B,MAAM,MAAM,MAAM,KAAK,KAAK,SAAS,MAAM,EAAE,OAAO,KAAK,MAAM,GAAG,QAAQ,MAAM;EAChF,MAAM,OAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,YAAY,IAAI;EACvD,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,kBACR,WAAW,MAAM,gCAAgC,IAAI,OAAO,EAAE,GAC9D,IAAI,QACJ,IACF;EACF,IACE,CAAC,SAAS,IAAI,KACd,CAAC,iBAAiB,KAAK,WAAW,KAClC,CAAC,iBAAiB,KAAK,SAAS,KAChC,CAAC,iBAAiB,KAAK,gBAAgB,KACvC,OAAO,KAAK,eAAe,YAC3B,CAAC,OAAO,cAAc,KAAK,UAAU,KACrC,KAAK,cAAc,KAClB,KAAK,aAAa,KAAA,MAChB,OAAO,KAAK,aAAa,YACxB,CAAC,OAAO,cAAc,KAAK,QAAQ,KACnC,KAAK,YAAY,IAErB,MAAM,IAAI,kBAAkB,2CAA2C,IAAI,QAAQ,EACjF,MAAM,0BACR,CAAC;EAEH,KAAK,MAAM,SAAS,CAAC,KAAK,kBAAkB,KAAK,yBAAyB,GAAG;GAC3E,IAAI,UAAU,KAAA,GAAW;GACzB,IAAI,CAAC,iBAAiB,KAAK,GACzB,MAAM,IAAI,kBAAkB,mCAAmC,KAAK,EAClE,MAAM,0BACR,CAAC;GACH,MAAM,MAAM,IAAI,IAAI,KAAK;GACzB,IAAI,IAAI,WAAW,UAAU,IAAI,YAAY,IAAI,YAAY,IAAI,MAC/D,MAAM,IAAI,kBAAkB,iDAAiD,KAAK,EAChF,MAAM,0BACR,CAAC;EAEL;EACA,OAAO;GACL,YAAY,KAAK;GACjB,UAAU,KAAK;GACf,iBAAiB,KAAK;GACtB,GAAI,iBAAiB,KAAK,yBAAyB,IAC/C,EAAE,yBAAyB,KAAK,0BAA0B,IAC1D,CAAC;GACL,WAAW,KAAK;GAChB,WAAW,YAAY,KAAK,aAAa;GACzC,UAAU,OAAO,KAAK,aAAa,WAAW,KAAK,WAAW;EAChE;CACF;;CAGA,MAAM,wBACJ,OACA,UAAoC,CAAC,GAChB;EACrB,IACE,CAAC,MAAM,cACP,CAAC,OAAO,SAAS,MAAM,SAAS,KAChC,CAAC,OAAO,SAAS,MAAM,QAAQ,KAC/B,MAAM,YAAY,GAElB,MAAM,IAAI,MAAM,kEAAkE;EAEpF,IAAI,aAAa,MAAM,WAAW;EAClC,OAAO,KAAK,IAAI,IAAI,MAAM,WAAW;GACnC,QAAQ,QAAQ,eAAe;GAC/B,MAAM,MAAM,KAAK,IAAI,YAAY,KAAK,IAAI,GAAG,MAAM,YAAY,KAAK,IAAI,CAAC,CAAC,GAAG,QAAQ,MAAM;GAC3F,MAAM,YAAY,MAAM,YAAY,KAAK,IAAI;GAC7C,IAAI,aAAa,GAAG;GACpB,MAAM,UAAU,YAAY,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAQ,KAAK,MAAM,SAAS,CAAC,CAAC,CAAC;GACxF,MAAM,SAAS,QAAQ,SAAS,YAAY,IAAI,CAAC,QAAQ,QAAQ,OAAO,CAAC,IAAI;GAC7E,IAAI;IACF,OAAO,MAAM,KAAK,MAAM;KAAE,YAAY;KAAc,aAAa,MAAM;IAAW,GAAG,MAAM;GAC7F,SAAS,OAAO;IACd,QAAQ,QAAQ,eAAe;IAC/B,IAAI,QAAQ,SAAS;KACnB,cAAc;KACd;IACF;IACA,IAAI,EAAE,iBAAiB,sBAAsB,CAAC,SAAS,MAAM,IAAI,GAAG,MAAM;IAC1E,IAAI,MAAM,KAAK,UAAU,yBAAyB;IAClD,IAAI,MAAM,KAAK,UAAU,aAAa;KACpC,cAAc;KACd;IACF;IACA,MAAM;GACR;EACF;EACA,MAAM,IAAI,kBAAkB,gCAAgC,KAAK,EAAE,OAAO,gBAAgB,CAAC;CAC7F;CAEA,MAAc,MAAM,QAAgC,QAA2C;EAC7F,MAAM,MAAM,MAAM,KAAK,KAAK,GAAG,KAAK,QAAQ,yBAAyB,QAAQ,MAAM;EACnF,MAAM,OAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,YAAY,IAAI;EACvD,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,kBACR,WAAW,MAAM,kCAAkC,IAAI,OAAO,EAAE,GAChE,IAAI,QACJ,IACF;EACF,OAAO,YAAY,MAAM,IAAI,MAAM;CACrC;CAEA,KACE,KACA,QACA,QACA,mBAAmB,MACA;EACnB,MAAM,OAAO,IAAI,gBAAgB,MAAM;EACvC,MAAM,UAAkC,EAAE,gBAAgB,oCAAoC;EAC9F,IAAI,KAAK,cAEP,QAAQ,gBAAgB,SAAS,KAAK,GAAG,cAAc,KAAK,QAAQ,EAAE,GAAG,cAAc,KAAK,YAAY,GAAG;OACtG,KAAK,IAAI,aAAa,KAAK,QAAQ;EAC1C,IAAI,kBAAkB,KAAK,MAAM,YAAY,KAAK,WAAW,KAAK,OAAO,YAAY,QAAQ;EAC7F,OAAO,KAAK,UAAU,KAAK;GAAE,QAAQ;GAAQ;GAAS;GAAM,UAAU;GAAS;EAAO,CAAC;CACzF;AACF"}
|
|
1
|
+
{"version":3,"file":"platform.js","names":["isNonemptyString"],"sources":["../src/platform/auth.ts","../src/platform/integrations.ts","../src/platform/oidc.ts"],"sourcesContent":["/**\n * Server-side client for the Tangle platform's cross-site SSO bridge.\n *\n * Consumer apps (gtm-agent, tax-agent, legal-agent, creative-agent, …)\n * use this to:\n * 1. Build an /authorize URL that lands the user on id.tangle.tools\n * and brings them back with a single-use code.\n * 2. Exchange that code for an API key + the user's identity.\n *\n * The platform endpoint contract is documented in\n * the cross-site route in agent-container's platform API. This client only\n * speaks HTTP — no SDK weight, no transitive deps.\n */\n\nimport { isRecord } from '@tangle-network/agent-core'\n\nexport interface PlatformAuthClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** App id as registered in the platform's TRUSTED_APPS registry. */\n appId: string\n /** Override the global fetch (useful for tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\nexport interface AuthorizeUrlOptions {\n /** Required CSRF token; the consumer verifies it on the callback. */\n state: string\n /**\n * Final redirect URI. Must be one of the URIs registered for `appId`\n * on the platform. Omit to use the first registered URI.\n */\n redirectUri?: string\n /** Force the login screen even if a session is already active. */\n prompt?: 'login'\n /** Pre-fill the email field on the login screen. */\n email?: string\n}\n\nexport interface ExchangeCodeResult {\n apiKey: string\n emailVerified: true\n user: {\n id: string\n email: string\n name?: string | null\n }\n /** Null when the platform could not provide a subscription. This is not a paid-access grant. */\n plan: {\n tier: string\n } | null\n}\n\n/** Thrown when a `PlatformAuthClient` request returns a non-success status. */\nexport class PlatformAuthError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformAuthError'\n }\n}\n\nfunction isNonemptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0\n}\n\n/** Validate the platform's verified identity before consumers create a local session. */\nfunction parseExchangeResult(body: unknown, status: number): ExchangeCodeResult {\n const invalid = (): never => {\n // A successful but malformed response can contain the one-time API secret.\n throw new PlatformAuthError(\n 'Platform exchange response has no valid verified identity',\n status,\n { code: 'INVALID_EXCHANGE_RESPONSE' },\n )\n }\n if (\n !isRecord(body) ||\n !isNonemptyString(body.apiKey) ||\n body.emailVerified !== true ||\n !isRecord(body.user)\n )\n return invalid()\n const user = body.user\n if (!isNonemptyString(user.id) || !isNonemptyString(user.email)) return invalid()\n const email = user.email.trim()\n if (\n email.length > 320 ||\n !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email) ||\n /(?:@users\\.noreply\\.tangle\\.tools$|^0x[a-f0-9]{40}@tangle\\.tools$)/i.test(email)\n )\n return invalid()\n if (user.name !== undefined && user.name !== null && typeof user.name !== 'string')\n return invalid()\n let plan: ExchangeCodeResult['plan'] = null\n if (body.subscription !== undefined) {\n if (!isRecord(body.subscription) || !isNonemptyString(body.subscription.plan)) return invalid()\n plan = { tier: body.subscription.plan }\n }\n return {\n apiKey: body.apiKey,\n emailVerified: true,\n user: { id: user.id, email, ...(user.name !== undefined ? { name: user.name } : {}) },\n plan,\n }\n}\n\n/** HTTP client for the Tangle Platform SSO: builds authorize URLs and exchanges auth codes for API keys. */\nexport class PlatformAuthClient {\n private readonly baseUrl: string\n private readonly appId: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformAuthClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformAuthClient: baseUrl is required')\n if (!options.appId) throw new Error('PlatformAuthClient: appId is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.appId = options.appId\n this.fetchImpl =\n options.fetchImpl ??\n ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => fetch(url, init))\n }\n\n /**\n * Build the URL the user is redirected to in order to start SSO.\n * The platform redirects back to one of `appId`'s registered\n * `redirectUris` with `?code=...&app=...&state=...`.\n */\n authorizeUrl(options: AuthorizeUrlOptions): string {\n if (!options.state) {\n throw new Error('PlatformAuthClient.authorizeUrl: state is required for CSRF')\n }\n const url = new URL('/cross-site/authorize', this.baseUrl)\n url.searchParams.set('app', this.appId)\n url.searchParams.set('state', options.state)\n if (options.redirectUri) url.searchParams.set('redirect', options.redirectUri)\n if (options.prompt) url.searchParams.set('prompt', options.prompt)\n if (options.email) url.searchParams.set('email', options.email)\n return url.toString()\n }\n\n /**\n * Exchange a single-use auth code (delivered to the consumer's\n * callback by the platform) for an API key + the user's identity.\n * Codes are single-use and expire ~5 minutes after issue.\n */\n async exchange(code: string): Promise<ExchangeCodeResult> {\n if (!code) throw new Error('PlatformAuthClient.exchange: code is required')\n const res = await this.fetchImpl(`${this.baseUrl}/cross-site/exchange`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ code, app: this.appId }),\n })\n const body = await res.json().catch(() => null)\n if (!res.ok) {\n const message =\n body && typeof body === 'object' && 'error' in body && typeof body.error === 'string'\n ? body.error\n : `Platform exchange failed (${res.status})`\n throw new PlatformAuthError(message, res.status, body)\n }\n return parseExchangeResult(body, res.status)\n }\n}\n","/**\n * Server-side client for the Tangle platform's integration hub\n * (`/v1/hub/*`). Consumer apps use this instead of rolling their own\n * OAuth + connection tables.\n *\n * Auth: the caller supplies a bearer (either the user's API key from\n * cross-site exchange, or a platform service token) on construction.\n *\n * Endpoint contract (authoritative): the platform API's hub contract\n * and hub route (both in agent-container's platform API). The platform wraps every response in\n * `{ success, data }`; non-2xx or `success:false` surfaces as `PlatformHubError`\n * carrying the real upstream status.\n */\n\nexport interface PlatformHubClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** Bearer credential — user API key or service token. */\n bearer: string\n /** Override fetch (tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\n/** A live integration connection, as returned by `/v1/hub/connections`. */\nexport interface PlatformConnection {\n id: string\n providerId: string\n displayName: string\n accountDisplay: string | null\n scopes: string[]\n status: 'active' | 'revoked' | 'unhealthy' | 'reconnect_required' | (string & {})\n health: 'unknown' | 'healthy' | 'unhealthy' | 'rate_limited' | (string & {})\n createdAt: string\n updatedAt: string\n lastUsedAt: string | null\n}\n\n/** A connectable provider in the catalog (`/v1/hub/providers`). */\nexport interface PlatformCatalogProvider {\n providerId: string\n title?: string\n authKind?: string\n category?: string\n scopes?: string[]\n capabilityCount?: number\n native?: boolean\n /** Whether the OAuth app's credentials are wired — the UI offers Connect\n * only when true. */\n configured?: boolean\n [k: string]: unknown\n}\n\nexport interface CatalogResult {\n providers: PlatformCatalogProvider[]\n /** Count of substrate-bundled connectors behind the catalog. */\n substrateBundled?: number\n [k: string]: unknown\n}\n\nexport interface StartAuthInput {\n /** The provider to connect (goes in the URL path). */\n providerId: string\n /** Accepted for interface compatibility; the platform's start endpoint is\n * provider-level and does not consume a connector id. */\n connectorId?: string\n /** Where the platform redirects the user back to after OAuth. */\n returnUrl: string\n /** Accepted for interface compatibility; not consumed by the start endpoint. */\n requestedScopes?: string[]\n /** CLI flow flag — affects the platform's post-auth redirect handling. */\n cli?: boolean\n}\n\nexport interface StartAuthResult {\n /** The URL to send the user to. Normalized across the platform's two start\n * branches: github returns `authorizationUrl`, substrate returns\n * `redirectUrl`. */\n authorizationUrl: string\n state: string\n expiresAt?: string\n scopes?: string[]\n}\n\nexport interface ConnectionHealth {\n status: 'unknown' | 'healthy' | 'unhealthy' | 'rate_limited' | (string & {})\n checkedAt: string\n error?: { code: string; message: string }\n}\n\nexport interface ConnectionHealthResult {\n connection: PlatformConnection\n health: ConnectionHealth\n}\n\n/** Last-known health for a connection, derived from the connection row. */\nexport interface HealthCheck {\n connectionId: string\n providerId: string\n /** Mirrors `PlatformConnection.health`. */\n status: ConnectionHealth['status']\n checkedAt?: string\n}\n\nexport interface MintTokenInput {\n /** The hub action the token authorizes (e.g. `slack.chat.postMessage`). */\n actionPath: string\n /** Bind to a specific connection, or … */\n connectionId?: string\n /** … resolve the connection by provider for the calling user. */\n provider?: string\n}\n\nexport interface MintTokenResult {\n tokenId: string\n token: string\n expiresAt: string\n}\n\nexport interface ExecInput {\n /** The hub action path to execute. */\n path: string\n input?: unknown\n connectionId?: string\n}\n\nexport interface PlatformHubStatus {\n contract?: unknown\n principal: { kind: string; userId: string; [k: string]: unknown }\n connections: { connectedProviderCount: number; unhealthyProviderCount: number }\n}\n\n/** Thrown when a `PlatformHubClient` request returns a non-success status. */\nexport class PlatformHubError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code: string | undefined,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformHubError'\n }\n}\n\ninterface PlatformEnvelope<T> {\n success: boolean\n data?: T\n error?: { code?: string; message?: string } | string\n}\n\n/** HTTP client for the Tangle Platform Hub API: provider catalog, connection flow, and status. */\nexport class PlatformHubClient {\n private readonly baseUrl: string\n private readonly bearer: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformHubClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformHubClient: baseUrl is required')\n if (!options.bearer) throw new Error('PlatformHubClient: bearer is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.bearer = options.bearer\n this.fetchImpl =\n options.fetchImpl ??\n ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => fetch(url, init))\n }\n\n /** GET /v1/hub/providers — the connectable provider catalog. */\n catalog(): Promise<CatalogResult> {\n return this.request('GET', '/v1/hub/providers')\n }\n\n /** GET /v1/hub/connections — the calling user's live connections. */\n async listConnections(): Promise<PlatformConnection[]> {\n const data = await this.request<{ connections: PlatformConnection[] }>(\n 'GET',\n '/v1/hub/connections',\n )\n return data.connections\n }\n\n /** DELETE /v1/hub/connections/:connectionId — revoke + disable a connection. */\n revokeConnection(connectionId: string): Promise<{ connection: PlatformConnection }> {\n return this.request('DELETE', `/v1/hub/connections/${encodeURIComponent(connectionId)}`)\n }\n\n /**\n * POST /v1/hub/connections/:provider/start — begin OAuth/grant. The provider\n * is taken from the URL; the body carries `returnUrl` (+ `cli`). The platform's\n * two start branches name the URL field differently (github → `authorizationUrl`,\n * substrate → `redirectUrl`); this normalizes to `authorizationUrl`.\n */\n async startAuth(input: StartAuthInput): Promise<StartAuthResult> {\n const body: { returnUrl: string; cli?: boolean } = { returnUrl: input.returnUrl }\n if (input.cli !== undefined) body.cli = input.cli\n const data = await this.request<{\n authorizationUrl?: string\n redirectUrl?: string\n state: string\n expiresAt?: string\n scopes?: string[]\n }>('POST', `/v1/hub/connections/${encodeURIComponent(input.providerId)}/start`, body)\n const authorizationUrl = data.authorizationUrl ?? data.redirectUrl\n if (!authorizationUrl) {\n throw new PlatformHubError(\n 'Platform hub start response missing an authorization URL',\n 502,\n 'HUB_INVALID_START_RESPONSE',\n data,\n )\n }\n return { authorizationUrl, state: data.state, expiresAt: data.expiresAt, scopes: data.scopes }\n }\n\n /**\n * Last-known health for every connection. The platform has no global\n * healthcheck listing — health rides on each connection row — so this derives\n * the list from `listConnections()` (one request, no extra round-trips).\n */\n async listHealthchecks(): Promise<HealthCheck[]> {\n const connections = await this.listConnections()\n return connections.map((c) => ({\n connectionId: c.id,\n providerId: c.providerId,\n status: c.health,\n checkedAt: c.updatedAt,\n }))\n }\n\n /**\n * POST /v1/hub/connections/:connectionId/health — trigger a fresh health\n * probe for one connection and return its updated state.\n */\n checkConnectionHealth(connectionId: string): Promise<ConnectionHealthResult> {\n return this.request('POST', `/v1/hub/connections/${encodeURIComponent(connectionId)}/health`)\n }\n\n /**\n * Trigger a fresh health probe across all of the user's connections. The\n * platform exposes health per-connection only, so this fans out over\n * `listConnections()`. `scheduled` is the number of probes dispatched.\n */\n async runHealthchecks(): Promise<{ scheduled: number }> {\n const connections = await this.listConnections()\n await Promise.allSettled(connections.map((c) => this.checkConnectionHealth(c.id)))\n return { scheduled: connections.length }\n }\n\n /** GET /v1/hub/status — principal + aggregate connection counts. */\n status(): Promise<PlatformHubStatus> {\n return this.request('GET', '/v1/hub/status')\n }\n\n /**\n * POST /v1/hub/tokens — mint a short-lived, action-scoped capability token a\n * sandbox can use to invoke one hub action on the user's behalf without\n * seeing the underlying provider credential.\n */\n mintToken(input: MintTokenInput): Promise<MintTokenResult> {\n return this.request('POST', '/v1/hub/tokens', input)\n }\n\n /** POST /v1/hub/exec — execute a hub action and return its result. */\n async exec(input: ExecInput): Promise<unknown> {\n const data = await this.request<{ result: unknown }>('POST', '/v1/hub/exec', input)\n return data.result\n }\n\n private async request<T>(\n method: 'GET' | 'POST' | 'DELETE' | 'PUT',\n path: string,\n body?: unknown,\n ): Promise<T> {\n const headers: Record<string, string> = {\n authorization: `Bearer ${this.bearer}`,\n accept: 'application/json',\n }\n if (body !== undefined) headers['content-type'] = 'application/json'\n\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n const text = await res.text()\n let parsed: PlatformEnvelope<T> | null = null\n if (text) {\n try {\n parsed = JSON.parse(text)\n } catch {\n // fall through to error handling below\n }\n }\n if (!res.ok || (parsed && parsed.success === false)) {\n const code = parsed?.error && typeof parsed.error === 'object' ? parsed.error.code : undefined\n const message =\n (parsed?.error && typeof parsed.error === 'object' && parsed.error.message) ||\n (typeof parsed?.error === 'string' ? parsed.error : `Platform hub error (${res.status})`)\n throw new PlatformHubError(message, res.status, code, parsed ?? text)\n }\n if (!parsed) {\n throw new PlatformHubError(\n `Platform hub returned non-JSON success (${res.status})`,\n res.status,\n undefined,\n text,\n )\n }\n if (parsed.data === undefined) {\n throw new PlatformHubError(\n 'Platform hub envelope missing `data`',\n res.status,\n undefined,\n parsed,\n )\n }\n return parsed.data\n }\n}\n","/**\n * OpenID Connect client for the Tangle authorization server. Identity tokens\n * are not platform API keys. Resource scopes and audiences must be registered\n * by the provider before a consumer can use these tokens at a paid API.\n */\n\nimport { isRecord } from '@tangle-network/agent-core'\nimport { PlatformAuthError } from './auth.js'\n\nexport interface PlatformOidcClientOptions {\n baseUrl: string\n clientId: string\n /** Omit only for clients registered with token_endpoint_auth_method=none. */\n clientSecret?: string\n /** Required for authorization code; not required for the device grant. */\n redirectUri?: string\n scope?: string\n /** RFC 8707 resource identifiers registered at the authorization server. */\n resources?: readonly string[]\n fetchImpl?: typeof fetch\n}\n\nexport interface OidcAuthorizeUrlOptions {\n state: string\n codeChallenge: string\n /** Only supply a nonce when the consumer also validates the ID token. */\n nonce?: string\n prompt?: 'login' | 'consent' | 'none'\n loginHint?: string\n}\n\nexport interface OidcTokens {\n accessToken: string\n tokenType: string\n expiresIn?: number\n refreshToken?: string\n idToken?: string\n scope?: string\n}\n\nexport interface OidcUser {\n id: string\n email: string\n emailVerified: true\n name?: string\n}\n\nexport interface OidcExchangeResult {\n tokens: OidcTokens\n user: OidcUser\n}\n\n/** Keep deviceCode secret. Only userCode and the verification URLs are displayed. */\nexport interface OidcDeviceAuthorization {\n deviceCode: string\n userCode: string\n verificationUri: string\n verificationUriComplete?: string\n expiresIn: number\n /** Absolute deadline preserves expiry when a polling process resumes. */\n expiresAt: number\n interval: number\n}\n\nconst DEFAULT_SCOPE = 'openid profile email offline_access'\nconst DEVICE_GRANT = 'urn:ietf:params:oauth:grant-type:device_code'\n\nfunction isNonemptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0\n}\n\nfunction base64url(bytes: Uint8Array): string {\n let binary = ''\n for (const byte of bytes) binary += String.fromCharCode(byte)\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\n/** Create an RFC 7636 verifier and its S256 challenge with Web Crypto. */\nexport async function createPkcePair(): Promise<{ verifier: string; challenge: string }> {\n const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)))\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier))\n return { verifier, challenge: base64url(new Uint8Array(digest)) }\n}\n\nfunction oauthError(body: unknown, fallback: string): string {\n if (!isRecord(body)) return fallback\n if (isNonemptyString(body.error_description)) return body.error_description\n if (isNonemptyString(body.error)) return body.error\n return fallback\n}\n\nfunction parseTokens(body: unknown, status: number): OidcTokens {\n if (!isRecord(body) || !isNonemptyString(body.access_token)) {\n throw new PlatformAuthError('Platform token response is malformed', status, {\n code: 'INVALID_TOKEN_RESPONSE',\n })\n }\n return {\n accessToken: body.access_token,\n tokenType: isNonemptyString(body.token_type) ? body.token_type : 'Bearer',\n ...(typeof body.expires_in === 'number' ? { expiresIn: body.expires_in } : {}),\n ...(isNonemptyString(body.refresh_token) ? { refreshToken: body.refresh_token } : {}),\n ...(isNonemptyString(body.id_token) ? { idToken: body.id_token } : {}),\n ...(isNonemptyString(body.scope) ? { scope: body.scope } : {}),\n }\n}\n\nfunction formComponent(value: string): string {\n return new URLSearchParams({ v: value }).toString().slice(2)\n}\n\nfunction pause(ms: number, signal?: AbortSignal): Promise<void> {\n signal?.throwIfAborted()\n return new Promise((resolve, reject) => {\n const finish = () => {\n signal?.removeEventListener('abort', abort)\n resolve()\n }\n const timer = setTimeout(finish, ms)\n const abort = () => {\n clearTimeout(timer)\n signal?.removeEventListener('abort', abort)\n reject(signal?.reason ?? new Error('Device authorization cancelled'))\n }\n signal?.addEventListener('abort', abort, { once: true })\n })\n}\n\n/** OIDC code + PKCE, refresh/revoke and discovery-bound RFC 8628 device grants. */\nexport class PlatformOidcClient {\n private readonly baseUrl: string\n private readonly clientId: string\n private readonly clientSecret: string | undefined\n private readonly redirectUri: string | undefined\n private readonly scope: string\n private readonly resources: readonly string[]\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformOidcClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformOidcClient: baseUrl is required')\n if (!options.clientId) throw new Error('PlatformOidcClient: clientId is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.clientId = options.clientId\n this.clientSecret = options.clientSecret || undefined\n this.redirectUri = options.redirectUri\n this.scope = options.scope ?? DEFAULT_SCOPE\n this.resources = [...new Set(options.resources ?? [])]\n for (const resource of this.resources) {\n const url = new URL(resource)\n if (url.hash || url.username || url.password) {\n throw new Error('PlatformOidcClient: resource must not contain a fragment or credentials')\n }\n }\n this.fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init))\n }\n\n authorizeUrl(options: OidcAuthorizeUrlOptions): string {\n if (!this.redirectUri)\n throw new Error('PlatformOidcClient: redirectUri is required for authorization code')\n if (!options.state)\n throw new Error('PlatformOidcClient.authorizeUrl: state is required for CSRF')\n if (!options.codeChallenge)\n throw new Error('PlatformOidcClient.authorizeUrl: codeChallenge is required for PKCE')\n const url = new URL('/api/auth/oauth2/authorize', this.baseUrl)\n url.searchParams.set('client_id', this.clientId)\n url.searchParams.set('redirect_uri', this.redirectUri)\n url.searchParams.set('response_type', 'code')\n url.searchParams.set('scope', this.scope)\n url.searchParams.set('state', options.state)\n url.searchParams.set('code_challenge', options.codeChallenge)\n url.searchParams.set('code_challenge_method', 'S256')\n for (const resource of this.resources) url.searchParams.append('resource', resource)\n if (options.nonce) url.searchParams.set('nonce', options.nonce)\n if (options.prompt) url.searchParams.set('prompt', options.prompt)\n if (options.loginHint) url.searchParams.set('login_hint', options.loginHint)\n return url.toString()\n }\n\n async exchange(code: string, codeVerifier: string): Promise<OidcExchangeResult> {\n if (!this.redirectUri)\n throw new Error('PlatformOidcClient: redirectUri is required for authorization code')\n if (!code) throw new Error('PlatformOidcClient.exchange: code is required')\n if (!codeVerifier)\n throw new Error('PlatformOidcClient.exchange: codeVerifier is required for PKCE')\n const tokens = await this.token({\n grant_type: 'authorization_code',\n code,\n redirect_uri: this.redirectUri,\n code_verifier: codeVerifier,\n })\n return { tokens, user: await this.userinfo(tokens.accessToken) }\n }\n\n /** Save the replacement refresh token. Never retry an old token as a new grant. */\n async refresh(refreshToken: string): Promise<OidcTokens> {\n if (!refreshToken) throw new Error('PlatformOidcClient.refresh: refreshToken is required')\n return this.token({ grant_type: 'refresh_token', refresh_token: refreshToken })\n }\n\n async userinfo(accessToken: string): Promise<OidcUser> {\n if (!accessToken) throw new Error('PlatformOidcClient.userinfo: accessToken is required')\n const res = await this.fetchImpl(`${this.baseUrl}/api/auth/oauth2/userinfo`, {\n headers: { authorization: `Bearer ${accessToken}` },\n redirect: 'error',\n })\n const body: unknown = await res.json().catch(() => null)\n if (!res.ok)\n throw new PlatformAuthError(\n oauthError(body, `Platform userinfo failed (${res.status})`),\n res.status,\n body,\n )\n if (\n !isRecord(body) ||\n !isNonemptyString(body.sub) ||\n !isNonemptyString(body.email) ||\n body.email_verified !== true\n ) {\n throw new PlatformAuthError('Platform userinfo has no verified identity', res.status, {\n code: 'INVALID_USERINFO_RESPONSE',\n })\n }\n return {\n id: body.sub,\n email: body.email,\n emailVerified: true,\n ...(isNonemptyString(body.name) ? { name: body.name } : {}),\n }\n }\n\n /** RFC 7009. A local logout alone is not a provider disconnect. */\n async revoke(token: string, tokenTypeHint?: 'access_token' | 'refresh_token'): Promise<void> {\n if (!token) throw new Error('PlatformOidcClient.revoke: token is required')\n const res = await this.post(\n `${this.baseUrl}/api/auth/oauth2/revoke`,\n {\n token,\n ...(tokenTypeHint ? { token_type_hint: tokenTypeHint } : {}),\n },\n undefined,\n false,\n )\n if (!res.ok) {\n const body: unknown = await res.json().catch(() => null)\n throw new PlatformAuthError(\n oauthError(body, `Platform revoke failed (${res.status})`),\n res.status,\n body,\n )\n }\n }\n\n /**\n * Start a device grant only when this issuer advertises the OAuth-integrated\n * device endpoint. No fallback to /cross-site/device or a standalone session\n * device endpoint: those issue different credentials.\n */\n async deviceAuthorize(options: { signal?: AbortSignal } = {}): Promise<OidcDeviceAuthorization> {\n const discovery = await this.fetchImpl(\n `${this.baseUrl}/api/auth/.well-known/openid-configuration`,\n {\n redirect: 'error',\n signal: options.signal,\n },\n )\n const metadata: unknown = await discovery.json().catch(() => null)\n const issuer = `${this.baseUrl}/api/auth`\n if (\n !discovery.ok ||\n !isRecord(metadata) ||\n metadata.issuer !== issuer ||\n metadata.token_endpoint !== `${issuer}/oauth2/token` ||\n !Array.isArray(metadata.grant_types_supported) ||\n !metadata.grant_types_supported.includes(DEVICE_GRANT) ||\n !isNonemptyString(metadata.device_authorization_endpoint)\n ) {\n throw new PlatformAuthError(\n 'Issuer does not advertise an OAuth device grant',\n discovery.status,\n { code: 'OAUTH_DEVICE_GRANT_UNAVAILABLE' },\n )\n }\n const endpoint = new URL(metadata.device_authorization_endpoint)\n const origin = new URL(this.baseUrl).origin\n if (endpoint.origin !== origin || endpoint.username || endpoint.password || endpoint.hash) {\n throw new PlatformAuthError('Device endpoint is outside the configured issuer', 400, {\n code: 'INVALID_DEVICE_ENDPOINT',\n })\n }\n const startedAt = Date.now()\n const res = await this.post(endpoint.href, { scope: this.scope }, options.signal)\n const body: unknown = await res.json().catch(() => null)\n if (!res.ok)\n throw new PlatformAuthError(\n oauthError(body, `Device authorization failed (${res.status})`),\n res.status,\n body,\n )\n if (\n !isRecord(body) ||\n !isNonemptyString(body.device_code) ||\n !isNonemptyString(body.user_code) ||\n !isNonemptyString(body.verification_uri) ||\n typeof body.expires_in !== 'number' ||\n !Number.isSafeInteger(body.expires_in) ||\n body.expires_in <= 0 ||\n (body.interval !== undefined &&\n (typeof body.interval !== 'number' ||\n !Number.isSafeInteger(body.interval) ||\n body.interval <= 0))\n ) {\n throw new PlatformAuthError('Malformed device authorization response', res.status, {\n code: 'INVALID_DEVICE_RESPONSE',\n })\n }\n for (const value of [body.verification_uri, body.verification_uri_complete]) {\n if (value === undefined) continue\n if (!isNonemptyString(value))\n throw new PlatformAuthError('Invalid device verification URI', 400, {\n code: 'INVALID_DEVICE_RESPONSE',\n })\n const uri = new URL(value)\n if (uri.origin !== origin || uri.username || uri.password || uri.hash) {\n throw new PlatformAuthError('Device verification URI is outside the issuer', 400, {\n code: 'INVALID_DEVICE_RESPONSE',\n })\n }\n }\n return {\n deviceCode: body.device_code,\n userCode: body.user_code,\n verificationUri: body.verification_uri,\n ...(isNonemptyString(body.verification_uri_complete)\n ? { verificationUriComplete: body.verification_uri_complete }\n : {}),\n expiresIn: body.expires_in,\n expiresAt: startedAt + body.expires_in * 1000,\n interval: typeof body.interval === 'number' ? body.interval : 5,\n }\n }\n\n /** RFC 8628 pending/slow_down handling, expiry, cancellation and timeout backoff. */\n async pollDeviceAuthorization(\n grant: OidcDeviceAuthorization,\n options: { signal?: AbortSignal } = {},\n ): Promise<OidcTokens> {\n if (\n !grant.deviceCode ||\n !Number.isFinite(grant.expiresAt) ||\n !Number.isFinite(grant.interval) ||\n grant.interval <= 0\n ) {\n throw new Error('PlatformOidcClient.pollDeviceAuthorization: invalid device grant')\n }\n let intervalMs = grant.interval * 1000\n while (Date.now() < grant.expiresAt) {\n options.signal?.throwIfAborted()\n await pause(Math.min(intervalMs, Math.max(0, grant.expiresAt - Date.now())), options.signal)\n const remaining = grant.expiresAt - Date.now()\n if (remaining <= 0) break\n const timeout = AbortSignal.timeout(Math.max(1, Math.min(30_000, Math.floor(remaining))))\n const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout\n try {\n return await this.token({ grant_type: DEVICE_GRANT, device_code: grant.deviceCode }, signal)\n } catch (error) {\n options.signal?.throwIfAborted()\n if (timeout.aborted) {\n intervalMs *= 2\n continue\n }\n if (!(error instanceof PlatformAuthError) || !isRecord(error.body)) throw error\n if (error.body.error === 'authorization_pending') continue\n if (error.body.error === 'slow_down') {\n intervalMs += 5_000\n continue\n }\n throw error\n }\n }\n throw new PlatformAuthError('Device authorization expired', 400, { error: 'expired_token' })\n }\n\n private async token(params: Record<string, string>, signal?: AbortSignal): Promise<OidcTokens> {\n const res = await this.post(`${this.baseUrl}/api/auth/oauth2/token`, params, signal)\n const body: unknown = await res.json().catch(() => null)\n if (!res.ok)\n throw new PlatformAuthError(\n oauthError(body, `Platform token request failed (${res.status})`),\n res.status,\n body,\n )\n return parseTokens(body, res.status)\n }\n\n private post(\n url: string,\n params: Record<string, string>,\n signal?: AbortSignal,\n includeResources = true,\n ): Promise<Response> {\n const body = new URLSearchParams(params)\n const headers: Record<string, string> = { 'content-type': 'application/x-www-form-urlencoded' }\n if (this.clientSecret) {\n // RFC 6749 section 2.3.1: form-encode each component before HTTP Basic.\n headers.authorization = `Basic ${btoa(`${formComponent(this.clientId)}:${formComponent(this.clientSecret)}`)}`\n } else body.set('client_id', this.clientId)\n if (includeResources) for (const resource of this.resources) body.append('resource', resource)\n return this.fetchImpl(url, { method: 'POST', headers, body, redirect: 'error', signal })\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { c as errorMessage } from "./util-ebWMWzY0.js";
|
|
2
|
+
import { A as verifyMaterializedProfileWorkspace, B as sha256Bytes$1, D as readMaterializedWorkspaceFiles, F as canonicalCandidateDocument, H as hasControlCharacter, I as deepFreezeCandidate, L as embeddedCandidateArtifact, M as verifyWorkspaceSnapshotArtifacts, N as canonicalCandidateBytes$1, O as readVerifiedArtifact, P as canonicalCandidateDigest$1, R as immutableCandidateValue, S as isWellFormedUnicode, b as persistCandidateOutputArtifact, d as readCandidateGitHubResource, f as verifyCandidateCode, j as verifyMaterializedWorkspace, k as verifyBytes, m as verifyTaskOutcomePatch, p as verifyTaskCheckout, w as artifactCacheKey, x as assertExactObjectKeys, z as omitTopLevelDigest } from "./sandbox-profile-compat-CXjozdWL.js";
|
|
3
|
+
import { _ as parseAgentCandidateProfileActivation, c as buildLaunch, f as exactProfileExecutorFiles, h as modelRoutes, l as candidateEntrypointReceipt, m as materializeAgentCandidateProfilePlan, n as PI_CANDIDATE_SESSION_DIR_ENV, r as absoluteExecutionCwd, s as assertCandidateProfileExecutionSupport, t as PI_CANDIDATE_AGENT_DIR_ENV, u as candidateProfileAgentPaths, x as requirePublicCandidateConfigValue } from "./profile-C01SQZKa.js";
|
|
4
|
+
import { i as redactProtectedValue, n as createProtectedRecordRedactor, r as redactProtectedReason, t as assertNoProtectedBytes } from "./protected-redaction-DilFZch5.js";
|
|
4
5
|
import { agentCandidateArtifactRefSchema, agentCandidateBenchmarkResultEvidenceSchema, agentCandidateBenchmarkSuiteSchema, agentCandidateBenchmarkTaskSchema, agentCandidateBundleSchema, agentCandidateContainerSchema, agentCandidateExecutionLimitsSchema, agentCandidateExecutionPlanEvidenceSchema, agentCandidateExecutionPlanMaterialSchema, agentCandidateMaterializationReceiptSchema, agentCandidateModelAccessNetworkSchema, agentCandidateModelSettlementEvidenceSchema, agentCandidateProfilePlanEvidenceSchema, agentCandidateResolvedModelSchema, agentCandidateRunCellSchema, agentCandidateRunReceiptSchema, agentCandidateTaskOutcomeEvidenceSchema, agentCandidateTaskOutcomeSpecSchema, agentCandidateTerminationSchema, agentCandidateWorkspaceManifestMaterialSchema, agentCandidateWorkspaceSnapshotEvidenceSchema, sha256DigestSchema } from "@tangle-network/agent-interface";
|
|
5
6
|
import { REDACTION_VERSION, isLlmSpan } from "@tangle-network/agent-eval";
|
|
6
7
|
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
@@ -10,7 +11,7 @@ import { applyAgentCandidateWorkspacePlan } from "@tangle-network/agent-profile-
|
|
|
10
11
|
import { isDeepStrictEqual } from "node:util";
|
|
11
12
|
import { tmpdir } from "node:os";
|
|
12
13
|
import { hashKnowledgeBase } from "@tangle-network/agent-knowledge";
|
|
13
|
-
|
|
14
|
+
// src/candidate-execution/execution-roots.ts
|
|
14
15
|
/** Validate the canonical identity and isolation boundary for execution roots. */
|
|
15
16
|
function assertAgentCandidateExecutionRoots(roots) {
|
|
16
17
|
const entries = [
|
|
@@ -40,8 +41,7 @@ function executionPathsOverlap(left, right) {
|
|
|
40
41
|
const b = posix.normalize(right);
|
|
41
42
|
return a === b || b.startsWith(a === "/" ? "/" : `${a}/`) || a.startsWith(b === "/" ? "/" : `${b}/`);
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
//#region src/candidate-execution/types.ts
|
|
44
|
+
// src/candidate-execution/types.ts
|
|
45
45
|
const verifiedCandidateBrand = Symbol("verifiedAgentCandidate");
|
|
46
46
|
const preparedCandidateBrand = Symbol("preparedAgentCandidate");
|
|
47
47
|
const verifiedTaskOutcomeBrand = Symbol("verifiedTaskOutcome");
|
|
@@ -60,8 +60,7 @@ const CANDIDATE_TRACE_ENV = {
|
|
|
60
60
|
materializationReceiptDigest: "TANGLE_CANDIDATE_MATERIALIZATION_RECEIPT_DIGEST",
|
|
61
61
|
traceRunId: "TANGLE_TRACE_RUN_ID"
|
|
62
62
|
};
|
|
63
|
-
|
|
64
|
-
//#region src/candidate-execution/verify.ts
|
|
63
|
+
// src/candidate-execution/verify.ts
|
|
65
64
|
const verifiedCandidateState = /* @__PURE__ */ new WeakMap();
|
|
66
65
|
/** Surfaces admitted by Runtime's verifier before an environment adapter is selected. */
|
|
67
66
|
const AGENT_CANDIDATE_EXECUTION_SUPPORT = Object.freeze({
|
|
@@ -174,8 +173,7 @@ function candidateResources(bundle) {
|
|
|
174
173
|
function resourceKey(resource) {
|
|
175
174
|
return canonicalCandidateDigest$1(resource);
|
|
176
175
|
}
|
|
177
|
-
|
|
178
|
-
//#region src/candidate-execution/knowledge.ts
|
|
176
|
+
// src/candidate-execution/knowledge.ts
|
|
179
177
|
/** Environment variable containing the materialized candidate knowledge root. */
|
|
180
178
|
const CANDIDATE_KNOWLEDGE_ROOT_ENV = "TANGLE_CANDIDATE_KNOWLEDGE_ROOT";
|
|
181
179
|
/** Environment variable containing the materialized retrieval configuration path. */
|
|
@@ -225,10 +223,9 @@ async function prepareAgentCandidateKnowledge(candidate, ports, arm) {
|
|
|
225
223
|
});
|
|
226
224
|
}
|
|
227
225
|
}
|
|
228
|
-
|
|
229
|
-
//#region src/candidate-execution/exact-process-executor.ts
|
|
226
|
+
// src/candidate-execution/exact-process-executor.ts
|
|
230
227
|
const DEFAULT_PROVISION_TIMEOUT_MS = 12e4;
|
|
231
|
-
const DEFAULT_RECOVERY_RETENTION_MS =
|
|
228
|
+
const DEFAULT_RECOVERY_RETENTION_MS = 9e5;
|
|
232
229
|
/** Adapt one neutral exact-process provider to Runtime's trusted candidate boundary. */
|
|
233
230
|
function exactProcessProviderAsCandidateExecutor(options) {
|
|
234
231
|
return new ExactProcessAgentCandidateExecutor(options);
|
|
@@ -266,7 +263,7 @@ var ExactProcessAgentCandidateExecutor = class {
|
|
|
266
263
|
if (this.states.has(key)) throw new Error("candidate execution environment is already active");
|
|
267
264
|
const image = exactImage(request.executionPlan.value.material.container.image, request.executionPlan.value.material.container.manifestDigest);
|
|
268
265
|
const maxLifetimeMs = environmentLifetimeMs(request.hardLimits.timeoutMs, this.recoveryRetentionMs);
|
|
269
|
-
const
|
|
266
|
+
const createMaterial = immutableCandidateValue({
|
|
270
267
|
kind: "agent-candidate-exact-process-create",
|
|
271
268
|
provider: this.options.provider.name,
|
|
272
269
|
executionId: request.executionId,
|
|
@@ -281,7 +278,8 @@ var ExactProcessAgentCandidateExecutor = class {
|
|
|
281
278
|
maxBytes: outcome.maxBytes
|
|
282
279
|
},
|
|
283
280
|
...this.providerOptions ? { providerOptions: this.providerOptions } : {}
|
|
284
|
-
})
|
|
281
|
+
});
|
|
282
|
+
const createInputDigest = canonicalCandidateDigest$1(createMaterial);
|
|
285
283
|
const metadata = immutableCandidateValue({
|
|
286
284
|
kind: "agent-candidate-execution",
|
|
287
285
|
provider: this.options.provider.name,
|
|
@@ -689,8 +687,7 @@ function beneath(root, relativePath) {
|
|
|
689
687
|
function isSha256Digest$1(value) {
|
|
690
688
|
return typeof value === "string" && /^sha256:[a-f0-9]{64}$/.test(value);
|
|
691
689
|
}
|
|
692
|
-
|
|
693
|
-
//#region src/candidate-execution/model-settlement.ts
|
|
690
|
+
// src/candidate-execution/model-settlement.ts
|
|
694
691
|
const USD_NANOS = 1e9;
|
|
695
692
|
/** Validate and detach the evaluator gateway's terminal, revoked call ledger. */
|
|
696
693
|
function sealAgentCandidateModelSettlement(settlement, expected) {
|
|
@@ -877,10 +874,9 @@ function safeAdd(left, right, label) {
|
|
|
877
874
|
if (!Number.isSafeInteger(total)) throw new Error(`${label} exceeds safe integer range`);
|
|
878
875
|
return total;
|
|
879
876
|
}
|
|
880
|
-
|
|
881
|
-
//#region src/candidate-execution/protected-model-port.ts
|
|
877
|
+
// src/candidate-execution/protected-model-port.ts
|
|
882
878
|
const MAX_RECENT_SETTLEMENTS = 4096;
|
|
883
|
-
const RECOVERED_SETTLEMENT_RETENTION_MS =
|
|
879
|
+
const RECOVERED_SETTLEMENT_RETENTION_MS = 9e5;
|
|
884
880
|
/**
|
|
885
881
|
* Bind a protected model-grant service to the immutable candidate runtime.
|
|
886
882
|
*
|
|
@@ -897,7 +893,8 @@ function createProtectedAgentCandidateModelPort(options) {
|
|
|
897
893
|
return {
|
|
898
894
|
resolve: async (input) => {
|
|
899
895
|
const request = immutableCandidateValue(input);
|
|
900
|
-
|
|
896
|
+
const resolved = validateResolvedModel(await options.resolveModel(request), request);
|
|
897
|
+
return immutableCandidateValue(resolved);
|
|
901
898
|
},
|
|
902
899
|
reserveGrant: async (input) => {
|
|
903
900
|
pruneExpiredState(reservations, expiredReservations, recentSettlements, Date.now());
|
|
@@ -1179,8 +1176,7 @@ function modelLimits(limits) {
|
|
|
1179
1176
|
maxCostUsd: limits.maxCostUsd
|
|
1180
1177
|
};
|
|
1181
1178
|
}
|
|
1182
|
-
|
|
1183
|
-
//#region src/candidate-execution/claim-file-formats.ts
|
|
1179
|
+
// src/candidate-execution/claim-file-formats.ts
|
|
1184
1180
|
function sealCandidatePreparationEvidence(value, executionPlanDigest) {
|
|
1185
1181
|
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("candidate execution preparation evidence must be an object");
|
|
1186
1182
|
const record = value;
|
|
@@ -1193,8 +1189,7 @@ function sealCandidatePreparationEvidence(value, executionPlanDigest) {
|
|
|
1193
1189
|
materializationReceipt
|
|
1194
1190
|
});
|
|
1195
1191
|
}
|
|
1196
|
-
|
|
1197
|
-
//#region src/candidate-execution/claim-terminal.ts
|
|
1192
|
+
// src/candidate-execution/claim-terminal.ts
|
|
1198
1193
|
const SHA256_PATTERN$1 = /^sha256:[a-f0-9]{64}$/;
|
|
1199
1194
|
function terminalRecord(claim, result) {
|
|
1200
1195
|
const terminal = sealTerminalResult(result);
|
|
@@ -1476,8 +1471,7 @@ function assertSha256Digest$1(value, field) {
|
|
|
1476
1471
|
function assertCount(value, label) {
|
|
1477
1472
|
if (!Number.isSafeInteger(value) || value < 0) throw new Error(`candidate execution ${label} must be a non-negative safe integer`);
|
|
1478
1473
|
}
|
|
1479
|
-
|
|
1480
|
-
//#region src/candidate-execution/cleanup.ts
|
|
1474
|
+
// src/candidate-execution/cleanup.ts
|
|
1481
1475
|
const DEFAULT_CANDIDATE_CLEANUP_TIMEOUT_MS = 3e4;
|
|
1482
1476
|
function candidateCleanupTimeout(timeoutMs) {
|
|
1483
1477
|
const effective = timeoutMs ?? DEFAULT_CANDIDATE_CLEANUP_TIMEOUT_MS;
|
|
@@ -1539,8 +1533,7 @@ var CandidateResultTimeoutError = class extends Error {
|
|
|
1539
1533
|
this.name = "CandidateResultTimeoutError";
|
|
1540
1534
|
}
|
|
1541
1535
|
};
|
|
1542
|
-
|
|
1543
|
-
//#region src/candidate-execution/claim.ts
|
|
1536
|
+
// src/candidate-execution/claim.ts
|
|
1544
1537
|
/** Durable one-shot lifecycle for candidate execution attempts. */
|
|
1545
1538
|
function attemptRecord(claim, phase, staged, terminal) {
|
|
1546
1539
|
return Object.freeze({
|
|
@@ -1879,8 +1872,7 @@ const candidateClaimFileInternals = Object.freeze({
|
|
|
1879
1872
|
sealClaim,
|
|
1880
1873
|
sealLease
|
|
1881
1874
|
});
|
|
1882
|
-
|
|
1883
|
-
//#region src/candidate-execution/execution-window.ts
|
|
1875
|
+
// src/candidate-execution/execution-window.ts
|
|
1884
1876
|
const CANDIDATE_TERMINAL_PERSISTENCE_MARGIN_MS = 1e4;
|
|
1885
1877
|
const CANDIDATE_POST_RUN_CLEANUP_PHASES = 4;
|
|
1886
1878
|
/** Process stop, access closure, model evidence, and task/result evidence. */
|
|
@@ -1901,8 +1893,7 @@ function candidateTerminalWindowMs(cleanupTimeoutMs) {
|
|
|
1901
1893
|
if (!Number.isSafeInteger(windowMs) || windowMs > 2147483647) throw new Error("candidate terminal window exceeds the supported timer range");
|
|
1902
1894
|
return windowMs;
|
|
1903
1895
|
}
|
|
1904
|
-
|
|
1905
|
-
//#region src/candidate-execution/prepared-state.ts
|
|
1896
|
+
// src/candidate-execution/prepared-state.ts
|
|
1906
1897
|
const stateByExecution = /* @__PURE__ */ new WeakMap();
|
|
1907
1898
|
const lifecycleByExecution = /* @__PURE__ */ new WeakMap();
|
|
1908
1899
|
function createPreparedCandidateExecution(input) {
|
|
@@ -2037,7 +2028,8 @@ function detachPreparedCandidateState(input) {
|
|
|
2037
2028
|
const profilePlan = immutableCandidateValue(agentCandidateProfilePlanEvidenceSchema.parse(input.profilePlan.value));
|
|
2038
2029
|
const profileActivation = parseAgentCandidateProfileActivation(input.profileActivation, profilePlan.digest);
|
|
2039
2030
|
const executionPlan = immutableCandidateValue(agentCandidateExecutionPlanEvidenceSchema.parse(input.executionPlan.value));
|
|
2040
|
-
const
|
|
2031
|
+
const receiptValue = immutableCandidateValue(agentCandidateMaterializationReceiptSchema.parse(input.materializationReceipt.value));
|
|
2032
|
+
const materializationReceipt = canonicalCandidateDocument(omitTopLevelDigest(receiptValue));
|
|
2041
2033
|
if (materializationReceipt.digest !== input.materializationReceipt.digest) throw new Error("materialization receipt digest changed while sealing prepared execution");
|
|
2042
2034
|
return Object.freeze({
|
|
2043
2035
|
ports: input.ports,
|
|
@@ -2087,7 +2079,8 @@ function detachPreparedCandidateState(input) {
|
|
|
2087
2079
|
}
|
|
2088
2080
|
function assertPrivateCandidateIntegrity(state) {
|
|
2089
2081
|
assertAgentCandidateExecutionRoots(state.roots.execution);
|
|
2090
|
-
|
|
2082
|
+
const bundleMaterial = omitTopLevelDigest(state.bundle);
|
|
2083
|
+
if (canonicalCandidateDigest$1(bundleMaterial) !== state.bundle.digest) throw new Error("prepared candidate bundle no longer matches its digest");
|
|
2091
2084
|
assertPlanEvidence(state.profilePlan.value, state.profilePlan.bytes, "profile plan");
|
|
2092
2085
|
parseAgentCandidateProfileActivation(state.profileActivation, state.profilePlan.value.digest);
|
|
2093
2086
|
assertPlanEvidence(state.executionPlan.value, state.executionPlan.bytes, "execution plan");
|
|
@@ -2248,8 +2241,7 @@ function assertProtectedEnvironment(state, modelEnvironment, memoryEnvironment)
|
|
|
2248
2241
|
seen.add(name);
|
|
2249
2242
|
}
|
|
2250
2243
|
}
|
|
2251
|
-
|
|
2252
|
-
//#region src/candidate-execution/claim-plan.ts
|
|
2244
|
+
// src/candidate-execution/claim-plan.ts
|
|
2253
2245
|
/** Extract the complete durable claim from a prepared execution. */
|
|
2254
2246
|
function candidateExecutionClaim(prepared, preparationEvidence) {
|
|
2255
2247
|
const state = assertPreparedCandidateIntegrity(prepared);
|
|
@@ -2333,8 +2325,7 @@ function retryLineageDigest(prepared, resultTimeoutMs) {
|
|
|
2333
2325
|
}
|
|
2334
2326
|
});
|
|
2335
2327
|
}
|
|
2336
|
-
|
|
2337
|
-
//#region src/candidate-execution/finalize.ts
|
|
2328
|
+
// src/candidate-execution/finalize.ts
|
|
2338
2329
|
/** Builds a candidate run receipt exclusively from protected trace and memory evidence. */
|
|
2339
2330
|
async function finalizeAgentCandidateRun(state, capture, traceStore, traceIdentity, settlement, evidence, protectedValues, writeRedactionReport, signal) {
|
|
2340
2331
|
let termination;
|
|
@@ -2373,7 +2364,7 @@ async function finalizeAgentCandidateRun(state, capture, traceStore, traceIdenti
|
|
|
2373
2364
|
}, protectedValues);
|
|
2374
2365
|
const combinedByRule = { ...writeRedactionReport?.byRule ?? {} };
|
|
2375
2366
|
for (const [rule, count] of Object.entries(redacted.report.byRule)) combinedByRule[rule] = (combinedByRule[rule] ?? 0) + count;
|
|
2376
|
-
const
|
|
2367
|
+
const traceMaterial = {
|
|
2377
2368
|
...redacted.value,
|
|
2378
2369
|
evaluatorLimits: { resultTimeoutMs: state.resultTimeoutMs },
|
|
2379
2370
|
redaction: {
|
|
@@ -2381,7 +2372,8 @@ async function finalizeAgentCandidateRun(state, capture, traceStore, traceIdenti
|
|
|
2381
2372
|
redactionCount: (writeRedactionReport?.redactionCount ?? 0) + redacted.report.redactionCount,
|
|
2382
2373
|
byRule: combinedByRule
|
|
2383
2374
|
}
|
|
2384
|
-
}
|
|
2375
|
+
};
|
|
2376
|
+
const traceBytes = canonicalCandidateBytes$1(traceMaterial);
|
|
2385
2377
|
assertNoProtectedBytes(traceBytes, protectedValues);
|
|
2386
2378
|
const trace = {
|
|
2387
2379
|
artifact: await persistCandidateOutputArtifact(evidence.outputArtifacts, {
|
|
@@ -2514,8 +2506,7 @@ function failedAgentCandidateRun(state, reason, termination, usage = null) {
|
|
|
2514
2506
|
function compareStrings(a, b) {
|
|
2515
2507
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
2516
2508
|
}
|
|
2517
|
-
|
|
2518
|
-
//#region src/candidate-execution/benchmark-grader.ts
|
|
2509
|
+
// src/candidate-execution/benchmark-grader.ts
|
|
2519
2510
|
/**
|
|
2520
2511
|
* Admit verified grader bytes to the evaluator runner and reject any result
|
|
2521
2512
|
* that is not bound to those bytes, the exact task outcome, and its raw output.
|
|
@@ -2560,12 +2551,13 @@ async function runBoundCandidateBenchmarkGrader(input) {
|
|
|
2560
2551
|
}
|
|
2561
2552
|
function snapshotGraderDescriptor(grader, expected) {
|
|
2562
2553
|
if (!grader.name || !grader.version) throw new Error("candidate benchmark grader name and version must be non-empty");
|
|
2563
|
-
|
|
2554
|
+
const actual = {
|
|
2564
2555
|
name: grader.name,
|
|
2565
2556
|
version: grader.version,
|
|
2566
2557
|
format: "tangle-grader",
|
|
2567
2558
|
artifact: grader.artifact
|
|
2568
|
-
}
|
|
2559
|
+
};
|
|
2560
|
+
if (canonicalCandidateDigest$1(actual) !== canonicalCandidateDigest$1(expected)) throw new Error("candidate benchmark grader does not match the signed task grader");
|
|
2569
2561
|
return immutableCandidateValue(expected);
|
|
2570
2562
|
}
|
|
2571
2563
|
function emptyFixedSpend() {
|
|
@@ -2598,8 +2590,7 @@ function assertExactRunnerResult(value) {
|
|
|
2598
2590
|
const bindingKeys = Object.keys(result.binding).sort();
|
|
2599
2591
|
if (bindingKeys.length !== 3 || bindingKeys[0] !== "implementationDigest" || bindingKeys[1] !== "outputDigest" || bindingKeys[2] !== "taskOutcomeDigest") throw new Error("candidate benchmark grader binding returned unknown or missing fields");
|
|
2600
2592
|
}
|
|
2601
|
-
|
|
2602
|
-
//#region src/candidate-execution/executor-capture-evidence.ts
|
|
2593
|
+
// src/candidate-execution/executor-capture-evidence.ts
|
|
2603
2594
|
/** Persist structurally valid post-stop bytes without claiming they passed outcome verification. */
|
|
2604
2595
|
async function persistAgentCandidateExecutorCapture(identity, expected, capture, outputArtifacts, signal) {
|
|
2605
2596
|
const executorEvidence = capture.evidence ? await persistCandidateOutputArtifact(outputArtifacts, {
|
|
@@ -2681,8 +2672,7 @@ async function persistWorkspaceCapture(executionId, manifestPurpose, archivePurp
|
|
|
2681
2672
|
archive
|
|
2682
2673
|
};
|
|
2683
2674
|
}
|
|
2684
|
-
|
|
2685
|
-
//#region src/candidate-execution/outcome-evidence.ts
|
|
2675
|
+
// src/candidate-execution/outcome-evidence.ts
|
|
2686
2676
|
/** Persist the closed evaluator model ledger as canonical receipt evidence. */
|
|
2687
2677
|
async function persistCandidateModelSettlement(state, settlement, outputArtifacts) {
|
|
2688
2678
|
return await persistCandidateModelSettlementEvidence({
|
|
@@ -3033,8 +3023,7 @@ async function persistFailureEvidence(state, reason, failureClass, termination,
|
|
|
3033
3023
|
bytes
|
|
3034
3024
|
});
|
|
3035
3025
|
}
|
|
3036
|
-
|
|
3037
|
-
//#region src/candidate-execution/execute-cleanup.ts
|
|
3026
|
+
// src/candidate-execution/execute-cleanup.ts
|
|
3038
3027
|
/**
|
|
3039
3028
|
* Failure and cleanup paths of an execution: closing isolated memory, settling the model grant,
|
|
3040
3029
|
* recording a failed attempt's terminal result, and reporting why a run failed.
|
|
@@ -3129,8 +3118,7 @@ function protectedEnvironmentValues(activation, memoryActivation) {
|
|
|
3129
3118
|
function joinErrors(...errors) {
|
|
3130
3119
|
return errors.filter((error) => error !== void 0).map(errorMessage).join("; ");
|
|
3131
3120
|
}
|
|
3132
|
-
|
|
3133
|
-
//#region src/candidate-execution/executor-capture.ts
|
|
3121
|
+
// src/candidate-execution/executor-capture.ts
|
|
3134
3122
|
const sealedFinalCaptureBrand = Symbol("sealedAgentCandidateExecutorFinalCapture");
|
|
3135
3123
|
/** Validate and detach the only candidate-authored fields accepted from execution. */
|
|
3136
3124
|
function sealAgentCandidateProtectedRunCapture(value) {
|
|
@@ -3212,8 +3200,7 @@ function requireRecord(value, label) {
|
|
|
3212
3200
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object`);
|
|
3213
3201
|
return value;
|
|
3214
3202
|
}
|
|
3215
|
-
|
|
3216
|
-
//#region src/candidate-execution/execute-executor.ts
|
|
3203
|
+
// src/candidate-execution/execute-executor.ts
|
|
3217
3204
|
/** Run the executor until it returns or the deadline passes, then stop and capture it. */
|
|
3218
3205
|
async function runAndStopExecutor(executor, request, expectedOutcome, traceStore, deadlineAtMs, cleanupTimeoutMs) {
|
|
3219
3206
|
const timeoutMs = request.hardLimits.timeoutMs;
|
|
@@ -3385,8 +3372,7 @@ var CandidateExecutionDeadlineError = class extends Error {
|
|
|
3385
3372
|
this.name = "CandidateExecutionDeadlineError";
|
|
3386
3373
|
}
|
|
3387
3374
|
};
|
|
3388
|
-
|
|
3389
|
-
//#region src/candidate-execution/protected-trace-store.ts
|
|
3375
|
+
// src/candidate-execution/protected-trace-store.ts
|
|
3390
3376
|
/** Keep the identity key in evaluator-owned closures and expose only the redacting store to code. */
|
|
3391
3377
|
function createProtectedAgentCandidateTraceAccess(inner, protectedValues) {
|
|
3392
3378
|
const redactor = createProtectedRecordRedactor(protectedValues);
|
|
@@ -3436,8 +3422,7 @@ function createProtectedAgentCandidateTraceAccess(inner, protectedValues) {
|
|
|
3436
3422
|
report: () => redactor.report()
|
|
3437
3423
|
});
|
|
3438
3424
|
}
|
|
3439
|
-
|
|
3440
|
-
//#region src/candidate-execution/execute.ts
|
|
3425
|
+
// src/candidate-execution/execute.ts
|
|
3441
3426
|
/** Executes and finalizes one durably claimed candidate without exposing an unproven result. */
|
|
3442
3427
|
async function executePreparedAgentCandidate(prepared, options) {
|
|
3443
3428
|
const initialState = assertPreparedCandidateIntegrity(prepared);
|
|
@@ -3698,8 +3683,7 @@ async function finalizeEvidence(run, options, claimed, settled, modelSettlement)
|
|
|
3698
3683
|
return failedAgentCandidateRun(state, redactProtectedReason(errorMessage(error), protectedValues), execution.termination, settlement.usage);
|
|
3699
3684
|
}
|
|
3700
3685
|
}
|
|
3701
|
-
|
|
3702
|
-
//#region src/candidate-execution/prepare-plan.ts
|
|
3686
|
+
// src/candidate-execution/prepare-plan.ts
|
|
3703
3687
|
/**
|
|
3704
3688
|
* The evaluator-owned documents of a preparation: the launch environment, the execution plan,
|
|
3705
3689
|
* the materialization receipt, and the trace bindings that tie a run back to them.
|
|
@@ -3867,8 +3851,7 @@ function assertEnvironmentDisjoint(publicEnv, traceEnv) {
|
|
|
3867
3851
|
seen.add(name);
|
|
3868
3852
|
}
|
|
3869
3853
|
}
|
|
3870
|
-
|
|
3871
|
-
//#region src/candidate-execution/prepare-workspaces.ts
|
|
3854
|
+
// src/candidate-execution/prepare-workspaces.ts
|
|
3872
3855
|
/**
|
|
3873
3856
|
* The three host staging roots of a preparation: the task workspace, the candidate workspace,
|
|
3874
3857
|
* and the profile workspace, each materialized and verified against its signed material.
|
|
@@ -3946,10 +3929,9 @@ async function assertEmptyDirectory(path) {
|
|
|
3946
3929
|
if (!stats.isDirectory() || stats.isSymbolicLink()) throw new Error("profile staging root must be a real directory");
|
|
3947
3930
|
if ((await readdir(path)).length !== 0) throw new Error("profile staging root must be empty before materialization");
|
|
3948
3931
|
}
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
const
|
|
3952
|
-
const PREPARED_HOLD_MARGIN_MS = 5 * 6e4;
|
|
3932
|
+
// src/candidate-execution/prepare.ts
|
|
3933
|
+
const MIN_RESERVATION_TTL_MS = 9e5;
|
|
3934
|
+
const PREPARED_HOLD_MARGIN_MS = 3e5;
|
|
3953
3935
|
/** Materializes a verified candidate into one immutable evaluator-owned execution plan. */
|
|
3954
3936
|
async function prepareAgentCandidateExecution(candidate, task, ports, options = {}) {
|
|
3955
3937
|
const { cleanupTimeoutMs, resultTimeoutMs, reservationWindowMs } = checkPreparation(candidate, task, ports, options);
|
|
@@ -4335,7 +4317,6 @@ async function cleanupFailedPreparation(held, error) {
|
|
|
4335
4317
|
const cleanupErrors = (await Promise.allSettled(cleanup)).filter((result) => result.status === "rejected").map((result) => result.reason);
|
|
4336
4318
|
if (cleanupErrors.length > 0) throw new Error(`candidate preparation failed and protected access cleanup failed: ${cleanupErrors.map(errorMessage).join("; ")}`, { cause: error });
|
|
4337
4319
|
}
|
|
4338
|
-
//#endregion
|
|
4339
4320
|
export { verifiedResourceTextByDigest as C, AGENT_CANDIDATE_EXECUTION_SUPPORT as S, sealTerminalDigest as _, consumePreparedCandidateExecution as a, sealAgentCandidateModelSettlement as b, withinCandidateCleanupDeadline as c, assertTerminalMatchesClaim as d, assertTerminalMatchesStaged as f, requireStagedTerminal as g, rejectedStage as h, beginPreparedCandidateDisposal as i, assertRecoveryMatchesStaged as l, rejectedFinish as m, executePreparedAgentCandidate as n, candidateClaimFileInternals as o, recoveredTerminalRecord as p, assertPreparedCandidateIntegrity as r, candidateCleanupDeadline as s, prepareAgentCandidateExecution as t, assertTerminalAllowedInPhase as u, terminalRecord as v, verifyAgentCandidateBundle as w, exactProcessProviderAsCandidateExecutor as x, createProtectedAgentCandidateModelPort as y };
|
|
4340
4321
|
|
|
4341
|
-
//# sourceMappingURL=prepare-
|
|
4322
|
+
//# sourceMappingURL=prepare-XWwsOh8O.js.map
|