@runtypelabs/cli 2.33.0 → 2.33.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.
Files changed (2) hide show
  1. package/dist/index.js +590 -55
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -616,9 +616,6 @@ var OAuthManager = class {
616
616
  // src/auth/api-key-manager.ts
617
617
  import { RuntypeApiError } from "@runtypelabs/sdk";
618
618
 
619
- // src/lib/sdk-client.ts
620
- import { createClient } from "@runtypelabs/sdk";
621
-
622
619
  // ../shared/dist/chunk-ZUODFMLO.mjs
623
620
  var DEFAULT_MODELS_FOR_NEW_ACCOUNTS = [
624
621
  // Mixlayer models
@@ -15364,7 +15361,7 @@ var edgeContextPayloadSchema = external_exports.object({
15364
15361
  // ../shared/dist/chunk-SCJRL6LP.mjs
15365
15362
  var MAX_DURABLE_POLL_ATTEMPTS = 1e3;
15366
15363
 
15367
- // ../shared/dist/chunk-FSHR33DZ.mjs
15364
+ // ../shared/dist/chunk-MATCHJ7V.mjs
15368
15365
  function getNestedValue(obj, path20) {
15369
15366
  let normalizedPath = path20;
15370
15367
  normalizedPath = normalizedPath.replace(/^\$\.?/, "");
@@ -20376,14 +20373,14 @@ function normalizeVectorSearchConfig(config3) {
20376
20373
  }
20377
20374
  const providerInput = config3.provider || config3.vectorStore || "record";
20378
20375
  const vectorStore = providerInput === "record" ? "pgvector" : providerInput;
20379
- const vectorizeConfig = config3.vectorizeConfigId || config3.vectorizeNamespace ? {
20376
+ const vectorizeConfig = config3.vectorizeConfig || (config3.vectorizeConfigId || config3.vectorizeNamespace ? {
20380
20377
  configId: config3.vectorizeConfigId,
20381
20378
  namespace: config3.vectorizeNamespace
20382
- } : void 0;
20383
- const weaviateConfig = config3.weaviateClassName || config3.weaviateConfigId ? {
20379
+ } : void 0);
20380
+ const weaviateConfig = config3.weaviateConfig || (config3.weaviateClassName || config3.weaviateConfigId ? {
20384
20381
  configId: config3.weaviateConfigId,
20385
20382
  className: config3.weaviateClassName || ""
20386
- } : void 0;
20383
+ } : void 0);
20387
20384
  return {
20388
20385
  query: config3.query,
20389
20386
  embeddingModel: config3.embeddingModel,
@@ -20956,6 +20953,9 @@ function sanitizeCodeToolIdentifier(name) {
20956
20953
  if (/^[0-9]/.test(safe)) safe = "_" + safe;
20957
20954
  return safe;
20958
20955
  }
20956
+ function snakeToCamel(str) {
20957
+ return str.replace(/_([a-z])/g, (_2, letter) => letter.toUpperCase());
20958
+ }
20959
20959
  var flowStepValidationSchema = external_exports.object({
20960
20960
  // Optional stable client-supplied identifier. Preserved across saves so that
20961
20961
  // `flow_step_results.stepId` references stay valid and dashboard UI state
@@ -21018,6 +21018,12 @@ var KNOWN_TOOL_KEYS = /* @__PURE__ */ new Set([
21018
21018
  ...Object.keys(CAMEL_CASE_TOOL_KEYS),
21019
21019
  ...Object.keys(SNAKE_CASE_TOOL_KEYS)
21020
21020
  ]);
21021
+ for (const snakeKey of Object.keys(SNAKE_CASE_TOOL_KEYS)) {
21022
+ const camelKey = snakeToCamel(snakeKey);
21023
+ if (!(camelKey in CAMEL_CASE_TOOL_KEYS)) {
21024
+ throw new Error(`No camelCase tool key for snake_case key "${snakeKey}"`);
21025
+ }
21026
+ }
21021
21027
  var LEGACY_TOOL_KEY_SUGGESTIONS = {
21022
21028
  builtinTools: "toolIds"
21023
21029
  };
@@ -22749,16 +22755,50 @@ var runtimeArtifactManifestSchema = external_exports.object({
22749
22755
  var KNOWN_FLOW_STEP_TYPES = new Set(FLOW_STEP_TYPES);
22750
22756
  var API_INPROCESS_CAPABILITY_MATRIX = {
22751
22757
  target: "api-inprocess",
22752
- // Bumped 2026-08-03: adds the §A1 `promptCodeModeTools` fold (a prompt step's
22753
- // `config.tools.codeModeConfig` has no runtime flow-lane port). Carries
22754
- // forward 2026-07-31: the `unmaterializedPromptToolRefs` fold. Carries
22755
- // forward 2026-07-30: the IMPLICIT platform-default fallback candidate no
22756
- // longer folds (see `implicitPlatformFallback` below). Carries forward
22757
- // 2026-07-29.4: api-hosted runtime fulfills managed fetch methods through
22758
- // ManagedFetchExecutor (the managed-fetch fact remains for attribution). The
22759
- // EXPLICIT Layer-2 fallback fold and the remaining parity-audit folds are
22760
- // unchanged.
22761
- version: "2026-08-03.1",
22758
+ // Bumped 2026-08-05.3: graduates `conditionalNestedExecuteAgentStep` to
22759
+ // SUPPORTED (the runtime-conditional-nested-execute-agent leg-2 port): a
22760
+ // conditional-nested `execute-agent` runs on the engine-owned nested path
22761
+ // (the shared `conditionalSubStepExecutor` re-enters `runContextStep`, whose
22762
+ // default engine path dispatches `executeExecuteAgent`), so it no longer folds
22763
+ // to legacy. The fact stays computed for decision attribution. Rollback lever:
22764
+ // revert this bit to `true`.
22765
+ // Bumped 2026-08-05.3: graduates `promptMcpServers` to SUPPORTED (the #6013
22766
+ // fold — the runtime FLOW lane now discovers `config.tools.mcpServers` on
22767
+ // prompt steps via `discoverMCPTools`, exactly like the agent lane, merging
22768
+ // each step's servers' tools into its `config.tools.runtimeTools` before the
22769
+ // prompt runs). The `hasPromptMcpServers` FACT is still computed for
22770
+ // decision attribution but no longer folds. Rollback lever: revert this bit
22771
+ // to `true`.
22772
+ // Bumped 2026-08-05.2: graduates `conditionalNestedPromptStep` to SUPPORTED
22773
+ // (the #6016 leg-1 port routes nested prompt sub-steps through the engine-owned
22774
+ // `runPromptStep` path instead of the portable executor's throw). The
22775
+ // `hasConditionalNestedPromptStep` FACT is still computed for decision
22776
+ // attribution but no longer folds. Rollback lever: revert this bit to `true`.
22777
+ // Bumped 2026-08-05.1: adds the #6023 leg 1 `customToolExecution` fold (a
22778
+ // custom runtime tool requesting code_mode / a non-JS language / a
22779
+ // container-backed sandbox provider the runtime's JS-only executor cannot
22780
+ // honor). Carries forward 2026-08-03: the §A1 `promptCodeModeTools` fold.
22781
+ // Carries forward 2026-07-31: the `unmaterializedPromptToolRefs` fold.
22782
+ // Carries forward 2026-07-30: the IMPLICIT platform-default fallback
22783
+ // candidate no longer folds (see `implicitPlatformFallback` below). Carries
22784
+ // forward 2026-07-29.4: api-hosted runtime fulfills managed fetch methods
22785
+ // through ManagedFetchExecutor (the managed-fetch fact remains for
22786
+ // attribution). The EXPLICIT Layer-2 fallback fold and the remaining
22787
+ // parity-audit folds are unchanged.
22788
+ // Bumped 2026-08-06.1: graduates `promptCodeModeTools` + the
22789
+ // `transformDataCodeModeTools` runtimeTools/toolIds cases (#6013) — the
22790
+ // runtime flow lane synthesizes `code_mode` and runs it (plus transform-data
22791
+ // tool pools) through the host `CodeModeExecutor`
22792
+ // (`SANDBOX.workerLoaderExecuteTransformWithTools`). The
22793
+ // `transformDataCodeModeTools` fact now folds only the `mcpServers` case.
22794
+ // Rollback lever: revert the two bits to `true` (plus their tests).
22795
+ // Bumped 2026-08-06.3: integration re-bump past the .1/.2 collisions — five
22796
+ // #6013/#6016 graduations (advisorTools, transformDataCodeModeTools,
22797
+ // promptCodeModeTools, promptMcpServers, promptArtifacts) landed on
22798
+ // independent branches that each claimed their own suffix, plus the
22799
+ // vendored-export re-fold pass. No bit changes with this bump; it exists so
22800
+ // the combined base carries one unambiguous version.
22801
+ version: "2026-08-06.3",
22762
22802
  unsupportedStepTypes: ["wait-until", "crawl"],
22763
22803
  unsupportedFeatures: {
22764
22804
  approvalSteps: true,
@@ -22766,8 +22806,18 @@ var API_INPROCESS_CAPABILITY_MATRIX = {
22766
22806
  claudeManagedAgent: true,
22767
22807
  inexpressibleVectorStep: true,
22768
22808
  unresolvableAgentRef: true,
22769
- conditionalNestedPromptStep: true,
22770
- conditionalNestedExecuteAgentStep: true,
22809
+ // SUPPORTED as of 2026-08-05 (#6016 leg 1): the runtime flow lane routes a
22810
+ // conditional-nested prompt through the engine-owned `runPromptStep` path
22811
+ // (nested prompt dispatch in flow-engine.ts), so a prompt inside a
22812
+ // conditional branch no longer folds to legacy.
22813
+ conditionalNestedPromptStep: false,
22814
+ // SUPPORTED as of 2026-08-05.3 (runtime-conditional-nested-execute-agent):
22815
+ // the runtime flow lane routes a conditional-nested `execute-agent` through
22816
+ // the engine-owned nested path (`conditionalSubStepExecutor` -> `runContextStep`
22817
+ // -> the default engine dispatch of `executeExecuteAgent`), so an execute-agent
22818
+ // inside a conditional branch no longer folds to legacy. The fact stays
22819
+ // computed for decision attribution. Rollback lever: revert this bit.
22820
+ conditionalNestedExecuteAgentStep: false,
22771
22821
  // SUPPORTED as of 2026-07-23 (slice 6 activation): the runtime flow lane
22772
22822
  // now PAUSES on definition-embedded client-executed (local / webmcp) tools
22773
22823
  // — `ClientToolRequiredError` → `step_await` / `flow_await` → durable KV
@@ -22777,7 +22827,13 @@ var API_INPROCESS_CAPABILITY_MATRIX = {
22777
22827
  // Rollback lever after retiring the flow request override: revert this bit
22778
22828
  // to `true` (the agent lane retains its separate rollout gate).
22779
22829
  clientExecutedTools: false,
22780
- advisorTools: true,
22830
+ // SUPPORTED as of 2026-08-06 (#6013 advisor port): the runtime flow lane
22831
+ // now executes advisor runtime tools server-side via nested model inference
22832
+ // (`RuntimeToolExecutor.runAdvisor`), so an advisor flow stays on the
22833
+ // runtime lane instead of folding to legacy. The `hasAdvisorTools` FACT is
22834
+ // still computed for decision attribution but no longer folds. Rollback
22835
+ // lever: flip this bit back to `true` (plus its test).
22836
+ advisorTools: false,
22781
22837
  // G2 SUPPORTED: api-hosted runtime delegates Firecrawl / Massive fetch-url
22782
22838
  // methods through ManagedFetchExecutor to the same API implementations the
22783
22839
  // legacy executor uses. Keep the fact computed for attribution, like
@@ -22785,19 +22841,48 @@ var API_INPROCESS_CAPABILITY_MATRIX = {
22785
22841
  unsupportedFetchMethod: false,
22786
22842
  // Remaining 2026-07-29 parity-audit BRIDGE folds (G4/G5/G10/G14): feature
22787
22843
  // classes the runtime flow lane still cannot faithfully run.
22788
- transformDataCodeModeTools: true,
22844
+ // SUPPORTED as of 2026-08-06 (#6013): a `transform-data` step whose
22845
+ // `config.tools` carries a runtime tool pool binds those tools through the
22846
+ // host `CodeModeExecutor` (`workerLoaderExecuteTransformWithTools`). The
22847
+ // `mcpServers`-only case STAYS folded via the narrow
22848
+ // `transformDataMcpServers` bit below (the runtime has no MCP discovery on
22849
+ // transform steps, so an MCP tool pool would silently lose its tools).
22850
+ // Rollback lever: revert this bit to `true` (plus its test).
22851
+ transformDataCodeModeTools: false,
22852
+ // #6013 narrow carve-out — the mcpServers-only transform code-mode case.
22853
+ // `transformDataHasCodeModeTools` now fires only on `config.tools.mcpServers`,
22854
+ // and this bit keeps that narrow case routed to legacy while the
22855
+ // runtimeTools/toolIds cases graduate (bit above flipped false).
22856
+ transformDataMcpServers: true,
22789
22857
  unsupportedTransformExecution: true,
22790
- promptMcpServers: true,
22791
- promptArtifacts: true,
22792
- // §A1 parity-audit BRIDGE fold (2026-08-03): a PROMPT step's
22793
- // `config.tools.codeModeConfig` with a non-empty `toolPool`. The
22794
- // `transformDataCodeModeTools` fold above covers only a TRANSFORM-DATA
22795
- // step's `config.tools` bag; a prompt step's code_mode synthesizer (the
22796
- // legacy `buildSynthesizedCodeModeTool`) has no runtime flow-lane port, so
22797
- // an unfolded prompt would run on the runtime lane with its code_mode tool
22798
- // pool silently absent. Routes to legacy until the prompt-step code_mode
22799
- // synthesizer is ported.
22800
- promptCodeModeTools: true,
22858
+ // #6023 leg 1 (2026-08-05): a custom runtime tool requesting code_mode / a
22859
+ // non-JS language / a container-backed sandbox provider has no runtime-lane
22860
+ // port — `runCustom` ignores all three and silently misexecutes as JS. Same
22861
+ // bridge class as `unsupportedTransformExecution` (G5), at the tool level.
22862
+ customToolExecution: true,
22863
+ // SUPPORTED as of 2026-08-05 (#6013 fold): the runtime FLOW lane now
22864
+ // discovers `config.tools.mcpServers` on prompt steps via `discoverMCPTools`
22865
+ // (mirroring the agent lane's agent-engine.ts wiring) and merges the
22866
+ // discovered tools into each prompt step's `config.tools.runtimeTools`
22867
+ // before it runs. Runtime discovery is the ONLY model-visible schema source
22868
+ // (real `tools/list` schemas + fresh auth — no export-time materialization,
22869
+ // which would ship empty schemas for allowedTools-gated servers). The
22870
+ // `hasPromptMcpServers` FACT is still computed for decision-attribution logs
22871
+ // but no longer folds. Rollback lever: revert this bit to `true`.
22872
+ promptMcpServers: false,
22873
+ // #6013 (G14, 2026-08-06): prompt-step artifact emission is ported to the
22874
+ // runtime lane (injection + emit_artifact_* execution + artifact_* frame
22875
+ // emission + strip). `hasPromptArtifacts` stays computed for decision
22876
+ // attribution. Rollback lever: set this back to `true` (plus its test).
22877
+ promptArtifacts: false,
22878
+ // SUPPORTED as of 2026-08-06 (#6013): the runtime flow lane synthesizes
22879
+ // the `code_mode` tool (byte-identical description/schema to legacy via the
22880
+ // shared builders) and executes it through the host `CodeModeExecutor`.
22881
+ // The `hasPromptCodeModeTools` FACT is still computed (for decision
22882
+ // attribution) but no longer folds. A pool referencing an unmaterialized
22883
+ // class still folds via the separate `unmaterializedPromptToolRefs` fact.
22884
+ // Rollback lever: revert this bit to `true` (plus its test).
22885
+ promptCodeModeTools: false,
22801
22886
  // SUPPORTED as of the fallback-chain port: the runtime flow engine now
22802
22887
  // executes EXPLICIT author-configured Layer-2 chains and synthesizes their
22803
22888
  // `usedFallback` / `fallbackModel` / `fallbackExecutions` attribution, so
@@ -22842,6 +22927,180 @@ var API_DURABLE_RESUME_CAPABILITY_MATRIX = {
22842
22927
  (stepType) => !DURABLE_HOSTED_STEP_TYPES.has(stepType)
22843
22928
  )
22844
22929
  };
22930
+ var VENDORED_EXPORT_CAPABILITY_MATRIX = {
22931
+ ...API_INPROCESS_CAPABILITY_MATRIX,
22932
+ target: "vendored-export",
22933
+ // Bumped 2026-08-06.3: one-pass re-decision of the restated fold block after
22934
+ // the five #6013/#6016 api-inprocess graduations (advisorTools,
22935
+ // transformDataCodeModeTools, promptCodeModeTools, promptMcpServers,
22936
+ // promptArtifacts) plus `conditionalNestedExecuteAgentStep`. Each restated
22937
+ // literal was re-classified against this file's own criterion — ENGINE-owned
22938
+ // (a self-contained container runs it) inherits the base `false`; HOST-SEAM
22939
+ // (fulfilled only by an api-wired optional executor a vendored container
22940
+ // lacks) becomes a documented entry in {@link VENDORED_EXPORT_REFOLDS}. The
22941
+ // two CodeModeExecutor-backed bits re-fold; the other four graduate here too.
22942
+ // Bumped 2026-08-06.2: re-folds `unsupportedFetchMethod` (see
22943
+ // VENDORED_EXPORT_REFOLDS) — api-inprocess supports managed fetch methods
22944
+ // only because the api host wires `ManagedFetchExecutor`; no export bundle
22945
+ // does, so a firecrawl/massive fetch-url step fails as-shipped.
22946
+ version: "2026-08-06.3",
22947
+ unsupportedStepTypes: [
22948
+ // ── Carried over from api-inprocess: durable-host-only step types. A
22949
+ // self-contained container has no durable host (BYOC §3.3 / S0 — the
22950
+ // exported runtime's `waitUntil` seam is unset; crawl needs the
22951
+ // `CrawlPendingError` durable pause). Graduation lever: wire a durable
22952
+ // store in the export (e.g. a Cloud SQL CheckpointStore) — then flip.
22953
+ "wait-until",
22954
+ "crawl",
22955
+ // ── Hosted-service / DB-backed record & email steps (BYOC §7.2). A
22956
+ // self-contained container has no hosted RecordStore / EmailSender; the
22957
+ // Hosted endpoints are PROPOSED, not built, and S0 shows send-email /
22958
+ // record steps fail in BOTH default and wired configs (no Bundled mode).
22959
+ // Graduation lever: build the Hosted endpoints OR ship a Bundled
22960
+ // RecordStore/EmailSender in the standard export — then remove.
22961
+ "send-email",
22962
+ "upsert-record",
22963
+ "update-record",
22964
+ "retrieve-record",
22965
+ "get-record",
22966
+ "list-records",
22967
+ "search",
22968
+ // ── Vector DB / embedding provider steps (BYOC §3.4 / §7.4). Only a
22969
+ // customer-wired VectorStore / EmbeddingProvider can host these; the
22970
+ // container ships neither. Graduation lever: bundle a pgvector
22971
+ // VectorStore + a provider-backed EmbeddingProvider in the export.
22972
+ "generate-embedding",
22973
+ "vector-search",
22974
+ "store-vector",
22975
+ // ── Hosted asset / PDF service steps (BYOC §7.2). store-asset /
22976
+ // generate-pdf are Hosted-only; no Bundled fulfillment. Graduation lever:
22977
+ // build the Hosted asset/PDF endpoints or ship a Bundled renderer/store.
22978
+ "store-asset",
22979
+ "generate-pdf",
22980
+ // ── Hosted memory-store steps (BYOC §3.4 / §7.2). Memory has Hosted/Custom
22981
+ // only, no Bundled mode. Graduation lever: a Bundled MemoryStore seam in
22982
+ // the export (or the Hosted memory endpoints).
22983
+ "save-memory",
22984
+ "recall-memory",
22985
+ "memory-summary",
22986
+ // ── template & transform-data: FAIL AS-SHIPPED (S0 §5.2.1 / §5.2.2). The
22987
+ // export does NOT bundle liquidjs / QuickJS, so a self-contained container
22988
+ // throws `TemplateRenderer not configured` / `SandboxNotConfiguredError`
22989
+ // out of the box; they only PASS once the container wires the Bundled
22990
+ // fulfillment (LiquidTemplateRenderer + QuickJSSafeCodeExecutor). Per the
22991
+ // fail-closed / keep-gates-truthful principle these stay UNSUPPORTED for
22992
+ // this v1. Graduation lever: bundle liquidjs + QuickJS as part of the
22993
+ // STANDARD export (default-wire the renderer and sandbox) — then flip both
22994
+ // to supported.
22995
+ "template",
22996
+ "transform-data"
22997
+ ],
22998
+ // Every api-inprocess feature fold carries over (shared engine, derived by
22999
+ // spreading the base). Each is restated below with its evidence + graduation
23000
+ // lever so the contract is self-documenting; values are pinned to the
23001
+ // api-inprocess semantics a container inherits, never loosened — except the
23002
+ // vendored-specific RE-FOLDS enumerated in {@link VENDORED_EXPORT_REFOLDS},
23003
+ // which are strictly stricter.
23004
+ unsupportedFeatures: {
23005
+ ...API_INPROCESS_CAPABILITY_MATRIX.unsupportedFeatures,
23006
+ approvalSteps: true,
23007
+ // api-inprocess fold; the runtime flow engine derives no approval config. Graduation: port the approval rail.
23008
+ batchInputMode: true,
23009
+ // api-inprocess fold; batch has no conversational context (BYOC §3.2).
23010
+ claudeManagedAgent: true,
23011
+ // api-inprocess fold; exported execute-agent rejects claude_managed/external (BYOC §3.6, D-030/D-031).
23012
+ inexpressibleVectorStep: true,
23013
+ // api-inprocess fold; no vector seam in a self-contained container.
23014
+ unresolvableAgentRef: true,
23015
+ // api-inprocess fold; execute-agent resolves only against the embedded registry (ADR 0014).
23016
+ // Nested-prompt dispatch is ENGINE-owned and works identically in a
23017
+ // container, so this stays SUPPORTED (false) exactly as api-inprocess has
23018
+ // it — a container does not re-fold what the engine runs itself.
23019
+ conditionalNestedPromptStep: false,
23020
+ // Conditional-nested `execute-agent` dispatch is ENGINE-owned exactly like
23021
+ // nested prompt above (`conditionalSubStepExecutor` -> `runContextStep` ->
23022
+ // `executeExecuteAgent`), so it inherits the base SUPPORTED (`false`) from
23023
+ // the spread. NOT restated as a literal: the 2026-08-06.3 re-decision pass
23024
+ // exists because a restated literal went stale when the base graduated.
23025
+ // Client-executed (local/webmcp) tools PAUSE natively on the runtime flow
23026
+ // lane; a self-contained container still pauses on them, so SUPPORTED
23027
+ // (false) — carried over verbatim.
23028
+ clientExecutedTools: false,
23029
+ // `advisorTools` inherits the base SUPPORTED (`false`): `RuntimeToolExecutor
23030
+ // .runAdvisor` resolves the advisor model through `PROVIDER_REGISTRY` +
23031
+ // `adapter.getSecret`/`getBinding` — the same machinery every prompt step
23032
+ // already uses — so a container that runs prompts runs advisors. No host
23033
+ // seam involved.
23034
+ // VENDORED RE-FOLD (not carried over): api-inprocess marks managed fetch
23035
+ // methods SUPPORTED (false) only because the api host wires
23036
+ // `ManagedFetchExecutor` — the seam exists precisely because the portable
23037
+ // runtime cannot own Firecrawl / Massive credentials, rollout gates, or
23038
+ // platform-spend metering. No export bundle wires it (the only
23039
+ // implementation is `ApiManagedFetchExecutor`, wired solely by
23040
+ // `apps/api/src/lib/runtime/playground-runtime.ts`), so a `fetch-url` step
23041
+ // with `fetchMethod: 'firecrawl' | 'massive'` falls through to the portable
23042
+ // base's not-supported error — and under the default `errorHandling:
23043
+ // 'continue'` that failure is SWALLOWED and downstream steps see null.
23044
+ // Declaring such a flow container-eligible is exactly the silent-misexecution
23045
+ // class the fail-closed posture (which folded template / transform-data for
23046
+ // the identical "passes only when hand-wired" reason) exists to prevent.
23047
+ // Graduation lever: ship a Bundled managed-fetch fulfillment in the standard
23048
+ // export (direct provider-credential fetch, or a hosted managed-fetch
23049
+ // endpoint) — then flip back to false and drop it from
23050
+ // {@link VENDORED_EXPORT_REFOLDS}. Plain `fetch-url` (no managed method)
23051
+ // stays supported; only the managed methods fold.
23052
+ unsupportedFetchMethod: true,
23053
+ // VENDORED RE-FOLD (not carried over): api-inprocess graduated a
23054
+ // `transform-data` step's runtimeTools/toolIds pool (#6013) only because the
23055
+ // api host wires `ApiCodeModeExecutor` → `SANDBOX
23056
+ // .workerLoaderExecuteTransformWithTools`. The seam exists precisely because
23057
+ // NONE of the runtime's four shipped `SafeCodeExecutor`s can bind pool tools
23058
+ // to sandboxed code, so an unwired container throws
23059
+ // `CodeModeExecutorNotConfiguredError` (`runtime-context-step-executor.ts`
23060
+ // fails closed on the transform-data path). Graduation lever: ship a Bundled
23061
+ // code-with-tools fulfillment in the standard export — then flip to false and
23062
+ // drop from {@link VENDORED_EXPORT_REFOLDS}.
23063
+ transformDataCodeModeTools: true,
23064
+ // The narrow mcpServers-only transform carve-out (#6013) is a base fold;
23065
+ // carried over as `true` and restated for the same reason (no MCP discovery
23066
+ // on transform steps).
23067
+ transformDataMcpServers: true,
23068
+ unsupportedTransformExecution: true,
23069
+ // api-inprocess fold (G5); carried over.
23070
+ customToolExecution: true,
23071
+ // api-inprocess fold (#6023 leg 1); carried over.
23072
+ // `promptMcpServers` inherits the base SUPPORTED (`false`). The runtime owns
23073
+ // MCP end to end for the shipped default transport: `discoverMCPTools` falls
23074
+ // back to its own `listServerTools` over `adapter.fetch` when no host
23075
+ // `MCPToolExecutor` is present, and `RuntimeToolExecutor.runMCP` has a
23076
+ // portable Streamable-HTTP JSON-RPC dispatch path on the same fallback. Only
23077
+ // `transport: 'rest'` requires the host executor, and that is a per-server
23078
+ // authoring choice this flow-level bit cannot express — the agent lane makes
23079
+ // the identical bet in a container today.
23080
+ // `promptArtifacts` inherits the base SUPPORTED (`false`): artifact emission
23081
+ // is pure `UnifiedEventEmitter` frame production plus builtin-tool injection
23082
+ // and strip, entirely inside the engine. (Persisting an artifact to hosted
23083
+ // storage is the separate `store-asset` STEP TYPE, which stays folded above.)
23084
+ // VENDORED RE-FOLD (not carried over): api-inprocess graduated a PROMPT
23085
+ // step's `codeModeConfig.toolPool` (#6013) on the same `ApiCodeModeExecutor`
23086
+ // seam as `transformDataCodeModeTools` above. The runtime synthesizes the
23087
+ // `code_mode` tool byte-identically, but firing it without a host executor
23088
+ // throws `CodeModeExecutorNotConfiguredError` (`tool-executor.ts` fails
23089
+ // closed rather than silently degrading the pool to plain model tools).
23090
+ // Under the default `errorHandling: 'continue'` that failure is swallowed —
23091
+ // the same silent-misexecution class the fail-closed posture exists to
23092
+ // prevent. Same graduation lever as the transform-data bit.
23093
+ promptCodeModeTools: true,
23094
+ // Explicit Layer-2 fallback chains are SUPPORTED (false) on the runtime
23095
+ // lane, engine-owned, so a container runs them — carried over verbatim.
23096
+ fallbackErrorHandling: false,
23097
+ // Implicit platform-default fallback SUPPORTED (false) — engine-owned
23098
+ // resilience; carried over verbatim (a container is not less capable).
23099
+ implicitPlatformFallback: false,
23100
+ unmaterializedPromptToolRefs: true
23101
+ // api-inprocess fold (§A1); carried over.
23102
+ }
23103
+ };
22845
23104
  var edgeAuthSnapshotSchema = external_exports.object({
22846
23105
  /**
22847
23106
  * Schema version. A plain positive int (not a literal) so a consumer pinned
@@ -37822,7 +38081,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
37822
38081
  {
37823
38082
  id: "sandbox:exec",
37824
38083
  name: "Sandbox Exec",
37825
- description: "Run a shell command in a Linux sandbox (Node 22, Python 3.12, git, pnpm). The sandbox persists across tool calls within the same execution \u2014 install packages, write files, then run them. Returns stdout, stderr, and exit code.",
38084
+ description: "Run a shell command in a Linux sandbox (Node 22, Python 3.12, git, pnpm). Commands run in /workspace; installed packages and files you write there stay available to later calls in the same execution, but the working directory does not carry over \u2014 every call starts in /workspace again. Chain a directory change inside one command (`cd app && npm test`) or use absolute paths; a lone `cd` does nothing. Returns stdout, stderr, and exit code.",
37826
38085
  category: BuiltInToolCategory.SANDBOX,
37827
38086
  toolGroup: BuiltInToolGroup.SANDBOX_USE,
37828
38087
  providers: [BuiltInToolProvider.MULTI],
@@ -37831,7 +38090,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
37831
38090
  properties: {
37832
38091
  command: {
37833
38092
  type: "string",
37834
- description: "Shell command to execute (runs in bash)"
38093
+ description: "Shell command to execute (runs in bash, cwd is /workspace)."
37835
38094
  },
37836
38095
  timeout: {
37837
38096
  type: "number",
@@ -37873,7 +38132,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
37873
38132
  {
37874
38133
  id: "sandbox:write_file",
37875
38134
  name: "Sandbox Write File",
37876
- description: "Write a file to the sandbox filesystem. Creates parent directories automatically. Use sandbox:exec to run files after writing them.",
38135
+ description: "Write a file to the sandbox filesystem. Creates parent directories automatically. Relative paths resolve against /workspace, the directory every sandbox call starts in. Files written there stay available to later calls in the same execution. Use sandbox:exec to run files after writing them.",
37877
38136
  category: BuiltInToolCategory.SANDBOX,
37878
38137
  toolGroup: BuiltInToolGroup.SANDBOX_USE,
37879
38138
  providers: [BuiltInToolProvider.MULTI],
@@ -37882,7 +38141,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
37882
38141
  properties: {
37883
38142
  path: {
37884
38143
  type: "string",
37885
- description: "File path in the sandbox (e.g., /home/user/app/index.js)"
38144
+ description: "File path in the sandbox (e.g. /workspace/app/index.js, or app/index.js relative to /workspace)"
37886
38145
  },
37887
38146
  content: {
37888
38147
  type: "string",
@@ -37898,7 +38157,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
37898
38157
  {
37899
38158
  id: "sandbox:read_file",
37900
38159
  name: "Sandbox Read File",
37901
- description: "Read a file from the sandbox filesystem. Returns the file content as a string.",
38160
+ description: "Read a file from the sandbox filesystem. Relative paths resolve against /workspace, the directory every sandbox call starts in. Returns the file content as a string.",
37902
38161
  category: BuiltInToolCategory.SANDBOX,
37903
38162
  toolGroup: BuiltInToolGroup.SANDBOX_USE,
37904
38163
  providers: [BuiltInToolProvider.MULTI],
@@ -37907,7 +38166,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
37907
38166
  properties: {
37908
38167
  path: {
37909
38168
  type: "string",
37910
- description: "File path to read"
38169
+ description: "File path to read (relative paths resolve against /workspace)"
37911
38170
  }
37912
38171
  },
37913
38172
  required: ["path"]
@@ -37944,7 +38203,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
37944
38203
  {
37945
38204
  id: "sandbox:git_checkout",
37946
38205
  name: "Sandbox Git Checkout",
37947
- description: "Clone a git repository into the sandbox. The repo is cloned into the current working directory.",
38206
+ description: "Clone a git repository into the sandbox. The repo is cloned under /workspace, the directory every sandbox call starts in; reach it afterward with an explicit path (`cd <repo> && ...`), since the working directory does not carry over between calls.",
37948
38207
  category: BuiltInToolCategory.SANDBOX,
37949
38208
  toolGroup: BuiltInToolGroup.SANDBOX_USE,
37950
38209
  providers: [BuiltInToolProvider.MULTI],
@@ -37993,7 +38252,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
37993
38252
  {
37994
38253
  id: "sandbox:session_exec",
37995
38254
  name: "Sandbox Session Exec",
37996
- description: "Run a shell command in a specific sandbox identified by sandboxId.",
38255
+ description: "Run a shell command in a specific sandbox identified by sandboxId. Commands run in /workspace; files stay available across calls but the working directory does not carry over \u2014 every call starts in /workspace again, so chain a directory change inside one command (`cd app && npm test`) or use absolute paths.",
37997
38256
  category: BuiltInToolCategory.SANDBOX,
37998
38257
  toolGroup: BuiltInToolGroup.SANDBOX_SESSION,
37999
38258
  providers: [BuiltInToolProvider.MULTI],
@@ -38006,7 +38265,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
38006
38265
  },
38007
38266
  command: {
38008
38267
  type: "string",
38009
- description: "Shell command to execute"
38268
+ description: "Shell command to execute (runs in bash, cwd is /workspace)."
38010
38269
  },
38011
38270
  timeout: {
38012
38271
  type: "number",
@@ -38195,7 +38454,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
38195
38454
  {
38196
38455
  id: "bash",
38197
38456
  name: "Bash",
38198
- description: "Run a shell command on your Linux computer (Node 22, Python 3.12, git, pnpm, uv, ripgrep preinstalled). Commands run in /workspace; files you write there are available to later commands, but system-level changes outside /workspace may not persist. Combined stdout/stderr is returned. Prefer searching over dumping: use `rg`/`grep` to find the lines you need and `head`/`tail`/`sed -n` to read slices. Output is capped. If the command is still running at timeout_ms, it is NOT killed: bash returns a durable process_id and partial output. When the result has a deliveryId, pass it as ack_delivery_id on the next bash_output poll so newer output can advance. Poll only new output with bash_output, stop it with kill_process, or inspect handles with list_processes. Use run_in_background=true to yield immediately.",
38457
+ description: "Run a shell command on your Linux computer (Node 22, Python 3.12, git, pnpm, uv, ripgrep preinstalled). Commands run in /workspace; files you write there are available to later commands, but system-level changes outside /workspace may not persist. Combined stdout/stderr is returned. Prefer searching over dumping: use `rg`/`grep` to find the lines you need and `head`/`tail`/`sed -n` to read slices. Output is capped. If the command is still running at timeout_ms, it is NOT killed: bash returns a durable process_id and partial output. When the result has a deliveryId, pass it as ack_delivery_id on the next bash_output poll so newer output can advance. Read only new output with bash_output (pass its wait_for_exit_ms to wait for the process rather than polling in a loop), stop it with kill_process, or inspect handles with list_processes. Use run_in_background=true to yield immediately.",
38199
38458
  category: BuiltInToolCategory.SANDBOX,
38200
38459
  toolGroup: BuiltInToolGroup.SANDBOX_AGENT,
38201
38460
  providers: [BuiltInToolProvider.MULTI],
@@ -38237,7 +38496,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
38237
38496
  {
38238
38497
  id: "bash_output",
38239
38498
  name: "Bash Output",
38240
- description: "Read only the new combined stdout/stderr produced after the last acknowledged delivery of a background bash process. Pass the previous successful bash or bash_output result's deliveryId as ack_delivery_id on the next poll; unacknowledged output is replayed so an API timeout cannot lose it. Acknowledge a terminal result's final delivery with one more poll so its bounded history record can retire. Returns status and an actual exitCode only after the process is terminal. Output is bounded and untrusted.",
38499
+ description: "Read only the new combined stdout/stderr produced after the last acknowledged delivery of a background bash process. Do NOT poll in a tight loop: pass wait_for_exit_ms to wait server-side for the process to finish, so one call replaces many. Pass the previous successful bash or bash_output result's deliveryId as ack_delivery_id on the next poll; unacknowledged output is replayed so an API timeout cannot lose it. Acknowledge a terminal result's final delivery with one more poll so its bounded history record can retire. Returns status and an actual exitCode only after the process is terminal. Output is bounded and untrusted.",
38241
38500
  category: BuiltInToolCategory.SANDBOX,
38242
38501
  toolGroup: BuiltInToolGroup.SANDBOX_AGENT,
38243
38502
  providers: [BuiltInToolProvider.MULTI],
@@ -38256,6 +38515,10 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
38256
38515
  description: "deliveryId from the most recent successful bash or bash_output result for this process. Acknowledges that batch before reading newer output. Omit when no deliveryId has been received.",
38257
38516
  minLength: 1,
38258
38517
  maxLength: 64
38518
+ },
38519
+ wait_for_exit_ms: {
38520
+ type: "number",
38521
+ description: "Milliseconds to wait for the process to exit before returning. Use this instead of repeated polling when you expect the command to finish soon: it returns as soon as the process exits, or immediately if output is already waiting or the process has already finished. It waits for EXIT, so a process that prints progress as it goes still returns only at exit or at this deadline. Clamped to at most 240000 and to the time left in the turn; defaults to 0 (return whatever is available now)."
38259
38522
  }
38260
38523
  },
38261
38524
  required: ["process_id"]
@@ -45053,7 +45316,7 @@ var FLOW_STEP_TYPE_METADATA = {
45053
45316
  configHints: "recordId, recordType, recordName, recordFilter ({ type, where: { field, op, value } }), outputVariable (returns one object \u2014 access as {{var.field}})"
45054
45317
  },
45055
45318
  "list-records": {
45056
- description: "Load an ARRAY of records from the Runtype record store by type, name, or a chip-style recordFilter (metadata + top-level columns: id, name, createdAt, updatedAt), ordered by updated_at desc. Always returns an array \u2014 even for a single match \u2014 so index it in templates ({{var.0.field}}). Default limit 50 (max 1000).",
45319
+ description: "Load an ARRAY of records from the Runtype record store by type, name, or a chip-style recordFilter (metadata + top-level columns: id, name, createdAt, updatedAt, schemaValid), ordered by updated_at desc. Always returns an array \u2014 even for a single match \u2014 so index it in templates ({{var.0.field}}). Default limit 50 (max 1000).",
45057
45320
  category: "data",
45058
45321
  isPrompt: false,
45059
45322
  configHints: "recordType, recordName, recordFilter ({ type, where: { field, op, value } }), limit (default 50, max 1000), onEmpty (succeed|fail), outputVariable (returns an array \u2014 index as {{var.0.field}})"
@@ -46026,7 +46289,7 @@ var FLOW_GENERATION_GUIDE = `## Flow Generation Guide
46026
46289
  - **conditional**: Branch logic. Either the binary shape (condition (JS expression), trueSteps, falseSteps) or N-way named branches (branches: [{ id, name, condition, steps }], evaluated first-match-wins, with otherwiseSteps as the fallback). Set outputVariable to merge whichever branch ran into one named result.
46027
46290
  - **fetch-url**: HTTP request. Config: http (url, method, headers, body), responseType, outputVariable. Optional fetchMethod: 'firecrawl' (structured extraction) or 'massive' (JS-rendered/blocked pages, with massive: { format, country, delay, expiration }) instead of a raw fetch
46028
46291
  - **api-call**: Structured API call. Config: http, auth, responseMapping, outputVariable
46029
- - **get-record**: Load a SINGLE record OBJECT. Config: recordId, OR recordType + recordName, OR recordFilter ({ type, where: { field, op, value } }) for richer metadata-aware queries; outputVariable. Reachable filter columns include id, name, createdAt, updatedAt plus any metadata key. Returns one object \u2014 access fields directly in templates (\`{{record.field}}\`). On multiple matches the first by updated_at desc wins; fails if none match.
46292
+ - **get-record**: Load a SINGLE record OBJECT. Config: recordId, OR recordType + recordName, OR recordFilter ({ type, where: { field, op, value } }) for richer metadata-aware queries; outputVariable. Reachable filter columns include id, name, createdAt, updatedAt, schemaValid (the collection-validation stamp) plus any metadata key. Returns one object \u2014 access fields directly in templates (\`{{record.field}}\`). On multiple matches the first by updated_at desc wins; fails if none match.
46030
46293
  - **list-records**: Load an ARRAY of records. Config: recordType, recordName, OR recordFilter ({ type, where: { field, op, value } }); limit (default 50, max 1000), onEmpty (succeed|fail, default succeed), outputVariable. Ordered by updated_at desc. Always writes an array \u2014 even for a single match \u2014 so index it in templates (\`{{records.0.field}}\` or \`{{records[0].field}}\`); object-style access (\`{{records.field}}\`) on the array resolves to undefined.
46031
46294
  - **retrieve-record**: DEPRECATED \u2014 use get-record (single object) or list-records (array). Still accepted at write and aliased at execution onto one of them; its return shape is inferred from the lookup method (recordId \u2192 object, type/name/filter \u2192 array), which is the ambiguity the successors remove.
46032
46295
  - **upsert-record**: Create/update a record keyed by \`(recordType, recordName)\` per owner. Config: recordType, **recordName** (REQUIRED for upsert semantics \u2014 without it each run creates a fresh \`\${recordType}-\${Date.now()}\` record), sourceVariable (the JSON metadata payload only \u2014 do NOT wrap as \`{ name, type, metadata }\`; the wrapper gets stored verbatim), outputVariable. See "Record-Keyed Upsert Patterns" in the build-product instructions for the full anti-pattern list (silent timestamped fallback, wrapped-source footgun, JSONB-blob aggregate races).
@@ -46855,7 +47118,15 @@ var FlowInputSchema = external_exports.object({
46855
47118
  name: external_exports.string().min(1).optional(),
46856
47119
  description: external_exports.string().optional(),
46857
47120
  steps: external_exports.array(external_exports.any()).optional(),
46858
- contentHash: external_exports.string().length(64).optional()
47121
+ contentHash: external_exports.string().length(64).optional(),
47122
+ // An inline/virtual flow may embed an agent registry (an `agents` map,
47123
+ // mirroring `ExportedFlowDefinition.agents`) so the lane-routing eligibility
47124
+ // analyzer and the runtime leg can resolve `execute-agent` refs against it
47125
+ // instead of folding a resolvable embedded ref to legacy (or failing with
47126
+ // AGENT_NOT_RESOLVED at execution). Optional and backward-compatible: flows
47127
+ // without embedded agents omit it, and the values pass through verbatim so
47128
+ // the full ExportedAgent shape survives the schema boundary.
47129
+ agents: external_exports.record(external_exports.string(), external_exports.any()).optional()
46859
47130
  }).refine(
46860
47131
  (data) => {
46861
47132
  const hasFlowId = !!data.id;
@@ -47394,7 +47665,12 @@ var RuntimeStoredRecordSchema = external_exports.object({
47394
47665
  userId: external_exports.string(),
47395
47666
  organizationId: external_exports.string().nullable(),
47396
47667
  createdAt: external_exports.string(),
47397
- updatedAt: external_exports.string()
47668
+ updatedAt: external_exports.string(),
47669
+ metadataSchema: external_exports.record(external_exports.string(), external_exports.unknown()).nullable().optional(),
47670
+ metadataLabels: external_exports.record(external_exports.string(), external_exports.string()).nullable().optional(),
47671
+ schemaValid: external_exports.boolean().nullable().optional(),
47672
+ messages: external_exports.array(external_exports.object({ role: external_exports.string(), content: external_exports.string() })).nullable().optional(),
47673
+ productSurfaceId: external_exports.string().nullable().optional()
47398
47674
  });
47399
47675
  var FILTER_FIELD_NAME_RE = /^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,63}$/;
47400
47676
  var runtimeRecordFilterConditionSchema = external_exports.object({
@@ -47714,6 +47990,167 @@ var appDataGrantSchema = external_exports.object({
47714
47990
  // this field directly.
47715
47991
  writePolicy: external_exports.enum(["app", "creator"]).optional()
47716
47992
  });
47993
+ var APP_CSP_DIRECTIVES = [
47994
+ "default-src",
47995
+ "script-src",
47996
+ "script-src-elem",
47997
+ "script-src-attr",
47998
+ "style-src",
47999
+ "style-src-elem",
48000
+ "style-src-attr",
48001
+ "img-src",
48002
+ "media-src",
48003
+ "font-src",
48004
+ "connect-src",
48005
+ "frame-src",
48006
+ "child-src",
48007
+ "worker-src",
48008
+ "object-src",
48009
+ "manifest-src",
48010
+ "form-action",
48011
+ "base-uri",
48012
+ "frame-ancestors"
48013
+ ];
48014
+ var APP_CSP_KEYWORD_SOURCES = [
48015
+ "'self'",
48016
+ "'none'",
48017
+ "'unsafe-inline'",
48018
+ "'unsafe-eval'",
48019
+ "'wasm-unsafe-eval'",
48020
+ "'strict-dynamic'",
48021
+ "'report-sample'"
48022
+ ];
48023
+ var APP_CSP_SCHEME_SOURCES = ["https:", "data:", "blob:", "wss:", "mediastream:"];
48024
+ var APP_CSP_HOST_SOURCE_PATTERN = /^(https|wss):\/\/(\*\.)?[a-z0-9-]+(\.[a-z0-9-]+)*(:\d{1,5})?$/i;
48025
+ var APP_CSP_LIMITS = {
48026
+ maxSourcesPerDirective: 20,
48027
+ sourceMaxLength: 256
48028
+ };
48029
+ var APP_RESPONSE_HEADER_LIMITS = {
48030
+ maxEntries: 20,
48031
+ nameMaxLength: 128,
48032
+ valueMaxLength: 1024
48033
+ };
48034
+ var APP_RESPONSE_HEADER_NAME_PATTERN = /^[a-zA-Z0-9-]+$/;
48035
+ var APP_DENIED_RESPONSE_HEADERS = {
48036
+ "content-security-policy": 'Use the manifest "csp" field instead.',
48037
+ "content-type": "Content types are inferred from the file extension.",
48038
+ "content-length": "Runtype sets transport headers for the served response.",
48039
+ "content-encoding": "Runtype sets transport headers for the served response.",
48040
+ "transfer-encoding": "Runtype sets transport headers for the served response.",
48041
+ connection: "Runtype sets transport headers for the served response.",
48042
+ etag: "The ETag is derived from the stored bundle file.",
48043
+ "cache-control": "Runtype owns caching so activating an older version takes effect immediately.",
48044
+ "set-cookie": "Apps authenticate through the injected client token, not cookies.",
48045
+ "x-robots-tag": "Indexing follows the app's visibility setting.",
48046
+ "x-content-type-options": "Runtype always sends nosniff.",
48047
+ "strict-transport-security": "HSTS is set for the whole serving domain.",
48048
+ location: "Served bundle files are static content and never redirect."
48049
+ };
48050
+ function isAllowedAppCspDirective(name) {
48051
+ return APP_CSP_DIRECTIVES.includes(name);
48052
+ }
48053
+ function isValidAppCspSource(source) {
48054
+ if (source.length === 0 || source.length > APP_CSP_LIMITS.sourceMaxLength) return false;
48055
+ if (APP_CSP_KEYWORD_SOURCES.includes(source)) return true;
48056
+ if (APP_CSP_SCHEME_SOURCES.includes(source)) return true;
48057
+ return APP_CSP_HOST_SOURCE_PATTERN.test(source);
48058
+ }
48059
+ function appResponseHeaderDenialReason(name) {
48060
+ return APP_DENIED_RESPONSE_HEADERS[name.toLowerCase()] ?? null;
48061
+ }
48062
+ var APP_CSP_SOURCE_HELP = `Use a quoted keyword (${APP_CSP_KEYWORD_SOURCES.join(
48063
+ ", "
48064
+ )}), a scheme (${APP_CSP_SCHEME_SOURCES.join(", ")}), or an https/wss origin such as https://cdn.example.com`;
48065
+ var appCspOverridesSchema = external_exports.record(external_exports.string(), external_exports.array(external_exports.string())).superRefine((overrides, ctx) => {
48066
+ for (const [directive, sources] of Object.entries(overrides)) {
48067
+ if (!isAllowedAppCspDirective(directive)) {
48068
+ ctx.addIssue({
48069
+ code: "custom",
48070
+ path: [directive],
48071
+ message: `Unsupported CSP directive "${directive}". Allowed directives: ${APP_CSP_DIRECTIVES.join(", ")}.`
48072
+ });
48073
+ continue;
48074
+ }
48075
+ if (sources.length === 0) {
48076
+ ctx.addIssue({
48077
+ code: "custom",
48078
+ path: [directive],
48079
+ message: `CSP directive "${directive}" needs at least one source. Use "'none'" to block everything.`
48080
+ });
48081
+ continue;
48082
+ }
48083
+ if (sources.length > APP_CSP_LIMITS.maxSourcesPerDirective) {
48084
+ ctx.addIssue({
48085
+ code: "custom",
48086
+ path: [directive],
48087
+ message: `CSP directive "${directive}" has ${sources.length} sources, which exceeds the ${APP_CSP_LIMITS.maxSourcesPerDirective}-source limit.`
48088
+ });
48089
+ continue;
48090
+ }
48091
+ for (const [index, source] of sources.entries()) {
48092
+ if (source.length > APP_CSP_LIMITS.sourceMaxLength) {
48093
+ ctx.addIssue({
48094
+ code: "custom",
48095
+ path: [directive, index],
48096
+ message: `CSP source in "${directive}" exceeds the ${APP_CSP_LIMITS.sourceMaxLength}-character limit.`
48097
+ });
48098
+ continue;
48099
+ }
48100
+ if (!isValidAppCspSource(source)) {
48101
+ ctx.addIssue({
48102
+ code: "custom",
48103
+ path: [directive, index],
48104
+ message: `CSP directive "${directive}" has an unsupported source "${source}". ${APP_CSP_SOURCE_HELP}.`
48105
+ });
48106
+ }
48107
+ }
48108
+ }
48109
+ });
48110
+ var appResponseHeaderOverridesSchema = external_exports.record(external_exports.string(), external_exports.string()).superRefine((headers, ctx) => {
48111
+ const entries = Object.entries(headers);
48112
+ if (entries.length > APP_RESPONSE_HEADER_LIMITS.maxEntries) {
48113
+ ctx.addIssue({
48114
+ code: "custom",
48115
+ message: `${entries.length} response headers exceeds the ${APP_RESPONSE_HEADER_LIMITS.maxEntries}-header limit.`
48116
+ });
48117
+ return;
48118
+ }
48119
+ for (const [name, value] of entries) {
48120
+ if (name.length > APP_RESPONSE_HEADER_LIMITS.nameMaxLength || !APP_RESPONSE_HEADER_NAME_PATTERN.test(name)) {
48121
+ ctx.addIssue({
48122
+ code: "custom",
48123
+ path: [name],
48124
+ message: `Response header name "${name}" is invalid. Use letters, digits, and hyphens only (max ${APP_RESPONSE_HEADER_LIMITS.nameMaxLength} characters).`
48125
+ });
48126
+ continue;
48127
+ }
48128
+ const denied = appResponseHeaderDenialReason(name);
48129
+ if (denied) {
48130
+ ctx.addIssue({
48131
+ code: "custom",
48132
+ path: [name],
48133
+ message: `Response header "${name}" is set by Runtype and cannot be overridden. ${denied}`
48134
+ });
48135
+ continue;
48136
+ }
48137
+ if (/[\r\n]/.test(value)) {
48138
+ ctx.addIssue({
48139
+ code: "custom",
48140
+ path: [name],
48141
+ message: `Response header "${name}" must not contain a carriage return or newline.`
48142
+ });
48143
+ continue;
48144
+ }
48145
+ if (value.length > APP_RESPONSE_HEADER_LIMITS.valueMaxLength) {
48146
+ ctx.addIssue({
48147
+ code: "custom",
48148
+ path: [name],
48149
+ message: `Response header "${name}" exceeds the ${APP_RESPONSE_HEADER_LIMITS.valueMaxLength}-character value limit.`
48150
+ });
48151
+ }
48152
+ }
48153
+ });
47717
48154
  var appManifestSchema = external_exports.object({
47718
48155
  name: external_exports.string().min(1).max(APP_MANIFEST_LIMITS.nameMaxLength),
47719
48156
  description: external_exports.string().max(2e3).optional(),
@@ -47722,7 +48159,9 @@ var appManifestSchema = external_exports.object({
47722
48159
  agents: external_exports.array(external_exports.string()).max(APP_MANIFEST_LIMITS.maxAgents).default([])
47723
48160
  }).strict().default({ flows: [], agents: [] }),
47724
48161
  data: external_exports.array(appDataGrantSchema).max(APP_MANIFEST_LIMITS.maxDataNamespaces).default([]),
47725
- auth: external_exports.enum(["none", "optional", "required"]).default("none")
48162
+ auth: external_exports.enum(["none", "optional", "required"]).default("none"),
48163
+ csp: appCspOverridesSchema.optional(),
48164
+ headers: appResponseHeaderOverridesSchema.optional()
47726
48165
  }).strict();
47727
48166
  var appRoutingDocSchema = external_exports.object({
47728
48167
  appId: external_exports.string(),
@@ -47739,6 +48178,20 @@ var appRoutingDocSchema = external_exports.object({
47739
48178
  apiUrl: external_exports.string(),
47740
48179
  clientToken: external_exports.string().nullable()
47741
48180
  }),
48181
+ /**
48182
+ * The active manifest's serving policy, copied forward on activation.
48183
+ * Optional so routing docs written before this field keep parsing.
48184
+ *
48185
+ * The SHAPE is validated here but the CONTENT deliberately is not: a doc
48186
+ * whose csp/headers fail the stricter manifest rules must still parse, or a
48187
+ * single bad value would take the whole app off the air. The edge runs
48188
+ * `sanitizeAppCspOverrides` / `sanitizeAppResponseHeaders` at header-build
48189
+ * time and falls back to the platform default for anything it rejects.
48190
+ */
48191
+ serving: external_exports.object({
48192
+ csp: external_exports.record(external_exports.string(), external_exports.array(external_exports.string())).optional(),
48193
+ headers: external_exports.record(external_exports.string(), external_exports.string()).optional()
48194
+ }).optional(),
47742
48195
  updatedAt: external_exports.string()
47743
48196
  });
47744
48197
  var SKILL_SCAN_HARD_BLOCK_CATEGORIES = [
@@ -47775,6 +48228,9 @@ function getDevPlanOverride() {
47775
48228
  return process.env.RUNTYPE_DEV_PLAN_OVERRIDE;
47776
48229
  }
47777
48230
 
48231
+ // src/lib/sdk-client.ts
48232
+ import { createClient } from "@runtypelabs/sdk";
48233
+
47778
48234
  // src/lib/cli-version.ts
47779
48235
  import { readFileSync as readFileSync2 } from "fs";
47780
48236
  import { dirname, join } from "path";
@@ -47839,6 +48295,24 @@ var isAuthMeResponse = (value) => {
47839
48295
  const record2 = value;
47840
48296
  return typeof record2.userId === "string";
47841
48297
  };
48298
+ var ApiKeyValidationUnavailableError = class extends Error {
48299
+ constructor(message, statusCode, options) {
48300
+ super(message, options);
48301
+ this.statusCode = statusCode;
48302
+ this.name = "ApiKeyValidationUnavailableError";
48303
+ }
48304
+ statusCode;
48305
+ };
48306
+ var describeUnverifiableStatus = (statusCode, apiUrl) => {
48307
+ const answered = `Could not verify the API key: the API at ${apiUrl} answered HTTP ${statusCode}`;
48308
+ if (statusCode === 403 || statusCode === 407) {
48309
+ return `${answered} (this can be an egress proxy or firewall blocking ${apiUrl}, not an invalid key)`;
48310
+ }
48311
+ if (statusCode >= 500) {
48312
+ return `${answered} (the API or something in front of it is failing, not an invalid key). Try again shortly.`;
48313
+ }
48314
+ return `${answered}, which is neither a success nor a credential rejection, so the key was not verified.`;
48315
+ };
47842
48316
  var ApiKeyManager = class {
47843
48317
  /**
47844
48318
  * Exchange a Clerk session JWT for a persistent API key.
@@ -47868,14 +48342,32 @@ var ApiKeyManager = class {
47868
48342
  }
47869
48343
  return result;
47870
48344
  }
48345
+ /**
48346
+ * Resolve whether the API accepts this key.
48347
+ *
48348
+ * `false` means strictly "the API looked at these credentials and rejected
48349
+ * them". Anything that leaves the key unchecked throws instead — the SDK
48350
+ * mints a `RuntypeApiError` for every non-2xx response, so returning false
48351
+ * for all of them reported an intercepting proxy's 403, a 407, or an API
48352
+ * 5xx as "Invalid API key" and sent people hunting for a credential problem
48353
+ * that did not exist.
48354
+ */
47871
48355
  async validateApiKey(apiKey, apiUrl) {
47872
- const client = createCliClient(apiKey, apiUrl);
48356
+ const resolvedApiUrl = apiUrl || getApiUrl();
48357
+ const client = createCliClient(apiKey, resolvedApiUrl);
47873
48358
  try {
47874
48359
  await client.get("/users/profile");
47875
48360
  return true;
47876
48361
  } catch (error51) {
47877
48362
  if (error51 instanceof RuntypeApiError) {
47878
- return false;
48363
+ if (error51.statusCode === 401) {
48364
+ return false;
48365
+ }
48366
+ throw new ApiKeyValidationUnavailableError(
48367
+ describeUnverifiableStatus(error51.statusCode, resolvedApiUrl),
48368
+ error51.statusCode,
48369
+ { cause: error51 }
48370
+ );
47879
48371
  }
47880
48372
  throw error51;
47881
48373
  }
@@ -48549,6 +49041,10 @@ var NON_TTY_LOGIN_GUIDANCE = {
48549
49041
  "Existing account: ask the user for an API key from the dashboard (Settings > API keys), then run: runtype auth login --api-key <key>"
48550
49042
  ]
48551
49043
  };
49044
+ var API_UNREACHABLE_NEXT = [
49045
+ "Confirm this environment can reach the Runtype API directly over HTTPS.",
49046
+ "If egress is restricted, allowlist api.runtype.com (staging: api.runtype-staging.com), then re-run: runtype auth login --api-key <key>"
49047
+ ];
48552
49048
  function refuseForcedTtyLogin(options) {
48553
49049
  if (options.tty === true && process.stdout.isTTY !== true) {
48554
49050
  console.error(
@@ -48661,6 +49157,21 @@ async function loginAction(options) {
48661
49157
  )
48662
49158
  );
48663
49159
  } catch (error51) {
49160
+ if (error51 instanceof ApiKeyValidationUnavailableError) {
49161
+ console.error(
49162
+ JSON.stringify(
49163
+ {
49164
+ status: "error",
49165
+ code: "api_unreachable",
49166
+ error: error51.message,
49167
+ next: API_UNREACHABLE_NEXT
49168
+ },
49169
+ null,
49170
+ 2
49171
+ )
49172
+ );
49173
+ process.exit(1);
49174
+ }
48664
49175
  const message = error51 instanceof Error ? error51.message : "Unknown error";
48665
49176
  console.error(JSON.stringify({ status: "error", error: message }, null, 2));
48666
49177
  process.exit(1);
@@ -49131,7 +49642,11 @@ async function ensureAuth(options) {
49131
49642
  if (isValid) {
49132
49643
  return envApiKey;
49133
49644
  }
49134
- } catch {
49645
+ } catch (error51) {
49646
+ if (error51 instanceof ApiKeyValidationUnavailableError) {
49647
+ console.error(chalk4.yellow(`
49648
+ ${error51.message}`));
49649
+ }
49135
49650
  }
49136
49651
  }
49137
49652
  const store = new CredentialStore();
@@ -54001,6 +54516,7 @@ function InitApp({ apiUrl, onComplete }) {
54001
54516
  const checkAndAuth = async () => {
54002
54517
  const store = new CredentialStore();
54003
54518
  const existingKey = await store.getApiKey();
54519
+ let storedKeyNotice = null;
54004
54520
  if (existingKey) {
54005
54521
  const apiKeyManager = new ApiKeyManager();
54006
54522
  try {
@@ -54019,14 +54535,15 @@ function InitApp({ apiUrl, onComplete }) {
54019
54535
  }));
54020
54536
  return;
54021
54537
  }
54022
- } catch {
54538
+ } catch (err) {
54539
+ storedKeyNotice = err instanceof Error ? err.message : String(err);
54023
54540
  }
54024
54541
  }
54025
54542
  setState((prev) => ({
54026
54543
  ...prev,
54027
54544
  step: 1,
54028
54545
  loading: true,
54029
- loadingLabel: "Opening browser to sign in..."
54546
+ loadingLabel: storedKeyNotice ? `${storedKeyNotice} Opening browser to sign in instead...` : "Opening browser to sign in..."
54030
54547
  }));
54031
54548
  try {
54032
54549
  const oauth = new OAuthManager({
@@ -54534,6 +55051,21 @@ var initCommand = new Command14("init").description("Set up Runtype CLI with gui
54534
55051
  )
54535
55052
  );
54536
55053
  } catch (error51) {
55054
+ if (error51 instanceof ApiKeyValidationUnavailableError) {
55055
+ console.error(
55056
+ JSON.stringify(
55057
+ {
55058
+ status: "error",
55059
+ code: "api_unreachable",
55060
+ error: error51.message,
55061
+ next: "If egress is restricted, allowlist api.runtype.com (staging: api.runtype-staging.com), then re-run: runtype init --api-key <key>"
55062
+ },
55063
+ null,
55064
+ 2
55065
+ )
55066
+ );
55067
+ process.exit(1);
55068
+ }
54537
55069
  const message = error51 instanceof Error ? error51.message : "Authentication failed";
54538
55070
  console.error(
54539
55071
  JSON.stringify({ status: "error", error: message }, null, 2)
@@ -70337,7 +70869,10 @@ async function getPersonaInitApiKeyNonInteractive(apiUrl) {
70337
70869
  if (isValid) {
70338
70870
  return envApiKey;
70339
70871
  }
70340
- } catch {
70872
+ } catch (error51) {
70873
+ if (error51 instanceof ApiKeyValidationUnavailableError) {
70874
+ console.error(error51.message);
70875
+ }
70341
70876
  }
70342
70877
  }
70343
70878
  const store = new CredentialStore();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runtypelabs/cli",
3
- "version": "2.33.0",
3
+ "version": "2.33.1",
4
4
  "description": "Command-line interface for Runtype AI platform",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -27,7 +27,7 @@
27
27
  "rosie-skills": "0.8.1",
28
28
  "yaml": "^2.9.0",
29
29
  "@runtypelabs/ink-components": "0.3.6",
30
- "@runtypelabs/sdk": "6.6.0",
30
+ "@runtypelabs/sdk": "6.6.1",
31
31
  "@runtypelabs/terminal-animations": "0.2.3"
32
32
  },
33
33
  "devDependencies": {
@@ -36,14 +36,14 @@
36
36
  "@types/express": "^5.0.6",
37
37
  "@types/micromatch": "^4.0.9",
38
38
  "@types/node": "^25.3.3",
39
- "@types/react": "^19.2.17",
39
+ "@types/react": "^19.2.18",
40
40
  "@vitest/coverage-v8": "^4.1.5",
41
41
  "ink-testing-library": "4.0.0",
42
42
  "tsup": "^8.0.2",
43
43
  "tsx": "^4.7.1",
44
44
  "typescript": "^6.0.3",
45
45
  "vitest": "^4.1.0",
46
- "@runtypelabs/shared": "3.15.0"
46
+ "@runtypelabs/shared": "3.17.0"
47
47
  },
48
48
  "engines": {
49
49
  "node": ">=22.12.0"