@go-to-k/cdkd 0.204.0 → 0.206.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +131 -9
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -534,6 +534,35 @@ function parseAssumeRoleToken(raw, previous) {
|
|
|
534
534
|
return acc;
|
|
535
535
|
}
|
|
536
536
|
/**
|
|
537
|
+
* Compose `--assume-role` (value-form accumulator) and the separate
|
|
538
|
+
* `--assume-role-auto` boolean flag into the in-process
|
|
539
|
+
* representation `cdkd local start-api` consumes downstream.
|
|
540
|
+
*
|
|
541
|
+
* - both unset -> `undefined` (pass dev creds through)
|
|
542
|
+
* - only `--assume-role-auto` -> `{ perLambda: {}, bareAutoResolve: true }`
|
|
543
|
+
* (per-Lambda auto-resolve for every routed Lambda)
|
|
544
|
+
* - only `--assume-role` -> the value-form accumulator (global ARN
|
|
545
|
+
* and/or per-Lambda map) as-is
|
|
546
|
+
* - both -> accumulator with `bareAutoResolve = true` overlaid;
|
|
547
|
+
* the per-Lambda map still wins for named Lambdas, auto-resolve
|
|
548
|
+
* fills in for every Lambda the map does NOT name
|
|
549
|
+
*
|
|
550
|
+
* Enforces the mutual-exclusion guard: `--assume-role-auto` and a
|
|
551
|
+
* global ARN (`--assume-role <arn>`) both occupy the "default for
|
|
552
|
+
* every other Lambda" slot, so the combination is ambiguous and
|
|
553
|
+
* rejected at boot with a clear error. The per-Lambda map IS
|
|
554
|
+
* compatible with either side.
|
|
555
|
+
*/
|
|
556
|
+
function normalizeStartApiAssumeRole(raw, autoResolve) {
|
|
557
|
+
if (raw === void 0) return autoResolve ? {
|
|
558
|
+
perLambda: {},
|
|
559
|
+
bareAutoResolve: true
|
|
560
|
+
} : void 0;
|
|
561
|
+
if (autoResolve && raw.globalArn) throw new Error(`--assume-role-auto auto-resolves EACH routed Lambda's own execution role, but --assume-role ${raw.globalArn} also names a single global default. These are mutually exclusive on the global slot. Either drop the global ARN to keep --assume-role-auto for every Lambda, or drop --assume-role-auto to keep the global default. Per-Lambda overrides (--assume-role <LogicalId>=<arn>) are compatible with either side.`);
|
|
562
|
+
if (autoResolve) raw.bareAutoResolve = true;
|
|
563
|
+
return raw;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
537
566
|
* Resolve the effective IAM role ARN for a given Lambda. Per-Lambda
|
|
538
567
|
* override wins; otherwise the global default; otherwise `undefined`
|
|
539
568
|
* (no role to assume — pass developer creds through).
|
|
@@ -46636,6 +46665,9 @@ async function localStartApiCommand(target, options) {
|
|
|
46636
46665
|
roleArn: options.roleArn,
|
|
46637
46666
|
region: options.region
|
|
46638
46667
|
});
|
|
46668
|
+
const normalizedAssumeRole = normalizeStartApiAssumeRole(options.assumeRole, options.assumeRoleAuto ?? false);
|
|
46669
|
+
if (normalizedAssumeRole === void 0) delete options.assumeRole;
|
|
46670
|
+
else options.assumeRole = normalizedAssumeRole;
|
|
46639
46671
|
await ensureDockerAvailable();
|
|
46640
46672
|
const appCmd = resolveApp(options.app);
|
|
46641
46673
|
if (!appCmd) throw new Error("No CDK app specified. Pass --app, set CDKD_APP, or add \"app\" to cdk.json.");
|
|
@@ -47202,6 +47234,57 @@ function warnIamRoutes(routesWithAuth) {
|
|
|
47202
47234
|
return true;
|
|
47203
47235
|
}
|
|
47204
47236
|
/**
|
|
47237
|
+
* Resolve the effective IAM role ARN to assume for a single routed
|
|
47238
|
+
* Lambda, honoring the four `--assume-role` forms of issue #256
|
|
47239
|
+
* Option 1 (non-breaking step):
|
|
47240
|
+
*
|
|
47241
|
+
* - per-Lambda override (`<LogicalId>=<arn>`) — wins over every other
|
|
47242
|
+
* form for the named Lambda.
|
|
47243
|
+
* - global default (bare ARN) — used when the per-Lambda map misses.
|
|
47244
|
+
* - bare-auto-resolve (`--assume-role-auto`) — when neither the
|
|
47245
|
+
* per-Lambda map nor a global default applies, resolves THIS
|
|
47246
|
+
* Lambda's own `Role` (its `AWS::Lambda::Function`'s `Role`
|
|
47247
|
+
* property -> role ARN). Resolution sources, in order:
|
|
47248
|
+
* 1. literal-ARN form of `Properties.Role` in the SYNTHESIZED
|
|
47249
|
+
* template (rare in CDK output but possible);
|
|
47250
|
+
* 2. deployed state (`stateBundle.state.resources`) when
|
|
47251
|
+
* `--from-state` / `--from-cfn-stack` is active, via the same
|
|
47252
|
+
* shared helper `cdkd local invoke`'s bare-form uses
|
|
47253
|
+
* (`resolveExecutionRoleArnFromState`).
|
|
47254
|
+
* - flag absent / `--no-assume-role-auto` — returns `undefined`
|
|
47255
|
+
* (per-Lambda map and global default already filtered out by the
|
|
47256
|
+
* null-check at the top; bare-auto-resolve = false short-circuits
|
|
47257
|
+
* before the state lookup).
|
|
47258
|
+
*
|
|
47259
|
+
* The shape-level mutual exclusion (bare-auto-resolve + global ARN
|
|
47260
|
+
* together) is caught at boot by `normalizeStartApiAssumeRole`; this
|
|
47261
|
+
* resolver only sees a well-formed `AssumeRoleOption`.
|
|
47262
|
+
*
|
|
47263
|
+
* Bare-auto-resolve misses (no literal-ARN, no state, state did not
|
|
47264
|
+
* carry the role attribute) warn-and-fall-through to the
|
|
47265
|
+
* dev-creds-passed-through branch — same trade-off `cdkd local invoke
|
|
47266
|
+
* --assume-role` makes when bare auto-resolve cannot find an ARN.
|
|
47267
|
+
*
|
|
47268
|
+
* Exported for unit testing.
|
|
47269
|
+
*/
|
|
47270
|
+
function resolveStartApiAssumeRoleArn(args) {
|
|
47271
|
+
const { logicalId, assumeRole, lambdaResource, stateBundle } = args;
|
|
47272
|
+
if (!assumeRole) return void 0;
|
|
47273
|
+
const explicit = effectiveAssumeRoleArn(logicalId, assumeRole);
|
|
47274
|
+
if (explicit) return explicit;
|
|
47275
|
+
if (!assumeRole.bareAutoResolve) return void 0;
|
|
47276
|
+
const roleProp = (lambdaResource.Properties ?? {})["Role"];
|
|
47277
|
+
if (typeof roleProp === "string" && roleProp.startsWith("arn:")) return roleProp;
|
|
47278
|
+
if (stateBundle) {
|
|
47279
|
+
const fromState = resolveExecutionRoleArnFromState(stateBundle.state, logicalId);
|
|
47280
|
+
if (fromState) {
|
|
47281
|
+
getLogger().info(`--assume-role: auto-resolved execution role for '${logicalId}' from state: ${fromState}`);
|
|
47282
|
+
return fromState;
|
|
47283
|
+
}
|
|
47284
|
+
}
|
|
47285
|
+
getLogger().warn(`--assume-role: could not auto-resolve the execution role ARN for '${logicalId}'. Pair --assume-role-auto with --from-state or --from-cfn-stack so the deployed Role's ARN can be looked up, OR pin the ARN explicitly with --assume-role ${logicalId}=<arn>. Falling back to the developer's shell credentials for this Lambda.`);
|
|
47286
|
+
}
|
|
47287
|
+
/**
|
|
47205
47288
|
* Build the per-Lambda container spec — code dir, env vars (template +
|
|
47206
47289
|
* --env-vars overlay), STS-issued creds when --assume-role names this
|
|
47207
47290
|
* Lambda, optional --debug-port reservation. Errors out with a clear
|
|
@@ -47250,7 +47333,12 @@ async function buildContainerSpec(args) {
|
|
|
47250
47333
|
AWS_LAMBDA_LOG_STREAM_NAME: "local",
|
|
47251
47334
|
...envResult.resolved
|
|
47252
47335
|
};
|
|
47253
|
-
const roleArn =
|
|
47336
|
+
const roleArn = resolveStartApiAssumeRoleArn({
|
|
47337
|
+
logicalId,
|
|
47338
|
+
assumeRole,
|
|
47339
|
+
lambdaResource: lambda.resource,
|
|
47340
|
+
stateBundle
|
|
47341
|
+
});
|
|
47254
47342
|
if (roleArn) {
|
|
47255
47343
|
const creds = await assumeLambdaExecutionRole$1(roleArn, stsRegion);
|
|
47256
47344
|
dockerEnv["AWS_ACCESS_KEY_ID"] = creds.accessKeyId;
|
|
@@ -48021,7 +48109,7 @@ function resolveMtlsConfig(options) {
|
|
|
48021
48109
|
* Builder for the `start-api` subcommand. Wired up by `local.ts`.
|
|
48022
48110
|
*/
|
|
48023
48111
|
function createLocalStartApiCommand() {
|
|
48024
|
-
const startApi = new Command("start-api").description("Run a long-running local HTTP server that maps API Gateway routes (REST v1, HTTP API, Function URL) to Lambda invocations against the AWS Lambda Runtime Interface Emulator (Docker required). Supports Lambda TOKEN/REQUEST authorizers, Cognito User Pool / HTTP v2 JWT authorizers, and AWS_IAM auth (REST v1 `AuthorizationType: AWS_IAM` and Function URL `AuthType: AWS_IAM` — SigV4 signature verification only; IAM policy evaluation is NOT emulated; see https://github.com/go-to-k/cdkd/blob/main/docs/local-emulation.md). When JWKS is unreachable, JWT authorizers fall back to pass-through (every token accepted) with a warn line — local dev fallback. VPC-config Lambdas run locally and surface a warn line at startup; their containers do NOT get attached to the deployed VPC subnets, so calls to private RDS / ElastiCache will fail.").argument("[target]", "Optional API filter. Accepts the bare CDK logical id ('MyHttpApi'; single-stack apps only), stack-qualified logical id ('MyStack:MyHttpApi'), full CDK Construct path ('MyStack/MyHttpApi/Resource'), or an ancestor Construct path that prefix-matches ('MyStack/MyHttpApi'). When omitted, every discovered API gets its own server. Mirrors `cdkd local invoke` / `cdkd local run-task` target syntax.").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("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(new Option("--warm", "Pre-start one container per Lambda at server boot").default(false)).addOption(new Option("--per-lambda-concurrency <n>", "Pool size cap per Lambda (default 2, max 4)").default("2")).addOption(new Option("--no-pull", "Skip docker pull (cached image)")).addOption(new Option("--container-host <host>", "IP the host uses to bind/probe the RIE port (must be a numeric IP — `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--debug-port-base <port>", "Reserve a contiguous --debug-port range (one per Lambda)")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--assume-role <arn-or-pair>", "Assume the Lambda's execution role and forward STS-issued temp creds.
|
|
48112
|
+
const startApi = new Command("start-api").description("Run a long-running local HTTP server that maps API Gateway routes (REST v1, HTTP API, Function URL) to Lambda invocations against the AWS Lambda Runtime Interface Emulator (Docker required). Supports Lambda TOKEN/REQUEST authorizers, Cognito User Pool / HTTP v2 JWT authorizers, and AWS_IAM auth (REST v1 `AuthorizationType: AWS_IAM` and Function URL `AuthType: AWS_IAM` — SigV4 signature verification only; IAM policy evaluation is NOT emulated; see https://github.com/go-to-k/cdkd/blob/main/docs/local-emulation.md). When JWKS is unreachable, JWT authorizers fall back to pass-through (every token accepted) with a warn line — local dev fallback. VPC-config Lambdas run locally and surface a warn line at startup; their containers do NOT get attached to the deployed VPC subnets, so calls to private RDS / ElastiCache will fail.").argument("[target]", "Optional API filter. Accepts the bare CDK logical id ('MyHttpApi'; single-stack apps only), stack-qualified logical id ('MyStack:MyHttpApi'), full CDK Construct path ('MyStack/MyHttpApi/Resource'), or an ancestor Construct path that prefix-matches ('MyStack/MyHttpApi'). When omitted, every discovered API gets its own server. Mirrors `cdkd local invoke` / `cdkd local run-task` target syntax.").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("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(new Option("--warm", "Pre-start one container per Lambda at server boot").default(false)).addOption(new Option("--per-lambda-concurrency <n>", "Pool size cap per Lambda (default 2, max 4)").default("2")).addOption(new Option("--no-pull", "Skip docker pull (cached image)")).addOption(new Option("--container-host <host>", "IP the host uses to bind/probe the RIE port (must be a numeric IP — `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--debug-port-base <port>", "Reserve a contiguous --debug-port range (one per Lambda)")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--assume-role <arn-or-pair>", "Assume the Lambda's execution role and forward STS-issued temp creds. Two forms: (1) `--assume-role <arn>` sets a single global default ARN used for every routed Lambda; (2) `--assume-role <LogicalId>=<arn>` (repeatable) is a per-Lambda override (wins over the global default and over --assume-role-auto for the named Lambda). Pair with --assume-role-auto to auto-resolve every other Lambda. Precedence: per-Lambda > (--assume-role-auto OR global default) > unset (developer creds passed through).").argParser((raw, prev) => parseAssumeRoleToken(raw, prev))).addOption(new Option("--assume-role-auto", "Auto-resolve EACH routed Lambda's own execution role per-Lambda (literal ARN / Fn::GetAtt against template / --from-cfn-stack state). Slower boot — one STS call per Lambda — but the right shape when each Lambda's deployed role differs. Mutually exclusive with `--assume-role <arn>` (global default); errors at boot. Compatible with `--assume-role <LogicalId>=<arn>` per-Lambda overrides — the map wins for named Lambdas, auto-resolve handles the rest.").default(false)).addOption(new Option("--watch", "Hot-reload: watch the CDK app source tree and re-synth + re-discover routes on a source edit (cdk.out / node_modules / .git excluded; honors cdk.json watch.include / watch.exclude). Off by default; the server keeps the previous version serving when synth fails mid-reload.").default(false)).addOption(new Option("--stage <name>", "Select an API Gateway Stage by its 'StageName'. Default: the first Stage attached to each API. Drives event.stageVariables for both REST v1 and HTTP API v2. NOTE: For HTTP API v2 routes, requestContext.stage is always '$default' regardless of this flag (AWS-side limitation — HTTP API only exposes one stage to the integration event); only event.stageVariables is affected for v2 routes. For REST v1 routes the selected StageName is also threaded into requestContext.stage.")).addOption(new Option("--api <id>", "DEPRECATED — use the positional <target> argument instead. Same accepted forms (bare logical id, stack-qualified, Construct path, ancestor prefix). Will be removed in a future major release.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers (issue #448). Use only when the dev credentials cannot read the layer — typically cross-account layers. AWS-published public layers (e.g. Lambda Powertools) are readable from every account and need no role.")).addOption(new Option("--from-state", "Read cdkd S3 state for every routed stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::Join (and AWS pseudo parameters) in Lambda env vars with the deployed physical IDs / attributes. Off by default — pre-PR warn-and-drop semantics are preserved. Turn on for stacks already deployed via cdkd deploy. Mirrors `cdkd local invoke --from-state` / `cdkd local run-task --from-state`. Re-runs against fresh state on every hot-reload firing (--watch).").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via DescribeStackResources and substitute Ref / Fn::ImportValue in Lambda env vars with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the cdkd stack name per routed stack; pass an explicit value when a single CFn stack should serve every routed stack. Mutually exclusive with --from-state. Fn::GetAtt is warn-and-dropped in v1 (CFn DescribeStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-state when the same stack name has state in multiple regions, and with --from-cfn-stack as the CFn client region (cdkd does not have a separate --cfn-stack-region flag).")).addOption(new Option("--mtls-truststore <path>", "PEM-encoded CA bundle for client-certificate verification (mutual TLS). When set, the local server switches from HTTP to HTTPS and the TLS handshake rejects clients whose certificate doesn't chain to one of these CAs. Verified certs are surfaced on the Lambda event under requestContext.identity.clientCert (REST v1) / requestContext.authentication.clientCert (HTTP API v2). Must be set together with --mtls-cert + --mtls-key; partial flag sets are rejected. Generate a CA + server + client cert for local dev: openssl req -x509 -newkey rsa:2048 -nodes -keyout ca-key.pem -out ca.pem -subj \"/CN=cdkd-local-ca\" -days 365; openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-csr.pem -subj \"/CN=localhost\"; openssl x509 -req -in server-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365; openssl req -newkey rsa:2048 -nodes -keyout client-key.pem -out client-csr.pem -subj \"/CN=client\"; openssl x509 -req -in client-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365; curl --cacert ca.pem --cert client-cert.pem --key client-key.pem https://localhost:<port>/...")).addOption(new Option("--mtls-cert <path>", "PEM-encoded server certificate for mutual TLS. Self-signed is fine for local dev. Must be set together with --mtls-truststore + --mtls-key.")).addOption(new Option("--mtls-key <path>", "PEM-encoded server private key matching --mtls-cert. Must be set together with --mtls-truststore + --mtls-cert.")).addOption(new Option("--strict-sigv4", "Opt-in: enforce strict AWS_IAM SigV4 verification. When set, requests whose signature cannot be cryptographically verified (foreign access-key-id, OR no local AWS credentials configured) are denied. DEFAULT off — warn-and-pass with a placeholder principalId, matching cdk-local's `cdkl start-api`. Enable this when you want local parity with the deployed API Gateway's signature enforcement.").default(false)).action(withErrorHandling(localStartApiCommand));
|
|
48025
48113
|
[
|
|
48026
48114
|
...commonOptions,
|
|
48027
48115
|
...appOptions,
|
|
@@ -49285,7 +49373,6 @@ async function localInvokeAgentCoreCommand(target, options) {
|
|
|
49285
49373
|
const isA2a = resolved.protocol === AGENTCORE_A2A_PROTOCOL;
|
|
49286
49374
|
if (resolved.protocol === AGENTCORE_AGUI_PROTOCOL) logger.info("AGUI runtime: routing through the HTTP /invocations + /ws path (AG-UI wire is SSE / WebSocket on port 8080).");
|
|
49287
49375
|
if ((isMcp || isA2a) && options.ws) logger.warn(`--ws applies only to the HTTP / AGUI protocols; ignoring it for this ${resolved.protocol} runtime.`);
|
|
49288
|
-
if (options.wsInteractive && !options.ws) logger.warn("--ws-interactive is meaningful only with --ws; ignoring.");
|
|
49289
49376
|
if (options.sigv4 && (isMcp || isA2a || options.ws)) logger.warn("--sigv4 signs the HTTP /invocations request only; ignoring it for the " + (isMcp ? "MCP" : isA2a ? "A2A" : "/ws WebSocket") + " path.");
|
|
49290
49377
|
const sessionId = options.sessionId ?? randomUUID();
|
|
49291
49378
|
const event = await readEvent$1(options);
|
|
@@ -49335,13 +49422,14 @@ async function localInvokeAgentCoreCommand(target, options) {
|
|
|
49335
49422
|
await new Promise((r) => setTimeout(r, 250));
|
|
49336
49423
|
emitA2aResult(a2a);
|
|
49337
49424
|
} else if (options.ws) {
|
|
49425
|
+
const interactive = process.stdin.isTTY === true;
|
|
49338
49426
|
await waitForAgentCorePing(containerHost, hostPort);
|
|
49339
|
-
const frameSource =
|
|
49340
|
-
logger.info(
|
|
49427
|
+
const frameSource = interactive ? readStdinLines() : void 0;
|
|
49428
|
+
logger.info(interactive ? "Opening the agent /ws WebSocket (interactive — stdin lines = follow-up frames; Ctrl-D to end)..." : "Opening the agent /ws WebSocket and streaming frames...");
|
|
49341
49429
|
const wsResult = await invokeAgentCoreWs(containerHost, hostPort, event, {
|
|
49342
49430
|
sessionId,
|
|
49343
49431
|
timeoutMs: options.timeout,
|
|
49344
|
-
onMessage: (text) => process.stdout.write(text),
|
|
49432
|
+
onMessage: wrapWsOnMessage((text) => process.stdout.write(text), interactive),
|
|
49345
49433
|
...authorization && { authorization },
|
|
49346
49434
|
...frameSource && { frameSource }
|
|
49347
49435
|
});
|
|
@@ -49962,11 +50050,45 @@ async function* readStdinLines() {
|
|
|
49962
50050
|
crlfDelay: Infinity
|
|
49963
50051
|
});
|
|
49964
50052
|
try {
|
|
49965
|
-
for await (const line of rl)
|
|
50053
|
+
for await (const line of rl) {
|
|
50054
|
+
if (line.length === 0) continue;
|
|
50055
|
+
yield line;
|
|
50056
|
+
}
|
|
49966
50057
|
} finally {
|
|
49967
50058
|
rl.close();
|
|
49968
50059
|
}
|
|
49969
50060
|
}
|
|
50061
|
+
/**
|
|
50062
|
+
* REPL prompt indicator for the auto-detected TTY mode. Written to stdout (no
|
|
50063
|
+
* trailing newline) after each received agent frame, so the user has a clear
|
|
50064
|
+
* visual signal that the REPL is waiting for input.
|
|
50065
|
+
*
|
|
50066
|
+
* Exported so a unit test can assert the prompt shape.
|
|
50067
|
+
*/
|
|
50068
|
+
const WS_REPL_PROMPT = "> ";
|
|
50069
|
+
/**
|
|
50070
|
+
* Wrap `onMessage` so each agent WS text frame lands on its own line when the
|
|
50071
|
+
* auto-REPL is active AND a `> ` prompt indicator follows. WS frames carry no
|
|
50072
|
+
* trailing `\n` by protocol (each frame is a discrete message); the cloud
|
|
50073
|
+
* `/ws` endpoint behaves the same. That's correct on the wire but visually
|
|
50074
|
+
* run-on in an interactive terminal — the user's next keystroke concatenates
|
|
50075
|
+
* onto the last frame's tail char and they have no signal that the REPL is
|
|
50076
|
+
* waiting for input. In interactive mode we append `\n` (unless already
|
|
50077
|
+
* present) and then write a `> ` prompt, so each agent message is presented as
|
|
50078
|
+
* its own line and the next input prompt is visible.
|
|
50079
|
+
*
|
|
50080
|
+
* Non-interactive (piped / CI) is unchanged — the raw stdout shape is what
|
|
50081
|
+
* scripts rely on, and the WS-protocol-faithful pass-through stays.
|
|
50082
|
+
*
|
|
50083
|
+
* Exported so a unit test can drive the wrapping without the full WS pipeline.
|
|
50084
|
+
*/
|
|
50085
|
+
function wrapWsOnMessage(sink, interactive) {
|
|
50086
|
+
if (!interactive) return sink;
|
|
50087
|
+
return (text) => {
|
|
50088
|
+
sink(text.endsWith("\n") ? text : `${text}\n`);
|
|
50089
|
+
sink("> ");
|
|
50090
|
+
};
|
|
50091
|
+
}
|
|
49970
50092
|
function readEnvOverridesFile$1(filePath) {
|
|
49971
50093
|
if (!filePath) return void 0;
|
|
49972
50094
|
let raw;
|
|
@@ -49985,7 +50107,7 @@ function readEnvOverridesFile$1(filePath) {
|
|
|
49985
50107
|
return parsed;
|
|
49986
50108
|
}
|
|
49987
50109
|
function createLocalInvokeAgentCoreCommand() {
|
|
49988
|
-
const cmd = new Command("invoke-agentcore").description("Run a Bedrock AgentCore Runtime container locally and invoke it once over its protocol contract: HTTP (POST /invocations + GET /ping on 8080) or MCP (POST /mcp Streamable HTTP on 8000). Resolves the AWS::BedrockAgentCore::Runtime, pulls/builds its container, injects env vars + AWS credentials, and prints the response. For an MCP runtime, runs the session handshake then sends one JSON-RPC request (tools/list by default, or the method/params from --event). Target accepts a CDK display path (MyStack/MyAgent) or stack-qualified logical ID (MyStack:MyAgentRuntime1234). Single-stack apps may omit the stack prefix. Omit <target> in an interactive terminal to pick from a list. Supports the container artifact and the CodeConfiguration managed-runtime artifact (fromCodeAsset, built from source) on the HTTP + MCP protocols; the agent calls real AWS for managed services.").argument("[target]", "CDK display path or stack-qualified logical ID of the AgentCore Runtime to invoke (omit to pick interactively in a TTY)").addOption(new Option("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option("--event-stdin", "Read event JSON from stdin").default(false)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}})")).addOption(new Option("--session-id <id>", "AgentCore runtime session id header value (default: a random UUID)")).addOption(new Option("--ws", "Stream over the HTTP-protocol agent's bidirectional /ws WebSocket endpoint (on 8080) instead of POST /invocations: send --event as the first frame and print every received frame to stdout until the agent closes.
|
|
50110
|
+
const cmd = new Command("invoke-agentcore").description("Run a Bedrock AgentCore Runtime container locally and invoke it once over its protocol contract: HTTP (POST /invocations + GET /ping on 8080) or MCP (POST /mcp Streamable HTTP on 8000). Resolves the AWS::BedrockAgentCore::Runtime, pulls/builds its container, injects env vars + AWS credentials, and prints the response. For an MCP runtime, runs the session handshake then sends one JSON-RPC request (tools/list by default, or the method/params from --event). Target accepts a CDK display path (MyStack/MyAgent) or stack-qualified logical ID (MyStack:MyAgentRuntime1234). Single-stack apps may omit the stack prefix. Omit <target> in an interactive terminal to pick from a list. Supports the container artifact and the CodeConfiguration managed-runtime artifact (fromCodeAsset, built from source) on the HTTP + MCP protocols; the agent calls real AWS for managed services.").argument("[target]", "CDK display path or stack-qualified logical ID of the AgentCore Runtime to invoke (omit to pick interactively in a TTY)").addOption(new Option("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option("--event-stdin", "Read event JSON from stdin").default(false)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}})")).addOption(new Option("--session-id <id>", "AgentCore runtime session id header value (default: a random UUID)")).addOption(new Option("--ws", "Stream over the HTTP-protocol agent's bidirectional /ws WebSocket endpoint (on 8080) instead of POST /invocations: send --event as the first frame and print every received frame to stdout until the agent closes. When stdin is a TTY, auto-enters a REPL — each typed line is sent as a follow-up text frame until Ctrl-D / agent close; pipe from /dev/null to force one-shot in a TTY. Ignored for an MCP runtime.").default(false)).addOption(new Option("--bearer-token <jwt>", "Bearer JWT to present when the runtime declares a customJwtAuthorizer. Verified against the runtime OIDC discovery URL (signature / issuer / expiry / audience) before the container starts, then forwarded to /invocations as Authorization: Bearer <jwt>.")).addOption(new Option("--no-verify-auth", "Skip inbound JWT verification even when the runtime declares a customJwtAuthorizer (local-dev escape hatch). A --bearer-token, if given, is still forwarded.")).addOption(new Option("--sigv4", "Sign the /invocations POST with AWS SigV4 (service bedrock-agentcore) using the resolved credentials, matching the cloud default when the runtime declares no customJwtAuthorizer. Opt-in: default unsigned. Mutually exclusive with --bearer-token; ignored on a JWT-protected runtime.").default(false)).addOption(new Option("--platform <platform>", "docker --platform for the agent container (linux/amd64 or linux/arm64)").choices(["linux/amd64", "linux/arm64"]).default("linux/arm64")).addOption(new Option("--no-pull", "Skip docker pull (use cached image) — no-op for the local-build path")).addOption(new Option("--no-build", "Skip docker build on the local-asset path (use the previously-built tag). No-op for the ECR / registry pull paths.")).addOption(new Option("--container-host <host>", "Host to bind the agent port to").default("127.0.0.1")).addOption(new Option("--timeout <ms>", "Per-request timeout in milliseconds. Applied to POST /invocations, POST /mcp, and the /ws open-to-close window. Raise this for long-running agent calls that exceed the default.").default(12e4).argParser(parseTimeoutMs)).addOption(new Option("--assume-role [arn]", "Assume the runtime's execution role and forward STS-issued temp credentials to the container so the agent runs with the deployed role. Three forms: (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) uses the runtime's RoleArn when it is a literal ARN; (3) `--no-assume-role` opts out. Off by default — the developer's shell credentials are forwarded unchanged.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries. Same-account / same-region pulls do not need this flag.")).addOption(new Option("--from-state", "Load cdkd's S3 state for the target stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::ImportValue in env vars with the deployed physical IDs / cross-stack exports. Mutually exclusive with --from-cfn-stack.").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via DescribeStackResources and substitute Ref / Fn::ImportValue in env vars with the deployed physical IDs / exports. For CDK apps deployed via the upstream CDK CLI. Bare form uses the resolved stack name; pass an explicit value when the CFn stack name differs. Mutually exclusive with --from-state.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).action(withErrorHandling(async (target, options) => {
|
|
49989
50111
|
await localInvokeAgentCoreCommand(target, options);
|
|
49990
50112
|
}));
|
|
49991
50113
|
[
|
|
@@ -51931,7 +52053,7 @@ function reorderArgs(argv) {
|
|
|
51931
52053
|
*/
|
|
51932
52054
|
async function main() {
|
|
51933
52055
|
const program = new Command();
|
|
51934
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
52056
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.206.0");
|
|
51935
52057
|
program.addCommand(createBootstrapCommand());
|
|
51936
52058
|
program.addCommand(createSynthCommand());
|
|
51937
52059
|
program.addCommand(createListCommand());
|