cdk-local 0.140.0 → 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.
@@ -31977,172 +31977,6 @@ function createStudioStore(bus, options = {}) {
31977
31977
  };
31978
31978
  }
31979
31979
 
31980
- //#endregion
31981
- //#region src/local/studio-option-catalog.ts
31982
- /**
31983
- * Auto-derived full-flag catalog for `cdkl studio` (issue #301).
31984
- *
31985
- * The per-target {@link OPTION_SPECS} in `studio-option-specs.ts` is a
31986
- * CURATED subset — the handful of flags worth a rich control (a checkbox, a
31987
- * KV editor, an add-row list). But a command like `cdkl start-api` accepts
31988
- * many more flags than studio renders a control for, and hiding them makes
31989
- * the UI strictly less capable than the headless CLI.
31990
- *
31991
- * This module closes that gap by INTROSPECTING each runnable kind's Commander
31992
- * command factory and emitting the complete flag list (name + description).
31993
- * The studio UI serializes it into the page and renders, inside a collapsed
31994
- * "All options" section, (a) the full catalog as a read-only reference and
31995
- * (b) a raw extra-args input (see {@link tokenizeRawArgs}) so any flag the
31996
- * curated controls don't expose can still be passed verbatim. Auto-derivation
31997
- * means the catalog can never drift from the command's real option set.
31998
- *
31999
- * Session-global flags (handled by the studio Session bar / `studio-child-args`)
32000
- * and the auto-added `--help` / `--version` are excluded — passing them per-run
32001
- * would conflict with the session-wide wiring.
32002
- */
32003
- /**
32004
- * Long flag names handled by the session bar / `studio-child-args` (forwarded
32005
- * to every spawned child once, session-wide). Excluded from the per-target
32006
- * catalog so a user does not re-specify them per-run and collide with the
32007
- * session-wide value. Plus the Commander-managed `--help` / `--version`.
32008
- */
32009
- const CATALOG_EXCLUDED_FLAGS = new Set([
32010
- "--app",
32011
- "--profile",
32012
- "--region",
32013
- "--context",
32014
- "--from-cfn-stack",
32015
- "--assume-role",
32016
- "--help",
32017
- "--version"
32018
- ]);
32019
- const KIND_FACTORIES = {
32020
- lambda: {
32021
- command: "invoke",
32022
- factory: createLocalInvokeCommand
32023
- },
32024
- agentcore: {
32025
- command: "invoke-agentcore",
32026
- factory: createLocalInvokeAgentCoreCommand
32027
- },
32028
- api: {
32029
- command: "start-api",
32030
- factory: createLocalStartApiCommand
32031
- },
32032
- alb: {
32033
- command: "start-alb",
32034
- factory: createLocalStartAlbCommand
32035
- },
32036
- ecs: {
32037
- command: "start-service",
32038
- factory: createLocalStartServiceCommand
32039
- },
32040
- "ecs-task": {
32041
- command: "run-task",
32042
- factory: createLocalRunTaskCommand
32043
- },
32044
- cloudfront: {
32045
- command: "start-cloudfront",
32046
- factory: createLocalStartCloudFrontCommand
32047
- },
32048
- "agentcore-ws": {
32049
- command: "start-agentcore",
32050
- factory: createLocalStartAgentCoreCommand
32051
- }
32052
- };
32053
- let cached;
32054
- /**
32055
- * Build (and memoize) the full per-kind flag catalog by introspecting each
32056
- * runnable kind's Commander command factory.
32057
- *
32058
- * Each factory calls `setEmbedConfig(opts.embedConfig)` at construction — with
32059
- * no opts that resets the active embed config to cdk-local defaults, which
32060
- * would wipe a host CLI's branding. So the active config is snapshotted and
32061
- * each factory is re-handed it: branding is preserved AND the derived flag
32062
- * descriptions reflect the host's active branding. The `finally` restore is a
32063
- * belt-and-suspenders against a factory that ignores the passed config.
32064
- * Memoized: the factories are instantiated exactly once per process, not per
32065
- * page render.
32066
- */
32067
- function buildFlagCatalog() {
32068
- if (cached) return cached;
32069
- const savedEmbedConfig = getEmbedConfig();
32070
- try {
32071
- const out = {};
32072
- for (const kind of Object.keys(KIND_FACTORIES)) {
32073
- const { command, factory } = KIND_FACTORIES[kind];
32074
- const cmd = factory({ embedConfig: savedEmbedConfig });
32075
- const flags = [];
32076
- for (const opt of cmd.options) {
32077
- if (opt.hidden) continue;
32078
- if (opt.long && CATALOG_EXCLUDED_FLAGS.has(opt.long)) continue;
32079
- flags.push({
32080
- flags: opt.flags,
32081
- description: opt.description ?? ""
32082
- });
32083
- }
32084
- out[kind] = {
32085
- command,
32086
- flags
32087
- };
32088
- }
32089
- cached = out;
32090
- return out;
32091
- } finally {
32092
- setEmbedConfig(savedEmbedConfig);
32093
- }
32094
- }
32095
- /**
32096
- * Tokenize a raw extra-args string into discrete argv elements, honoring
32097
- * single / double quotes and backslash escaping so values with spaces survive
32098
- * (`--name "two words"` -> `['--name', 'two words']`). studio spawns children
32099
- * WITHOUT a shell (argv array), so the tokens are appended verbatim — there is
32100
- * no shell-injection surface; the child command still validates each arg.
32101
- *
32102
- * Returns `[]` for an empty / whitespace-only input. Throws on an unterminated
32103
- * quote so a malformed raw-args string fails as a clean boundary error rather
32104
- * than spawning a child with a mis-split argv.
32105
- */
32106
- function tokenizeRawArgs(raw) {
32107
- if (raw === void 0) return [];
32108
- const tokens = [];
32109
- let current = "";
32110
- let inToken = false;
32111
- let quote = null;
32112
- for (let i = 0; i < raw.length; i++) {
32113
- const ch = raw[i];
32114
- if (quote) {
32115
- if (ch === "\\" && quote === "\"" && i + 1 < raw.length) current += raw[++i];
32116
- else if (ch === quote) quote = null;
32117
- else current += ch;
32118
- continue;
32119
- }
32120
- if (ch === "\"" || ch === "'") {
32121
- quote = ch;
32122
- inToken = true;
32123
- continue;
32124
- }
32125
- if (ch === "\\" && i + 1 < raw.length) {
32126
- current += raw[++i];
32127
- inToken = true;
32128
- continue;
32129
- }
32130
- if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
32131
- if (inToken) {
32132
- tokens.push(current);
32133
- current = "";
32134
- inToken = false;
32135
- }
32136
- continue;
32137
- }
32138
- current += ch;
32139
- inToken = true;
32140
- }
32141
- if (quote) throw new Error(`Raw extra args have an unterminated ${quote} quote.`);
32142
- if (inToken) tokens.push(current);
32143
- return tokens;
32144
- }
32145
-
32146
31980
  //#endregion
32147
31981
  //#region src/local/studio-option-specs.ts
32148
31982
  /**
@@ -32446,6 +32280,264 @@ function resolveEnvVars(kind, values) {
32446
32280
  throw new Error(`Option '${spec.flag}' must be KEY/VALUE rows or a JSON object string.`);
32447
32281
  }
32448
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
+
32449
32541
  //#endregion
32450
32542
  //#region src/local/studio-ui.ts
32451
32543
  /**
@@ -32781,10 +32873,18 @@ const STUDIO_CSS = `
32781
32873
  read — kept small as it is secondary. */
32782
32874
  .io-label { color: #d7dde5; font-weight: 500; overflow-wrap: anywhere; min-width: 0; }
32783
32875
  .io-hint { color: #e3b34a; font-size: 11px; }
32784
- .flag-catalog { margin-top: 8px; display: flex; flex-direction: column; gap: 2px; }
32785
- .flag-row { display: flex; gap: 8px; align-items: baseline; font-size: 11px; }
32786
- .flag-name { color: #7bd88f; font-family: ui-monospace, Menlo, monospace; white-space: nowrap; }
32787
- .flag-desc { color: #999; }
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; }
32788
32888
  .started-list { display: flex; flex-direction: column; gap: 3px; margin-top: 4px; }
32789
32889
  .started-flag { color: #7bd88f; font-family: ui-monospace, Menlo, monospace; font-size: 11px; white-space: pre-wrap; word-break: break-all; }
32790
32890
  .envkv-modes { display: flex; gap: 0; }
@@ -32878,7 +32978,7 @@ const STUDIO_SCRIPT = `
32878
32978
  // prefill (issue #398): the option map a stopped serve was last Started with
32879
32979
  // (serveApplied.options), so the re-rendered composer comes back filled.
32880
32980
  // rawPrefill is the raw-extra-args string (serveApplied.rawArgs).
32881
- function buildOptions(kind, prefill, rawPrefill) {
32981
+ function buildOptions(kind, prefill, rawPrefill, catalogPrefill) {
32882
32982
  const specs = OPTION_SPECS[kind] || [];
32883
32983
  // The composer always shows an "All options" section (raw extra args + the
32884
32984
  // auto-derived flag reference), even for kinds with no curated controls.
@@ -33029,7 +33129,7 @@ const STUDIO_SCRIPT = `
33029
33129
  }
33030
33130
  sec.appendChild(row);
33031
33131
  });
33032
- const allOpts = buildAllOptions(kind, rawPrefill);
33132
+ const allOpts = buildAllOptions(kind, rawPrefill, catalogPrefill);
33033
33133
  wrap.appendChild(allOpts.node);
33034
33134
  return {
33035
33135
  node: wrap,
@@ -33041,22 +33141,97 @@ const STUDIO_SCRIPT = `
33041
33141
  // body identical to before this section existed.
33042
33142
  return Object.keys(out).length ? out : undefined;
33043
33143
  },
33144
+ collectCatalog: allOpts.collectCatalog,
33044
33145
  collectRaw: allOpts.collectRaw,
33045
33146
  };
33046
33147
  }
33047
33148
 
33048
- // The collapsed "All options" section: a raw extra-args input (appended
33049
- // verbatim to the spawned child) + the auto-derived, read-only catalog of
33050
- // every flag the underlying command accepts. The curated controls above
33051
- // cover the common flags with rich UI; this exposes the rest so the studio
33052
- // UI is never strictly less capable than the headless CLI (issue #301).
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).
33053
33157
  const FLAG_CATALOG = window.__FLAG_CATALOG__ || {};
33054
33158
 
33055
- function buildAllOptions(kind, rawPrefill) {
33159
+ function buildAllOptions(kind, rawPrefill, catalogPrefill) {
33056
33160
  const cat = FLAG_CATALOG[kind] || { command: '', flags: [] };
33057
33161
  const det = el('details', 'all-options');
33058
33162
  det.appendChild(el('summary', null, 'All options'));
33059
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
+
33060
33235
  const rawRow = el('div', 'opt-row opt-col');
33061
33236
  rawRow.appendChild(el('span', 'opt-label', 'Raw extra args'));
33062
33237
  const rawIn = el('input', 'raw-args');
@@ -33073,20 +33248,25 @@ const STUDIO_SCRIPT = `
33073
33248
  rawRow.appendChild(el('div', 'opt-hint', hint));
33074
33249
  det.appendChild(rawRow);
33075
33250
 
33076
- if (cat.flags.length) {
33077
- const ref = el('div', 'flag-catalog');
33078
- ref.appendChild(el('div', 'opt-label', 'Available flags'));
33079
- cat.flags.forEach(function (f) {
33080
- const row = el('div', 'flag-row');
33081
- row.appendChild(el('code', 'flag-name', f.flags));
33082
- if (f.description) row.appendChild(el('span', 'flag-desc', f.description));
33083
- ref.appendChild(row);
33084
- });
33085
- det.appendChild(ref);
33086
- }
33087
-
33088
33251
  return {
33089
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
+ },
33090
33270
  collectRaw: function () {
33091
33271
  const v = rawIn.value.trim();
33092
33272
  return v === '' ? undefined : v;
@@ -33505,6 +33685,16 @@ const STUDIO_SCRIPT = `
33505
33685
  }
33506
33686
  });
33507
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
+ }
33508
33698
  if (applied && applied.imageOverride) {
33509
33699
  lines.push('--image-override ' + applied.imageOverride);
33510
33700
  }
@@ -33523,7 +33713,7 @@ const STUDIO_SCRIPT = `
33523
33713
  return lines;
33524
33714
  }
33525
33715
 
33526
- async function startServe(id, options, rawArgs, imageOverride, imageOverrides) {
33716
+ async function startServe(id, options, catalogArgs, rawArgs, imageOverride, imageOverrides) {
33527
33717
  // The serve kind (api / alb / ecs) drives which headless command the
33528
33718
  // server spawns; it is recorded on the row when the target list loads.
33529
33719
  const meta = serveMeta.get(id);
@@ -33539,6 +33729,7 @@ const STUDIO_SCRIPT = `
33539
33729
  const watchEl = document.getElementById('sess-watch');
33540
33730
  serveApplied.set(id, {
33541
33731
  options: options,
33732
+ catalogArgs: catalogArgs,
33542
33733
  rawArgs: rawArgs,
33543
33734
  imageOverride: imageOverride,
33544
33735
  imageOverrides: imageOverrides,
@@ -33553,6 +33744,7 @@ const STUDIO_SCRIPT = `
33553
33744
  try {
33554
33745
  const body = { targetId: id, kind };
33555
33746
  if (options) body.options = options;
33747
+ if (catalogArgs) body.catalogArgs = catalogArgs;
33556
33748
  if (rawArgs) body.rawArgs = rawArgs;
33557
33749
  if (imageOverride) body.imageOverride = imageOverride;
33558
33750
  if (imageOverrides) body.imageOverrides = imageOverrides;
@@ -33659,6 +33851,7 @@ const STUDIO_SCRIPT = `
33659
33851
  }
33660
33852
  // Per-run options are only set before a start; collected on the Start click.
33661
33853
  let collectOpts = function () { return undefined; };
33854
+ let collectCatalog = function () { return undefined; };
33662
33855
  let collectRaw = function () { return undefined; };
33663
33856
  let collectImageOverride = function () { return undefined; };
33664
33857
  let collectImageOverrides = function () { return undefined; };
@@ -33672,7 +33865,14 @@ const STUDIO_SCRIPT = `
33672
33865
  serveState.set(id, { status: 'stopped', endpoints: [] });
33673
33866
  renderServeWorkspace(id);
33674
33867
  } else {
33675
- startServe(id, collectOpts(), collectRaw(), collectImageOverride(), collectImageOverrides());
33868
+ startServe(
33869
+ id,
33870
+ collectOpts(),
33871
+ collectCatalog(),
33872
+ collectRaw(),
33873
+ collectImageOverride(),
33874
+ collectImageOverrides()
33875
+ );
33676
33876
  }
33677
33877
  };
33678
33878
  head.appendChild(btn);
@@ -33712,9 +33912,15 @@ const STUDIO_SCRIPT = `
33712
33912
  ws.appendChild(io.node);
33713
33913
  collectImageOverrides = io.collect;
33714
33914
  }
33715
- const opt = buildOptions(kind, applied && applied.options, applied && applied.rawArgs);
33915
+ const opt = buildOptions(
33916
+ kind,
33917
+ applied && applied.options,
33918
+ applied && applied.rawArgs,
33919
+ applied && applied.catalogArgs
33920
+ );
33716
33921
  if (opt.node) ws.appendChild(opt.node);
33717
33922
  collectOpts = opt.collect;
33923
+ collectCatalog = opt.collectCatalog;
33718
33924
  collectRaw = opt.collectRaw;
33719
33925
  }
33720
33926
 
@@ -34333,7 +34539,7 @@ const STUDIO_SCRIPT = `
34333
34539
  // target; per-run options are not carried over, so the options section is
34334
34540
  // omitted (the payload is the thing being tweaked). A fresh invoke keeps
34335
34541
  // the per-run options (e.g. env vars) below the event, above Invoke.
34336
- let opt = { collect: undefined, collectRaw: undefined };
34542
+ let opt = { collect: undefined, collectCatalog: undefined, collectRaw: undefined };
34337
34543
  if (reinvokeOf) {
34338
34544
  composer.appendChild(
34339
34545
  el('div', 'opt-hint', 'Re-invoke runs the edited event through the same target (per-run options use defaults).')
@@ -34361,6 +34567,7 @@ const STUDIO_SCRIPT = `
34361
34567
  msg,
34362
34568
  result,
34363
34569
  collectOpts: opt.collect,
34570
+ collectCatalog: opt.collectCatalog,
34364
34571
  collectRaw: opt.collectRaw,
34365
34572
  reinvokeOf: reinvokeOf || null,
34366
34573
  };
@@ -34399,6 +34606,8 @@ const STUDIO_SCRIPT = `
34399
34606
  body = { targetId: id, kind, event };
34400
34607
  const options = active.collectOpts ? active.collectOpts() : undefined;
34401
34608
  if (options) body.options = options;
34609
+ const catalogArgs = active.collectCatalog ? active.collectCatalog() : undefined;
34610
+ if (catalogArgs) body.catalogArgs = catalogArgs;
34402
34611
  const rawArgs = active.collectRaw ? active.collectRaw() : undefined;
34403
34612
  if (rawArgs) body.rawArgs = rawArgs;
34404
34613
  }
@@ -35593,6 +35802,7 @@ function createStudioDispatcher(config) {
35593
35802
  eventFile,
35594
35803
  ...buildSharedChildArgs(config, { preferAssembly: true }),
35595
35804
  ...buildPerRunArgs(req.kind, req.options),
35805
+ ...buildCatalogArgs(req.kind, req.catalogArgs),
35596
35806
  ...responseFilePath ? ["--response-file", responseFilePath] : []
35597
35807
  ];
35598
35808
  const envVars = resolveEnvVars(req.kind, req.options);
@@ -36259,6 +36469,7 @@ function createStudioServeManager(config) {
36259
36469
  ...spec.portArgs,
36260
36470
  ...buildSharedChildArgs(config, { preferAssembly }),
36261
36471
  ...buildPerRunArgs(req.kind, req.options),
36472
+ ...buildCatalogArgs(req.kind, req.catalogArgs),
36262
36473
  ...envFile ? ["--env-vars", envFile] : [],
36263
36474
  ...req.imageOverride && req.imageOverride.trim() !== "" ? ["--image-override", req.targetId + "=" + req.imageOverride.trim()] : [],
36264
36475
  ...Object.entries(req.imageOverrides ?? {}).flatMap(([svc, df]) => df && df.trim() !== "" ? ["--image-override", svc + "=" + df.trim()] : []),
@@ -36525,7 +36736,7 @@ const STUDIO_TARGET_KINDS = [
36525
36736
  */
36526
36737
  function coerceRunRequest(body) {
36527
36738
  if (typeof body !== "object" || body === null) throw new Error("Request body must be a JSON object.");
36528
- const { targetId, kind, event, options, rawArgs, imageOverride, imageOverrides } = body;
36739
+ const { targetId, kind, event, options, catalogArgs, rawArgs, imageOverride, imageOverrides } = body;
36529
36740
  if (typeof targetId !== "string" || targetId.trim() === "") throw new Error("Request body must include a non-empty \"targetId\" string.");
36530
36741
  if (typeof kind !== "string" || !STUDIO_TARGET_KINDS.includes(kind)) throw new Error(`Request body "kind" must be one of: ${STUDIO_TARGET_KINDS.join(", ")}.`);
36531
36742
  let runOptions;
@@ -36535,6 +36746,12 @@ function coerceRunRequest(body) {
36535
36746
  buildPerRunArgs(kind, runOptions);
36536
36747
  resolveEnvVars(kind, runOptions);
36537
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
+ }
36538
36755
  let runRawArgs;
36539
36756
  if (rawArgs !== void 0) {
36540
36757
  if (typeof rawArgs !== "string") throw new Error("Request body \"rawArgs\" must be a string.");
@@ -36561,6 +36778,7 @@ function coerceRunRequest(body) {
36561
36778
  kind,
36562
36779
  event,
36563
36780
  ...runOptions !== void 0 ? { options: runOptions } : {},
36781
+ ...runCatalogArgs !== void 0 ? { catalogArgs: runCatalogArgs } : {},
36564
36782
  ...runRawArgs !== void 0 ? { rawArgs: runRawArgs } : {},
36565
36783
  ...runImageOverride !== void 0 ? { imageOverride: runImageOverride } : {},
36566
36784
  ...runImageOverrides !== void 0 ? { imageOverrides: runImageOverrides } : {}
@@ -37367,4 +37585,4 @@ function addStudioSpecificOptions(cmd) {
37367
37585
 
37368
37586
  //#endregion
37369
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 };
37370
- //# sourceMappingURL=local-studio-BeiTYBHR.js.map
37588
+ //# sourceMappingURL=local-studio-fdztI6b8.js.map