@runtypelabs/cli 2.42.3 → 2.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +378 -102
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -11312,7 +11312,7 @@ function isDataConnectionToolId(toolId) {
|
|
|
11312
11312
|
return toolId.startsWith("dc:");
|
|
11313
11313
|
}
|
|
11314
11314
|
//#endregion
|
|
11315
|
-
//#region ../shared/dist/chunk-
|
|
11315
|
+
//#region ../shared/dist/chunk-CN8mv6N6.mjs
|
|
11316
11316
|
/**
|
|
11317
11317
|
* Maps model families to provider-specific model IDs.
|
|
11318
11318
|
* Use for routing: family + provider → exact model ID
|
|
@@ -11745,6 +11745,11 @@ const MODEL_FAMILY_PROVIDER_IDS = {
|
|
|
11745
11745
|
"vercel": "openai/gpt-5.6-terra"
|
|
11746
11746
|
},
|
|
11747
11747
|
"gpt-5.6-terra-fast": { "vercel": "openai/gpt-5.6-terra-fast" },
|
|
11748
|
+
"gpt-6-1-sol": {
|
|
11749
|
+
"openai": "gpt-6.1-sol",
|
|
11750
|
+
"vercel": "openai/gpt-6.1-sol"
|
|
11751
|
+
},
|
|
11752
|
+
"gpt-6-1-sol-fast": { "vercel": "openai/gpt-6.1-sol-fast" },
|
|
11748
11753
|
"gpt-6-astra": {
|
|
11749
11754
|
"openai": "gpt-6-astra",
|
|
11750
11755
|
"vercel": "openai/gpt-6-astra"
|
|
@@ -11760,6 +11765,11 @@ const MODEL_FAMILY_PROVIDER_IDS = {
|
|
|
11760
11765
|
"vercel": "openai/gpt-6-sol"
|
|
11761
11766
|
},
|
|
11762
11767
|
"gpt-6-sol-fast": { "vercel": "openai/gpt-6-sol-fast" },
|
|
11768
|
+
"gpt-6.1-sol": {
|
|
11769
|
+
"openai": "gpt-6.1-sol",
|
|
11770
|
+
"vercel": "openai/gpt-6.1-sol"
|
|
11771
|
+
},
|
|
11772
|
+
"gpt-6.1-sol-fast": { "vercel": "openai/gpt-6.1-sol-fast" },
|
|
11763
11773
|
"gpt-image-1-5": { "openai": "gpt-image-1.5" },
|
|
11764
11774
|
"gpt-image-1-mini": { "openai": "gpt-image-1-mini" },
|
|
11765
11775
|
"gpt-image-1.5": { "openai": "gpt-image-1.5" },
|
|
@@ -11848,10 +11858,14 @@ const MODEL_FAMILY_PROVIDER_IDS = {
|
|
|
11848
11858
|
"ling-3-0-flash-sante": { "vercel": "inclusionai/ling-3.0-flash-sante" },
|
|
11849
11859
|
"ling-3-0-flash-sante-free": { "vercel": "inclusionai/ling-3.0-flash-sante-free" },
|
|
11850
11860
|
"ling-3-0-flash-vl": { "vercel": "inclusionai/ling-3.0-flash-vl" },
|
|
11861
|
+
"ling-3-1-flash": { "vercel": "inclusionai/ling-3.1-flash" },
|
|
11862
|
+
"ling-3-1-flash-free": { "vercel": "inclusionai/ling-3.1-flash-free" },
|
|
11851
11863
|
"ling-3.0-flash": { "vercel": "inclusionai/ling-3.0-flash" },
|
|
11852
11864
|
"ling-3.0-flash-sante": { "vercel": "inclusionai/ling-3.0-flash-sante" },
|
|
11853
11865
|
"ling-3.0-flash-sante-free": { "vercel": "inclusionai/ling-3.0-flash-sante-free" },
|
|
11854
11866
|
"ling-3.0-flash-vl": { "vercel": "inclusionai/ling-3.0-flash-vl" },
|
|
11867
|
+
"ling-3.1-flash": { "vercel": "inclusionai/ling-3.1-flash" },
|
|
11868
|
+
"ling-3.1-flash-free": { "vercel": "inclusionai/ling-3.1-flash-free" },
|
|
11855
11869
|
"llama-3.1-70b": { "vercel": "meta/llama-3.1-70b" },
|
|
11856
11870
|
"llama-3.1-8b": { "vercel": "meta/llama-3.1-8b" },
|
|
11857
11871
|
"llama-3.3-70b": { "vercel": "meta/llama-3.3-70b" },
|
|
@@ -12265,7 +12279,7 @@ const CREATOR_TO_PROVIDER = {
|
|
|
12265
12279
|
"unknown": "openai"
|
|
12266
12280
|
};
|
|
12267
12281
|
//#endregion
|
|
12268
|
-
//#region ../shared/dist/chunk-
|
|
12282
|
+
//#region ../shared/dist/chunk-AzlYBwl7.mjs
|
|
12269
12283
|
/**
|
|
12270
12284
|
* The reserved model-facing name of the agent state write tool
|
|
12271
12285
|
* (`packages/runtime/src/engine/state-write-tool.ts`). The model is told to call
|
|
@@ -12464,7 +12478,7 @@ const GEN_AI_ATTRIBUTES = {
|
|
|
12464
12478
|
toolCallId: "gen_ai.tool.call.id"
|
|
12465
12479
|
};
|
|
12466
12480
|
//#endregion
|
|
12467
|
-
//#region ../shared/dist/chunk-
|
|
12481
|
+
//#region ../shared/dist/chunk-B1SxgkWd.mjs
|
|
12468
12482
|
/**
|
|
12469
12483
|
* GenAI semconv content attributes, set by a customer's own instrumentation when it opts into content export.
|
|
12470
12484
|
* Two first-party producers write them: @runtypelabs/runtime's OTLP tracer for exported agents (content on by default), and @runtypelabs/flue-otel (opt-in).
|
|
@@ -14828,6 +14842,11 @@ _enum([
|
|
|
14828
14842
|
"pending"
|
|
14829
14843
|
]);
|
|
14830
14844
|
/**
|
|
14845
|
+
* Pattern enforced by `SecretStoreService.validateSecretKey`:
|
|
14846
|
+
* `/^[A-Z][A-Z0-9_]{0,98}[A-Z0-9]$/`. Keep in sync if that validator changes.
|
|
14847
|
+
*/
|
|
14848
|
+
const SECRET_KEY_PATTERN = /^[A-Z][A-Z0-9_]{0,98}[A-Z0-9]$/;
|
|
14849
|
+
/**
|
|
14831
14850
|
* Operator allowlist for a single filter condition. No raw SQL passthrough —
|
|
14832
14851
|
* the SQL compiler maps each operator to a parameterized fragment.
|
|
14833
14852
|
*/
|
|
@@ -15221,7 +15240,7 @@ const memoryConfigSchema = object({
|
|
|
15221
15240
|
* With 'open', a prompt-injected agent can exfiltrate context to any host; no separate plan entitlement restricts it.
|
|
15222
15241
|
* Revisit with a Schematic entitlement if/when sandbox egress becomes plan-differentiated.
|
|
15223
15242
|
*/
|
|
15224
|
-
const sandboxNetworkAccessSchema = union([_enum([
|
|
15243
|
+
const sandboxNetworkAccessSchema$1 = union([_enum([
|
|
15225
15244
|
"none",
|
|
15226
15245
|
"essentials",
|
|
15227
15246
|
"open"
|
|
@@ -15253,7 +15272,7 @@ const sandboxConfigSchema = object({
|
|
|
15253
15272
|
"standard-3",
|
|
15254
15273
|
"standard-4"
|
|
15255
15274
|
]).optional().describe("Only standard-4 is supported on the hosted Agent Sandbox path; other sizes cannot be enabled."),
|
|
15256
|
-
networkAccess: sandboxNetworkAccessSchema.optional(),
|
|
15275
|
+
networkAccess: sandboxNetworkAccessSchema$1.optional(),
|
|
15257
15276
|
ttl: _enum([
|
|
15258
15277
|
"5m",
|
|
15259
15278
|
"1h",
|
|
@@ -15428,6 +15447,288 @@ const agentRuntimeConfigSchema = object({
|
|
|
15428
15447
|
durability: agentDurabilityConfigSchema.optional(),
|
|
15429
15448
|
state: agentStateChannelSchema.optional()
|
|
15430
15449
|
}).strict();
|
|
15450
|
+
const injectionModeSchema = _enum([
|
|
15451
|
+
"bearer_header",
|
|
15452
|
+
"api_key_header",
|
|
15453
|
+
"query_param",
|
|
15454
|
+
"basic_auth"
|
|
15455
|
+
]);
|
|
15456
|
+
const credentialProxyConfigSchema = object({
|
|
15457
|
+
secretKey: string().min(1),
|
|
15458
|
+
hostnamePattern: string().min(1),
|
|
15459
|
+
pathPattern: string().default("/*"),
|
|
15460
|
+
injectionMode: injectionModeSchema,
|
|
15461
|
+
injectionConfig: record(string(), unknown()).default({}),
|
|
15462
|
+
envVarName: string().optional()
|
|
15463
|
+
});
|
|
15464
|
+
/**
|
|
15465
|
+
* Sandbox provider capability table, the single source of truth for which `transform-data` sandbox provider runs which language.
|
|
15466
|
+
* #6521 needed the same provider/language relation in four places; the first draft forked it into four unpinned hand-copies.
|
|
15467
|
+
* This module is a pure leaf (no imports, no I/O) so every layer can depend on it; the table MIRRORS `TransformSandboxRouter`, asserted entry-for-entry by `apps/api/tests/flow-eligibility-facts.test.ts`.
|
|
15468
|
+
* Since `transform-data` continues on error by default, anything this table cannot vouch for must route to the legacy engine rather than silently produce wrong data.
|
|
15469
|
+
*/
|
|
15470
|
+
/**
|
|
15471
|
+
* The provider a `transform-data` step gets when `config.sandboxProvider` is
|
|
15472
|
+
* unset. Mirrors the default in `TransformSandboxRouter.selectExecutor` and in
|
|
15473
|
+
* the legacy `ApiContextStepExecutor.executeJavaScriptTransform`.
|
|
15474
|
+
*/
|
|
15475
|
+
const DEFAULT_SANDBOX_PROVIDER = "cloudflare-worker";
|
|
15476
|
+
/**
|
|
15477
|
+
* Every routable provider mapped to the languages its executor declares.
|
|
15478
|
+
* PROTOTYPE-LESS ON PURPOSE: the provider string is attacker-controlled on unauthenticated validation routes with no enum check in front.
|
|
15479
|
+
* On a normal object literal, `SANDBOX_PROVIDER_LANGUAGES['constructor']` resolves truthy and the following `.includes` throws, surfacing as a 500.
|
|
15480
|
+
* `Object.create(null)` plus an `Object.hasOwn` gate in `lookupLanguages` both close it; kept together since this table is read from four packages.
|
|
15481
|
+
*/
|
|
15482
|
+
const SANDBOX_PROVIDER_LANGUAGES = Object.assign(Object.create(null), {
|
|
15483
|
+
quickjs: ["javascript"],
|
|
15484
|
+
"cloudflare-worker": ["javascript"],
|
|
15485
|
+
"runtype-sandbox": [
|
|
15486
|
+
"javascript",
|
|
15487
|
+
"typescript",
|
|
15488
|
+
"python"
|
|
15489
|
+
],
|
|
15490
|
+
"cloudflare-sandbox": [
|
|
15491
|
+
"javascript",
|
|
15492
|
+
"typescript",
|
|
15493
|
+
"python"
|
|
15494
|
+
],
|
|
15495
|
+
daytona: [
|
|
15496
|
+
"javascript",
|
|
15497
|
+
"typescript",
|
|
15498
|
+
"python"
|
|
15499
|
+
]
|
|
15500
|
+
});
|
|
15501
|
+
/** Normalize an unset / non-string provider to the documented default. */
|
|
15502
|
+
function resolveSandboxProvider(provider) {
|
|
15503
|
+
return typeof provider === "string" ? provider : DEFAULT_SANDBOX_PROVIDER;
|
|
15504
|
+
}
|
|
15505
|
+
/**
|
|
15506
|
+
* The one lookup every predicate below goes through. Returns `undefined` for
|
|
15507
|
+
* anything that is not an OWN entry, so an inherited key can never be mistaken
|
|
15508
|
+
* for a provider — see the note on {@link SANDBOX_PROVIDER_LANGUAGES}.
|
|
15509
|
+
*/
|
|
15510
|
+
function lookupLanguages(provider) {
|
|
15511
|
+
const resolved = resolveSandboxProvider(provider);
|
|
15512
|
+
if (!Object.prototype.hasOwnProperty.call(SANDBOX_PROVIDER_LANGUAGES, resolved)) return void 0;
|
|
15513
|
+
const languages = SANDBOX_PROVIDER_LANGUAGES[resolved];
|
|
15514
|
+
return Array.isArray(languages) ? languages : void 0;
|
|
15515
|
+
}
|
|
15516
|
+
/** Providers whose executor runs JavaScript and nothing else — the Cloudflare Worker Loader and in-process QuickJS. */
|
|
15517
|
+
function isJsOnlySandboxProvider(provider) {
|
|
15518
|
+
const languages = lookupLanguages(provider);
|
|
15519
|
+
return languages !== void 0 && languages.length === 1 && languages[0] === "javascript";
|
|
15520
|
+
}
|
|
15521
|
+
/**
|
|
15522
|
+
* Can a `transform-data` step on this provider bind a code-mode tool pool? ONLY `cloudflare-worker`.
|
|
15523
|
+
* This is narrower than `isJsOnlySandboxProvider` and the gap is deliberate: the seam is the api's `SANDBOX.workerLoaderExecuteTransformWithTools` RPC, which exists for Worker Loader alone.
|
|
15524
|
+
* Legacy and the dashboard both gate on this same single provider.
|
|
15525
|
+
*/
|
|
15526
|
+
function supportsCodeModeToolPool(provider) {
|
|
15527
|
+
return resolveSandboxProvider(provider) === "cloudflare-worker";
|
|
15528
|
+
}
|
|
15529
|
+
/**
|
|
15530
|
+
* Sandbox egress posture shared by `transform-data` steps and `custom` tools:
|
|
15531
|
+
* `'off'` (the default when omitted), `'on'`, or an explicit hostname allowlist.
|
|
15532
|
+
*/
|
|
15533
|
+
const sandboxNetworkAccessSchema = union([
|
|
15534
|
+
literal("off"),
|
|
15535
|
+
literal("on"),
|
|
15536
|
+
object({ allowedHostnames: array(string()).min(1) })
|
|
15537
|
+
]);
|
|
15538
|
+
/**
|
|
15539
|
+
* One managed secret a `custom` tool may send, and where. Code sees only the
|
|
15540
|
+
* phantom token as `secrets.<key>`; the sandbox egress proxy swaps in the real
|
|
15541
|
+
* credential for requests that match `hostnamePattern` and `pathPattern`.
|
|
15542
|
+
*/
|
|
15543
|
+
const customToolSecretSchema = object({
|
|
15544
|
+
key: string().regex(SECRET_KEY_PATTERN, "key must be a managed secret name, e.g. GITHUB_TOKEN"),
|
|
15545
|
+
hostnamePattern: string().min(1),
|
|
15546
|
+
pathPattern: string().min(1).optional(),
|
|
15547
|
+
injectionMode: injectionModeSchema,
|
|
15548
|
+
injectionConfig: record(string(), unknown()).optional()
|
|
15549
|
+
});
|
|
15550
|
+
/** Every code {@link collectCustomToolEgressIssues} can emit, for validators that forward core codes. */
|
|
15551
|
+
const CUSTOM_TOOL_EGRESS_ISSUE_CODES = [
|
|
15552
|
+
"CUSTOM_TOOL_EGRESS_CONFIG_INVALID",
|
|
15553
|
+
"CUSTOM_TOOL_EGRESS_PROVIDER_UNSUPPORTED",
|
|
15554
|
+
"CUSTOM_TOOL_SECRET_HOST_NOT_ALLOWED"
|
|
15555
|
+
];
|
|
15556
|
+
/**
|
|
15557
|
+
* Shared-hosting suffixes where every subdomain belongs to a different tenant, so
|
|
15558
|
+
* `*.<suffix>` would send a credential to strangers. Curated from the Public Suffix
|
|
15559
|
+
* List's private section; extend it when a new host platform shows up.
|
|
15560
|
+
*/
|
|
15561
|
+
const SHARED_HOSTING_SUFFIXES = /* @__PURE__ */ new Set([
|
|
15562
|
+
"github.io",
|
|
15563
|
+
"gitlab.io",
|
|
15564
|
+
"pages.dev",
|
|
15565
|
+
"workers.dev",
|
|
15566
|
+
"vercel.app",
|
|
15567
|
+
"netlify.app",
|
|
15568
|
+
"herokuapp.com",
|
|
15569
|
+
"azurewebsites.net",
|
|
15570
|
+
"cloudfront.net",
|
|
15571
|
+
"appspot.com",
|
|
15572
|
+
"firebaseapp.com",
|
|
15573
|
+
"web.app",
|
|
15574
|
+
"onrender.com",
|
|
15575
|
+
"fly.dev",
|
|
15576
|
+
"glitch.me",
|
|
15577
|
+
"repl.co",
|
|
15578
|
+
"replit.app",
|
|
15579
|
+
"deno.dev",
|
|
15580
|
+
"railway.app",
|
|
15581
|
+
"ngrok.io",
|
|
15582
|
+
"ngrok-free.app",
|
|
15583
|
+
"trycloudflare.com",
|
|
15584
|
+
"blogspot.com",
|
|
15585
|
+
"wordpress.com",
|
|
15586
|
+
"s3.amazonaws.com",
|
|
15587
|
+
"amplifyapp.com",
|
|
15588
|
+
"azurestaticapps.net",
|
|
15589
|
+
"surge.sh",
|
|
15590
|
+
"myshopify.com"
|
|
15591
|
+
]);
|
|
15592
|
+
/** Second-level labels that registries sell under a two-letter country code (co.uk, com.au, ne.jp). */
|
|
15593
|
+
const COUNTRY_SECOND_LEVELS = /* @__PURE__ */ new Set([
|
|
15594
|
+
"ac",
|
|
15595
|
+
"co",
|
|
15596
|
+
"com",
|
|
15597
|
+
"edu",
|
|
15598
|
+
"gov",
|
|
15599
|
+
"go",
|
|
15600
|
+
"ne",
|
|
15601
|
+
"net",
|
|
15602
|
+
"or",
|
|
15603
|
+
"org",
|
|
15604
|
+
"ltd",
|
|
15605
|
+
"plc",
|
|
15606
|
+
"nom",
|
|
15607
|
+
"gob",
|
|
15608
|
+
"mil"
|
|
15609
|
+
]);
|
|
15610
|
+
/** Is `domain` a public suffix (a registry or shared-hosting zone), not one owner's domain? */
|
|
15611
|
+
function isPublicSuffixDomain(domain) {
|
|
15612
|
+
const host = domain.toLowerCase().replace(/\.+$/, "");
|
|
15613
|
+
if (SHARED_HOSTING_SUFFIXES.has(host)) return true;
|
|
15614
|
+
const labels = host.split(".");
|
|
15615
|
+
if (labels.length === 1) return true;
|
|
15616
|
+
if (labels.length !== 2) return false;
|
|
15617
|
+
const [second = "", top = ""] = labels;
|
|
15618
|
+
return top.length === 2 && COUNTRY_SECOND_LEVELS.has(second);
|
|
15619
|
+
}
|
|
15620
|
+
/**
|
|
15621
|
+
* A secret's hostname pattern must name one public DNS host (`api.github.com`) or one
|
|
15622
|
+
* domain's subdomains (`*.github.com`): never a TLD, a public suffix (`*.co.uk`,
|
|
15623
|
+
* `*.github.io`), everything, an IP literal, `localhost`, or an `.internal` name.
|
|
15624
|
+
*/
|
|
15625
|
+
function isConcreteSecretHostnamePattern(pattern) {
|
|
15626
|
+
const wildcard = pattern.startsWith("*.");
|
|
15627
|
+
const host = (wildcard ? pattern.slice(2) : pattern).toLowerCase();
|
|
15628
|
+
if (host.includes("*")) return false;
|
|
15629
|
+
const labels = host.split(".");
|
|
15630
|
+
if (labels.length < 2) return false;
|
|
15631
|
+
if (labels.some((label) => !/^[a-z0-9-]+$/.test(label))) return false;
|
|
15632
|
+
const topLevel = labels[labels.length - 1] ?? "";
|
|
15633
|
+
if (!/[a-z]/.test(topLevel)) return false;
|
|
15634
|
+
if (topLevel === "internal" || topLevel === "local" || topLevel === "localhost") return false;
|
|
15635
|
+
return !(wildcard && isPublicSuffixDomain(host));
|
|
15636
|
+
}
|
|
15637
|
+
/** Is every host `secretPattern` can match also allowed by the tool's network posture? */
|
|
15638
|
+
function networkAccessCoversHostnamePattern(networkAccess, secretPattern) {
|
|
15639
|
+
if (networkAccess === "on") return true;
|
|
15640
|
+
if (networkAccess === "off") return false;
|
|
15641
|
+
return networkAccess.allowedHostnames.some((allowed) => {
|
|
15642
|
+
if (allowed === secretPattern) return true;
|
|
15643
|
+
if (!allowed.startsWith("*.")) return false;
|
|
15644
|
+
const suffix = allowed.slice(1);
|
|
15645
|
+
return (secretPattern.startsWith("*.") ? secretPattern.slice(1) : secretPattern).endsWith(suffix);
|
|
15646
|
+
});
|
|
15647
|
+
}
|
|
15648
|
+
const PROVIDERS_WITHOUT_EGRESS_PROXY = /* @__PURE__ */ new Set(["quickjs"]);
|
|
15649
|
+
const PROVIDERS_WITHOUT_SECRET_PROXY = /* @__PURE__ */ new Set(["quickjs", "daytona"]);
|
|
15650
|
+
const EGRESS_PROVIDER_REMEDIATION = "Set sandboxProvider to \"cloudflare-worker\" (JavaScript) or \"runtype-sandbox\" (JavaScript, TypeScript, Python).";
|
|
15651
|
+
/**
|
|
15652
|
+
* Pure checks on a custom tool's `networkAccess` / `secrets` against its provider.
|
|
15653
|
+
* Returns every issue so validators can surface them together.
|
|
15654
|
+
*/
|
|
15655
|
+
function collectCustomToolEgressIssues(config) {
|
|
15656
|
+
if (!isRecord$1(config)) return [];
|
|
15657
|
+
const issues = [];
|
|
15658
|
+
const provider = resolveSandboxProvider(config.sandboxProvider);
|
|
15659
|
+
const networkParse = config.networkAccess === void 0 ? void 0 : sandboxNetworkAccessSchema.safeParse(config.networkAccess);
|
|
15660
|
+
if (networkParse && !networkParse.success) issues.push({
|
|
15661
|
+
code: "CUSTOM_TOOL_EGRESS_CONFIG_INVALID",
|
|
15662
|
+
message: `networkAccess must be 'off', 'on', or { allowedHostnames: [...] } with at least one hostname.`,
|
|
15663
|
+
path: "networkAccess"
|
|
15664
|
+
});
|
|
15665
|
+
const networkAccess = networkParse?.success === true ? networkParse.data : "off";
|
|
15666
|
+
if (networkAccess !== "off" && PROVIDERS_WITHOUT_EGRESS_PROXY.has(provider)) issues.push({
|
|
15667
|
+
code: "CUSTOM_TOOL_EGRESS_PROVIDER_UNSUPPORTED",
|
|
15668
|
+
message: `sandboxProvider "${provider}" has no fetch and no egress proxy, so networkAccess cannot be enabled. ${EGRESS_PROVIDER_REMEDIATION}`,
|
|
15669
|
+
path: "networkAccess"
|
|
15670
|
+
});
|
|
15671
|
+
if (typeof networkAccess === "object" && provider === "daytona") issues.push({
|
|
15672
|
+
code: "CUSTOM_TOOL_EGRESS_PROVIDER_UNSUPPORTED",
|
|
15673
|
+
message: `sandboxProvider "daytona" manages its own egress and cannot enforce an allowedHostnames list. ${EGRESS_PROVIDER_REMEDIATION}`,
|
|
15674
|
+
path: "networkAccess"
|
|
15675
|
+
});
|
|
15676
|
+
if (config.secrets === void 0) return issues;
|
|
15677
|
+
if (!Array.isArray(config.secrets)) {
|
|
15678
|
+
issues.push({
|
|
15679
|
+
code: "CUSTOM_TOOL_EGRESS_CONFIG_INVALID",
|
|
15680
|
+
message: "secrets must be an array of { key, hostnamePattern, injectionMode } entries.",
|
|
15681
|
+
path: "secrets"
|
|
15682
|
+
});
|
|
15683
|
+
return issues;
|
|
15684
|
+
}
|
|
15685
|
+
if (config.secrets.length === 0) return issues;
|
|
15686
|
+
if (PROVIDERS_WITHOUT_SECRET_PROXY.has(provider)) issues.push({
|
|
15687
|
+
code: "CUSTOM_TOOL_EGRESS_PROVIDER_UNSUPPORTED",
|
|
15688
|
+
message: `sandboxProvider "${provider}" has no credential proxy, so managed secrets cannot be injected. ${EGRESS_PROVIDER_REMEDIATION}`,
|
|
15689
|
+
path: "secrets"
|
|
15690
|
+
});
|
|
15691
|
+
if (config.secrets.length > 10) issues.push({
|
|
15692
|
+
code: "CUSTOM_TOOL_EGRESS_CONFIG_INVALID",
|
|
15693
|
+
message: `A custom tool can declare at most 10 secrets.`,
|
|
15694
|
+
path: "secrets"
|
|
15695
|
+
});
|
|
15696
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
15697
|
+
config.secrets.forEach((entry, index) => {
|
|
15698
|
+
const path = `secrets[${index}]`;
|
|
15699
|
+
const parsed = customToolSecretSchema.safeParse(entry);
|
|
15700
|
+
if (!parsed.success) {
|
|
15701
|
+
const first = parsed.error.issues[0];
|
|
15702
|
+
issues.push({
|
|
15703
|
+
code: "CUSTOM_TOOL_EGRESS_CONFIG_INVALID",
|
|
15704
|
+
message: `Invalid secret entry: ${first?.path.join(".") || "entry"} ${first?.message ?? "is invalid"}. Use the bare secret name as key (GITHUB_TOKEN, not {{secret:GITHUB_TOKEN}}).`,
|
|
15705
|
+
path
|
|
15706
|
+
});
|
|
15707
|
+
return;
|
|
15708
|
+
}
|
|
15709
|
+
const secret = parsed.data;
|
|
15710
|
+
if (seenKeys.has(secret.key)) issues.push({
|
|
15711
|
+
code: "CUSTOM_TOOL_EGRESS_CONFIG_INVALID",
|
|
15712
|
+
message: `Secret "${secret.key}" is declared twice. Declare each secret once; it is injected for one hostname pattern.`,
|
|
15713
|
+
path: `${path}.key`
|
|
15714
|
+
});
|
|
15715
|
+
seenKeys.add(secret.key);
|
|
15716
|
+
if (!isConcreteSecretHostnamePattern(secret.hostnamePattern)) {
|
|
15717
|
+
issues.push({
|
|
15718
|
+
code: "CUSTOM_TOOL_EGRESS_CONFIG_INVALID",
|
|
15719
|
+
message: `Secret "${secret.key}" hostnamePattern "${secret.hostnamePattern}" is not a single public host. Name the API host (api.github.com) or one domain's subdomains (*.github.com); public suffixes (*.co.uk, *.github.io), IP literals, localhost and internal names are refused.`,
|
|
15720
|
+
path: `${path}.hostnamePattern`
|
|
15721
|
+
});
|
|
15722
|
+
return;
|
|
15723
|
+
}
|
|
15724
|
+
if (!networkAccessCoversHostnamePattern(networkAccess, secret.hostnamePattern)) issues.push({
|
|
15725
|
+
code: "CUSTOM_TOOL_SECRET_HOST_NOT_ALLOWED",
|
|
15726
|
+
message: `Secret "${secret.key}" is sent to "${secret.hostnamePattern}", but networkAccess does not allow that host. Add it to networkAccess.allowedHostnames.`,
|
|
15727
|
+
path: `${path}.hostnamePattern`
|
|
15728
|
+
});
|
|
15729
|
+
});
|
|
15730
|
+
return issues;
|
|
15731
|
+
}
|
|
15431
15732
|
/**
|
|
15432
15733
|
* A single entry in a context-step fallback chain. Mirrors `ContextFallback`
|
|
15433
15734
|
* (`retry` | `step` | `flow`) in `error-handling.ts`. Discriminated by `type`.
|
|
@@ -16220,16 +16521,6 @@ const updateRecordConfigSchema = object({
|
|
|
16220
16521
|
defaultValue: any().optional()
|
|
16221
16522
|
});
|
|
16222
16523
|
/**
|
|
16223
|
-
* Network-access policy for sandboxed transform-data execution (cloudflare-worker/runtype-sandbox providers).
|
|
16224
|
-
* Mirrors the inline union on TransformDataStep.config.networkAccess: 'off' (default), 'on', or an explicit allowlist.
|
|
16225
|
-
* Lives here rather than the api validator because it's transform-data-specific.
|
|
16226
|
-
*/
|
|
16227
|
-
const transformDataNetworkAccessSchema = union([
|
|
16228
|
-
literal("off"),
|
|
16229
|
-
literal("on"),
|
|
16230
|
-
object({ allowedHostnames: array(string()).min(1) })
|
|
16231
|
-
]);
|
|
16232
|
-
/**
|
|
16233
16524
|
* Canonical transform-data config, the strict field set only; superset of the prior validator and TransformDataStep.config.
|
|
16234
16525
|
* errorHandling tightens to the canonical union (prod-verified safe: of 1654 steps, only 4 carry it, all valid).
|
|
16235
16526
|
* inputMode/packageJson/persistSandbox/reuseSandboxId are recovered fields the validator silently stripped.
|
|
@@ -16256,7 +16547,7 @@ const transformDataConfigSchema = object({
|
|
|
16256
16547
|
packageJson: string().optional(),
|
|
16257
16548
|
persistSandbox: boolean().optional(),
|
|
16258
16549
|
reuseSandboxId: string().optional(),
|
|
16259
|
-
networkAccess:
|
|
16550
|
+
networkAccess: sandboxNetworkAccessSchema.optional(),
|
|
16260
16551
|
inference: boolean().optional(),
|
|
16261
16552
|
errorHandling: contextErrorHandlingConfigSchema.optional(),
|
|
16262
16553
|
defaultValue: any().optional(),
|
|
@@ -18302,71 +18593,6 @@ function sanitizeCodeToolIdentifier(name) {
|
|
|
18302
18593
|
return safe;
|
|
18303
18594
|
}
|
|
18304
18595
|
/**
|
|
18305
|
-
* Sandbox provider capability table, the single source of truth for which `transform-data` sandbox provider runs which language.
|
|
18306
|
-
* #6521 needed the same provider/language relation in four places; the first draft forked it into four unpinned hand-copies.
|
|
18307
|
-
* This module is a pure leaf (no imports, no I/O) so every layer can depend on it; the table MIRRORS `TransformSandboxRouter`, asserted entry-for-entry by `apps/api/tests/flow-eligibility-facts.test.ts`.
|
|
18308
|
-
* Since `transform-data` continues on error by default, anything this table cannot vouch for must route to the legacy engine rather than silently produce wrong data.
|
|
18309
|
-
*/
|
|
18310
|
-
/**
|
|
18311
|
-
* The provider a `transform-data` step gets when `config.sandboxProvider` is
|
|
18312
|
-
* unset. Mirrors the default in `TransformSandboxRouter.selectExecutor` and in
|
|
18313
|
-
* the legacy `ApiContextStepExecutor.executeJavaScriptTransform`.
|
|
18314
|
-
*/
|
|
18315
|
-
const DEFAULT_SANDBOX_PROVIDER = "cloudflare-worker";
|
|
18316
|
-
/**
|
|
18317
|
-
* Every routable provider mapped to the languages its executor declares.
|
|
18318
|
-
* PROTOTYPE-LESS ON PURPOSE: the provider string is attacker-controlled on unauthenticated validation routes with no enum check in front.
|
|
18319
|
-
* On a normal object literal, `SANDBOX_PROVIDER_LANGUAGES['constructor']` resolves truthy and the following `.includes` throws, surfacing as a 500.
|
|
18320
|
-
* `Object.create(null)` plus an `Object.hasOwn` gate in `lookupLanguages` both close it; kept together since this table is read from four packages.
|
|
18321
|
-
*/
|
|
18322
|
-
const SANDBOX_PROVIDER_LANGUAGES = Object.assign(Object.create(null), {
|
|
18323
|
-
quickjs: ["javascript"],
|
|
18324
|
-
"cloudflare-worker": ["javascript"],
|
|
18325
|
-
"runtype-sandbox": [
|
|
18326
|
-
"javascript",
|
|
18327
|
-
"typescript",
|
|
18328
|
-
"python"
|
|
18329
|
-
],
|
|
18330
|
-
"cloudflare-sandbox": [
|
|
18331
|
-
"javascript",
|
|
18332
|
-
"typescript",
|
|
18333
|
-
"python"
|
|
18334
|
-
],
|
|
18335
|
-
daytona: [
|
|
18336
|
-
"javascript",
|
|
18337
|
-
"typescript",
|
|
18338
|
-
"python"
|
|
18339
|
-
]
|
|
18340
|
-
});
|
|
18341
|
-
/** Normalize an unset / non-string provider to the documented default. */
|
|
18342
|
-
function resolveSandboxProvider(provider) {
|
|
18343
|
-
return typeof provider === "string" ? provider : DEFAULT_SANDBOX_PROVIDER;
|
|
18344
|
-
}
|
|
18345
|
-
/**
|
|
18346
|
-
* The one lookup every predicate below goes through. Returns `undefined` for
|
|
18347
|
-
* anything that is not an OWN entry, so an inherited key can never be mistaken
|
|
18348
|
-
* for a provider — see the note on {@link SANDBOX_PROVIDER_LANGUAGES}.
|
|
18349
|
-
*/
|
|
18350
|
-
function lookupLanguages(provider) {
|
|
18351
|
-
const resolved = resolveSandboxProvider(provider);
|
|
18352
|
-
if (!Object.prototype.hasOwnProperty.call(SANDBOX_PROVIDER_LANGUAGES, resolved)) return void 0;
|
|
18353
|
-
const languages = SANDBOX_PROVIDER_LANGUAGES[resolved];
|
|
18354
|
-
return Array.isArray(languages) ? languages : void 0;
|
|
18355
|
-
}
|
|
18356
|
-
/** Providers whose executor runs JavaScript and nothing else — the Cloudflare Worker Loader and in-process QuickJS. */
|
|
18357
|
-
function isJsOnlySandboxProvider(provider) {
|
|
18358
|
-
const languages = lookupLanguages(provider);
|
|
18359
|
-
return languages !== void 0 && languages.length === 1 && languages[0] === "javascript";
|
|
18360
|
-
}
|
|
18361
|
-
/**
|
|
18362
|
-
* Can a `transform-data` step on this provider bind a code-mode tool pool? ONLY `cloudflare-worker`.
|
|
18363
|
-
* This is narrower than `isJsOnlySandboxProvider` and the gap is deliberate: the seam is the api's `SANDBOX.workerLoaderExecuteTransformWithTools` RPC, which exists for Worker Loader alone.
|
|
18364
|
-
* Legacy and the dashboard both gate on this same single provider.
|
|
18365
|
-
*/
|
|
18366
|
-
function supportsCodeModeToolPool(provider) {
|
|
18367
|
-
return resolveSandboxProvider(provider) === "cloudflare-worker";
|
|
18368
|
-
}
|
|
18369
|
-
/**
|
|
18370
18596
|
* Convert snake_case string to camelCase
|
|
18371
18597
|
* @example snakeToCamel('flow_name') // 'flowName'
|
|
18372
18598
|
* @example snakeToCamel('user_id') // 'userId'
|
|
@@ -20825,6 +21051,25 @@ function validateCodeModeConfig(value, stepTools, stepIndex, stepRef) {
|
|
|
20825
21051
|
}
|
|
20826
21052
|
return null;
|
|
20827
21053
|
}
|
|
21054
|
+
/**
|
|
21055
|
+
* Pure half of the custom-tool egress rules (#8103): a runtime `custom` tool whose
|
|
21056
|
+
* `networkAccess` / `secrets` its provider cannot honor, or whose secret is sent to
|
|
21057
|
+
* a host its own networkAccess blocks. The api's validateRuntimeTools enforces the same rules at dispatch.
|
|
21058
|
+
*/
|
|
21059
|
+
function validateCustomToolEgress(tools, stepIndex, stepRef, buckets) {
|
|
21060
|
+
if (!Array.isArray(tools.runtimeTools)) return;
|
|
21061
|
+
tools.runtimeTools.forEach((tool, toolIndex) => {
|
|
21062
|
+
if (!isRecord$1(tool) || tool.toolType !== "custom") return;
|
|
21063
|
+
const toolName = typeof tool.name === "string" ? tool.name : `#${toolIndex}`;
|
|
21064
|
+
for (const issue of collectCustomToolEgressIssues(tool.config)) addIssue("error", {
|
|
21065
|
+
code: issue.code,
|
|
21066
|
+
message: `Custom tool "${toolName}": ${issue.message}`,
|
|
21067
|
+
path: `flowSteps[${stepIndex}].config.tools.runtimeTools[${toolIndex}].config.${issue.path}`,
|
|
21068
|
+
step: stepRef,
|
|
21069
|
+
details: { toolName }
|
|
21070
|
+
}, buckets);
|
|
21071
|
+
});
|
|
21072
|
+
}
|
|
20828
21073
|
function validateTransformDataCodeTools(toolsConfig, stepIndex, stepRef, buckets) {
|
|
20829
21074
|
const runtimeTools = Array.isArray(toolsConfig.runtimeTools) ? toolsConfig.runtimeTools : [];
|
|
20830
21075
|
const runtimeToolNames = [];
|
|
@@ -21008,6 +21253,7 @@ function collectFlowStructureIssues(flowData, deps, buckets) {
|
|
|
21008
21253
|
step: stepRef
|
|
21009
21254
|
}, buckets);
|
|
21010
21255
|
}
|
|
21256
|
+
validateCustomToolEgress(step.config.tools, stepIndex, stepRef, buckets);
|
|
21011
21257
|
if (step.type === "transform-data") validateTransformDataCodeTools(step.config.tools, stepIndex, stepRef, buckets);
|
|
21012
21258
|
const subagentCfg = step.config.tools.subagentConfig;
|
|
21013
21259
|
if (subagentCfg !== void 0) {
|
|
@@ -23204,7 +23450,8 @@ const FORWARDED_CORE_CODES = /* @__PURE__ */ new Set([
|
|
|
23204
23450
|
TOOL_CALL_ERROR_HANDLING_IGNORED_CODE,
|
|
23205
23451
|
EXECUTE_AGENT_TEMPLATED_REF_UNRUNNABLE_CODE,
|
|
23206
23452
|
PROVIDER_TOOLS_MIXED_OWNERS_CODE,
|
|
23207
|
-
FLOW_TOOL_OUTPUT_VARIABLE_RESERVED_CODE
|
|
23453
|
+
FLOW_TOOL_OUTPUT_VARIABLE_RESERVED_CODE,
|
|
23454
|
+
...CUSTOM_TOOL_EGRESS_ISSUE_CODES
|
|
23208
23455
|
]);
|
|
23209
23456
|
function validateFlowDefinition(flow, capIndex, context) {
|
|
23210
23457
|
const result = emptyResult();
|
|
@@ -23408,6 +23655,10 @@ function memoryPointerIssues(memory, context, path) {
|
|
|
23408
23655
|
* v2 nested-`config` shape. The v2 branch reads the equivalent fields from
|
|
23409
23656
|
* `agent.config` and reports them under `.config.*` paths.
|
|
23410
23657
|
*/
|
|
23658
|
+
/** Same egress rules the pure flow validator's validateCustomToolEgress applies (#8103), for AGENT-level runtimeTools. */
|
|
23659
|
+
function pushCustomToolEgressIssues(config, configPath, result) {
|
|
23660
|
+
for (const issue of collectCustomToolEgressIssues(config)) result.errors.push(createIssue("error", issue.code, issue.message, `${configPath}.${issue.path}`));
|
|
23661
|
+
}
|
|
23411
23662
|
function validateAgentDefinition(agent, capIndex) {
|
|
23412
23663
|
const result = emptyResult();
|
|
23413
23664
|
const base = `capabilities[${capIndex}].agent`;
|
|
@@ -23451,6 +23702,7 @@ function validateFlatAgent(agent, base, result) {
|
|
|
23451
23702
|
const outputVariableIssue = flowToolOutputVariableIssue(tool.config?.outputVariable, `${base}.toolsConfig.runtimeTools[${i}].config.outputVariable`);
|
|
23452
23703
|
if (outputVariableIssue) result.errors.push(outputVariableIssue);
|
|
23453
23704
|
}
|
|
23705
|
+
if (tool.toolType === "custom") pushCustomToolEgressIssues(tool.config, `${base}.toolsConfig.runtimeTools[${i}].config`, result);
|
|
23454
23706
|
}
|
|
23455
23707
|
}
|
|
23456
23708
|
function validateNestedAgent(agent, base, result) {
|
|
@@ -23476,6 +23728,7 @@ function validateNestedAgent(agent, base, result) {
|
|
|
23476
23728
|
const outputVariableIssue = flowToolOutputVariableIssue(tool.config?.outputVariable, `${base}.config.tools.runtimeTools[${i}].config.outputVariable`);
|
|
23477
23729
|
if (outputVariableIssue) result.errors.push(outputVariableIssue);
|
|
23478
23730
|
}
|
|
23731
|
+
if (tool.toolType === "custom") pushCustomToolEgressIssues(tool.config, `${base}.config.tools.runtimeTools[${i}].config`, result);
|
|
23479
23732
|
}
|
|
23480
23733
|
}
|
|
23481
23734
|
const KEBAB_CASE_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
@@ -24226,20 +24479,6 @@ function isNonAIProvider(id) {
|
|
|
24226
24479
|
if (colonIndex > 0) return NON_AI_PROVIDER_IDS.has(normalized.slice(0, colonIndex));
|
|
24227
24480
|
return false;
|
|
24228
24481
|
}
|
|
24229
|
-
const injectionModeSchema = _enum([
|
|
24230
|
-
"bearer_header",
|
|
24231
|
-
"api_key_header",
|
|
24232
|
-
"query_param",
|
|
24233
|
-
"basic_auth"
|
|
24234
|
-
]);
|
|
24235
|
-
const credentialProxyConfigSchema = object({
|
|
24236
|
-
secretKey: string().min(1),
|
|
24237
|
-
hostnamePattern: string().min(1),
|
|
24238
|
-
pathPattern: string().default("/*"),
|
|
24239
|
-
injectionMode: injectionModeSchema,
|
|
24240
|
-
injectionConfig: record(string(), unknown()).default({}),
|
|
24241
|
-
envVarName: string().optional()
|
|
24242
|
-
});
|
|
24243
24482
|
const LocalInferenceSurfaceSchema = _enum([
|
|
24244
24483
|
"playground",
|
|
24245
24484
|
"flows",
|
|
@@ -24874,7 +25113,11 @@ object({
|
|
|
24874
25113
|
externalAgent: object({
|
|
24875
25114
|
contextId: string().optional(),
|
|
24876
25115
|
taskId: string().optional()
|
|
24877
|
-
}).optional()
|
|
25116
|
+
}).optional(),
|
|
25117
|
+
/** The published agent version the run executed; absent when no stored version ran. */
|
|
25118
|
+
agentVersionId: string().optional(),
|
|
25119
|
+
/** The release alias the version was resolved through (`live`, `staging`, ...), when one was. */
|
|
25120
|
+
alias: string().optional()
|
|
24878
25121
|
});
|
|
24879
25122
|
object({
|
|
24880
25123
|
recordId: string().optional(),
|
|
@@ -36925,7 +37168,7 @@ function createSandboxInstructions(provider) {
|
|
|
36925
37168
|
"{ \"code\": \"...\", \"parameters\": { ... }, \"language\": \"javascript|typescript|python\", \"timeoutMs\": 30000 }",
|
|
36926
37169
|
"Runtype Sandbox rules:",
|
|
36927
37170
|
"1. Choose one language: javascript, typescript, or python.",
|
|
36928
|
-
"2. Each session is a full Linux container (Node
|
|
37171
|
+
"2. Each session is a full Linux container (Node 24, Python 3.13 with numpy/pandas/matplotlib, pnpm, tsx, uv, git).",
|
|
36929
37172
|
"3. Inputs are available as the `parameters` object (JS/TS) or `parameters` dict (Python).",
|
|
36930
37173
|
"4. async/await, Promises, and long-running processes are fully supported.",
|
|
36931
37174
|
"5. Write the final result to stdout (JSON string is preferred for structured output).",
|
|
@@ -54201,6 +54444,9 @@ function collectExportedExecutionInventory(definition) {
|
|
|
54201
54444
|
walkTools(agent.config.tools);
|
|
54202
54445
|
}
|
|
54203
54446
|
if (isObject(agent.claudeManagedConfig)) addModel(agent.claudeManagedConfig.model);
|
|
54447
|
+
if (Array.isArray(agent.skills)) {
|
|
54448
|
+
for (const skill of agent.skills) if (isObject(skill)) walkRuntimeTools(skill.resolvedTools);
|
|
54449
|
+
}
|
|
54204
54450
|
if (Array.isArray(agent.capabilities)) for (const capability of agent.capabilities) {
|
|
54205
54451
|
if (!isObject(capability)) continue;
|
|
54206
54452
|
if (isObject(capability.flow)) walkFlow(capability.flow);
|
|
@@ -54260,16 +54506,41 @@ function describeAgentExportFailure(err) {
|
|
|
54260
54506
|
if ((err.data && typeof err.data === "object" && "code" in err.data ? err.data.code : void 0) === "BYOC_PLAN_REQUIRED") return ["Self-hosting (BYOC) requires an Enterprise plan. Contact support to enable it for your account.", "The API key also needs the RUNTIME:EXPORT scope."];
|
|
54261
54507
|
return ["The API key needs the RUNTIME:EXPORT scope, and self-hosting (BYOC) requires an Enterprise plan."];
|
|
54262
54508
|
}
|
|
54263
|
-
if (err.statusCode === 404)
|
|
54509
|
+
if (err.statusCode === 404) {
|
|
54510
|
+
const code = err.data && typeof err.data === "object" && "code" in err.data ? err.data.code : void 0;
|
|
54511
|
+
if (typeof code === "string" && RELEASE_SELECTOR_NOT_FOUND_CODES.has(code)) return ["The requested --alias or --version-id does not exist on this agent, or the alias is archived or expired."];
|
|
54512
|
+
return ["Agent not found, or not owned by this account."];
|
|
54513
|
+
}
|
|
54264
54514
|
return [];
|
|
54265
54515
|
}
|
|
54516
|
+
const RELEASE_SELECTOR_NOT_FOUND_CODES = /* @__PURE__ */ new Set([
|
|
54517
|
+
"alias_not_found",
|
|
54518
|
+
"alias_archived",
|
|
54519
|
+
"alias_expired",
|
|
54520
|
+
"version_not_found"
|
|
54521
|
+
]);
|
|
54522
|
+
/** The export-runtime query for a release selector; errors when both selectors are given. */
|
|
54523
|
+
function agentReleaseSelectorParams(options, agentCount) {
|
|
54524
|
+
if (options.alias !== void 0 && options.versionId !== void 0) return { error: "Pass either --alias or --version-id, not both." };
|
|
54525
|
+
if (options.versionId !== void 0 && agentCount !== 1) return { error: "--version-id names one agent version, so pass exactly one --agent with it." };
|
|
54526
|
+
return { params: {
|
|
54527
|
+
...options.alias !== void 0 ? { alias: options.alias } : {},
|
|
54528
|
+
...options.versionId !== void 0 ? { versionId: options.versionId } : {}
|
|
54529
|
+
} };
|
|
54530
|
+
}
|
|
54531
|
+
function describeExportedRelease(def) {
|
|
54532
|
+
const release = def.release;
|
|
54533
|
+
if (!release?.versionId) return "";
|
|
54534
|
+
const via = release.alias ? ` via ${release.alias}${release.aliasRevision !== void 0 ? ` r${release.aliasRevision}` : ""}` : "";
|
|
54535
|
+
return chalk.dim(` (${release.versionId}${via})`);
|
|
54536
|
+
}
|
|
54266
54537
|
const deployCommand = new Command("deploy").description("Export an agent and scaffold a deployment (cloud-run, cloudflare, or vercel)").option("--agent <id>", "Agent ID to export (may be repeated)", (v, acc) => {
|
|
54267
54538
|
acc.push(v);
|
|
54268
54539
|
return acc;
|
|
54269
54540
|
}, []).option("--flow <id>", "Removed (ADR 0024): export the agent that runs the flow instead", (v, acc) => {
|
|
54270
54541
|
acc.push(v);
|
|
54271
54542
|
return acc;
|
|
54272
|
-
}, []).option("--output <dir>", "Output directory for the scaffold (default: ./runtype-deploy)", "./runtype-deploy").option("--name <name>", "Project name used in package.json (default: derived from output dir)").option("--target <target>", "Deployment target: cloud-run, cloudflare, or vercel (default: cloud-run)", "cloud-run").action(async (options) => {
|
|
54543
|
+
}, []).option("--output <dir>", "Output directory for the scaffold (default: ./runtype-deploy)", "./runtype-deploy").option("--name <name>", "Project name used in package.json (default: derived from output dir)").option("--target <target>", "Deployment target: cloud-run, cloudflare, or vercel (default: cloud-run)", "cloud-run").option("--alias <name>", "Export the version each agent's release alias points at (e.g. staging, live, pr-42)").option("--version-id <id>", "Export this published agent version (requires exactly one --agent)").action(async (options) => {
|
|
54273
54544
|
const agentIds = options.agent;
|
|
54274
54545
|
if (options.flow.length > 0) {
|
|
54275
54546
|
for (const line of RETIRED_DEPLOY_FLOW_MESSAGE) console.error(chalk.yellow(line));
|
|
@@ -54279,6 +54550,11 @@ const deployCommand = new Command("deploy").description("Export an agent and sca
|
|
|
54279
54550
|
console.error(chalk.red("Error: provide at least one --agent <id>"));
|
|
54280
54551
|
process.exit(1);
|
|
54281
54552
|
}
|
|
54553
|
+
const selector = agentReleaseSelectorParams(options, agentIds.length);
|
|
54554
|
+
if ("error" in selector) {
|
|
54555
|
+
console.error(chalk.red(`Error: ${selector.error}`));
|
|
54556
|
+
process.exit(1);
|
|
54557
|
+
}
|
|
54282
54558
|
const target = options.target;
|
|
54283
54559
|
if (target !== "cloud-run" && target !== "cloudflare" && target !== "vercel") {
|
|
54284
54560
|
console.error(chalk.red(`Error: unknown --target "${target}". Must be one of: cloud-run, cloudflare, vercel`));
|
|
@@ -54294,13 +54570,13 @@ const deployCommand = new Command("deploy").description("Export an agent and sca
|
|
|
54294
54570
|
for (const id of agentIds) {
|
|
54295
54571
|
process.stdout.write(` Exporting agent ${chalk.green(id)}... `);
|
|
54296
54572
|
try {
|
|
54297
|
-
const def = await client.get(`/agents/${id}/export-runtime
|
|
54573
|
+
const def = await client.get(`/agents/${id}/export-runtime`, selector.params);
|
|
54298
54574
|
agentDefs.push({
|
|
54299
54575
|
id,
|
|
54300
54576
|
name: String(def.name ?? id),
|
|
54301
54577
|
def
|
|
54302
54578
|
});
|
|
54303
|
-
process.stdout.write(chalk.green("
|
|
54579
|
+
process.stdout.write(chalk.green("✓") + describeExportedRelease(def) + "\n");
|
|
54304
54580
|
} catch (err) {
|
|
54305
54581
|
const msg = err instanceof RuntypeApiError ? err.message : String(err);
|
|
54306
54582
|
process.stdout.write(chalk.red(`✗\n`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runtypelabs/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.43.0",
|
|
4
4
|
"description": "Command-line interface for Runtype AI platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"@modelcontextprotocol/client": "2.0.0",
|
|
12
12
|
"@modelcontextprotocol/core": "2.0.0",
|
|
13
13
|
"@runtypelabs/ink-components": "0.3.9",
|
|
14
|
-
"@runtypelabs/sdk": "10.
|
|
14
|
+
"@runtypelabs/sdk": "10.7.0",
|
|
15
15
|
"@runtypelabs/terminal-animations": "0.2.4",
|
|
16
16
|
"add-mcp": "2.0.0",
|
|
17
17
|
"chalk": "^5.3.0",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@modelcontextprotocol/server": "2.0.0",
|
|
35
35
|
"@runtypelabs/persona": "4.24.0",
|
|
36
|
-
"@runtypelabs/shared": "3.
|
|
36
|
+
"@runtypelabs/shared": "3.68.0",
|
|
37
37
|
"@types/express": "^5.0.6",
|
|
38
38
|
"@types/micromatch": "^4.0.9",
|
|
39
39
|
"@types/node": "^25.3.3",
|