cdk-local 0.139.3 → 0.141.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/README.md +81 -58
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +2 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -2
- package/dist/{local-studio-BNV_vs04.d.ts → local-studio-C1YGBilh.d.ts} +8 -2
- package/dist/local-studio-C1YGBilh.d.ts.map +1 -0
- package/dist/{local-studio-BvuYWUHm.js → local-studio-fdztI6b8.js} +472 -205
- package/dist/{local-studio-BvuYWUHm.js.map → local-studio-fdztI6b8.js.map} +1 -1
- package/package.json +1 -1
- package/dist/local-studio-BNV_vs04.d.ts.map +0 -1
|
@@ -30533,22 +30533,70 @@ function parseOriginOverrides(values) {
|
|
|
30533
30533
|
return out;
|
|
30534
30534
|
}
|
|
30535
30535
|
/**
|
|
30536
|
-
* Parse the repeatable `--kvs-file <
|
|
30536
|
+
* Parse the repeatable `--kvs-file <key>=<file.json>` overrides into a
|
|
30537
30537
|
* map. Each entry backs a CloudFront Function's `cf.kvs()` reads with a local
|
|
30538
30538
|
* JSON map instead of the deployed store — the AWS-free escape hatch for KVS,
|
|
30539
|
-
* symmetric with `--origin <id>=<dir>`. The key is
|
|
30540
|
-
* `AWS::CloudFront::KeyValueStore` resource logical id
|
|
30541
|
-
*
|
|
30539
|
+
* symmetric with `--origin <id>=<dir>`. The key is a KeyValueStore handle —
|
|
30540
|
+
* its `AWS::CloudFront::KeyValueStore` resource logical id, its construct path,
|
|
30541
|
+
* or its bare construct id — resolved to a logical id by
|
|
30542
|
+
* {@link normalizeKvsFileKeys} once the template is known.
|
|
30542
30543
|
*/
|
|
30543
30544
|
function parseKvsFileOverrides(values) {
|
|
30544
30545
|
const out = /* @__PURE__ */ new Map();
|
|
30545
30546
|
for (const raw of values ?? []) {
|
|
30546
30547
|
const eq = raw.indexOf("=");
|
|
30547
|
-
if (eq <= 0 || eq === raw.length - 1) throw new LocalStartCloudFrontError(`Invalid --kvs-file '${raw}'. Expected <
|
|
30548
|
+
if (eq <= 0 || eq === raw.length - 1) throw new LocalStartCloudFrontError(`Invalid --kvs-file '${raw}'. Expected <key>=<file.json> (e.g. RoutesKvs=./kvs.json).`);
|
|
30548
30549
|
out.set(raw.slice(0, eq).trim(), raw.slice(eq + 1).trim());
|
|
30549
30550
|
}
|
|
30550
30551
|
return out;
|
|
30551
30552
|
}
|
|
30553
|
+
/** Index every `AWS::CloudFront::KeyValueStore` in a template for key matching. */
|
|
30554
|
+
function collectKvsStoreIdentities(template) {
|
|
30555
|
+
const out = [];
|
|
30556
|
+
for (const [logicalId, resource] of Object.entries(template.Resources ?? {})) {
|
|
30557
|
+
if (resource.Type !== "AWS::CloudFront::KeyValueStore") continue;
|
|
30558
|
+
const cdkPath = readCdkPath(resource) || void 0;
|
|
30559
|
+
const constructPath = cdkPath?.endsWith("/Resource") ? cdkPath.slice(0, -9) : cdkPath;
|
|
30560
|
+
const constructId = constructPath?.split("/").pop();
|
|
30561
|
+
out.push({
|
|
30562
|
+
logicalId,
|
|
30563
|
+
...cdkPath !== void 0 && { cdkPath },
|
|
30564
|
+
...constructPath !== void 0 && { constructPath },
|
|
30565
|
+
...constructId !== void 0 && constructId !== "" && { constructId }
|
|
30566
|
+
});
|
|
30567
|
+
}
|
|
30568
|
+
return out;
|
|
30569
|
+
}
|
|
30570
|
+
/**
|
|
30571
|
+
* Resolve the `--kvs-file` keys (a logical id, a construct path, or a bare
|
|
30572
|
+
* construct id) to `AWS::CloudFront::KeyValueStore` resource logical ids, so the
|
|
30573
|
+
* binding layer — which matches strictly by logical id — finds them. Mirrors the
|
|
30574
|
+
* construct-path ergonomics the `start-cloudfront` target argument already has,
|
|
30575
|
+
* removing the need to synth + grep the template for the hash-suffixed logical
|
|
30576
|
+
* id (issue #465).
|
|
30577
|
+
*
|
|
30578
|
+
* Match priority per key: exact logical id, then exact construct path (the
|
|
30579
|
+
* `aws:cdk:path` with or without the synthesized `/Resource` leaf), then bare
|
|
30580
|
+
* construct id. A key matching no store, or a bare id matching more than one,
|
|
30581
|
+
* throws a {@link LocalStartCloudFrontError} listing the candidates.
|
|
30582
|
+
*/
|
|
30583
|
+
function normalizeKvsFileKeys(kvsFiles, template) {
|
|
30584
|
+
if (kvsFiles.size === 0) return kvsFiles;
|
|
30585
|
+
const stores = collectKvsStoreIdentities(template);
|
|
30586
|
+
const candidates = () => stores.map((s) => s.constructPath ? `${s.logicalId} (${s.constructPath})` : s.logicalId).join(", ") || "(none in this distribution)";
|
|
30587
|
+
const out = /* @__PURE__ */ new Map();
|
|
30588
|
+
for (const [key, filePath] of kvsFiles) {
|
|
30589
|
+
const matched = [
|
|
30590
|
+
stores.filter((s) => s.logicalId === key),
|
|
30591
|
+
stores.filter((s) => s.constructPath === key || s.cdkPath === key),
|
|
30592
|
+
stores.filter((s) => s.constructId === key)
|
|
30593
|
+
].find((t) => t.length > 0) ?? [];
|
|
30594
|
+
if (matched.length === 0) throw new LocalStartCloudFrontError(`--kvs-file key '${key}' matched no AWS::CloudFront::KeyValueStore in the distribution. Pass a store's logical id, construct path, or bare construct id. Candidates: ${candidates()}.`);
|
|
30595
|
+
if (matched.length > 1) throw new LocalStartCloudFrontError(`--kvs-file key '${key}' is ambiguous — it matched ${matched.length} KeyValueStores (${matched.map((s) => s.logicalId).join(", ")}). Use the logical id or full construct path.`);
|
|
30596
|
+
out.set(matched[0].logicalId, filePath);
|
|
30597
|
+
}
|
|
30598
|
+
return out;
|
|
30599
|
+
}
|
|
30552
30600
|
/**
|
|
30553
30601
|
* Resolve + attach the `cf` KeyValueStore module to every KVS-reading
|
|
30554
30602
|
* CloudFront Function in the distribution (run after each synth, initial +
|
|
@@ -30558,8 +30606,9 @@ function parseKvsFileOverrides(values) {
|
|
|
30558
30606
|
* runtime then fails the read with the same guidance).
|
|
30559
30607
|
*/
|
|
30560
30608
|
async function attachKvsModules(distribution, stacks, options, profileCredentials, logger, extraStateProviders) {
|
|
30561
|
-
const
|
|
30562
|
-
const synthRegion =
|
|
30609
|
+
const stack = stacks.find((s) => s.stackName === distribution.stackName);
|
|
30610
|
+
const synthRegion = stack?.region;
|
|
30611
|
+
const kvsFiles = stack ? normalizeKvsFileKeys(parseKvsFileOverrides(options.kvsFile), stack.template) : parseKvsFileOverrides(options.kvsFile);
|
|
30563
30612
|
const resolveDeployedKvs = isCfnFlagPresent(options) ? async (kvsLogicalId) => {
|
|
30564
30613
|
const provider = createLocalStateProvider(options, distribution.stackName, synthRegion, extraStateProviders);
|
|
30565
30614
|
if (!provider) return void 0;
|
|
@@ -30962,7 +31011,7 @@ function createLocalStartCloudFrontCommand(opts = {}) {
|
|
|
30962
31011
|
* `cmd`.
|
|
30963
31012
|
*/
|
|
30964
31013
|
function addStartCloudFrontSpecificOptions(cmd) {
|
|
30965
|
-
return cmd.addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--origin <originId=dir>", "Point a distribution origin at a local directory (repeatable). Use when cdk-local cannot resolve the origin's BucketDeployment source automatically (content uploaded out of band, or a non-CDK bucket).").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--kvs-file <
|
|
31014
|
+
return cmd.addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--origin <originId=dir>", "Point a distribution origin at a local directory (repeatable). Use when cdk-local cannot resolve the origin's BucketDeployment source automatically (content uploaded out of band, or a non-CDK bucket).").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--kvs-file <key=file.json>", "Back a CloudFront Function's KeyValueStore reads (cf.kvs().get()) with a local JSON map (repeatable). The key is a KeyValueStore handle — its AWS::CloudFront::KeyValueStore resource logical id, its construct path, or its bare construct id; the file is a flat { \"key\": \"value\" } object. The AWS-free alternative to --from-cfn-stack, which instead reads the deployed store via the GetKey API.").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--tls", "Terminate real TLS (HTTPS). Uses --tls-cert / --tls-key when supplied, else an auto-generated self-signed cert.").default(false)).addOption(new Option("--tls-cert <path>", "PEM server certificate for --tls (implies --tls).")).addOption(new Option("--tls-key <path>", "PEM server private key for --tls (implies --tls).")).addOption(new Option("--no-pull", "Skip 'docker pull' for a Lambda Function URL origin's base image (use the locally cached image).")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Bind to a deployed CloudFormation stack (ListStackResources). Resolves an S3 origin that has no local BucketDeployment source to its deployed bucket and serves it from real S3 on demand (the front/back-split case: files uploaded out of band), and resolves a Lambda Function URL / Lambda@Edge function's env vars to the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the resolved stack name; pass a value when the CFn stack name differs.")).addOption(new Option("--cache-origin", "For a deployed-S3 origin (served from real S3 under --from-cfn-stack): keep fetched objects in memory for the session instead of re-reading on every request. Faster repeat reads / fewer S3 GETs, but an out-of-band S3 content change is not reflected until a --watch reload (which clears the cache) or a restart. Off by default (every request re-reads, always current). Not CloudFront CDN caching.").default(false)).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--assume-role [arn]", "Assume a Lambda Function URL origin's deployed execution role and forward STS-issued temp credentials into its container so the handler runs with the deployed permissions. Three forms: `--assume-role <arn>` (explicit ARN); `--assume-role` (bare, auto-resolves from state — requires --from-cfn-stack); `--no-assume-role` (opt out). Off by default (the dev shell credentials are forwarded).")).addOption(new Option("--watch", "Hot-reload: re-synth + re-resolve the distribution when the CDK app's source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). The server keeps the previous version serving when synth fails mid-reload.").default(false));
|
|
30966
31015
|
}
|
|
30967
31016
|
|
|
30968
31017
|
//#endregion
|
|
@@ -31928,172 +31977,6 @@ function createStudioStore(bus, options = {}) {
|
|
|
31928
31977
|
};
|
|
31929
31978
|
}
|
|
31930
31979
|
|
|
31931
|
-
//#endregion
|
|
31932
|
-
//#region src/local/studio-option-catalog.ts
|
|
31933
|
-
/**
|
|
31934
|
-
* Auto-derived full-flag catalog for `cdkl studio` (issue #301).
|
|
31935
|
-
*
|
|
31936
|
-
* The per-target {@link OPTION_SPECS} in `studio-option-specs.ts` is a
|
|
31937
|
-
* CURATED subset — the handful of flags worth a rich control (a checkbox, a
|
|
31938
|
-
* KV editor, an add-row list). But a command like `cdkl start-api` accepts
|
|
31939
|
-
* many more flags than studio renders a control for, and hiding them makes
|
|
31940
|
-
* the UI strictly less capable than the headless CLI.
|
|
31941
|
-
*
|
|
31942
|
-
* This module closes that gap by INTROSPECTING each runnable kind's Commander
|
|
31943
|
-
* command factory and emitting the complete flag list (name + description).
|
|
31944
|
-
* The studio UI serializes it into the page and renders, inside a collapsed
|
|
31945
|
-
* "All options" section, (a) the full catalog as a read-only reference and
|
|
31946
|
-
* (b) a raw extra-args input (see {@link tokenizeRawArgs}) so any flag the
|
|
31947
|
-
* curated controls don't expose can still be passed verbatim. Auto-derivation
|
|
31948
|
-
* means the catalog can never drift from the command's real option set.
|
|
31949
|
-
*
|
|
31950
|
-
* Session-global flags (handled by the studio Session bar / `studio-child-args`)
|
|
31951
|
-
* and the auto-added `--help` / `--version` are excluded — passing them per-run
|
|
31952
|
-
* would conflict with the session-wide wiring.
|
|
31953
|
-
*/
|
|
31954
|
-
/**
|
|
31955
|
-
* Long flag names handled by the session bar / `studio-child-args` (forwarded
|
|
31956
|
-
* to every spawned child once, session-wide). Excluded from the per-target
|
|
31957
|
-
* catalog so a user does not re-specify them per-run and collide with the
|
|
31958
|
-
* session-wide value. Plus the Commander-managed `--help` / `--version`.
|
|
31959
|
-
*/
|
|
31960
|
-
const CATALOG_EXCLUDED_FLAGS = new Set([
|
|
31961
|
-
"--app",
|
|
31962
|
-
"--profile",
|
|
31963
|
-
"--region",
|
|
31964
|
-
"--context",
|
|
31965
|
-
"--from-cfn-stack",
|
|
31966
|
-
"--assume-role",
|
|
31967
|
-
"--help",
|
|
31968
|
-
"--version"
|
|
31969
|
-
]);
|
|
31970
|
-
const KIND_FACTORIES = {
|
|
31971
|
-
lambda: {
|
|
31972
|
-
command: "invoke",
|
|
31973
|
-
factory: createLocalInvokeCommand
|
|
31974
|
-
},
|
|
31975
|
-
agentcore: {
|
|
31976
|
-
command: "invoke-agentcore",
|
|
31977
|
-
factory: createLocalInvokeAgentCoreCommand
|
|
31978
|
-
},
|
|
31979
|
-
api: {
|
|
31980
|
-
command: "start-api",
|
|
31981
|
-
factory: createLocalStartApiCommand
|
|
31982
|
-
},
|
|
31983
|
-
alb: {
|
|
31984
|
-
command: "start-alb",
|
|
31985
|
-
factory: createLocalStartAlbCommand
|
|
31986
|
-
},
|
|
31987
|
-
ecs: {
|
|
31988
|
-
command: "start-service",
|
|
31989
|
-
factory: createLocalStartServiceCommand
|
|
31990
|
-
},
|
|
31991
|
-
"ecs-task": {
|
|
31992
|
-
command: "run-task",
|
|
31993
|
-
factory: createLocalRunTaskCommand
|
|
31994
|
-
},
|
|
31995
|
-
cloudfront: {
|
|
31996
|
-
command: "start-cloudfront",
|
|
31997
|
-
factory: createLocalStartCloudFrontCommand
|
|
31998
|
-
},
|
|
31999
|
-
"agentcore-ws": {
|
|
32000
|
-
command: "start-agentcore",
|
|
32001
|
-
factory: createLocalStartAgentCoreCommand
|
|
32002
|
-
}
|
|
32003
|
-
};
|
|
32004
|
-
let cached;
|
|
32005
|
-
/**
|
|
32006
|
-
* Build (and memoize) the full per-kind flag catalog by introspecting each
|
|
32007
|
-
* runnable kind's Commander command factory.
|
|
32008
|
-
*
|
|
32009
|
-
* Each factory calls `setEmbedConfig(opts.embedConfig)` at construction — with
|
|
32010
|
-
* no opts that resets the active embed config to cdk-local defaults, which
|
|
32011
|
-
* would wipe a host CLI's branding. So the active config is snapshotted and
|
|
32012
|
-
* each factory is re-handed it: branding is preserved AND the derived flag
|
|
32013
|
-
* descriptions reflect the host's active branding. The `finally` restore is a
|
|
32014
|
-
* belt-and-suspenders against a factory that ignores the passed config.
|
|
32015
|
-
* Memoized: the factories are instantiated exactly once per process, not per
|
|
32016
|
-
* page render.
|
|
32017
|
-
*/
|
|
32018
|
-
function buildFlagCatalog() {
|
|
32019
|
-
if (cached) return cached;
|
|
32020
|
-
const savedEmbedConfig = getEmbedConfig();
|
|
32021
|
-
try {
|
|
32022
|
-
const out = {};
|
|
32023
|
-
for (const kind of Object.keys(KIND_FACTORIES)) {
|
|
32024
|
-
const { command, factory } = KIND_FACTORIES[kind];
|
|
32025
|
-
const cmd = factory({ embedConfig: savedEmbedConfig });
|
|
32026
|
-
const flags = [];
|
|
32027
|
-
for (const opt of cmd.options) {
|
|
32028
|
-
if (opt.hidden) continue;
|
|
32029
|
-
if (opt.long && CATALOG_EXCLUDED_FLAGS.has(opt.long)) continue;
|
|
32030
|
-
flags.push({
|
|
32031
|
-
flags: opt.flags,
|
|
32032
|
-
description: opt.description ?? ""
|
|
32033
|
-
});
|
|
32034
|
-
}
|
|
32035
|
-
out[kind] = {
|
|
32036
|
-
command,
|
|
32037
|
-
flags
|
|
32038
|
-
};
|
|
32039
|
-
}
|
|
32040
|
-
cached = out;
|
|
32041
|
-
return out;
|
|
32042
|
-
} finally {
|
|
32043
|
-
setEmbedConfig(savedEmbedConfig);
|
|
32044
|
-
}
|
|
32045
|
-
}
|
|
32046
|
-
/**
|
|
32047
|
-
* Tokenize a raw extra-args string into discrete argv elements, honoring
|
|
32048
|
-
* single / double quotes and backslash escaping so values with spaces survive
|
|
32049
|
-
* (`--name "two words"` -> `['--name', 'two words']`). studio spawns children
|
|
32050
|
-
* WITHOUT a shell (argv array), so the tokens are appended verbatim — there is
|
|
32051
|
-
* no shell-injection surface; the child command still validates each arg.
|
|
32052
|
-
*
|
|
32053
|
-
* Returns `[]` for an empty / whitespace-only input. Throws on an unterminated
|
|
32054
|
-
* quote so a malformed raw-args string fails as a clean boundary error rather
|
|
32055
|
-
* than spawning a child with a mis-split argv.
|
|
32056
|
-
*/
|
|
32057
|
-
function tokenizeRawArgs(raw) {
|
|
32058
|
-
if (raw === void 0) return [];
|
|
32059
|
-
const tokens = [];
|
|
32060
|
-
let current = "";
|
|
32061
|
-
let inToken = false;
|
|
32062
|
-
let quote = null;
|
|
32063
|
-
for (let i = 0; i < raw.length; i++) {
|
|
32064
|
-
const ch = raw[i];
|
|
32065
|
-
if (quote) {
|
|
32066
|
-
if (ch === "\\" && quote === "\"" && i + 1 < raw.length) current += raw[++i];
|
|
32067
|
-
else if (ch === quote) quote = null;
|
|
32068
|
-
else current += ch;
|
|
32069
|
-
continue;
|
|
32070
|
-
}
|
|
32071
|
-
if (ch === "\"" || ch === "'") {
|
|
32072
|
-
quote = ch;
|
|
32073
|
-
inToken = true;
|
|
32074
|
-
continue;
|
|
32075
|
-
}
|
|
32076
|
-
if (ch === "\\" && i + 1 < raw.length) {
|
|
32077
|
-
current += raw[++i];
|
|
32078
|
-
inToken = true;
|
|
32079
|
-
continue;
|
|
32080
|
-
}
|
|
32081
|
-
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
32082
|
-
if (inToken) {
|
|
32083
|
-
tokens.push(current);
|
|
32084
|
-
current = "";
|
|
32085
|
-
inToken = false;
|
|
32086
|
-
}
|
|
32087
|
-
continue;
|
|
32088
|
-
}
|
|
32089
|
-
current += ch;
|
|
32090
|
-
inToken = true;
|
|
32091
|
-
}
|
|
32092
|
-
if (quote) throw new Error(`Raw extra args have an unterminated ${quote} quote.`);
|
|
32093
|
-
if (inToken) tokens.push(current);
|
|
32094
|
-
return tokens;
|
|
32095
|
-
}
|
|
32096
|
-
|
|
32097
31980
|
//#endregion
|
|
32098
31981
|
//#region src/local/studio-option-specs.ts
|
|
32099
31982
|
/**
|
|
@@ -32397,6 +32280,264 @@ function resolveEnvVars(kind, values) {
|
|
|
32397
32280
|
throw new Error(`Option '${spec.flag}' must be KEY/VALUE rows or a JSON object string.`);
|
|
32398
32281
|
}
|
|
32399
32282
|
|
|
32283
|
+
//#endregion
|
|
32284
|
+
//#region src/local/studio-option-catalog.ts
|
|
32285
|
+
/**
|
|
32286
|
+
* Auto-derived full-flag catalog for `cdkl studio` (issue #301).
|
|
32287
|
+
*
|
|
32288
|
+
* The per-target {@link OPTION_SPECS} in `studio-option-specs.ts` is a
|
|
32289
|
+
* CURATED subset — the handful of flags worth a rich control (a checkbox, a
|
|
32290
|
+
* KV editor, an add-row list). But a command like `cdkl start-api` accepts
|
|
32291
|
+
* many more flags than studio renders a control for, and hiding them makes
|
|
32292
|
+
* the UI strictly less capable than the headless CLI.
|
|
32293
|
+
*
|
|
32294
|
+
* This module closes that gap by INTROSPECTING each runnable kind's Commander
|
|
32295
|
+
* command factory and emitting the complete flag list (name + description).
|
|
32296
|
+
* The studio UI serializes it into the page and renders, inside a collapsed
|
|
32297
|
+
* "All options" section, (a) the full catalog as a read-only reference and
|
|
32298
|
+
* (b) a raw extra-args input (see {@link tokenizeRawArgs}) so any flag the
|
|
32299
|
+
* curated controls don't expose can still be passed verbatim. Auto-derivation
|
|
32300
|
+
* means the catalog can never drift from the command's real option set.
|
|
32301
|
+
*
|
|
32302
|
+
* Session-global flags (handled by the studio Session bar / `studio-child-args`)
|
|
32303
|
+
* and the auto-added `--help` / `--version` are excluded — passing them per-run
|
|
32304
|
+
* would conflict with the session-wide wiring.
|
|
32305
|
+
*/
|
|
32306
|
+
/**
|
|
32307
|
+
* Long flag names handled by the session bar / `studio-child-args` (forwarded
|
|
32308
|
+
* to every spawned child once, session-wide). Excluded from the per-target
|
|
32309
|
+
* catalog so a user does not re-specify them per-run and collide with the
|
|
32310
|
+
* session-wide value. Plus the Commander-managed `--help` / `--version`.
|
|
32311
|
+
*/
|
|
32312
|
+
const CATALOG_EXCLUDED_FLAGS = new Set([
|
|
32313
|
+
"--app",
|
|
32314
|
+
"--profile",
|
|
32315
|
+
"--region",
|
|
32316
|
+
"--context",
|
|
32317
|
+
"--from-cfn-stack",
|
|
32318
|
+
"--assume-role",
|
|
32319
|
+
"--help",
|
|
32320
|
+
"--version"
|
|
32321
|
+
]);
|
|
32322
|
+
/**
|
|
32323
|
+
* Long flags studio INJECTS or binds itself per run, so the "All options"
|
|
32324
|
+
* section must NOT auto-render an editable control for them (a user-set value
|
|
32325
|
+
* would collide with — or break — studio's own wiring). They still appear in
|
|
32326
|
+
* the catalog (so it stays a complete reference), just `renderable: false`; a
|
|
32327
|
+
* power user can still force one via the raw extra-args input, which is
|
|
32328
|
+
* appended last.
|
|
32329
|
+
*
|
|
32330
|
+
* - `--event` / `--response-file`: studio writes the composed event /
|
|
32331
|
+
* response-capture file and passes these itself (the invoke kinds).
|
|
32332
|
+
* - `--host` / `--port`: the serve-manager binds the listen host/port and the
|
|
32333
|
+
* capture proxy fronts it; a user override would desync the proxy URL.
|
|
32334
|
+
* - `--watch`: the session-global Session-bar toggle (appended by the
|
|
32335
|
+
* serve-manager from the mutable config), not a per-run flag.
|
|
32336
|
+
* - the `--image-*` override family: handled by the dedicated Dockerfile
|
|
32337
|
+
* picker (a partial control here would produce a half-wired override).
|
|
32338
|
+
*/
|
|
32339
|
+
const CATALOG_MANAGED_FLAGS = new Set([
|
|
32340
|
+
"--event",
|
|
32341
|
+
"--response-file",
|
|
32342
|
+
"--host",
|
|
32343
|
+
"--port",
|
|
32344
|
+
"--watch",
|
|
32345
|
+
"--image-override",
|
|
32346
|
+
"--image-build-arg",
|
|
32347
|
+
"--image-build-secret",
|
|
32348
|
+
"--image-target",
|
|
32349
|
+
"--no-interactive-overrides",
|
|
32350
|
+
"--strict-overrides"
|
|
32351
|
+
]);
|
|
32352
|
+
const KIND_FACTORIES = {
|
|
32353
|
+
lambda: {
|
|
32354
|
+
command: "invoke",
|
|
32355
|
+
factory: createLocalInvokeCommand
|
|
32356
|
+
},
|
|
32357
|
+
agentcore: {
|
|
32358
|
+
command: "invoke-agentcore",
|
|
32359
|
+
factory: createLocalInvokeAgentCoreCommand
|
|
32360
|
+
},
|
|
32361
|
+
api: {
|
|
32362
|
+
command: "start-api",
|
|
32363
|
+
factory: createLocalStartApiCommand
|
|
32364
|
+
},
|
|
32365
|
+
alb: {
|
|
32366
|
+
command: "start-alb",
|
|
32367
|
+
factory: createLocalStartAlbCommand
|
|
32368
|
+
},
|
|
32369
|
+
ecs: {
|
|
32370
|
+
command: "start-service",
|
|
32371
|
+
factory: createLocalStartServiceCommand
|
|
32372
|
+
},
|
|
32373
|
+
"ecs-task": {
|
|
32374
|
+
command: "run-task",
|
|
32375
|
+
factory: createLocalRunTaskCommand
|
|
32376
|
+
},
|
|
32377
|
+
cloudfront: {
|
|
32378
|
+
command: "start-cloudfront",
|
|
32379
|
+
factory: createLocalStartCloudFrontCommand
|
|
32380
|
+
},
|
|
32381
|
+
"agentcore-ws": {
|
|
32382
|
+
command: "start-agentcore",
|
|
32383
|
+
factory: createLocalStartAgentCoreCommand
|
|
32384
|
+
}
|
|
32385
|
+
};
|
|
32386
|
+
let cached;
|
|
32387
|
+
/**
|
|
32388
|
+
* Parse the value-token placeholder out of a Commander flags string for a
|
|
32389
|
+
* value-taking option: `-e, --event <file>` -> `file`,
|
|
32390
|
+
* `--platform <platform>` -> `platform`, `--lb-port <listener=host>` ->
|
|
32391
|
+
* `listener=host`. The trailing `...` of a variadic token is dropped. Returns
|
|
32392
|
+
* undefined for a boolean flag (no `<...>` / `[...]` token), so the input
|
|
32393
|
+
* placeholder falls back to a generic hint.
|
|
32394
|
+
*/
|
|
32395
|
+
function parseFlagPlaceholder(flags) {
|
|
32396
|
+
const m = /[<[]([^>\]]+)[>\]]/.exec(flags);
|
|
32397
|
+
if (!m || m[1] === void 0) return void 0;
|
|
32398
|
+
return m[1].replace(/\.\.\.$/, "").trim() || void 0;
|
|
32399
|
+
}
|
|
32400
|
+
/**
|
|
32401
|
+
* Build (and memoize) the full per-kind flag catalog by introspecting each
|
|
32402
|
+
* runnable kind's Commander command factory.
|
|
32403
|
+
*
|
|
32404
|
+
* Each factory calls `setEmbedConfig(opts.embedConfig)` at construction — with
|
|
32405
|
+
* no opts that resets the active embed config to cdk-local defaults, which
|
|
32406
|
+
* would wipe a host CLI's branding. So the active config is snapshotted and
|
|
32407
|
+
* each factory is re-handed it: branding is preserved AND the derived flag
|
|
32408
|
+
* descriptions reflect the host's active branding. The `finally` restore is a
|
|
32409
|
+
* belt-and-suspenders against a factory that ignores the passed config.
|
|
32410
|
+
* Memoized: the factories are instantiated exactly once per process, not per
|
|
32411
|
+
* page render.
|
|
32412
|
+
*/
|
|
32413
|
+
function buildFlagCatalog() {
|
|
32414
|
+
if (cached) return cached;
|
|
32415
|
+
const savedEmbedConfig = getEmbedConfig();
|
|
32416
|
+
try {
|
|
32417
|
+
const out = {};
|
|
32418
|
+
for (const kind of Object.keys(KIND_FACTORIES)) {
|
|
32419
|
+
const { command, factory } = KIND_FACTORIES[kind];
|
|
32420
|
+
const cmd = factory({ embedConfig: savedEmbedConfig });
|
|
32421
|
+
const curated = new Set((OPTION_SPECS[kind] ?? []).map((s) => s.flag));
|
|
32422
|
+
const flags = [];
|
|
32423
|
+
for (const opt of cmd.options) {
|
|
32424
|
+
if (opt.hidden) continue;
|
|
32425
|
+
if (opt.long && CATALOG_EXCLUDED_FLAGS.has(opt.long)) continue;
|
|
32426
|
+
const long = opt.long ?? "";
|
|
32427
|
+
const takesValue = Boolean(opt.required || opt.optional);
|
|
32428
|
+
const negate = Boolean(opt.negate);
|
|
32429
|
+
const variadic = Boolean(opt.variadic);
|
|
32430
|
+
const choices = Array.isArray(opt.argChoices) ? [...opt.argChoices] : void 0;
|
|
32431
|
+
const placeholder = parseFlagPlaceholder(opt.flags);
|
|
32432
|
+
const renderable = long !== "" && !curated.has(long) && !CATALOG_MANAGED_FLAGS.has(long);
|
|
32433
|
+
const info = {
|
|
32434
|
+
flags: opt.flags,
|
|
32435
|
+
description: opt.description ?? "",
|
|
32436
|
+
long,
|
|
32437
|
+
takesValue,
|
|
32438
|
+
negate,
|
|
32439
|
+
variadic,
|
|
32440
|
+
renderable
|
|
32441
|
+
};
|
|
32442
|
+
if (placeholder !== void 0) info.placeholder = placeholder;
|
|
32443
|
+
if (choices) info.choices = choices;
|
|
32444
|
+
flags.push(info);
|
|
32445
|
+
}
|
|
32446
|
+
out[kind] = {
|
|
32447
|
+
command,
|
|
32448
|
+
flags
|
|
32449
|
+
};
|
|
32450
|
+
}
|
|
32451
|
+
cached = out;
|
|
32452
|
+
return out;
|
|
32453
|
+
} finally {
|
|
32454
|
+
setEmbedConfig(savedEmbedConfig);
|
|
32455
|
+
}
|
|
32456
|
+
}
|
|
32457
|
+
/**
|
|
32458
|
+
* Tokenize a raw extra-args string into discrete argv elements, honoring
|
|
32459
|
+
* single / double quotes and backslash escaping so values with spaces survive
|
|
32460
|
+
* (`--name "two words"` -> `['--name', 'two words']`). studio spawns children
|
|
32461
|
+
* WITHOUT a shell (argv array), so the tokens are appended verbatim — there is
|
|
32462
|
+
* no shell-injection surface; the child command still validates each arg.
|
|
32463
|
+
*
|
|
32464
|
+
* Returns `[]` for an empty / whitespace-only input. Throws on an unterminated
|
|
32465
|
+
* quote so a malformed raw-args string fails as a clean boundary error rather
|
|
32466
|
+
* than spawning a child with a mis-split argv.
|
|
32467
|
+
*/
|
|
32468
|
+
function tokenizeRawArgs(raw) {
|
|
32469
|
+
if (raw === void 0) return [];
|
|
32470
|
+
const tokens = [];
|
|
32471
|
+
let current = "";
|
|
32472
|
+
let inToken = false;
|
|
32473
|
+
let quote = null;
|
|
32474
|
+
for (let i = 0; i < raw.length; i++) {
|
|
32475
|
+
const ch = raw[i];
|
|
32476
|
+
if (quote) {
|
|
32477
|
+
if (ch === "\\" && quote === "\"" && i + 1 < raw.length) current += raw[++i];
|
|
32478
|
+
else if (ch === quote) quote = null;
|
|
32479
|
+
else current += ch;
|
|
32480
|
+
continue;
|
|
32481
|
+
}
|
|
32482
|
+
if (ch === "\"" || ch === "'") {
|
|
32483
|
+
quote = ch;
|
|
32484
|
+
inToken = true;
|
|
32485
|
+
continue;
|
|
32486
|
+
}
|
|
32487
|
+
if (ch === "\\" && i + 1 < raw.length) {
|
|
32488
|
+
current += raw[++i];
|
|
32489
|
+
inToken = true;
|
|
32490
|
+
continue;
|
|
32491
|
+
}
|
|
32492
|
+
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
32493
|
+
if (inToken) {
|
|
32494
|
+
tokens.push(current);
|
|
32495
|
+
current = "";
|
|
32496
|
+
inToken = false;
|
|
32497
|
+
}
|
|
32498
|
+
continue;
|
|
32499
|
+
}
|
|
32500
|
+
current += ch;
|
|
32501
|
+
inToken = true;
|
|
32502
|
+
}
|
|
32503
|
+
if (quote) throw new Error(`Raw extra args have an unterminated ${quote} quote.`);
|
|
32504
|
+
if (inToken) tokens.push(current);
|
|
32505
|
+
return tokens;
|
|
32506
|
+
}
|
|
32507
|
+
/**
|
|
32508
|
+
* Build the argv fragment for the auto-rendered "All options" controls from the
|
|
32509
|
+
* UI-posted {@link CatalogValues}, validating each key against the kind's flag
|
|
32510
|
+
* catalog. Emits `--flag` for a checked boolean (bare/negate) flag and
|
|
32511
|
+
* `--flag <value>` for a non-empty value flag. Blank / false values are
|
|
32512
|
+
* omitted.
|
|
32513
|
+
*
|
|
32514
|
+
* Throws (→ a clean 400 at the `/api/run` boundary) on a key that is not a
|
|
32515
|
+
* RENDERABLE catalog flag for the kind — an unknown flag, a session-global /
|
|
32516
|
+
* studio-managed flag, or a curated flag (which belongs to the `options` path,
|
|
32517
|
+
* not here). The studio UI only ever posts renderable flags; the validation
|
|
32518
|
+
* guards a hand-rolled curl body. studio spawns children WITHOUT a shell, so
|
|
32519
|
+
* each emitted token is a discrete argv element with no injection surface.
|
|
32520
|
+
*/
|
|
32521
|
+
function buildCatalogArgs(kind, values) {
|
|
32522
|
+
if (values === void 0) return [];
|
|
32523
|
+
const catalog = buildFlagCatalog()[kind];
|
|
32524
|
+
const byFlag = new Map((catalog?.flags ?? []).filter((f) => f.renderable).map((f) => [f.long, f]));
|
|
32525
|
+
const args = [];
|
|
32526
|
+
for (const [flag, value] of Object.entries(values)) {
|
|
32527
|
+
const info = byFlag.get(flag);
|
|
32528
|
+
if (!info) throw new Error(`Unknown / non-overridable option '${flag}' for target kind '${kind}'.`);
|
|
32529
|
+
if (info.takesValue) {
|
|
32530
|
+
if (typeof value !== "string") throw new Error(`Option '${flag}' must be a string value.`);
|
|
32531
|
+
const trimmed = value.trim();
|
|
32532
|
+
if (trimmed !== "") args.push(flag, trimmed);
|
|
32533
|
+
} else {
|
|
32534
|
+
if (typeof value !== "boolean") throw new Error(`Option '${flag}' must be a boolean.`);
|
|
32535
|
+
if (value) args.push(flag);
|
|
32536
|
+
}
|
|
32537
|
+
}
|
|
32538
|
+
return args;
|
|
32539
|
+
}
|
|
32540
|
+
|
|
32400
32541
|
//#endregion
|
|
32401
32542
|
//#region src/local/studio-ui.ts
|
|
32402
32543
|
/**
|
|
@@ -32732,10 +32873,18 @@ const STUDIO_CSS = `
|
|
|
32732
32873
|
read — kept small as it is secondary. */
|
|
32733
32874
|
.io-label { color: #d7dde5; font-weight: 500; overflow-wrap: anywhere; min-width: 0; }
|
|
32734
32875
|
.io-hint { color: #e3b34a; font-size: 11px; }
|
|
32735
|
-
|
|
32736
|
-
|
|
32737
|
-
|
|
32738
|
-
.flag-
|
|
32876
|
+
/* Auto-rendered controls for the residual (non-curated) command flags in the
|
|
32877
|
+
"All options" section: one stacked row per flag (label + input/select +
|
|
32878
|
+
description hint), styled to match the curated .options controls. */
|
|
32879
|
+
.flag-controls { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
|
|
32880
|
+
.all-options input.flag-control, .all-options select.flag-control {
|
|
32881
|
+
width: 100%; box-sizing: border-box; background: #111; color: #ddd; border: 1px solid #333;
|
|
32882
|
+
border-radius: 3px; padding: 4px 6px; font: 12px ui-monospace, Menlo, monospace;
|
|
32883
|
+
}
|
|
32884
|
+
.all-options input.flag-control:focus, .all-options select.flag-control:focus {
|
|
32885
|
+
outline: none; border-color: #4ec97a;
|
|
32886
|
+
}
|
|
32887
|
+
.all-options .opt-label { color: #9aa4ad; }
|
|
32739
32888
|
.started-list { display: flex; flex-direction: column; gap: 3px; margin-top: 4px; }
|
|
32740
32889
|
.started-flag { color: #7bd88f; font-family: ui-monospace, Menlo, monospace; font-size: 11px; white-space: pre-wrap; word-break: break-all; }
|
|
32741
32890
|
.envkv-modes { display: flex; gap: 0; }
|
|
@@ -32829,7 +32978,7 @@ const STUDIO_SCRIPT = `
|
|
|
32829
32978
|
// prefill (issue #398): the option map a stopped serve was last Started with
|
|
32830
32979
|
// (serveApplied.options), so the re-rendered composer comes back filled.
|
|
32831
32980
|
// rawPrefill is the raw-extra-args string (serveApplied.rawArgs).
|
|
32832
|
-
function buildOptions(kind, prefill, rawPrefill) {
|
|
32981
|
+
function buildOptions(kind, prefill, rawPrefill, catalogPrefill) {
|
|
32833
32982
|
const specs = OPTION_SPECS[kind] || [];
|
|
32834
32983
|
// The composer always shows an "All options" section (raw extra args + the
|
|
32835
32984
|
// auto-derived flag reference), even for kinds with no curated controls.
|
|
@@ -32980,7 +33129,7 @@ const STUDIO_SCRIPT = `
|
|
|
32980
33129
|
}
|
|
32981
33130
|
sec.appendChild(row);
|
|
32982
33131
|
});
|
|
32983
|
-
const allOpts = buildAllOptions(kind, rawPrefill);
|
|
33132
|
+
const allOpts = buildAllOptions(kind, rawPrefill, catalogPrefill);
|
|
32984
33133
|
wrap.appendChild(allOpts.node);
|
|
32985
33134
|
return {
|
|
32986
33135
|
node: wrap,
|
|
@@ -32992,22 +33141,97 @@ const STUDIO_SCRIPT = `
|
|
|
32992
33141
|
// body identical to before this section existed.
|
|
32993
33142
|
return Object.keys(out).length ? out : undefined;
|
|
32994
33143
|
},
|
|
33144
|
+
collectCatalog: allOpts.collectCatalog,
|
|
32995
33145
|
collectRaw: allOpts.collectRaw,
|
|
32996
33146
|
};
|
|
32997
33147
|
}
|
|
32998
33148
|
|
|
32999
|
-
// The collapsed "All options" section
|
|
33000
|
-
//
|
|
33001
|
-
//
|
|
33002
|
-
//
|
|
33003
|
-
//
|
|
33149
|
+
// The collapsed "All options" section. The curated controls above cover the
|
|
33150
|
+
// common flags with rich UI; this section auto-renders a real control
|
|
33151
|
+
// (checkbox / input / select) for EVERY other flag the underlying command
|
|
33152
|
+
// accepts (the catalog's renderable flags), so the studio UI is never
|
|
33153
|
+
// strictly less capable than the headless CLI AND a user does not have to
|
|
33154
|
+
// hand-type "--flag value" for the long tail of simple flags. A raw
|
|
33155
|
+
// extra-args input remains as the final escape hatch for anything the
|
|
33156
|
+
// auto-render cannot express (issue #301 + the all-options-controls slice).
|
|
33004
33157
|
const FLAG_CATALOG = window.__FLAG_CATALOG__ || {};
|
|
33005
33158
|
|
|
33006
|
-
function buildAllOptions(kind, rawPrefill) {
|
|
33159
|
+
function buildAllOptions(kind, rawPrefill, catalogPrefill) {
|
|
33007
33160
|
const cat = FLAG_CATALOG[kind] || { command: '', flags: [] };
|
|
33008
33161
|
const det = el('details', 'all-options');
|
|
33009
33162
|
det.appendChild(el('summary', null, 'All options'));
|
|
33010
33163
|
|
|
33164
|
+
// Auto-rendered controls for every renderable (non-curated, non-managed)
|
|
33165
|
+
// flag. The collected value map is keyed by the long flag.
|
|
33166
|
+
const catGetters = [];
|
|
33167
|
+
const renderable = (cat.flags || []).filter(function (f) {
|
|
33168
|
+
return f.renderable;
|
|
33169
|
+
});
|
|
33170
|
+
const preCat = function (flag) {
|
|
33171
|
+
return catalogPrefill ? catalogPrefill[flag] : undefined;
|
|
33172
|
+
};
|
|
33173
|
+
if (renderable.length) {
|
|
33174
|
+
const grid = el('div', 'flag-controls');
|
|
33175
|
+
renderable.forEach(function (f) {
|
|
33176
|
+
const row = el('div', 'opt-row opt-col');
|
|
33177
|
+
if (!f.takesValue) {
|
|
33178
|
+
// Boolean (bare / negate) flag -> checkbox; emits the bare flag.
|
|
33179
|
+
const cb = el('input');
|
|
33180
|
+
cb.type = 'checkbox';
|
|
33181
|
+
if (preCat(f.long) === true) {
|
|
33182
|
+
cb.checked = true;
|
|
33183
|
+
det.open = true;
|
|
33184
|
+
}
|
|
33185
|
+
const lab = el('label', 'opt-bool');
|
|
33186
|
+
lab.appendChild(cb);
|
|
33187
|
+
lab.appendChild(document.createTextNode(' ' + f.long));
|
|
33188
|
+
row.appendChild(lab);
|
|
33189
|
+
catGetters.push(function () {
|
|
33190
|
+
return [f.long, cb.checked];
|
|
33191
|
+
});
|
|
33192
|
+
} else if (f.choices && f.choices.length) {
|
|
33193
|
+
// Value flag with a fixed choice set -> select (blank = unset).
|
|
33194
|
+
row.appendChild(el('span', 'opt-label', f.long));
|
|
33195
|
+
const sel = el('select', 'flag-control');
|
|
33196
|
+
const none = el('option', null, '(default)');
|
|
33197
|
+
none.value = '';
|
|
33198
|
+
sel.appendChild(none);
|
|
33199
|
+
f.choices.forEach(function (c) {
|
|
33200
|
+
const o = el('option', null, c);
|
|
33201
|
+
o.value = c;
|
|
33202
|
+
sel.appendChild(o);
|
|
33203
|
+
});
|
|
33204
|
+
const pv = preCat(f.long);
|
|
33205
|
+
if (pv != null && pv !== '') {
|
|
33206
|
+
sel.value = String(pv);
|
|
33207
|
+
det.open = true;
|
|
33208
|
+
}
|
|
33209
|
+
row.appendChild(sel);
|
|
33210
|
+
catGetters.push(function () {
|
|
33211
|
+
return [f.long, sel.value];
|
|
33212
|
+
});
|
|
33213
|
+
} else {
|
|
33214
|
+
// Value flag -> text input. The placeholder is the flag's own value
|
|
33215
|
+
// token (e.g. file, from the flags' angle-bracket token).
|
|
33216
|
+
row.appendChild(el('span', 'opt-label', f.long));
|
|
33217
|
+
const inp = el('input', 'flag-control');
|
|
33218
|
+
inp.placeholder = f.placeholder || 'value';
|
|
33219
|
+
const pv = preCat(f.long);
|
|
33220
|
+
if (pv != null && pv !== '') {
|
|
33221
|
+
inp.value = String(pv);
|
|
33222
|
+
det.open = true;
|
|
33223
|
+
}
|
|
33224
|
+
row.appendChild(inp);
|
|
33225
|
+
catGetters.push(function () {
|
|
33226
|
+
return [f.long, inp.value];
|
|
33227
|
+
});
|
|
33228
|
+
}
|
|
33229
|
+
if (f.description) row.appendChild(el('div', 'opt-hint', f.description));
|
|
33230
|
+
grid.appendChild(row);
|
|
33231
|
+
});
|
|
33232
|
+
det.appendChild(grid);
|
|
33233
|
+
}
|
|
33234
|
+
|
|
33011
33235
|
const rawRow = el('div', 'opt-row opt-col');
|
|
33012
33236
|
rawRow.appendChild(el('span', 'opt-label', 'Raw extra args'));
|
|
33013
33237
|
const rawIn = el('input', 'raw-args');
|
|
@@ -33024,20 +33248,25 @@ const STUDIO_SCRIPT = `
|
|
|
33024
33248
|
rawRow.appendChild(el('div', 'opt-hint', hint));
|
|
33025
33249
|
det.appendChild(rawRow);
|
|
33026
33250
|
|
|
33027
|
-
if (cat.flags.length) {
|
|
33028
|
-
const ref = el('div', 'flag-catalog');
|
|
33029
|
-
ref.appendChild(el('div', 'opt-label', 'Available flags'));
|
|
33030
|
-
cat.flags.forEach(function (f) {
|
|
33031
|
-
const row = el('div', 'flag-row');
|
|
33032
|
-
row.appendChild(el('code', 'flag-name', f.flags));
|
|
33033
|
-
if (f.description) row.appendChild(el('span', 'flag-desc', f.description));
|
|
33034
|
-
ref.appendChild(row);
|
|
33035
|
-
});
|
|
33036
|
-
det.appendChild(ref);
|
|
33037
|
-
}
|
|
33038
|
-
|
|
33039
33251
|
return {
|
|
33040
33252
|
node: det,
|
|
33253
|
+
// Collect the auto-rendered control values, omitting unset ones (an
|
|
33254
|
+
// unchecked checkbox / a blank input or select) so the posted map carries
|
|
33255
|
+
// only flags the user actually set. Returns undefined when nothing is set.
|
|
33256
|
+
collectCatalog: function () {
|
|
33257
|
+
const out = {};
|
|
33258
|
+
catGetters.forEach(function (g) {
|
|
33259
|
+
const kv = g();
|
|
33260
|
+
const flag = kv[0];
|
|
33261
|
+
const val = kv[1];
|
|
33262
|
+
if (typeof val === 'boolean') {
|
|
33263
|
+
if (val) out[flag] = true;
|
|
33264
|
+
} else if (typeof val === 'string' && val.trim() !== '') {
|
|
33265
|
+
out[flag] = val.trim();
|
|
33266
|
+
}
|
|
33267
|
+
});
|
|
33268
|
+
return Object.keys(out).length ? out : undefined;
|
|
33269
|
+
},
|
|
33041
33270
|
collectRaw: function () {
|
|
33042
33271
|
const v = rawIn.value.trim();
|
|
33043
33272
|
return v === '' ? undefined : v;
|
|
@@ -33456,6 +33685,16 @@ const STUDIO_SCRIPT = `
|
|
|
33456
33685
|
}
|
|
33457
33686
|
});
|
|
33458
33687
|
}
|
|
33688
|
+
// Auto-rendered "All options" controls (the catalog flags). Surface each
|
|
33689
|
+
// set flag so the running view does not look like the picks vanished (the
|
|
33690
|
+
// issue #356 contract): the bare flag for a checked boolean, flag + value
|
|
33691
|
+
// otherwise.
|
|
33692
|
+
if (applied && applied.catalogArgs) {
|
|
33693
|
+
Object.keys(applied.catalogArgs).forEach(function (flag) {
|
|
33694
|
+
const v = applied.catalogArgs[flag];
|
|
33695
|
+
lines.push(v === true ? flag : flag + ' ' + v);
|
|
33696
|
+
});
|
|
33697
|
+
}
|
|
33459
33698
|
if (applied && applied.imageOverride) {
|
|
33460
33699
|
lines.push('--image-override ' + applied.imageOverride);
|
|
33461
33700
|
}
|
|
@@ -33474,7 +33713,7 @@ const STUDIO_SCRIPT = `
|
|
|
33474
33713
|
return lines;
|
|
33475
33714
|
}
|
|
33476
33715
|
|
|
33477
|
-
async function startServe(id, options, rawArgs, imageOverride, imageOverrides) {
|
|
33716
|
+
async function startServe(id, options, catalogArgs, rawArgs, imageOverride, imageOverrides) {
|
|
33478
33717
|
// The serve kind (api / alb / ecs) drives which headless command the
|
|
33479
33718
|
// server spawns; it is recorded on the row when the target list loads.
|
|
33480
33719
|
const meta = serveMeta.get(id);
|
|
@@ -33490,6 +33729,7 @@ const STUDIO_SCRIPT = `
|
|
|
33490
33729
|
const watchEl = document.getElementById('sess-watch');
|
|
33491
33730
|
serveApplied.set(id, {
|
|
33492
33731
|
options: options,
|
|
33732
|
+
catalogArgs: catalogArgs,
|
|
33493
33733
|
rawArgs: rawArgs,
|
|
33494
33734
|
imageOverride: imageOverride,
|
|
33495
33735
|
imageOverrides: imageOverrides,
|
|
@@ -33504,6 +33744,7 @@ const STUDIO_SCRIPT = `
|
|
|
33504
33744
|
try {
|
|
33505
33745
|
const body = { targetId: id, kind };
|
|
33506
33746
|
if (options) body.options = options;
|
|
33747
|
+
if (catalogArgs) body.catalogArgs = catalogArgs;
|
|
33507
33748
|
if (rawArgs) body.rawArgs = rawArgs;
|
|
33508
33749
|
if (imageOverride) body.imageOverride = imageOverride;
|
|
33509
33750
|
if (imageOverrides) body.imageOverrides = imageOverrides;
|
|
@@ -33610,6 +33851,7 @@ const STUDIO_SCRIPT = `
|
|
|
33610
33851
|
}
|
|
33611
33852
|
// Per-run options are only set before a start; collected on the Start click.
|
|
33612
33853
|
let collectOpts = function () { return undefined; };
|
|
33854
|
+
let collectCatalog = function () { return undefined; };
|
|
33613
33855
|
let collectRaw = function () { return undefined; };
|
|
33614
33856
|
let collectImageOverride = function () { return undefined; };
|
|
33615
33857
|
let collectImageOverrides = function () { return undefined; };
|
|
@@ -33623,7 +33865,14 @@ const STUDIO_SCRIPT = `
|
|
|
33623
33865
|
serveState.set(id, { status: 'stopped', endpoints: [] });
|
|
33624
33866
|
renderServeWorkspace(id);
|
|
33625
33867
|
} else {
|
|
33626
|
-
startServe(
|
|
33868
|
+
startServe(
|
|
33869
|
+
id,
|
|
33870
|
+
collectOpts(),
|
|
33871
|
+
collectCatalog(),
|
|
33872
|
+
collectRaw(),
|
|
33873
|
+
collectImageOverride(),
|
|
33874
|
+
collectImageOverrides()
|
|
33875
|
+
);
|
|
33627
33876
|
}
|
|
33628
33877
|
};
|
|
33629
33878
|
head.appendChild(btn);
|
|
@@ -33663,9 +33912,15 @@ const STUDIO_SCRIPT = `
|
|
|
33663
33912
|
ws.appendChild(io.node);
|
|
33664
33913
|
collectImageOverrides = io.collect;
|
|
33665
33914
|
}
|
|
33666
|
-
const opt = buildOptions(
|
|
33915
|
+
const opt = buildOptions(
|
|
33916
|
+
kind,
|
|
33917
|
+
applied && applied.options,
|
|
33918
|
+
applied && applied.rawArgs,
|
|
33919
|
+
applied && applied.catalogArgs
|
|
33920
|
+
);
|
|
33667
33921
|
if (opt.node) ws.appendChild(opt.node);
|
|
33668
33922
|
collectOpts = opt.collect;
|
|
33923
|
+
collectCatalog = opt.collectCatalog;
|
|
33669
33924
|
collectRaw = opt.collectRaw;
|
|
33670
33925
|
}
|
|
33671
33926
|
|
|
@@ -34284,7 +34539,7 @@ const STUDIO_SCRIPT = `
|
|
|
34284
34539
|
// target; per-run options are not carried over, so the options section is
|
|
34285
34540
|
// omitted (the payload is the thing being tweaked). A fresh invoke keeps
|
|
34286
34541
|
// the per-run options (e.g. env vars) below the event, above Invoke.
|
|
34287
|
-
let opt = { collect: undefined, collectRaw: undefined };
|
|
34542
|
+
let opt = { collect: undefined, collectCatalog: undefined, collectRaw: undefined };
|
|
34288
34543
|
if (reinvokeOf) {
|
|
34289
34544
|
composer.appendChild(
|
|
34290
34545
|
el('div', 'opt-hint', 'Re-invoke runs the edited event through the same target (per-run options use defaults).')
|
|
@@ -34312,6 +34567,7 @@ const STUDIO_SCRIPT = `
|
|
|
34312
34567
|
msg,
|
|
34313
34568
|
result,
|
|
34314
34569
|
collectOpts: opt.collect,
|
|
34570
|
+
collectCatalog: opt.collectCatalog,
|
|
34315
34571
|
collectRaw: opt.collectRaw,
|
|
34316
34572
|
reinvokeOf: reinvokeOf || null,
|
|
34317
34573
|
};
|
|
@@ -34350,6 +34606,8 @@ const STUDIO_SCRIPT = `
|
|
|
34350
34606
|
body = { targetId: id, kind, event };
|
|
34351
34607
|
const options = active.collectOpts ? active.collectOpts() : undefined;
|
|
34352
34608
|
if (options) body.options = options;
|
|
34609
|
+
const catalogArgs = active.collectCatalog ? active.collectCatalog() : undefined;
|
|
34610
|
+
if (catalogArgs) body.catalogArgs = catalogArgs;
|
|
34353
34611
|
const rawArgs = active.collectRaw ? active.collectRaw() : undefined;
|
|
34354
34612
|
if (rawArgs) body.rawArgs = rawArgs;
|
|
34355
34613
|
}
|
|
@@ -35544,6 +35802,7 @@ function createStudioDispatcher(config) {
|
|
|
35544
35802
|
eventFile,
|
|
35545
35803
|
...buildSharedChildArgs(config, { preferAssembly: true }),
|
|
35546
35804
|
...buildPerRunArgs(req.kind, req.options),
|
|
35805
|
+
...buildCatalogArgs(req.kind, req.catalogArgs),
|
|
35547
35806
|
...responseFilePath ? ["--response-file", responseFilePath] : []
|
|
35548
35807
|
];
|
|
35549
35808
|
const envVars = resolveEnvVars(req.kind, req.options);
|
|
@@ -36210,6 +36469,7 @@ function createStudioServeManager(config) {
|
|
|
36210
36469
|
...spec.portArgs,
|
|
36211
36470
|
...buildSharedChildArgs(config, { preferAssembly }),
|
|
36212
36471
|
...buildPerRunArgs(req.kind, req.options),
|
|
36472
|
+
...buildCatalogArgs(req.kind, req.catalogArgs),
|
|
36213
36473
|
...envFile ? ["--env-vars", envFile] : [],
|
|
36214
36474
|
...req.imageOverride && req.imageOverride.trim() !== "" ? ["--image-override", req.targetId + "=" + req.imageOverride.trim()] : [],
|
|
36215
36475
|
...Object.entries(req.imageOverrides ?? {}).flatMap(([svc, df]) => df && df.trim() !== "" ? ["--image-override", svc + "=" + df.trim()] : []),
|
|
@@ -36476,7 +36736,7 @@ const STUDIO_TARGET_KINDS = [
|
|
|
36476
36736
|
*/
|
|
36477
36737
|
function coerceRunRequest(body) {
|
|
36478
36738
|
if (typeof body !== "object" || body === null) throw new Error("Request body must be a JSON object.");
|
|
36479
|
-
const { targetId, kind, event, options, rawArgs, imageOverride, imageOverrides } = body;
|
|
36739
|
+
const { targetId, kind, event, options, catalogArgs, rawArgs, imageOverride, imageOverrides } = body;
|
|
36480
36740
|
if (typeof targetId !== "string" || targetId.trim() === "") throw new Error("Request body must include a non-empty \"targetId\" string.");
|
|
36481
36741
|
if (typeof kind !== "string" || !STUDIO_TARGET_KINDS.includes(kind)) throw new Error(`Request body "kind" must be one of: ${STUDIO_TARGET_KINDS.join(", ")}.`);
|
|
36482
36742
|
let runOptions;
|
|
@@ -36486,6 +36746,12 @@ function coerceRunRequest(body) {
|
|
|
36486
36746
|
buildPerRunArgs(kind, runOptions);
|
|
36487
36747
|
resolveEnvVars(kind, runOptions);
|
|
36488
36748
|
}
|
|
36749
|
+
let runCatalogArgs;
|
|
36750
|
+
if (catalogArgs !== void 0) {
|
|
36751
|
+
if (typeof catalogArgs !== "object" || catalogArgs === null || Array.isArray(catalogArgs)) throw new Error("Request body \"catalogArgs\" must be a JSON object keyed by flag.");
|
|
36752
|
+
runCatalogArgs = catalogArgs;
|
|
36753
|
+
buildCatalogArgs(kind, runCatalogArgs);
|
|
36754
|
+
}
|
|
36489
36755
|
let runRawArgs;
|
|
36490
36756
|
if (rawArgs !== void 0) {
|
|
36491
36757
|
if (typeof rawArgs !== "string") throw new Error("Request body \"rawArgs\" must be a string.");
|
|
@@ -36512,6 +36778,7 @@ function coerceRunRequest(body) {
|
|
|
36512
36778
|
kind,
|
|
36513
36779
|
event,
|
|
36514
36780
|
...runOptions !== void 0 ? { options: runOptions } : {},
|
|
36781
|
+
...runCatalogArgs !== void 0 ? { catalogArgs: runCatalogArgs } : {},
|
|
36515
36782
|
...runRawArgs !== void 0 ? { rawArgs: runRawArgs } : {},
|
|
36516
36783
|
...runImageOverride !== void 0 ? { imageOverride: runImageOverride } : {},
|
|
36517
36784
|
...runImageOverrides !== void 0 ? { imageOverrides: runImageOverrides } : {}
|
|
@@ -37317,5 +37584,5 @@ function addStudioSpecificOptions(cmd) {
|
|
|
37317
37584
|
}
|
|
37318
37585
|
|
|
37319
37586
|
//#endregion
|
|
37320
|
-
export {
|
|
37321
|
-
//# sourceMappingURL=local-studio-
|
|
37587
|
+
export { applyEdgeResponseResult as $, buildJwksUrlFromIssuer as $n, collectSsmParameterRefs as $r, buildCloudMapIndex as $t, startAgentCoreHttpServer as A, classifySourceChange as An, handleConnectionsRequest as Ar, addRunTaskSpecificOptions as At, idFromArn as B, buildStageMap as Bn, EcsTaskResolutionError as Br, resolveEcsAssumeRoleOption as Bt, addListSpecificOptions as C, formatStateRemedy as Ci, waitForAgentCorePing as Cn, tryParseStatus as Cr, parseLbPortOverrides as Ct, createLocalStartAgentCoreCommand as D, buildStsClientConfig as Di, computeCodeImageTag as Dn, bufferToBody as Dr, addStartServiceSpecificOptions as Dt, addStartAgentCoreSpecificOptions as E, LocalInvokeBuildError as Ei, buildAgentCoreCodeImage as En, probeHostGatewaySupport as Er, resolveAlbFrontDoor as Et, createLocalStartCloudFrontCommand as F, createWatchPredicates as Fn, architectureToPlatform as Fr, addImageOverrideOptions as Ft, classifyS3Error as G, filterRoutesByApiIdentifiers as Gn, LocalStateSourceError as Gr, enforceImageOverrideOrphans as Gt, createDeployedKvsDataSource as H, resolveEnvVars$1 as Hn, substituteAgainstStateAsync as Hr, runEcsServiceEmulator as Ht, normalizeKvsFileKeys as I, resolveApiTargetSubset as In, buildContainerImage as Ir, buildEcsImageResolutionContext$1 as It, startCloudFrontServer as J, startApiServer as Jn, rejectExplicitCfnStackWithMultipleStacks as Jr, resolveImageOverrides as Jt, createS3OriginReader as K, groupRoutesByServer as Kn, createLocalStateProvider as Kr, mergeForService as Kt, parseKvsFileOverrides as L, createAuthorizerCache as Ln, resolveRuntimeCodeMountPath as Lr, ecsClusterOption as Lt, startAgentCoreWsBridge as M, createLocalInvokeCommand as Mn, buildConnectEvent as Mr, MAX_TASKS_SUBNET_RANGE_CAP as Mt, LocalStartCloudFrontError as N, addStartApiSpecificOptions as Nn, buildDisconnectEvent as Nr, addCommonEcsServiceOptions as Nt, buildAgentCoreServeAuthCheck as O, resolveProfileCredentials as Oi, renderCodeDockerfile as On, ConnectionRegistry as Or, createLocalStartServiceCommand as Ot, addStartCloudFrontSpecificOptions as P, createLocalStartApiCommand as Pn, buildMessageEvent as Pr, addEcsAssumeRoleOptions as Pt, applyEdgeRequestResult as Q, buildCognitoJwksUrl as Qn, CfnLocalStateProvider as Qr, listPinnedTargets as Qt, parseOriginOverrides as R, createFileWatcher as Rn, resolveRuntimeFileExtension as Rr, parseMaxTasks as Rt, StudioEventBus as S, derivePseudoParametersFromRegion as Si, waitForAgentCoreHttpReady as Sn, selectIntegrationResponse as Sr, createLocalStartAlbCommand as St, formatTargetListing as T, tryResolveImageFnJoin as Ti, SUPPORTED_CODE_RUNTIMES as Tn, HOST_GATEWAY_MIN_VERSION as Tr, isApplicationLoadBalancer as Tt, resolveDeployedKvsArnByName as U, availableApiIdentifiers as Un, substituteEnvVarsFromState as Ur, ImageOverrideError as Ut, resolveKvsModulesForDistribution as V, materializeLayerFromArn as Vn, substituteAgainstState as Vr, resolveSharedSidecarCredentials as Vt, resolveDeployedOriginBucket as W, filterRoutesByApiIdentifier as Wn, substituteEnvVarsFromStateAsync as Wr, buildImageOverrideTag as Wt, serveFromStaticOrigin as X, resolveServiceIntegrationParameters as Xn, resolveCfnRegion as Xr, describePinnedImageUri as Xt, resolveErrorResponseCandidates as Y, resolveSelectionExpression as Yn, resolveCfnFallbackRegion as Yr, runImageOverrideBuilds as Yt, serveLambdaUrlOrigin as Z, defaultCredentialsLoader as Zn, resolveCfnStackName as Zr, isLocalCdkAssetImage as Zt, filterStudioTargetGroups as _, AGENTCORE_MCP_PROTOCOL as _i, parseSseForJsonRpc as _n, applyAuthorizerOverlay as _r, createCloudFrontModule as _t, createLocalStudioCommand as a, availableWebSocketApiIdentifiers as ai, attachContainerLogStreamer as an, computeRequestIdentityHash as ar, describeS3OriginDomain as at, renderStudioHtml as b, pickAgentCoreCandidateStack as bi, AGENTCORE_SESSION_ID_HEADER as bn, evaluateResponseParameters as br, addAlbSpecificOptions as bt, startStudioProxy as c, filterWebSocketApisByIdentifiers as ci, bridgeAgentCoreWs as cn, invokeTokenAuthorizer as cr, pickFunctionUrlLogicalIdFromOrigin as ct, createStudioDispatcher as d, discoverRoutes as di, A2A_PATH as dn, buildCorsConfigByApiId as dr, pickTargetFunctionLogicalId as dt, resolveSsmParameters as ei, CloudMapRegistry as en, createJwksCache as er, buildEdgeRequestEvent as et, filterStudioCustomResources as f, pickRefLogicalId as fi, a2aInvokeOnce as fn, buildCorsConfigFromCloudFrontChain as fr, resolveCloudFrontDistribution as ft, annotatePinnedEcsTargets as g, AGENTCORE_HTTP_PROTOCOL as gi, mcpInvokeOnce as gn, translateLambdaResponse as gr, stripCloudFrontImport as gt, annotateEcsTaskPinnedTargets as h, AGENTCORE_AGUI_PROTOCOL as hi, MCP_PROTOCOL_VERSION as hn, matchRoute as hr, runViewerResponse as ht, coerceStopRequest as i, listTargets as ii, getContainerNetworkIp as in, buildMethodArn as ir, CLOUDFRONT_DISTRIBUTION_TYPE as it, attachAgentCoreWsBridge as j, addInvokeSpecificOptions as jn, parseConnectionsPath as jr, createLocalRunTaskCommand as jt, selectServeInboundAuth as k, toCmdArgv as kn, buildMgmtEndpointEnvUrl as kr, serviceStrategy as kt, relayServeRequest as l, parseSelectionExpressionPath as li, invokeAgentCoreWs as ln, attachAuthorizers as lr, pickKvsLogicalIdFromArn as lt, annotateAlbPinnedBackingServices as m, AGENTCORE_A2A_PROTOCOL as mi, MCP_PATH as mn, matchPreflight as mr, runViewerRequest as mt, coerceRunRequest as n, resolveSingleTarget as ni, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as nn, verifyJwtAuthorizer as nr, edgeHeadersToHttp as nt, resolveServeBaseUrl as o, discoverWebSocketApis as oi, addInvokeAgentCoreSpecificOptions as on, evaluateCachedLambdaPolicy as or, extractKvsAssociations as ot, isCustomResourceLambdaTarget as p, resolveLambdaArnIntrinsic as pi, MCP_CONTAINER_PORT as pn, isFunctionUrlOacFronted as pr, compileCloudFrontFunction as pt, matchBehavior as q, readMtlsMaterialsFromDisk as qn, isCfnFlagPresent as qr, parseImageOverrideFlags as qt, coerceServeRequest as r, countTargets as ri, setShadowReadyTimeoutMs as rn, verifyJwtViaDiscovery as rr, httpHeadersToEdge as rt, createStudioServeManager as s, discoverWebSocketApisOrThrow as si, createLocalInvokeAgentCoreCommand as sn, invokeRequestAuthorizer as sr, isCloudFrontDistribution as st, addStudioSpecificOptions as t, resolveWatchConfig as ti, DEFAULT_SHADOW_READY_TIMEOUT_MS as tn, verifyCognitoJwt as tr, buildEdgeResponseEvent as tt, reinvoke as u, webSocketApiMatchesIdentifier as ui, A2A_CONTAINER_PORT as un, applyCorsResponseHeaders as ur, pickLambdaEdgeFunctionLogicalId as ut, startStudioServer as v, AGENTCORE_RUNTIME_TYPE as vi, AGENTCORE_SIGV4_SERVICE as vn, buildHttpApiV2Event as vr, createLocalFileKvsDataSource as vt, createLocalListCommand as w, substituteImagePlaceholders as wi, downloadAndExtractS3Bundle as wn, VtlEvaluationError as wr, resolveAlbTarget as wt, createStudioStore as x, resolveAgentCoreTarget as xi, invokeAgentCore as xn, pickResponseTemplate as xr, albStrategy as xt, toStudioTargetGroups as y, AgentCoreResolutionError as yi, signAgentCoreInvocation as yn, buildRestV1Event as yr, createUnboundCloudFrontModule as yt, resolveCloudFrontTarget as z, attachStageContext as zn, resolveRuntimeImage as zr, parseRestartPolicy as zt };
|
|
37588
|
+
//# sourceMappingURL=local-studio-fdztI6b8.js.map
|