cdk-local 0.94.0 → 0.96.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 +19 -1
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +5 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -2
- package/dist/{local-studio-CRz5S9Iu.d.ts → local-studio-BOLwXNkK.d.ts} +5 -1
- package/dist/{local-studio-CRz5S9Iu.d.ts.map → local-studio-BOLwXNkK.d.ts.map} +1 -1
- package/dist/{local-studio-MTJUk4NF.js → local-studio-DMYaMyCf.js} +350 -14
- package/dist/local-studio-DMYaMyCf.js.map +1 -0
- package/package.json +1 -1
- package/dist/local-studio-MTJUk4NF.js.map +0 -1
|
@@ -28024,6 +28024,160 @@ function createStudioStore(bus, options = {}) {
|
|
|
28024
28024
|
};
|
|
28025
28025
|
}
|
|
28026
28026
|
|
|
28027
|
+
//#endregion
|
|
28028
|
+
//#region src/local/studio-option-catalog.ts
|
|
28029
|
+
/**
|
|
28030
|
+
* Auto-derived full-flag catalog for `cdkl studio` (issue #301).
|
|
28031
|
+
*
|
|
28032
|
+
* The per-target {@link OPTION_SPECS} in `studio-option-specs.ts` is a
|
|
28033
|
+
* CURATED subset — the handful of flags worth a rich control (a checkbox, a
|
|
28034
|
+
* KV editor, an add-row list). But a command like `cdkl start-api` accepts
|
|
28035
|
+
* many more flags than studio renders a control for, and hiding them makes
|
|
28036
|
+
* the UI strictly less capable than the headless CLI.
|
|
28037
|
+
*
|
|
28038
|
+
* This module closes that gap by INTROSPECTING each runnable kind's Commander
|
|
28039
|
+
* command factory and emitting the complete flag list (name + description).
|
|
28040
|
+
* The studio UI serializes it into the page and renders, inside a collapsed
|
|
28041
|
+
* "All options" section, (a) the full catalog as a read-only reference and
|
|
28042
|
+
* (b) a raw extra-args input (see {@link tokenizeRawArgs}) so any flag the
|
|
28043
|
+
* curated controls don't expose can still be passed verbatim. Auto-derivation
|
|
28044
|
+
* means the catalog can never drift from the command's real option set.
|
|
28045
|
+
*
|
|
28046
|
+
* Session-global flags (handled by the studio Session bar / `studio-child-args`)
|
|
28047
|
+
* and the auto-added `--help` / `--version` are excluded — passing them per-run
|
|
28048
|
+
* would conflict with the session-wide wiring.
|
|
28049
|
+
*/
|
|
28050
|
+
/**
|
|
28051
|
+
* Long flag names handled by the session bar / `studio-child-args` (forwarded
|
|
28052
|
+
* to every spawned child once, session-wide). Excluded from the per-target
|
|
28053
|
+
* catalog so a user does not re-specify them per-run and collide with the
|
|
28054
|
+
* session-wide value. Plus the Commander-managed `--help` / `--version`.
|
|
28055
|
+
*/
|
|
28056
|
+
const CATALOG_EXCLUDED_FLAGS = new Set([
|
|
28057
|
+
"--app",
|
|
28058
|
+
"--profile",
|
|
28059
|
+
"--region",
|
|
28060
|
+
"--context",
|
|
28061
|
+
"--from-cfn-stack",
|
|
28062
|
+
"--assume-role",
|
|
28063
|
+
"--help",
|
|
28064
|
+
"--version"
|
|
28065
|
+
]);
|
|
28066
|
+
const KIND_FACTORIES = {
|
|
28067
|
+
lambda: {
|
|
28068
|
+
command: "invoke",
|
|
28069
|
+
factory: createLocalInvokeCommand
|
|
28070
|
+
},
|
|
28071
|
+
agentcore: {
|
|
28072
|
+
command: "invoke-agentcore",
|
|
28073
|
+
factory: createLocalInvokeAgentCoreCommand
|
|
28074
|
+
},
|
|
28075
|
+
api: {
|
|
28076
|
+
command: "start-api",
|
|
28077
|
+
factory: createLocalStartApiCommand
|
|
28078
|
+
},
|
|
28079
|
+
alb: {
|
|
28080
|
+
command: "start-alb",
|
|
28081
|
+
factory: createLocalStartAlbCommand
|
|
28082
|
+
},
|
|
28083
|
+
ecs: {
|
|
28084
|
+
command: "start-service",
|
|
28085
|
+
factory: createLocalStartServiceCommand
|
|
28086
|
+
}
|
|
28087
|
+
};
|
|
28088
|
+
let cached;
|
|
28089
|
+
/**
|
|
28090
|
+
* Build (and memoize) the full per-kind flag catalog by introspecting each
|
|
28091
|
+
* runnable kind's Commander command factory.
|
|
28092
|
+
*
|
|
28093
|
+
* Each factory calls `setEmbedConfig(opts.embedConfig)` at construction — with
|
|
28094
|
+
* no opts that resets the active embed config to cdk-local defaults, which
|
|
28095
|
+
* would wipe a host CLI's branding. So the active config is snapshotted and
|
|
28096
|
+
* each factory is re-handed it: branding is preserved AND the derived flag
|
|
28097
|
+
* descriptions reflect the host's active branding. The `finally` restore is a
|
|
28098
|
+
* belt-and-suspenders against a factory that ignores the passed config.
|
|
28099
|
+
* Memoized: the factories are instantiated exactly once per process, not per
|
|
28100
|
+
* page render.
|
|
28101
|
+
*/
|
|
28102
|
+
function buildFlagCatalog() {
|
|
28103
|
+
if (cached) return cached;
|
|
28104
|
+
const savedEmbedConfig = getEmbedConfig();
|
|
28105
|
+
try {
|
|
28106
|
+
const out = {};
|
|
28107
|
+
for (const kind of Object.keys(KIND_FACTORIES)) {
|
|
28108
|
+
const { command, factory } = KIND_FACTORIES[kind];
|
|
28109
|
+
const cmd = factory({ embedConfig: savedEmbedConfig });
|
|
28110
|
+
const flags = [];
|
|
28111
|
+
for (const opt of cmd.options) {
|
|
28112
|
+
if (opt.hidden) continue;
|
|
28113
|
+
if (opt.long && CATALOG_EXCLUDED_FLAGS.has(opt.long)) continue;
|
|
28114
|
+
flags.push({
|
|
28115
|
+
flags: opt.flags,
|
|
28116
|
+
description: opt.description ?? ""
|
|
28117
|
+
});
|
|
28118
|
+
}
|
|
28119
|
+
out[kind] = {
|
|
28120
|
+
command,
|
|
28121
|
+
flags
|
|
28122
|
+
};
|
|
28123
|
+
}
|
|
28124
|
+
cached = out;
|
|
28125
|
+
return out;
|
|
28126
|
+
} finally {
|
|
28127
|
+
setEmbedConfig(savedEmbedConfig);
|
|
28128
|
+
}
|
|
28129
|
+
}
|
|
28130
|
+
/**
|
|
28131
|
+
* Tokenize a raw extra-args string into discrete argv elements, honoring
|
|
28132
|
+
* single / double quotes and backslash escaping so values with spaces survive
|
|
28133
|
+
* (`--name "two words"` -> `['--name', 'two words']`). studio spawns children
|
|
28134
|
+
* WITHOUT a shell (argv array), so the tokens are appended verbatim — there is
|
|
28135
|
+
* no shell-injection surface; the child command still validates each arg.
|
|
28136
|
+
*
|
|
28137
|
+
* Returns `[]` for an empty / whitespace-only input. Throws on an unterminated
|
|
28138
|
+
* quote so a malformed raw-args string fails as a clean boundary error rather
|
|
28139
|
+
* than spawning a child with a mis-split argv.
|
|
28140
|
+
*/
|
|
28141
|
+
function tokenizeRawArgs(raw) {
|
|
28142
|
+
if (raw === void 0) return [];
|
|
28143
|
+
const tokens = [];
|
|
28144
|
+
let current = "";
|
|
28145
|
+
let inToken = false;
|
|
28146
|
+
let quote = null;
|
|
28147
|
+
for (let i = 0; i < raw.length; i++) {
|
|
28148
|
+
const ch = raw[i];
|
|
28149
|
+
if (quote) {
|
|
28150
|
+
if (ch === "\\" && quote === "\"" && i + 1 < raw.length) current += raw[++i];
|
|
28151
|
+
else if (ch === quote) quote = null;
|
|
28152
|
+
else current += ch;
|
|
28153
|
+
continue;
|
|
28154
|
+
}
|
|
28155
|
+
if (ch === "\"" || ch === "'") {
|
|
28156
|
+
quote = ch;
|
|
28157
|
+
inToken = true;
|
|
28158
|
+
continue;
|
|
28159
|
+
}
|
|
28160
|
+
if (ch === "\\" && i + 1 < raw.length) {
|
|
28161
|
+
current += raw[++i];
|
|
28162
|
+
inToken = true;
|
|
28163
|
+
continue;
|
|
28164
|
+
}
|
|
28165
|
+
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
28166
|
+
if (inToken) {
|
|
28167
|
+
tokens.push(current);
|
|
28168
|
+
current = "";
|
|
28169
|
+
inToken = false;
|
|
28170
|
+
}
|
|
28171
|
+
continue;
|
|
28172
|
+
}
|
|
28173
|
+
current += ch;
|
|
28174
|
+
inToken = true;
|
|
28175
|
+
}
|
|
28176
|
+
if (quote) throw new Error(`Raw extra args have an unterminated ${quote} quote.`);
|
|
28177
|
+
if (inToken) tokens.push(current);
|
|
28178
|
+
return tokens;
|
|
28179
|
+
}
|
|
28180
|
+
|
|
28027
28181
|
//#endregion
|
|
28028
28182
|
//#region src/local/studio-option-specs.ts
|
|
28029
28183
|
/**
|
|
@@ -28407,6 +28561,23 @@ const STUDIO_CSS = `
|
|
|
28407
28561
|
.pair-add { align-self: flex-start; background: #1d1d1d; color: #7bd88f; border: 1px solid #2f4030;
|
|
28408
28562
|
border-radius: 3px; cursor: pointer; padding: 3px 9px; font: 12px ui-monospace, monospace; }
|
|
28409
28563
|
.pair-add:hover { background: #243024; }
|
|
28564
|
+
.options select { flex: 1; background: #111; color: #ddd; border: 1px solid #333; border-radius: 3px;
|
|
28565
|
+
padding: 4px 6px; font: 12px ui-monospace, Menlo, monospace; min-width: 0; }
|
|
28566
|
+
.options select:focus { outline: none; border-color: #4ec97a; }
|
|
28567
|
+
details.all-options { margin: 8px 0; border-top: 1px solid #2a2a2a; padding-top: 6px; }
|
|
28568
|
+
details.all-options > summary { color: #8a8a8a; font-size: 12px; cursor: pointer; user-select: none; }
|
|
28569
|
+
details.all-options > summary:hover { color: #bbb; }
|
|
28570
|
+
.all-options .opt-row { display: flex; flex-direction: column; align-items: stretch; gap: 4px; margin: 6px 0; }
|
|
28571
|
+
.all-options input.raw-args {
|
|
28572
|
+
width: 100%; box-sizing: border-box; background: #111; color: #ddd; border: 1px solid #333;
|
|
28573
|
+
border-radius: 3px; padding: 4px 6px; font: 12px ui-monospace, Menlo, monospace;
|
|
28574
|
+
}
|
|
28575
|
+
.all-options input.raw-args:focus { outline: none; border-color: #4ec97a; }
|
|
28576
|
+
.opt-hint { color: #777; font-size: 11px; }
|
|
28577
|
+
.flag-catalog { margin-top: 8px; display: flex; flex-direction: column; gap: 2px; }
|
|
28578
|
+
.flag-row { display: flex; gap: 8px; align-items: baseline; font-size: 11px; }
|
|
28579
|
+
.flag-name { color: #7bd88f; font-family: ui-monospace, Menlo, monospace; white-space: nowrap; }
|
|
28580
|
+
.flag-desc { color: #999; }
|
|
28410
28581
|
.envkv-modes { display: flex; gap: 0; }
|
|
28411
28582
|
.envkv-mode { background: #1a1a1a; color: #999; border: 1px solid #333; cursor: pointer;
|
|
28412
28583
|
padding: 3px 12px; font: 11px ui-monospace, monospace; }
|
|
@@ -28431,6 +28602,7 @@ const STUDIO_SCRIPT = `
|
|
|
28431
28602
|
let shownInvId = null; // lambda invocation whose result is in the workspace
|
|
28432
28603
|
let shownServeId = null; // serve target whose workspace is shown
|
|
28433
28604
|
let shownDetailId = null; // captured request whose read-only detail is shown
|
|
28605
|
+
let studioDockerfiles = []; // Dockerfiles scanned at boot (pinned-ecs image-override picker)
|
|
28434
28606
|
|
|
28435
28607
|
function el(tag, cls, text) {
|
|
28436
28608
|
const e = document.createElement(tag);
|
|
@@ -28447,9 +28619,14 @@ const STUDIO_SCRIPT = `
|
|
|
28447
28619
|
|
|
28448
28620
|
function buildOptions(kind) {
|
|
28449
28621
|
const specs = OPTION_SPECS[kind] || [];
|
|
28450
|
-
|
|
28622
|
+
// The composer always shows an "All options" section (raw extra args + the
|
|
28623
|
+
// auto-derived flag reference), even for kinds with no curated controls.
|
|
28624
|
+
const wrap = el('div', 'options-wrap');
|
|
28451
28625
|
const sec = el('div', 'section options');
|
|
28452
|
-
|
|
28626
|
+
if (specs.length) {
|
|
28627
|
+
sec.appendChild(el('h3', null, 'Options'));
|
|
28628
|
+
wrap.appendChild(sec);
|
|
28629
|
+
}
|
|
28453
28630
|
const getters = [];
|
|
28454
28631
|
const bools = {};
|
|
28455
28632
|
|
|
@@ -28565,12 +28742,96 @@ const STUDIO_SCRIPT = `
|
|
|
28565
28742
|
}
|
|
28566
28743
|
sec.appendChild(row);
|
|
28567
28744
|
});
|
|
28745
|
+
const allOpts = buildAllOptions(kind);
|
|
28746
|
+
wrap.appendChild(allOpts.node);
|
|
28568
28747
|
return {
|
|
28569
|
-
node:
|
|
28748
|
+
node: wrap,
|
|
28570
28749
|
collect: function () {
|
|
28571
28750
|
const out = {};
|
|
28572
28751
|
getters.forEach(function (g) { const kv = g(); out[kv[0]] = kv[1]; });
|
|
28573
|
-
|
|
28752
|
+
// Omit-when-empty: a kind with no curated controls (e.g. api) collects
|
|
28753
|
+
// nothing, so return undefined rather than {} to keep the run/serve
|
|
28754
|
+
// body identical to before this section existed.
|
|
28755
|
+
return Object.keys(out).length ? out : undefined;
|
|
28756
|
+
},
|
|
28757
|
+
collectRaw: allOpts.collectRaw,
|
|
28758
|
+
};
|
|
28759
|
+
}
|
|
28760
|
+
|
|
28761
|
+
// The collapsed "All options" section: a raw extra-args input (appended
|
|
28762
|
+
// verbatim to the spawned child) + the auto-derived, read-only catalog of
|
|
28763
|
+
// every flag the underlying command accepts. The curated controls above
|
|
28764
|
+
// cover the common flags with rich UI; this exposes the rest so the studio
|
|
28765
|
+
// UI is never strictly less capable than the headless CLI (issue #301).
|
|
28766
|
+
const FLAG_CATALOG = window.__FLAG_CATALOG__ || {};
|
|
28767
|
+
|
|
28768
|
+
function buildAllOptions(kind) {
|
|
28769
|
+
const cat = FLAG_CATALOG[kind] || { command: '', flags: [] };
|
|
28770
|
+
const det = el('details', 'all-options');
|
|
28771
|
+
det.appendChild(el('summary', null, 'All options'));
|
|
28772
|
+
|
|
28773
|
+
const rawRow = el('div', 'opt-row opt-col');
|
|
28774
|
+
rawRow.appendChild(el('span', 'opt-label', 'Raw extra args'));
|
|
28775
|
+
const rawIn = el('input', 'raw-args');
|
|
28776
|
+
rawIn.placeholder = '--flag value --other "with spaces"';
|
|
28777
|
+
rawRow.appendChild(rawIn);
|
|
28778
|
+
const hint = cat.command
|
|
28779
|
+
? 'Appended verbatim to the spawned ' + cat.command + ' command. Quote values with spaces.'
|
|
28780
|
+
: 'Appended verbatim to the spawned command. Quote values with spaces.';
|
|
28781
|
+
rawRow.appendChild(el('div', 'opt-hint', hint));
|
|
28782
|
+
det.appendChild(rawRow);
|
|
28783
|
+
|
|
28784
|
+
if (cat.flags.length) {
|
|
28785
|
+
const ref = el('div', 'flag-catalog');
|
|
28786
|
+
ref.appendChild(el('div', 'opt-label', 'Available flags'));
|
|
28787
|
+
cat.flags.forEach(function (f) {
|
|
28788
|
+
const row = el('div', 'flag-row');
|
|
28789
|
+
row.appendChild(el('code', 'flag-name', f.flags));
|
|
28790
|
+
if (f.description) row.appendChild(el('span', 'flag-desc', f.description));
|
|
28791
|
+
ref.appendChild(row);
|
|
28792
|
+
});
|
|
28793
|
+
det.appendChild(ref);
|
|
28794
|
+
}
|
|
28795
|
+
|
|
28796
|
+
return {
|
|
28797
|
+
node: det,
|
|
28798
|
+
collectRaw: function () {
|
|
28799
|
+
const v = rawIn.value.trim();
|
|
28800
|
+
return v === '' ? undefined : v;
|
|
28801
|
+
},
|
|
28802
|
+
};
|
|
28803
|
+
}
|
|
28804
|
+
|
|
28805
|
+
// Image-override picker for a pinned ECS service (issue #301): a select of
|
|
28806
|
+
// the Dockerfiles discovered at boot. Picking one threads an
|
|
28807
|
+
// --image-override flag to start-service so the deployed-registry-pinned
|
|
28808
|
+
// image is rebuilt from local source. Default "(keep pinned image)" => no
|
|
28809
|
+
// override.
|
|
28810
|
+
function buildImageOverridePicker() {
|
|
28811
|
+
const sec = el('div', 'section options');
|
|
28812
|
+
sec.appendChild(el('h3', null, 'Image override'));
|
|
28813
|
+
const row = el('div', 'opt-row');
|
|
28814
|
+
row.appendChild(el('span', 'opt-label', 'Local Dockerfile'));
|
|
28815
|
+
const sel = el('select', 'image-override-select');
|
|
28816
|
+
const none = el('option', null, '(keep pinned image)');
|
|
28817
|
+
none.value = '';
|
|
28818
|
+
sel.appendChild(none);
|
|
28819
|
+
studioDockerfiles.forEach(function (df) {
|
|
28820
|
+
const o = el('option', null, df);
|
|
28821
|
+
o.value = df;
|
|
28822
|
+
sel.appendChild(o);
|
|
28823
|
+
});
|
|
28824
|
+
row.appendChild(sel);
|
|
28825
|
+
sec.appendChild(row);
|
|
28826
|
+
const hint = studioDockerfiles.length
|
|
28827
|
+
? 'This image is pinned to a deployed registry — local edits do not take effect. Pick a Dockerfile to rebuild it locally.'
|
|
28828
|
+
: 'This image is pinned to a deployed registry, but no Dockerfile was found under the app directory.';
|
|
28829
|
+
sec.appendChild(el('div', 'opt-hint', hint));
|
|
28830
|
+
return {
|
|
28831
|
+
node: sec,
|
|
28832
|
+
collect: function () {
|
|
28833
|
+
const v = sel.value.trim();
|
|
28834
|
+
return v === '' ? undefined : v;
|
|
28574
28835
|
},
|
|
28575
28836
|
};
|
|
28576
28837
|
}
|
|
@@ -28580,6 +28841,9 @@ const STUDIO_SCRIPT = `
|
|
|
28580
28841
|
try {
|
|
28581
28842
|
const res = await fetch('/api/targets');
|
|
28582
28843
|
const data = await res.json();
|
|
28844
|
+
// Dockerfiles discovered at boot — offered in a pinned ecs service's
|
|
28845
|
+
// image-override picker (issue #301).
|
|
28846
|
+
studioDockerfiles = Array.isArray(data.dockerfiles) ? data.dockerfiles : [];
|
|
28583
28847
|
pane.querySelectorAll('.group-title,.target,.empty').forEach((n) => n.remove());
|
|
28584
28848
|
let total = 0;
|
|
28585
28849
|
for (const group of data.groups) {
|
|
@@ -28613,7 +28877,7 @@ const STUDIO_SCRIPT = `
|
|
|
28613
28877
|
t.appendChild(btnSlot);
|
|
28614
28878
|
t.onclick = () => selectTarget(entry.id, group.kind);
|
|
28615
28879
|
targetEls.set(entry.id, t);
|
|
28616
|
-
serveMeta.set(entry.id, { dot, btnSlot, kind: group.kind });
|
|
28880
|
+
serveMeta.set(entry.id, { dot, btnSlot, kind: group.kind, pinned: entry.pinned === true });
|
|
28617
28881
|
updateServeRow(entry.id);
|
|
28618
28882
|
}
|
|
28619
28883
|
pane.appendChild(t);
|
|
@@ -28696,7 +28960,7 @@ const STUDIO_SCRIPT = `
|
|
|
28696
28960
|
}
|
|
28697
28961
|
}
|
|
28698
28962
|
|
|
28699
|
-
async function startServe(id, options) {
|
|
28963
|
+
async function startServe(id, options, rawArgs, imageOverride) {
|
|
28700
28964
|
// The serve kind (api / alb / ecs) drives which headless command the
|
|
28701
28965
|
// server spawns; it is recorded on the row when the target list loads.
|
|
28702
28966
|
const meta = serveMeta.get(id);
|
|
@@ -28706,6 +28970,8 @@ const STUDIO_SCRIPT = `
|
|
|
28706
28970
|
try {
|
|
28707
28971
|
const body = { targetId: id, kind };
|
|
28708
28972
|
if (options) body.options = options;
|
|
28973
|
+
if (rawArgs) body.rawArgs = rawArgs;
|
|
28974
|
+
if (imageOverride) body.imageOverride = imageOverride;
|
|
28709
28975
|
const res = await fetch('/api/run', {
|
|
28710
28976
|
method: 'POST',
|
|
28711
28977
|
headers: { 'content-type': 'application/json' },
|
|
@@ -28762,7 +29028,9 @@ const STUDIO_SCRIPT = `
|
|
|
28762
29028
|
: el('button', null, starting ? 'Starting…' : 'Start');
|
|
28763
29029
|
// Per-run options are only set before a start; collected on the Start click.
|
|
28764
29030
|
let collectOpts = function () { return undefined; };
|
|
28765
|
-
|
|
29031
|
+
let collectRaw = function () { return undefined; };
|
|
29032
|
+
let collectImageOverride = function () { return undefined; };
|
|
29033
|
+
btn.onclick = () => { if (running || starting) stopServe(id); else startServe(id, collectOpts(), collectRaw(), collectImageOverride()); };
|
|
28766
29034
|
head.appendChild(btn);
|
|
28767
29035
|
if (errMsg) {
|
|
28768
29036
|
const m = el('div', 'err', errMsg);
|
|
@@ -28771,9 +29039,19 @@ const STUDIO_SCRIPT = `
|
|
|
28771
29039
|
ws.appendChild(head);
|
|
28772
29040
|
|
|
28773
29041
|
if (!running && !starting) {
|
|
29042
|
+
// A pinned ECS service (deployed-registry image) does not pick up local
|
|
29043
|
+
// source edits — offer an image-override Dockerfile picker so it can be
|
|
29044
|
+
// rebuilt locally (issue #301). Local-asset services hot-reload under
|
|
29045
|
+
// --watch and get no picker.
|
|
29046
|
+
if (meta && meta.kind === 'ecs' && meta.pinned) {
|
|
29047
|
+
const io = buildImageOverridePicker();
|
|
29048
|
+
ws.appendChild(io.node);
|
|
29049
|
+
collectImageOverride = io.collect;
|
|
29050
|
+
}
|
|
28774
29051
|
const opt = buildOptions(kind);
|
|
28775
29052
|
if (opt.node) ws.appendChild(opt.node);
|
|
28776
29053
|
collectOpts = opt.collect;
|
|
29054
|
+
collectRaw = opt.collectRaw;
|
|
28777
29055
|
}
|
|
28778
29056
|
|
|
28779
29057
|
const isEcs = meta && meta.kind === 'ecs';
|
|
@@ -28973,7 +29251,7 @@ const STUDIO_SCRIPT = `
|
|
|
28973
29251
|
ws.appendChild(composer);
|
|
28974
29252
|
ws.appendChild(result);
|
|
28975
29253
|
|
|
28976
|
-
active = { id, kind, ta, btn, msg, result, collectOpts: opt.collect };
|
|
29254
|
+
active = { id, kind, ta, btn, msg, result, collectOpts: opt.collect, collectRaw: opt.collectRaw };
|
|
28977
29255
|
btn.onclick = () => runInvoke();
|
|
28978
29256
|
shownInvId = null;
|
|
28979
29257
|
shownDetailId = null;
|
|
@@ -28998,6 +29276,8 @@ const STUDIO_SCRIPT = `
|
|
|
28998
29276
|
const body = { targetId: id, kind, event };
|
|
28999
29277
|
const options = active.collectOpts ? active.collectOpts() : undefined;
|
|
29000
29278
|
if (options) body.options = options;
|
|
29279
|
+
const rawArgs = active.collectRaw ? active.collectRaw() : undefined;
|
|
29280
|
+
if (rawArgs) body.rawArgs = rawArgs;
|
|
29001
29281
|
const res = await fetch('/api/run', {
|
|
29002
29282
|
method: 'POST',
|
|
29003
29283
|
headers: { 'content-type': 'application/json' },
|
|
@@ -29396,6 +29676,7 @@ function renderStudioHtml(appLabel, cliName) {
|
|
|
29396
29676
|
</section>
|
|
29397
29677
|
</main>
|
|
29398
29678
|
<script>window.__OPTION_SPECS__ = ${JSON.stringify(OPTION_SPECS).replace(/</g, "\\u003c")};<\/script>
|
|
29679
|
+
<script>window.__FLAG_CATALOG__ = ${JSON.stringify(buildFlagCatalog()).replace(/</g, "\\u003c")};<\/script>
|
|
29399
29680
|
<script>${STUDIO_SCRIPT}<\/script>
|
|
29400
29681
|
</body>
|
|
29401
29682
|
</html>`;
|
|
@@ -29452,6 +29733,33 @@ function toStudioTargetGroups(listing) {
|
|
|
29452
29733
|
}
|
|
29453
29734
|
];
|
|
29454
29735
|
}
|
|
29736
|
+
/**
|
|
29737
|
+
* Annotate the servable `ecs` service entries of `groups` with `pinned: true`
|
|
29738
|
+
* when `classify(targetId)` returns true (issue #301). `classify` decides
|
|
29739
|
+
* pinned (deployed-registry image) vs local CDK asset for one service id; the
|
|
29740
|
+
* caller supplies it (studio's boot does `resolveEcsServiceTarget` +
|
|
29741
|
+
* `isLocalCdkAssetImage`, swallowing resolution failures as "not pinned").
|
|
29742
|
+
* Mutates the entries in place and returns whether ANY service was pinned, so
|
|
29743
|
+
* the caller can skip the (otherwise pointless) Dockerfile scan for an
|
|
29744
|
+
* all-local-asset app. Non-ecs groups and non-servable entries (task defs) are
|
|
29745
|
+
* left untouched. Exported so a host CLI building its own studio can reuse the
|
|
29746
|
+
* same pinned-target annotation, and so the boot logic is unit-testable
|
|
29747
|
+
* without a real synth.
|
|
29748
|
+
*/
|
|
29749
|
+
function annotatePinnedEcsTargets(groups, classify) {
|
|
29750
|
+
let anyPinned = false;
|
|
29751
|
+
for (const group of groups) {
|
|
29752
|
+
if (group.kind !== "ecs") continue;
|
|
29753
|
+
for (const entry of group.entries) {
|
|
29754
|
+
if (!entry.servable) continue;
|
|
29755
|
+
if (classify(entry.id)) {
|
|
29756
|
+
entry.pinned = true;
|
|
29757
|
+
anyPinned = true;
|
|
29758
|
+
}
|
|
29759
|
+
}
|
|
29760
|
+
}
|
|
29761
|
+
return anyPinned;
|
|
29762
|
+
}
|
|
29455
29763
|
/** Compile a `*` / `?` glob to an anchored RegExp matched against a target id. */
|
|
29456
29764
|
function globToRegExp(glob) {
|
|
29457
29765
|
const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
@@ -29485,7 +29793,10 @@ async function startStudioServer(options) {
|
|
|
29485
29793
|
const host = options.host ?? "127.0.0.1";
|
|
29486
29794
|
const maxBump = options.maxPortBump ?? 20;
|
|
29487
29795
|
const html = renderStudioHtml(options.appLabel, options.cliName);
|
|
29488
|
-
const targetsJson = JSON.stringify({
|
|
29796
|
+
const targetsJson = JSON.stringify({
|
|
29797
|
+
groups: options.targetGroups,
|
|
29798
|
+
dockerfiles: options.dockerfiles ?? []
|
|
29799
|
+
});
|
|
29489
29800
|
const server = createServer$1((req, res) => handleRequest(req, res, options.bus, html, targetsJson, options));
|
|
29490
29801
|
const boundPort = await listenWithBump(server, host, options.port, maxBump);
|
|
29491
29802
|
return {
|
|
@@ -29815,6 +30126,7 @@ function createStudioDispatcher(config) {
|
|
|
29815
30126
|
writeFileSync(envFile, JSON.stringify(envVars));
|
|
29816
30127
|
args.push("--env-vars", envFile);
|
|
29817
30128
|
}
|
|
30129
|
+
args.push(...tokenizeRawArgs(req.rawArgs));
|
|
29818
30130
|
const { code, stdout, stderr } = await runChild(spawnFn, nodeBin, [config.cliEntry, ...args], config.cwd ?? process.cwd(), invocationId, req.targetId, config.bus, clock);
|
|
29819
30131
|
const durationMs = clock() - startedAt;
|
|
29820
30132
|
const ok = code === 0;
|
|
@@ -30300,7 +30612,9 @@ function createStudioServeManager(config) {
|
|
|
30300
30612
|
...spec.portArgs,
|
|
30301
30613
|
...buildSharedChildArgs(config),
|
|
30302
30614
|
...buildPerRunArgs(req.kind, req.options),
|
|
30303
|
-
...
|
|
30615
|
+
...req.imageOverride && req.imageOverride.trim() !== "" ? ["--image-override", req.targetId + "=" + req.imageOverride.trim()] : [],
|
|
30616
|
+
...config.watch === true ? ["--watch"] : [],
|
|
30617
|
+
...tokenizeRawArgs(req.rawArgs)
|
|
30304
30618
|
];
|
|
30305
30619
|
}
|
|
30306
30620
|
async function start(req) {
|
|
@@ -30521,7 +30835,7 @@ const STUDIO_TARGET_KINDS = [
|
|
|
30521
30835
|
*/
|
|
30522
30836
|
function coerceRunRequest(body) {
|
|
30523
30837
|
if (typeof body !== "object" || body === null) throw new Error("Request body must be a JSON object.");
|
|
30524
|
-
const { targetId, kind, event, options } = body;
|
|
30838
|
+
const { targetId, kind, event, options, rawArgs, imageOverride } = body;
|
|
30525
30839
|
if (typeof targetId !== "string" || targetId.trim() === "") throw new Error("Request body must include a non-empty \"targetId\" string.");
|
|
30526
30840
|
if (typeof kind !== "string" || !STUDIO_TARGET_KINDS.includes(kind)) throw new Error(`Request body "kind" must be one of: ${STUDIO_TARGET_KINDS.join(", ")}.`);
|
|
30527
30841
|
let runOptions;
|
|
@@ -30531,11 +30845,24 @@ function coerceRunRequest(body) {
|
|
|
30531
30845
|
buildPerRunArgs(kind, runOptions);
|
|
30532
30846
|
resolveEnvVars(kind, runOptions);
|
|
30533
30847
|
}
|
|
30848
|
+
let runRawArgs;
|
|
30849
|
+
if (rawArgs !== void 0) {
|
|
30850
|
+
if (typeof rawArgs !== "string") throw new Error("Request body \"rawArgs\" must be a string.");
|
|
30851
|
+
tokenizeRawArgs(rawArgs);
|
|
30852
|
+
runRawArgs = rawArgs;
|
|
30853
|
+
}
|
|
30854
|
+
let runImageOverride;
|
|
30855
|
+
if (imageOverride !== void 0) {
|
|
30856
|
+
if (typeof imageOverride !== "string") throw new Error("Request body \"imageOverride\" must be a string.");
|
|
30857
|
+
if (imageOverride.trim() !== "") runImageOverride = imageOverride;
|
|
30858
|
+
}
|
|
30534
30859
|
return {
|
|
30535
30860
|
targetId,
|
|
30536
30861
|
kind,
|
|
30537
30862
|
event,
|
|
30538
|
-
...runOptions !== void 0 ? { options: runOptions } : {}
|
|
30863
|
+
...runOptions !== void 0 ? { options: runOptions } : {},
|
|
30864
|
+
...runRawArgs !== void 0 ? { rawArgs: runRawArgs } : {},
|
|
30865
|
+
...runImageOverride !== void 0 ? { imageOverride: runImageOverride } : {}
|
|
30539
30866
|
};
|
|
30540
30867
|
}
|
|
30541
30868
|
/**
|
|
@@ -30621,6 +30948,14 @@ async function localStudioCommand(options) {
|
|
|
30621
30948
|
}
|
|
30622
30949
|
const appLabel = stacks.map((s) => s.stackName).join(", ") || appCmd;
|
|
30623
30950
|
const servableEcs = new Set(targetGroups.filter((g) => g.kind === "ecs").flatMap((g) => g.entries.filter((e) => e.servable).map((e) => e.id)));
|
|
30951
|
+
const dockerfiles = annotatePinnedEcsTargets(targetGroups, (id) => {
|
|
30952
|
+
try {
|
|
30953
|
+
return !isLocalCdkAssetImage(resolveEcsServiceTarget(id, stacks));
|
|
30954
|
+
} catch (err) {
|
|
30955
|
+
logger.debug(`studio: could not classify pin status for '${id}': ${err instanceof Error ? err.message : String(err)}`);
|
|
30956
|
+
return false;
|
|
30957
|
+
}
|
|
30958
|
+
}) ? discoverDockerfiles(process.cwd()) : [];
|
|
30624
30959
|
const bus = new StudioEventBus();
|
|
30625
30960
|
const childConfig = {
|
|
30626
30961
|
cliEntry: process.argv[1] ?? "",
|
|
@@ -30651,6 +30986,7 @@ async function localStudioCommand(options) {
|
|
|
30651
30986
|
port,
|
|
30652
30987
|
bus,
|
|
30653
30988
|
targetGroups,
|
|
30989
|
+
dockerfiles,
|
|
30654
30990
|
appLabel,
|
|
30655
30991
|
cliName: getEmbedConfig().cliName,
|
|
30656
30992
|
store,
|
|
@@ -30746,5 +31082,5 @@ function addStudioSpecificOptions(cmd) {
|
|
|
30746
31082
|
}
|
|
30747
31083
|
|
|
30748
31084
|
//#endregion
|
|
30749
|
-
export {
|
|
30750
|
-
//# sourceMappingURL=local-studio-
|
|
31085
|
+
export { DEFAULT_SHADOW_READY_TIMEOUT_MS as $, countTargets as $n, verifyJwtViaDiscovery as $t, MAX_TASKS_SUBNET_RANGE_CAP as A, buildMessageEvent as An, createLocalStartApiCommand as At, runEcsServiceEmulator as B, substituteEnvVarsFromStateAsync as Bn, filterRoutesByApiIdentifier as Bt, isApplicationLoadBalancer as C, bufferToBody as Cn, buildStsClientConfig as Cr, computeCodeImageTag as Ct, serviceStrategy as D, parseConnectionsPath as Dn, addInvokeSpecificOptions as Dt, createLocalStartServiceCommand as E, handleConnectionsRequest as En, classifySourceChange as Et, ecsClusterOption as F, resolveRuntimeImage as Fn, attachStageContext as Ft, parseImageOverrideFlags as G, resolveCfnFallbackRegion as Gn, resolveSelectionExpression as Gt, buildImageOverrideTag as H, createLocalStateProvider as Hn, groupRoutesByServer as Ht, parseMaxTasks as I, EcsTaskResolutionError as In, buildStageMap as It, describePinnedImageUri as J, CfnLocalStateProvider as Jn, buildCognitoJwksUrl as Jt, resolveImageOverrides as K, resolveCfnRegion as Kn, resolveServiceIntegrationParameters as Kt, parseRestartPolicy as L, substituteAgainstState as Ln, materializeLayerFromArn as Lt, addEcsAssumeRoleOptions as M, buildContainerImage as Mn, resolveApiTargetSubset as Mt, addImageOverrideOptions as N, resolveRuntimeCodeMountPath as Nn, createAuthorizerCache as Nt, addRunTaskSpecificOptions as O, buildConnectEvent as On, createLocalInvokeCommand as Ot, buildEcsImageResolutionContext$1 as P, resolveRuntimeFileExtension as Pn, createFileWatcher as Pt, CloudMapRegistry as Q, resolveSingleTarget as Qn, verifyJwtAuthorizer as Qt, resolveEcsAssumeRoleOption as R, substituteAgainstStateAsync as Rn, resolveEnvVars$1 as Rt, resolveAlbTarget as S, probeHostGatewaySupport as Sn, LocalInvokeBuildError as Sr, buildAgentCoreCodeImage as St, addStartServiceSpecificOptions as T, buildMgmtEndpointEnvUrl as Tn, toCmdArgv as Tt, enforceImageOverrideOrphans as U, isCfnFlagPresent as Un, readMtlsMaterialsFromDisk as Ut, ImageOverrideError as V, LocalStateSourceError as Vn, filterRoutesByApiIdentifiers as Vt, mergeForService as W, rejectExplicitCfnStackWithMultipleStacks as Wn, startApiServer as Wt, listPinnedTargets as X, resolveSsmParameters as Xn, createJwksCache as Xt, isLocalCdkAssetImage as Y, collectSsmParameterRefs as Yn, buildJwksUrlFromIssuer as Yt, buildCloudMapIndex as Z, resolveWatchConfig as Zn, verifyCognitoJwt as Zt, formatTargetListing as _, pickResponseTemplate as _n, resolveAgentCoreTarget as _r, AGENTCORE_SESSION_ID_HEADER as _t, createStudioServeManager as a, attachAuthorizers as an, parseSelectionExpressionPath as ar, createLocalInvokeAgentCoreCommand as at, createLocalStartAlbCommand as b, VtlEvaluationError as bn, substituteImagePlaceholders as br, downloadAndExtractS3Bundle as bt, annotatePinnedEcsTargets as c, buildCorsConfigFromCloudFrontChain as cn, pickRefLogicalId as cr, A2A_PATH as ct, toStudioTargetGroups as d, matchRoute as dn, AGENTCORE_AGUI_PROTOCOL as dr, MCP_PATH as dt, buildMethodArn as en, listTargets as er, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as et, renderStudioHtml as f, translateLambdaResponse as fn, AGENTCORE_HTTP_PROTOCOL as fr, MCP_PROTOCOL_VERSION as ft, createLocalListCommand as g, evaluateResponseParameters as gn, pickAgentCoreCandidateStack as gr, signAgentCoreInvocation as gt, addListSpecificOptions as h, buildRestV1Event as hn, AgentCoreResolutionError as hr, AGENTCORE_SIGV4_SERVICE as ht, createLocalStudioCommand as i, invokeTokenAuthorizer as in, filterWebSocketApisByIdentifiers as ir, addInvokeAgentCoreSpecificOptions as it, addCommonEcsServiceOptions as j, architectureToPlatform as jn, createWatchPredicates as jt, createLocalRunTaskCommand as k, buildDisconnectEvent as kn, addStartApiSpecificOptions as kt, filterStudioTargetGroups as l, isFunctionUrlOacFronted as ln, resolveLambdaArnIntrinsic as lr, a2aInvokeOnce as lt, StudioEventBus as m, buildHttpApiV2Event as mn, AGENTCORE_RUNTIME_TYPE as mr, parseSseForJsonRpc as mt, coerceRunRequest as n, evaluateCachedLambdaPolicy as nn, discoverWebSocketApis as nr, getContainerNetworkIp as nt, startStudioProxy as o, applyCorsResponseHeaders as on, webSocketApiMatchesIdentifier as or, invokeAgentCoreWs as ot, createStudioStore as p, applyAuthorizerOverlay as pn, AGENTCORE_MCP_PROTOCOL as pr, mcpInvokeOnce as pt, runImageOverrideBuilds as q, resolveCfnStackName as qn, defaultCredentialsLoader as qt, coerceStopRequest as r, invokeRequestAuthorizer as rn, discoverWebSocketApisOrThrow as rr, attachContainerLogStreamer as rt, createStudioDispatcher as s, buildCorsConfigByApiId as sn, discoverRoutes as sr, A2A_CONTAINER_PORT as st, addStudioSpecificOptions as t, computeRequestIdentityHash as tn, availableWebSocketApiIdentifiers as tr, setShadowReadyTimeoutMs as tt, startStudioServer as u, matchPreflight as un, AGENTCORE_A2A_PROTOCOL as ur, MCP_CONTAINER_PORT as ut, addAlbSpecificOptions as v, selectIntegrationResponse as vn, derivePseudoParametersFromRegion as vr, invokeAgentCore as vt, resolveAlbFrontDoor as w, ConnectionRegistry as wn, resolveProfileCredentials as wr, renderCodeDockerfile as wt, parseLbPortOverrides as x, HOST_GATEWAY_MIN_VERSION as xn, tryResolveImageFnJoin as xr, SUPPORTED_CODE_RUNTIMES as xt, albStrategy as y, tryParseStatus as yn, formatStateRemedy as yr, waitForAgentCorePing as yt, resolveSharedSidecarCredentials as z, substituteEnvVarsFromState as zn, availableApiIdentifiers as zt };
|
|
31086
|
+
//# sourceMappingURL=local-studio-DMYaMyCf.js.map
|