@go-to-k/cdkd 0.190.0 → 0.192.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { _ as withSkipPrefix, a as runDockerStreaming, c as getLogger, d as getLiveRenderer, f as PATTERN_B_NAME_PROPERTIES, g as generateResourceNameWithFallback, h as generateResourceName, i as runDockerForeground, n as formatDockerLoginError, p as PATTERN_B_RESOURCE_TYPES, r as getDockerCmd, u as runStackBuffered, v as withStackName } from "./docker-cmd-iDMcWcre.js";
3
- import { A as S3StateBackend, B as resolveCaptureObservedState, C as assertRegionMatch, D as DagBuilder, E as DiffCalculator, F as buildDockerImage, G as CFN_TEMPLATE_BODY_LIMIT, H as resolveStateBucketWithDefault, I as Synthesizer, J as findLargeInlineResources, K as CFN_TEMPLATE_URL_LIMIT, L as getDefaultStateBucketName, M as AssetPublisher, N as stringifyValue, O as TemplateParser, P as WorkGraph, Q as resolveBucketRegion, R as getLegacyStateBucketName, S as CloudControlProvider, T as applyRoleArnIfSet, U as resolveStateBucketWithDefaultAndSource, V as resolveSkipPrefix, W as warnDeprecatedNoPrefixCliFlag, X as AssemblyReader, Y as uploadCfnTemplate, _ as matchesCdkPath, a as withRetry, at as LocalStartServiceError, b as ProviderRegistry, bt as withErrorHandling, c as bold, ct as NestedStackChildDirectDestroyError, d as green, dt as ResourceTimeoutError, et as CdkdError, f as red, ft as ResourceUpdateNotSupportedError, g as CDK_PATH_TAG, h as collectInlinePolicyNamesManagedBySiblings, i as withResourceDeadline, it as LocalMigrateError, j as shouldRetainResource, k as LockManager, l as cyan, lt as PartialFailureError, m as IAMRoleProvider, mt as StackTerminationProtectionError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, o as IMPLICIT_DELETE_DEPENDENCIES, p as yellow, pt as StackHasActiveImportsError, q as MIGRATE_TMP_PREFIX, r as DeployEngine, rt as LocalInvokeBuildError$1, s as formatResourceLine, st as MissingCdkCliError, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, ut as ProvisioningError, v as normalizeAwsTagsToCfn, w as IntrinsicFunctionResolver, x as findActionableSilentDrops, y as resolveExplicitPhysicalId, yt as normalizeAwsError, z as resolveApp } from "./deploy-engine-CapyHC2m.js";
3
+ import { A as S3StateBackend, B as resolveCaptureObservedState, C as assertRegionMatch, D as DagBuilder, E as DiffCalculator, F as buildDockerImage, G as CFN_TEMPLATE_BODY_LIMIT, H as resolveStateBucketWithDefault, I as Synthesizer, J as findLargeInlineResources, K as CFN_TEMPLATE_URL_LIMIT, L as getDefaultStateBucketName, M as AssetPublisher, N as stringifyValue, O as TemplateParser, P as WorkGraph, Q as resolveBucketRegion, R as getLegacyStateBucketName, S as CloudControlProvider, T as applyRoleArnIfSet, U as resolveStateBucketWithDefaultAndSource, V as resolveSkipPrefix, W as warnDeprecatedNoPrefixCliFlag, X as AssemblyReader, Y as uploadCfnTemplate, _ as matchesCdkPath, a as withRetry, at as LocalStartServiceError, b as ProviderRegistry, bt as withErrorHandling, c as bold, ct as NestedStackChildDirectDestroyError, d as green, dt as ResourceTimeoutError, et as CdkdError, f as red, ft as ResourceUpdateNotSupportedError, g as CDK_PATH_TAG, h as collectInlinePolicyNamesManagedBySiblings, i as withResourceDeadline, it as LocalMigrateError, j as shouldRetainResource, k as LockManager, l as cyan, lt as PartialFailureError, m as IAMRoleProvider, mt as StackTerminationProtectionError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, o as IMPLICIT_DELETE_DEPENDENCIES, p as yellow, pt as StackHasActiveImportsError, q as MIGRATE_TMP_PREFIX, r as DeployEngine, rt as LocalInvokeBuildError$1, s as formatResourceLine, st as MissingCdkCliError, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, ut as ProvisioningError, v as normalizeAwsTagsToCfn, w as IntrinsicFunctionResolver, x as findActionableSilentDrops, y as resolveExplicitPhysicalId, yt as normalizeAwsError, z as resolveApp } from "./deploy-engine-DbR6HZHx.js";
4
4
  import { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-B15NAPbL.js";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
  import { randomBytes, randomUUID } from "node:crypto";
@@ -62,8 +62,8 @@ import { CreateVectorBucketCommand, DeleteIndexCommand, DeleteVectorBucketComman
62
62
  import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableCommand as DeleteTableCommand$2, GetTableBucketCommand, GetTableCommand as GetTableCommand$1, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand as ListTablesCommand$1, ListTagsForResourceCommand as ListTagsForResourceCommand$19, NotFoundException as NotFoundException$5, S3TablesClient } from "@aws-sdk/client-s3tables";
63
63
  import { AttachLoadBalancerTargetGroupsCommand, AttachLoadBalancersCommand, AttachTrafficSourcesCommand, AutoScalingClient, CreateAutoScalingGroupCommand, CreateOrUpdateTagsCommand, DeleteAutoScalingGroupCommand, DeleteLifecycleHookCommand, DeleteNotificationConfigurationCommand, DeleteTagsCommand as DeleteTagsCommand$1, DescribeAutoScalingGroupsCommand, DescribeLifecycleHooksCommand, DescribeNotificationConfigurationsCommand, DescribeTrafficSourcesCommand, DetachLoadBalancerTargetGroupsCommand, DetachLoadBalancersCommand, DetachTrafficSourcesCommand, DisableMetricsCollectionCommand, EnableMetricsCollectionCommand, PutLifecycleHookCommand, PutNotificationConfigurationCommand, UpdateAutoScalingGroupCommand } from "@aws-sdk/client-auto-scaling";
64
64
  import { Document, Pair, Scalar, YAMLMap, YAMLSeq, parse as parse$1, stringify } from "yaml";
65
- import { createLocalStateProvider, isCfnFlagPresent, rejectExplicitCfnStackWithMultipleStacks, setEmbedConfig, substituteAgainstState, substituteAgainstStateAsync, substituteEnvVarsFromState, substituteEnvVarsFromStateAsync } from "cdk-local";
66
- import { CloudMapRegistry, ConnectionRegistry, EcsTaskResolutionError, HOST_GATEWAY_MIN_VERSION, LocalInvokeBuildError, architectureToPlatform, attachAuthorizers, attachStageContext, availableApiIdentifiers, bufferToBody, buildCloudMapIndex, buildCognitoJwksUrl, buildConnectEvent, buildContainerImage, buildCorsConfigByApiId, buildCorsConfigFromCloudFrontChain, buildDisconnectEvent, buildJwksUrlFromIssuer, buildMessageEvent, buildMgmtEndpointEnvUrl, buildStageMap, createAuthorizerCache, createFileWatcher, createJwksCache, createWatchPredicates, defaultCredentialsLoader, derivePseudoParametersFromRegion, discoverRoutes, discoverWebSocketApis, filterRoutesByApiIdentifier, getContainerNetworkIp, groupRoutesByServer, handleConnectionsRequest, materializeLayerFromArn, parseConnectionsPath, parseSelectionExpressionPath, probeHostGatewaySupport, readMtlsMaterialsFromDisk, resolveEnvVars, resolveRuntimeCodeMountPath, resolveRuntimeFileExtension, resolveRuntimeImage, resolveWatchConfig, startApiServer, substituteImagePlaceholders, tryResolveImageFnJoin } from "cdk-local/internal";
65
+ import { createLocalStateProvider, getEmbedConfig, isCfnFlagPresent, listTargets, rejectExplicitCfnStackWithMultipleStacks, resolveCfnFallbackRegion, setEmbedConfig, substituteAgainstState, substituteAgainstStateAsync, substituteEnvVarsFromState, substituteEnvVarsFromStateAsync } from "cdk-local";
66
+ import { A2A_CONTAINER_PORT, A2A_PATH, AGENTCORE_A2A_PROTOCOL, AGENTCORE_AGUI_PROTOCOL, AGENTCORE_MCP_PROTOCOL, CloudMapRegistry, ConnectionRegistry, EcsTaskResolutionError, HOST_GATEWAY_MIN_VERSION, LocalInvokeBuildError, MCP_CONTAINER_PORT, MCP_PATH, a2aInvokeOnce, architectureToPlatform, attachAuthorizers, attachStageContext, availableApiIdentifiers, bufferToBody, buildAgentCoreCodeImage, buildCloudMapIndex, buildCognitoJwksUrl, buildConnectEvent, buildContainerImage, buildCorsConfigByApiId, buildCorsConfigFromCloudFrontChain, buildDisconnectEvent, buildJwksUrlFromIssuer, buildMessageEvent, buildMgmtEndpointEnvUrl, buildStageMap, createAuthorizerCache, createFileWatcher, createJwksCache, createWatchPredicates, defaultCredentialsLoader, derivePseudoParametersFromRegion, discoverRoutes, discoverWebSocketApis, downloadAndExtractS3Bundle, filterRoutesByApiIdentifier, getContainerNetworkIp, groupRoutesByServer, handleConnectionsRequest, invokeAgentCore, invokeAgentCoreWs, materializeLayerFromArn, mcpInvokeOnce, parseConnectionsPath, parseSelectionExpressionPath, pickAgentCoreCandidateStack, probeHostGatewaySupport, readMtlsMaterialsFromDisk, resolveAgentCoreTarget, resolveEnvVars, resolveRuntimeCodeMountPath, resolveRuntimeFileExtension, resolveRuntimeImage, resolveSingleTarget, resolveWatchConfig, signAgentCoreInvocation, startApiServer, substituteImagePlaceholders, tryResolveImageFnJoin, verifyJwtViaDiscovery, waitForAgentCorePing } from "cdk-local/internal";
67
67
  import { createServer } from "node:net";
68
68
  import { promisify } from "node:util";
69
69
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
@@ -11415,7 +11415,8 @@ var SecretsManagerSecretProvider = class {
11415
11415
  "Description",
11416
11416
  "KmsKeyId",
11417
11417
  "Tags",
11418
- "ReplicaRegions"
11418
+ "ReplicaRegions",
11419
+ "Type"
11419
11420
  ])]]);
11420
11421
  constructor() {
11421
11422
  const awsClients = getAwsClients();
@@ -11444,6 +11445,7 @@ var SecretsManagerSecretProvider = class {
11444
11445
  Region: r["Region"],
11445
11446
  KmsKeyId: r["KmsKeyId"]
11446
11447
  }));
11448
+ if (properties["Type"]) createParams.Type = properties["Type"];
11447
11449
  const secretArn = (await this.smClient.send(new CreateSecretCommand(createParams))).ARN;
11448
11450
  if (!secretArn) throw new Error("CreateSecret did not return ARN");
11449
11451
  this.logger.debug(`Successfully created secret ${logicalId}: ${secretArn}`);
@@ -11470,6 +11472,7 @@ var SecretsManagerSecretProvider = class {
11470
11472
  if (secretString) updateParams.SecretString = secretString;
11471
11473
  if (properties["Description"] !== void 0) updateParams.Description = properties["Description"];
11472
11474
  if (properties["KmsKeyId"] !== void 0 && properties["KmsKeyId"] !== "") updateParams.KmsKeyId = properties["KmsKeyId"];
11475
+ if (properties["Type"]) updateParams.Type = properties["Type"];
11473
11476
  await this.smClient.send(new UpdateSecretCommand(updateParams));
11474
11477
  const newTags = properties["Tags"];
11475
11478
  const oldTags = previousProperties["Tags"];
@@ -11611,6 +11614,7 @@ var SecretsManagerSecretProvider = class {
11611
11614
  return out;
11612
11615
  });
11613
11616
  result["Tags"] = normalizeAwsTagsToCfn(resp.Tags);
11617
+ if (resp.Type !== void 0) result["Type"] = resp.Type;
11614
11618
  return result;
11615
11619
  } catch (err) {
11616
11620
  if (err instanceof ResourceNotFoundException$3) return void 0;
@@ -44392,7 +44396,7 @@ async function runDetached(opts) {
44392
44396
  if (opts.platform) args.push("--platform", opts.platform);
44393
44397
  if (opts.extraHosts) for (const entry of opts.extraHosts) args.push("--add-host", `${entry.host}:${entry.ip}`);
44394
44398
  const host = opts.host ?? "127.0.0.1";
44395
- args.push("-p", `${host}:${opts.hostPort}:8080`);
44399
+ args.push("-p", `${host}:${opts.hostPort}:${opts.containerPort ?? 8080}`);
44396
44400
  if (opts.debugPort !== void 0) args.push("-p", `${host}:${opts.debugPort}:${opts.debugPort}`);
44397
44401
  for (const mount of opts.mounts) {
44398
44402
  const ro = mount.readOnly ? ":ro" : "";
@@ -44402,7 +44406,12 @@ async function runDetached(opts) {
44402
44406
  const ro = mount.readOnly ? ":ro" : "";
44403
44407
  args.push("-v", `${mount.hostPath}:${mount.containerPath}${ro}`);
44404
44408
  }
44405
- for (const [k, v] of Object.entries(opts.env)) args.push("-e", `${k}=${v}`);
44409
+ const sensitiveKeys = opts.sensitiveEnvKeys && opts.sensitiveEnvKeys.size > 0 ? new Set([...SENSITIVE_ENV_KEYS, ...opts.sensitiveEnvKeys]) : SENSITIVE_ENV_KEYS;
44410
+ const passthroughEnv = {};
44411
+ for (const [k, v] of Object.entries(opts.env)) if (sensitiveKeys.has(k)) {
44412
+ args.push("-e", k);
44413
+ passthroughEnv[k] = v;
44414
+ } else args.push("-e", `${k}=${v}`);
44406
44415
  if (opts.tmpfs) args.push("--tmpfs", `${opts.tmpfs.target}:rw,size=${opts.tmpfs.sizeMb}m`);
44407
44416
  if (opts.workingDir) args.push("--workdir", opts.workingDir);
44408
44417
  let entryPointTail = [];
@@ -44413,7 +44422,13 @@ async function runDetached(opts) {
44413
44422
  args.push(opts.image, ...entryPointTail, ...opts.cmd);
44414
44423
  getLogger().child("docker").debug(`${getDockerCmd()} ${redactAwsCredentialsInArgs(args).join(" ")}`);
44415
44424
  try {
44416
- const { stdout } = await execFileAsync$3(getDockerCmd(), args, { maxBuffer: 10 * 1024 * 1024 });
44425
+ const { stdout } = await execFileAsync$3(getDockerCmd(), args, {
44426
+ maxBuffer: 10 * 1024 * 1024,
44427
+ env: {
44428
+ ...process.env,
44429
+ ...passthroughEnv
44430
+ }
44431
+ });
44417
44432
  return stdout.trim();
44418
44433
  } catch (error) {
44419
44434
  const err = error;
@@ -44521,6 +44536,22 @@ const REDACTED_ENV_KEYS = new Set([
44521
44536
  "AWS_SESSION_TOKEN"
44522
44537
  ]);
44523
44538
  /**
44539
+ * Built-in sensitive env keys whose VALUES are always routed through
44540
+ * docker's value-from-process-env form (`-e KEY` rather than
44541
+ * `-e KEY=value`) by {@link runDetached}. Mirrors the redaction-only
44542
+ * {@link REDACTED_ENV_KEYS} set above, but stronger: the value is kept
44543
+ * off the docker `run` argv (and therefore off `ps` / `/proc/<pid>/cmdline`
44544
+ * / verbose debug logs) instead of just being masked at log time. A caller
44545
+ * may extend this set via the `sensitiveEnvKeys` option (used by the
44546
+ * AgentCore local-invoke path to keep decrypted `--from-cfn-stack`
44547
+ * SecureString SSM values off the argv).
44548
+ */
44549
+ const SENSITIVE_ENV_KEYS = new Set([
44550
+ "AWS_ACCESS_KEY_ID",
44551
+ "AWS_SECRET_ACCESS_KEY",
44552
+ "AWS_SESSION_TOKEN"
44553
+ ]);
44554
+ /**
44524
44555
  * Returns a copy of `args` with any `-e <KEY>=<value>` pair whose KEY is
44525
44556
  * in {@link REDACTED_ENV_KEYS} replaced with `-e <KEY>=***`. The actual
44526
44557
  * `args` passed to `spawn` are never mutated — this is for log output
@@ -46070,7 +46101,7 @@ async function localStartApiCommand(target, options) {
46070
46101
  await ensureDockerAvailable();
46071
46102
  const appCmd = resolveApp(options.app);
46072
46103
  if (!appCmd) throw new Error("No CDK app specified. Pass --app, set CDKD_APP, or add \"app\" to cdk.json.");
46073
- const overrides = readEnvOverridesFile$3(options.envVars);
46104
+ const overrides = readEnvOverridesFile$4(options.envVars);
46074
46105
  const debugPortBase = options.debugPortBase ? parseDebugPort(options.debugPortBase) : void 0;
46075
46106
  const perLambdaConcurrency = parsePerLambdaConcurrency(options.perLambdaConcurrency);
46076
46107
  const inlineTmpDirs = /* @__PURE__ */ new Set();
@@ -46689,7 +46720,7 @@ async function buildContainerSpec(args) {
46689
46720
  dockerEnv["AWS_SESSION_TOKEN"] = creds.sessionToken;
46690
46721
  if (stsRegion) dockerEnv["AWS_REGION"] = stsRegion;
46691
46722
  } else {
46692
- forwardAwsEnv$1(dockerEnv);
46723
+ forwardAwsEnv$2(dockerEnv);
46693
46724
  if (profileCredentials) {
46694
46725
  dockerEnv["AWS_ACCESS_KEY_ID"] = profileCredentials.accessKeyId;
46695
46726
  dockerEnv["AWS_SECRET_ACCESS_KEY"] = profileCredentials.secretAccessKey;
@@ -47036,7 +47067,7 @@ function getTemplateEnv$1(resource) {
47036
47067
  return vars;
47037
47068
  }
47038
47069
  /** Read the SAM-shape `--env-vars` JSON file. */
47039
- function readEnvOverridesFile$3(filePath) {
47070
+ function readEnvOverridesFile$4(filePath) {
47040
47071
  if (!filePath) return void 0;
47041
47072
  let raw;
47042
47073
  try {
@@ -47058,7 +47089,7 @@ function readEnvOverridesFile$3(filePath) {
47058
47089
  * handler's AWS SDK calls can authenticate. Used when --assume-role is
47059
47090
  * NOT set for that Lambda — SAM-compatible default.
47060
47091
  */
47061
- function forwardAwsEnv$1(env) {
47092
+ function forwardAwsEnv$2(env) {
47062
47093
  for (const key of [
47063
47094
  "AWS_ACCESS_KEY_ID",
47064
47095
  "AWS_SECRET_ACCESS_KEY",
@@ -48429,7 +48460,7 @@ async function localRunTaskCommand(target, options) {
48429
48460
  }
48430
48461
  const sidecarCredentials = await resolveSidecarCredentials(options, assumedCredentials);
48431
48462
  if (options.profile && sidecarCredentials && !assumedCredentials) profileCredsFile = await writeProfileCredentialsFile(options.profile, sidecarCredentials);
48432
- const envOverrides = readEnvOverridesFile$2(options.envVars);
48463
+ const envOverrides = readEnvOverridesFile$3(options.envVars);
48433
48464
  const runOpts = {
48434
48465
  cluster: options.cluster,
48435
48466
  containerHost: options.containerHost,
@@ -48529,7 +48560,7 @@ async function buildEcsImageResolutionContext$1(candidate, stateProvider, option
48529
48560
  if (!region) logger.warn("Resolver references ${AWS::Region} but cdkd could not determine the target region. Pass --region, set AWS_REGION, or declare env.region on the CDK stack.");
48530
48561
  let accountId;
48531
48562
  try {
48532
- accountId = await resolveCallerAccountId$1(region);
48563
+ accountId = await resolveCallerAccountId$2(region);
48533
48564
  } catch (err) {
48534
48565
  logger.warn(`Resolver needs \${AWS::AccountId} but STS GetCallerIdentity failed: ${err instanceof Error ? err.message : String(err)}. Substitution will be skipped; affected env / secret entries will be dropped with per-key warnings.`);
48535
48566
  }
@@ -48559,7 +48590,7 @@ function pickCandidateStack$1(stackPattern, stacks) {
48559
48590
  const matched = matchStacks(stacks, [stackPattern]);
48560
48591
  if (matched.length === 1) return matched[0];
48561
48592
  }
48562
- async function resolveCallerAccountId$1(region) {
48593
+ async function resolveCallerAccountId$2(region) {
48563
48594
  const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
48564
48595
  const sts = new STSClient({ ...region && { region } });
48565
48596
  try {
@@ -48573,7 +48604,7 @@ async function resolveCallerAccountId$1(region) {
48573
48604
  * `cdkd local invoke --env-vars`: top-level keys are container names, with
48574
48605
  * `Parameters` reserved for global entries.
48575
48606
  */
48576
- function readEnvOverridesFile$2(filePath) {
48607
+ function readEnvOverridesFile$3(filePath) {
48577
48608
  if (!filePath) return void 0;
48578
48609
  let raw;
48579
48610
  try {
@@ -49488,7 +49519,7 @@ async function runOneTarget(target, runState, stacks, options, discovery, skipPu
49488
49519
  resolvedRoleArn = options.assumeTaskRole;
49489
49520
  assumedCredentials = await assumeTaskRole(resolvedRoleArn, options.region);
49490
49521
  }
49491
- const envOverrides = readEnvOverridesFile$1(options.envVars);
49522
+ const envOverrides = readEnvOverridesFile$2(options.envVars);
49492
49523
  const taskOpts = {
49493
49524
  cluster: options.cluster,
49494
49525
  containerHost: options.containerHost,
@@ -49564,7 +49595,7 @@ async function buildEcsImageResolutionContext(target, stacks, options, stateProv
49564
49595
  if (!region) logger.warn("Resolver references ${AWS::Region} but cdkd could not determine the target region. Pass --region, set AWS_REGION, or declare env.region on the CDK stack.");
49565
49596
  let accountId;
49566
49597
  try {
49567
- accountId = await resolveCallerAccountId(region);
49598
+ accountId = await resolveCallerAccountId$1(region);
49568
49599
  } catch (err) {
49569
49600
  logger.warn(`Resolver needs \${AWS::AccountId} but STS GetCallerIdentity failed: ${err instanceof Error ? err.message : String(err)}. Substitution will be skipped; affected env / secret entries will be dropped with per-key warnings.`);
49570
49601
  }
@@ -49594,7 +49625,7 @@ function pickCandidateStack(stackPattern, stacks) {
49594
49625
  const matched = matchStacks(stacks, [stackPattern]);
49595
49626
  if (matched.length === 1) return matched[0];
49596
49627
  }
49597
- async function resolveCallerAccountId(region) {
49628
+ async function resolveCallerAccountId$1(region) {
49598
49629
  const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
49599
49630
  const sts = new STSClient({ ...region && { region } });
49600
49631
  try {
@@ -49603,7 +49634,7 @@ async function resolveCallerAccountId(region) {
49603
49634
  sts.destroy();
49604
49635
  }
49605
49636
  }
49606
- function readEnvOverridesFile$1(filePath) {
49637
+ function readEnvOverridesFile$2(filePath) {
49607
49638
  if (!filePath) return void 0;
49608
49639
  let raw;
49609
49640
  try {
@@ -49693,6 +49724,812 @@ function createLocalStartServiceCommand() {
49693
49724
  return cmd;
49694
49725
  }
49695
49726
 
49727
+ //#endregion
49728
+ //#region src/cli/commands/local-invoke-agentcore.ts
49729
+ /**
49730
+ * Parser for `--timeout <ms>`. Accepts a positive integer; rejects 0,
49731
+ * negatives, fractions, and non-numeric input.
49732
+ */
49733
+ function parseTimeoutMs(raw) {
49734
+ const parsed = Number(raw);
49735
+ if (!Number.isInteger(parsed) || parsed <= 0) throw new CdkdError(`--timeout must be a positive integer number of milliseconds (got '${raw}').`, "LOCAL_INVOKE_AGENTCORE_TIMEOUT_INVALID");
49736
+ return parsed;
49737
+ }
49738
+ /**
49739
+ * `cdkd local invoke-agentcore <target>` — run a Bedrock AgentCore Runtime container
49740
+ * locally and invoke it once over the AgentCore HTTP contract. Resolves
49741
+ * the `AWS::BedrockAgentCore::Runtime`, pulls / builds its container,
49742
+ * starts it on port 8080, waits for `GET /ping`, POSTs the event to
49743
+ * `POST /invocations`, prints the response, and tears down. Covers the
49744
+ * container artifact and the CodeConfiguration managed-runtime artifact
49745
+ * (fromCodeAsset, built from source) on the HTTP + MCP protocols; the agent's
49746
+ * calls to real AWS go to real AWS (credentials injected like `cdkd local invoke`).
49747
+ */
49748
+ async function localInvokeAgentCoreCommand(target, options) {
49749
+ const logger = getLogger();
49750
+ if (options.verbose) logger.setLevel("debug");
49751
+ warnIfDeprecatedRegion(options);
49752
+ let containerId;
49753
+ let stopLogs;
49754
+ let sigintHandler;
49755
+ let profileCredsFile;
49756
+ let stateProvider;
49757
+ const cleanup = singleFlight(async () => {
49758
+ if (stateProvider) try {
49759
+ stateProvider.dispose();
49760
+ } catch (err) {
49761
+ getLogger().debug(`state provider dispose failed: ${err instanceof Error ? err.message : String(err)}`);
49762
+ }
49763
+ if (stopLogs) try {
49764
+ stopLogs();
49765
+ } catch (err) {
49766
+ getLogger().debug(`streamLogs stop failed: ${err instanceof Error ? err.message : String(err)}`);
49767
+ }
49768
+ if (containerId) try {
49769
+ await removeContainer(containerId);
49770
+ } catch (err) {
49771
+ getLogger().debug(`removeContainer(${containerId}) failed: ${err instanceof Error ? err.message : String(err)}`);
49772
+ }
49773
+ if (profileCredsFile) try {
49774
+ await profileCredsFile.dispose();
49775
+ } catch (err) {
49776
+ getLogger().debug(`Failed to remove profile credentials tmpdir ${profileCredsFile.hostPath}: ${err instanceof Error ? err.message : String(err)}`);
49777
+ }
49778
+ }, (err) => {
49779
+ getLogger().debug(`cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
49780
+ });
49781
+ try {
49782
+ await applyRoleArnIfSet({
49783
+ roleArn: options.roleArn,
49784
+ region: options.region
49785
+ });
49786
+ await ensureDockerAvailable();
49787
+ const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
49788
+ if (options.profile && profileCredentials) profileCredsFile = await writeProfileCredentialsFile(options.profile, profileCredentials);
49789
+ const appCmd = resolveApp(options.app);
49790
+ if (!appCmd) throw new CdkdError(`No CDK app specified. Pass --app, set ${getEmbedConfig().envPrefix}_APP, or add "app" to cdk.json.`, "LOCAL_INVOKE_AGENTCORE_NO_APP");
49791
+ logger.info("Synthesizing CDK app...");
49792
+ const synthesizer = new Synthesizer();
49793
+ const context = parseContextOptions(options.context);
49794
+ const synthOpts = {
49795
+ app: appCmd,
49796
+ output: options.output,
49797
+ ...options.region && { region: options.region },
49798
+ ...options.profile && { profile: options.profile },
49799
+ ...Object.keys(context).length > 0 && { context }
49800
+ };
49801
+ const { stacks } = await synthesizer.synthesize(synthOpts);
49802
+ const resolvedTarget = await resolveSingleTarget(target, {
49803
+ entries: listTargets(stacks).agentCoreRuntimes,
49804
+ message: "Select an AgentCore Runtime to invoke",
49805
+ noun: "AgentCore Runtimes",
49806
+ onMissing: () => new CdkdError(`${getEmbedConfig().cliName} invoke-agentcore requires a <target> (an AgentCore Runtime display path or logical ID). Run \`${getEmbedConfig().cliName} list\` to see them, or run it in a TTY to pick interactively.`, "LOCAL_INVOKE_AGENTCORE_TARGET_REQUIRED")
49807
+ });
49808
+ const candidate = pickAgentCoreCandidateStack(resolvedTarget, stacks);
49809
+ stateProvider = createLocalStateProvider$1(options, candidate?.stackName ?? "", await resolveCfnFallbackRegion(options, candidate?.region));
49810
+ const { context: imageContext, loaded: loadedState } = stateProvider && candidate ? await buildAgentCoreImageContext(candidate, stateProvider, options) : {
49811
+ context: void 0,
49812
+ loaded: void 0
49813
+ };
49814
+ const resolved = resolveAgentCoreTarget(resolvedTarget, stacks, imageContext);
49815
+ logger.info(`Target: ${resolved.stack.stackName}/${resolved.logicalId} (${resolved.protocol})`);
49816
+ const isMcp = resolved.protocol === AGENTCORE_MCP_PROTOCOL;
49817
+ const isA2a = resolved.protocol === AGENTCORE_A2A_PROTOCOL;
49818
+ 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).");
49819
+ if ((isMcp || isA2a) && options.ws) logger.warn(`--ws applies only to the HTTP / AGUI protocols; ignoring it for this ${resolved.protocol} runtime.`);
49820
+ if (options.wsInteractive && !options.ws) logger.warn("--ws-interactive is meaningful only with --ws; ignoring.");
49821
+ 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.");
49822
+ const sessionId = options.sessionId ?? randomUUID();
49823
+ const event = await readEvent$1(options);
49824
+ const mcpRequest = isMcp ? buildMcpRequest(event) : void 0;
49825
+ const a2aRequest = isA2a ? buildA2aRequest(event) : void 0;
49826
+ let authorization;
49827
+ if (isMcp || isA2a) {
49828
+ if (resolved.jwtAuthorizer || options.bearerToken) {
49829
+ const pathLabel = isMcp ? MCP_PATH : A2A_PATH;
49830
+ logger.info(`${resolved.protocol} runtime: invoking the local container's ${pathLabel} directly (vanilla ${resolved.protocol}). An inbound JWT / --bearer-token is an AgentCore managed-plane concern and is not applied locally.`);
49831
+ }
49832
+ } else authorization = await resolveInboundAuthorization(resolved, options);
49833
+ await resolveFromS3BucketIntrinsic(resolved, stateProvider, loadedState, imageContext);
49834
+ const image = await resolveAgentCoreImage(resolved, options, loadedState);
49835
+ const { env: dockerEnv, sensitiveEnvKeys } = await buildContainerEnv(resolved, options, profileCredentials, profileCredsFile, stateProvider, loadedState, imageContext);
49836
+ const hostPort = await pickFreePort();
49837
+ const containerHost = options.containerHost;
49838
+ const containerName = `${getEmbedConfig().resourceNamePrefix}-agentcore-${process.pid}-${Math.random().toString(36).slice(2, 8)}`;
49839
+ const containerPort = isMcp ? MCP_CONTAINER_PORT : isA2a ? A2A_CONTAINER_PORT : void 0;
49840
+ const containerPortLabel = isMcp ? `${MCP_CONTAINER_PORT}${MCP_PATH}` : isA2a ? `${A2A_CONTAINER_PORT}${A2A_PATH}` : "8080";
49841
+ logger.info(`Starting agent container (image=${image}, port=${hostPort} -> ${containerPortLabel})...`);
49842
+ containerId = await runDetached({
49843
+ image,
49844
+ mounts: [],
49845
+ env: dockerEnv,
49846
+ cmd: [],
49847
+ hostPort,
49848
+ host: containerHost,
49849
+ platform: options.platform,
49850
+ name: containerName,
49851
+ ...containerPort !== void 0 && { containerPort },
49852
+ ...sensitiveEnvKeys.size > 0 && { sensitiveEnvKeys }
49853
+ });
49854
+ stopLogs = streamLogs(containerId);
49855
+ sigintHandler = () => {
49856
+ cleanup().then(() => process.exit(130));
49857
+ };
49858
+ process.on("SIGINT", sigintHandler);
49859
+ if (isMcp && mcpRequest) {
49860
+ logger.info(`MCP request: ${mcpRequest.method}`);
49861
+ const mcp = await mcpInvokeOnce(containerHost, hostPort, mcpRequest, { requestTimeoutMs: options.timeout });
49862
+ await new Promise((r) => setTimeout(r, 250));
49863
+ emitMcpResult(mcp);
49864
+ } else if (isA2a && a2aRequest) {
49865
+ logger.info(`A2A request: ${a2aRequest.method}`);
49866
+ const a2a = await a2aInvokeOnce(containerHost, hostPort, a2aRequest, { requestTimeoutMs: options.timeout });
49867
+ await new Promise((r) => setTimeout(r, 250));
49868
+ emitA2aResult(a2a);
49869
+ } else if (options.ws) {
49870
+ await waitForAgentCorePing(containerHost, hostPort);
49871
+ const frameSource = options.wsInteractive ? readStdinLines() : void 0;
49872
+ logger.info(options.wsInteractive ? "Opening the agent /ws WebSocket (interactive — stdin lines = follow-up frames; Ctrl-D to end)..." : "Opening the agent /ws WebSocket and streaming frames...");
49873
+ const wsResult = await invokeAgentCoreWs(containerHost, hostPort, event, {
49874
+ sessionId,
49875
+ timeoutMs: options.timeout,
49876
+ onMessage: (text) => process.stdout.write(text),
49877
+ ...authorization && { authorization },
49878
+ ...frameSource && { frameSource }
49879
+ });
49880
+ await new Promise((r) => setTimeout(r, 250));
49881
+ emitWsResult(wsResult);
49882
+ } else {
49883
+ await waitForAgentCorePing(containerHost, hostPort);
49884
+ const additionalHeaders = await buildSigV4HeadersIfRequested(options, resolved, loadedState, containerHost, hostPort, event, sessionId);
49885
+ const result = await invokeAgentCore(containerHost, hostPort, event, {
49886
+ sessionId,
49887
+ timeoutMs: options.timeout,
49888
+ onChunk: (text) => process.stdout.write(text),
49889
+ ...authorization && { authorization },
49890
+ ...additionalHeaders && { additionalHeaders }
49891
+ });
49892
+ await new Promise((r) => setTimeout(r, 250));
49893
+ emitResult(result);
49894
+ }
49895
+ } finally {
49896
+ if (sigintHandler) process.off("SIGINT", sigintHandler);
49897
+ await cleanup();
49898
+ }
49899
+ }
49900
+ /**
49901
+ * Enforce the runtime's inbound JWT authorizer (when declared) and return
49902
+ * the `Authorization` header to forward to `/invocations`.
49903
+ *
49904
+ * - No authorizer → forward the token verbatim if one was given (no-op
49905
+ * otherwise).
49906
+ * - `--no-verify-auth` → warn + forward without verifying (local-dev escape).
49907
+ * - Authorizer + no token → reject (AgentCore returns 401).
49908
+ * - Authorizer + token → verify against the OIDC discovery URL; reject on
49909
+ * failure (AgentCore returns 403); forward on success. An unreachable
49910
+ * discovery URL falls back to pass-through accept (offline-dev fallback in
49911
+ * {@link verifyJwtViaDiscovery}).
49912
+ *
49913
+ * Exported so a unit test can drive the gate without the full Docker pipeline.
49914
+ */
49915
+ async function resolveInboundAuthorization(resolved, options) {
49916
+ const logger = getLogger();
49917
+ const authorizer = resolved.jwtAuthorizer;
49918
+ const header = options.bearerToken ? `Bearer ${options.bearerToken}` : void 0;
49919
+ if (!authorizer) return header;
49920
+ if (options.verifyAuth === false) {
49921
+ logger.warn(`Runtime '${resolved.logicalId}' declares a customJwtAuthorizer, but --no-verify-auth was set — skipping inbound JWT verification (local-dev escape hatch).`);
49922
+ return header;
49923
+ }
49924
+ if (!header) throw new CdkdError(`Runtime '${resolved.logicalId}' requires an inbound JWT (customJwtAuthorizer). Pass --bearer-token <jwt>, or --no-verify-auth to skip verification for local dev.`, "LOCAL_INVOKE_AGENTCORE_AUTH_REQUIRED");
49925
+ if (!(await verifyJwtViaDiscovery({
49926
+ discoveryUrl: authorizer.discoveryUrl,
49927
+ ...authorizer.allowedAudience && { allowedAudience: authorizer.allowedAudience },
49928
+ ...authorizer.allowedClients && { allowedClients: authorizer.allowedClients },
49929
+ ...authorizer.allowedScopes && { allowedScopes: authorizer.allowedScopes },
49930
+ ...authorizer.customClaims && { customClaims: authorizer.customClaims }
49931
+ }, header, createJwksCache(), { warned: /* @__PURE__ */ new Set() })).allow) throw new CdkdError(`Inbound JWT rejected by the runtime's customJwtAuthorizer (signature / issuer / expiry / audience check failed against ${authorizer.discoveryUrl}).`, "LOCAL_INVOKE_AGENTCORE_AUTH_DENIED");
49932
+ logger.info(`Inbound JWT verified against ${authorizer.discoveryUrl}.`);
49933
+ return header;
49934
+ }
49935
+ /**
49936
+ * Compute the SigV4 headers for the `/invocations` POST when `--sigv4` is
49937
+ * requested. Returns `undefined` (no header overlay) when:
49938
+ *
49939
+ * - `--sigv4` is not set,
49940
+ * - the runtime declares a `customJwtAuthorizer` (the JWT path wins; warns),
49941
+ *
49942
+ * Throws a {@link CdkdError} when `--sigv4` conflicts with
49943
+ * `--bearer-token`, or when no AWS credentials are resolvable for signing.
49944
+ *
49945
+ * Exported so a unit test can drive the gate without the full Docker pipeline.
49946
+ */
49947
+ async function buildSigV4HeadersIfRequested(options, resolved, loaded, host, port, event, sessionId) {
49948
+ if (!options.sigv4) return void 0;
49949
+ if (options.bearerToken) throw new CdkdError(`--sigv4 and --bearer-token are mutually exclusive: pick one inbound auth.`, "LOCAL_INVOKE_AGENTCORE_AUTH_CONFLICT");
49950
+ if (resolved.jwtAuthorizer) {
49951
+ getLogger().warn(`Runtime '${resolved.logicalId}' declares a customJwtAuthorizer; --sigv4 ignored (JWT path takes precedence).`);
49952
+ return;
49953
+ }
49954
+ const region = options.region ?? options.stackRegion ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"] ?? resolved.stack.region;
49955
+ if (!region) throw new CdkdError("--sigv4: no region resolved for the AgentCore signing scope. Pass --region <region>, set AWS_REGION, or use --from-cfn-stack with a region-bound stack.", "LOCAL_INVOKE_AGENTCORE_SIGV4_NO_REGION");
49956
+ const signed = await signAgentCoreInvocation({
49957
+ credentials: await resolveHostCredentialsForSigV4(options, resolved, loaded, region),
49958
+ region,
49959
+ host,
49960
+ port,
49961
+ path: "/invocations",
49962
+ body: JSON.stringify(event ?? {}),
49963
+ sessionId
49964
+ });
49965
+ const headers = {
49966
+ Authorization: signed.authorization,
49967
+ "X-Amz-Date": signed.amzDate,
49968
+ "X-Amz-Content-Sha256": signed.amzContentSha256
49969
+ };
49970
+ if (signed.amzSecurityToken) headers["X-Amz-Security-Token"] = signed.amzSecurityToken;
49971
+ getLogger().info(`Signed /invocations with SigV4 (region=${region}).`);
49972
+ return headers;
49973
+ }
49974
+ /**
49975
+ * Resolve credentials for host-side SigV4 signing. Precedence:
49976
+ * 1. `--assume-role` → STS temp creds (warn + fall through on STS failure);
49977
+ * 2. `--profile` → profile creds (sessionToken when the profile carries one);
49978
+ * 3. shell env (`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / optional
49979
+ * `AWS_SESSION_TOKEN`).
49980
+ *
49981
+ * Throws a {@link CdkdError} when none are available — `--sigv4` cannot
49982
+ * proceed without credentials, unlike the unsigned path.
49983
+ */
49984
+ async function resolveHostCredentialsForSigV4(options, resolved, loaded, region) {
49985
+ const logger = getLogger();
49986
+ const assumeRoleArn = resolveAssumeRoleArn(options, resolved, loaded);
49987
+ if (assumeRoleArn) try {
49988
+ return await assumeAgentCoreExecutionRole(assumeRoleArn, region);
49989
+ } catch (err) {
49990
+ logger.warn(`--assume-role: STS AssumeRole(${assumeRoleArn}) failed for --sigv4 signing: ${err instanceof Error ? err.message : String(err)}. Falling back to ${options.profile ? `--profile ${options.profile}` : "shell credentials"}.`);
49991
+ }
49992
+ if (options.profile) {
49993
+ const creds = await resolveProfileCredentials(options.profile);
49994
+ if (creds?.accessKeyId && creds.secretAccessKey) return {
49995
+ accessKeyId: creds.accessKeyId,
49996
+ secretAccessKey: creds.secretAccessKey,
49997
+ ...creds.sessionToken && { sessionToken: creds.sessionToken }
49998
+ };
49999
+ }
50000
+ const accessKeyId = process.env["AWS_ACCESS_KEY_ID"];
50001
+ const secretAccessKey = process.env["AWS_SECRET_ACCESS_KEY"];
50002
+ if (accessKeyId && secretAccessKey) {
50003
+ const sessionToken = process.env["AWS_SESSION_TOKEN"];
50004
+ return {
50005
+ accessKeyId,
50006
+ secretAccessKey,
50007
+ ...sessionToken && { sessionToken }
50008
+ };
50009
+ }
50010
+ throw new CdkdError("--sigv4: no AWS credentials available to sign the request. Set AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY, pass --profile <name>, or pass --assume-role <arn>.", "LOCAL_INVOKE_AGENTCORE_SIGV4_NO_CREDENTIALS");
50011
+ }
50012
+ /**
50013
+ * Acquire the agent image. A CODE artifact (managed runtime) is built from
50014
+ * source — a fromCodeAsset bundle from its cdk.out asset, a fromS3 bundle
50015
+ * downloaded + extracted from S3. A CONTAINER artifact mirrors the
50016
+ * container-Lambda path: build from a local cdk.out asset when the URI matches
50017
+ * one, else pull from ECR, else pull a plain registry image.
50018
+ *
50019
+ * `loaded` is the `--from-cfn-stack` state record (when available) — threaded
50020
+ * through so a bare `--assume-role` can resolve the execution-role ARN from
50021
+ * state for the fromS3 download.
50022
+ */
50023
+ async function resolveAgentCoreImage(resolved, options, loaded) {
50024
+ const logger = getLogger();
50025
+ const architecture = platformToArchitecture(options.platform);
50026
+ if (resolved.codeArtifact) return resolveAgentCoreCodeImage(resolved, resolved.codeArtifact, options, architecture, loaded);
50027
+ const containerUri = resolved.containerUri;
50028
+ if (containerUri === void 0) throw new CdkdError(`AgentCore Runtime '${resolved.logicalId}' has neither a container image nor a code artifact to run.`, "LOCAL_INVOKE_AGENTCORE_NO_ARTIFACT");
50029
+ const manifestPath = resolved.stack.assetManifestPath;
50030
+ if (manifestPath) {
50031
+ const cdkOutDir = dirname(manifestPath);
50032
+ const manifest = await new AssetManifestLoader().loadManifest(cdkOutDir, resolved.stack.stackName);
50033
+ if (manifest) {
50034
+ const entry = getDockerImageBySourceHash(manifest, containerUri);
50035
+ if (entry) return buildContainerImage$1(entry.asset, cdkOutDir, {
50036
+ architecture,
50037
+ noBuild: options.build === false
50038
+ });
50039
+ }
50040
+ }
50041
+ if (parseEcrUri(containerUri)) {
50042
+ logger.info(`Pulling agent image from ECR: ${containerUri}`);
50043
+ return pullEcrImage(containerUri, {
50044
+ skipPull: options.pull === false,
50045
+ ...options.region !== void 0 && { region: options.region },
50046
+ ...options.ecrRoleArn !== void 0 && { ecrRoleArn: options.ecrRoleArn },
50047
+ ...options.profile !== void 0 && { profile: options.profile }
50048
+ });
50049
+ }
50050
+ await pullImage(containerUri, options.pull === false);
50051
+ return containerUri;
50052
+ }
50053
+ /**
50054
+ * Build a local image from a `CodeConfiguration` (managed-runtime) bundle.
50055
+ *
50056
+ * - fromS3 (`code.s3Source` set, a literal S3 object): download + extract the
50057
+ * bundle, then run the from-source build over the extracted dir.
50058
+ * - fromCodeAsset: locate the source dir in cdk.out via its asset hash, then
50059
+ * run the same from-source build (generated Dockerfile → install deps → run
50060
+ * EntryPoint).
50061
+ */
50062
+ async function resolveAgentCoreCodeImage(resolved, code, options, architecture, loaded) {
50063
+ if (code.s3Source) return resolveAgentCoreCodeImageFromS3(resolved, code, code.s3Source, options, architecture, loaded);
50064
+ const manifestPath = resolved.stack.assetManifestPath;
50065
+ if (!manifestPath) throw new CdkdError(`AgentCore Runtime '${resolved.logicalId}' uses a code artifact, but its stack has no asset manifest in cdk.out to read the bundle source from.`, "LOCAL_INVOKE_AGENTCORE_CODE_NO_MANIFEST");
50066
+ const cdkOutDir = dirname(manifestPath);
50067
+ const loader = new AssetManifestLoader();
50068
+ const manifest = await loader.loadManifest(cdkOutDir, resolved.stack.stackName);
50069
+ const fileAssets = manifest ? loader.getFileAssets(manifest) : void 0;
50070
+ const asset = fileAssets ? fileAssets.get(code.codeAssetHash) ?? findFileAssetByObjectKey(fileAssets, code.codeAssetHash) : void 0;
50071
+ if (!asset) throw new CdkdError(`AgentCore Runtime '${resolved.logicalId}' code bundle (asset ${code.codeAssetHash}) was not found in the cdk.out asset manifest. ${getEmbedConfig().cliName} invoke-agentcore runs a local from-source build of a fromCodeAsset bundle — re-synthesize the app so the asset is staged in cdk.out and retry. (A fromS3 bundle is downloaded from S3 instead; this runtime has no literal Code.S3.Bucket.)`, "LOCAL_INVOKE_AGENTCORE_CODE_ASSET_NOT_FOUND");
50072
+ const sourceDir = loader.getAssetSourcePath(cdkOutDir, asset);
50073
+ if (!existsSync(sourceDir) || !statSync(sourceDir).isDirectory()) throw new CdkdError(`AgentCore Runtime '${resolved.logicalId}' code bundle source '${sourceDir}' does not exist or is not a directory. Re-synthesize the app and retry.`, "LOCAL_INVOKE_AGENTCORE_CODE_SOURCE_MISSING");
50074
+ return buildAgentCoreCodeImage({
50075
+ sourceDir,
50076
+ runtime: code.runtime,
50077
+ entryPoint: code.entryPoint,
50078
+ architecture,
50079
+ noBuild: options.build === false
50080
+ });
50081
+ }
50082
+ /**
50083
+ * Build a local image from a fromS3 CodeConfiguration bundle: download +
50084
+ * extract the S3 object, run the from-source build over the extracted dir, then
50085
+ * clean up the temp dir.
50086
+ *
50087
+ * Credentials mirror the rest of the command: an `--assume-role` ARN (explicit,
50088
+ * or resolved from `--from-cfn-stack` state for the bare form) yields STS temp
50089
+ * creds for the download; otherwise `--profile` / the default chain is used.
50090
+ * The region is `--region` / `--stack-region` / env / the stack's region.
50091
+ */
50092
+ async function resolveAgentCoreCodeImageFromS3(resolved, code, s3Source, options, architecture, loaded) {
50093
+ const logger = getLogger();
50094
+ if (typeof s3Source.bucket !== "string" || s3Source.bucket.length === 0) throw new CdkdError(`AgentCore Runtime '${resolved.logicalId}' fromS3 bundle reached the image step with no literal bucket. This is a cdkd bug — please report it.`, "LOCAL_INVOKE_AGENTCORE_FROMS3_BUCKET_UNRESOLVED");
50095
+ const location = {
50096
+ bucket: s3Source.bucket,
50097
+ key: s3Source.key,
50098
+ ...s3Source.versionId !== void 0 && { versionId: s3Source.versionId }
50099
+ };
50100
+ const region = options.region ?? options.stackRegion ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"] ?? resolved.stack.region;
50101
+ const assumeRoleArn = resolveAssumeRoleArn(options, resolved, loaded);
50102
+ let credentials;
50103
+ if (assumeRoleArn) try {
50104
+ credentials = await assumeAgentCoreExecutionRole(assumeRoleArn, region);
50105
+ } catch (err) {
50106
+ logger.warn(`--assume-role: STS AssumeRole(${assumeRoleArn}) failed for the fromS3 bundle download: ${err instanceof Error ? err.message : String(err)}. Falling back to ${options.profile ? `--profile ${options.profile}` : "the default credentials"}.`);
50107
+ }
50108
+ const bundle = await downloadAndExtractS3Bundle(location, {
50109
+ ...region !== void 0 && { region },
50110
+ ...options.profile !== void 0 && { profile: options.profile },
50111
+ ...credentials !== void 0 && { credentials }
50112
+ });
50113
+ try {
50114
+ return await buildAgentCoreCodeImage({
50115
+ sourceDir: bundle.dir,
50116
+ runtime: code.runtime,
50117
+ entryPoint: code.entryPoint,
50118
+ architecture,
50119
+ noBuild: options.build === false
50120
+ });
50121
+ } finally {
50122
+ await bundle.cleanup();
50123
+ }
50124
+ }
50125
+ /**
50126
+ * Find the file asset whose destination objectKey is `<hash>.zip` (matching the
50127
+ * `Code.S3.Prefix`'s hash) when the source-hash-keyed lookup misses — covers a
50128
+ * synthesizer whose source hash differs from the destination objectKey.
50129
+ */
50130
+ function findFileAssetByObjectKey(fileAssets, hash) {
50131
+ const zip = `${hash}.zip`;
50132
+ for (const asset of fileAssets.values()) if (Object.values(asset.destinations).some((d) => d.objectKey === zip || d.objectKey.endsWith(`/${zip}`))) return asset;
50133
+ }
50134
+ /**
50135
+ * Build the container env + the set of env keys to keep off the `docker run`
50136
+ * argv. Substitutes `--from-cfn-stack` state into the template env (reusing the
50137
+ * shared state load + image-resolution context — Ref / Fn::Sub / Fn::Join +
50138
+ * SSM parameters, with decrypted SecureString values flagged sensitive),
50139
+ * applies `--env-vars` overrides, then injects AWS credentials (`--assume-role`
50140
+ * STS temp creds — resolving an intrinsic RoleArn from state for bare
50141
+ * `--assume-role` — else `--profile` / dev creds).
50142
+ *
50143
+ * The state provider + loaded record + image context are built once by the
50144
+ * caller and shared here, so this does not re-load state.
50145
+ */
50146
+ async function buildContainerEnv(resolved, options, profileCredentials, profileCredsFile, stateProvider, loaded, imageContext) {
50147
+ const logger = getLogger();
50148
+ let templateEnv = resolved.environmentVariables;
50149
+ const sensitiveEnvKeys = /* @__PURE__ */ new Set();
50150
+ if (stateProvider && loaded) {
50151
+ const subContext = {
50152
+ resources: imageContext?.stateResources ?? loaded.resources,
50153
+ consumerRegion: loaded.region
50154
+ };
50155
+ const pseudo = imageContext?.pseudoParameters ?? derivePseudoParametersFromRegion(loaded.region);
50156
+ if (pseudo) subContext.pseudoParameters = pseudo;
50157
+ if (imageContext?.stateParameters) subContext.parameters = imageContext.stateParameters;
50158
+ if (imageContext?.stateSensitiveParameters?.length) subContext.sensitiveParameters = new Set(imageContext.stateSensitiveParameters);
50159
+ const resolver = await stateProvider.buildCrossStackResolver(loaded.region);
50160
+ if (resolver) subContext.crossStackResolver = resolver;
50161
+ const { env, audit } = await substituteEnvVarsFromStateAsync(templateEnv, subContext);
50162
+ templateEnv = env;
50163
+ for (const key of audit.resolvedKeys) logger.debug(`${stateProvider.label}: substituted env var ${key}`);
50164
+ for (const key of audit.sensitiveKeys) sensitiveEnvKeys.add(key);
50165
+ for (const { key, reason } of audit.unresolved) logger.warn(`${stateProvider.label}: could not substitute env var ${key} (${reason}). Override it via --env-vars or it will be dropped.`);
50166
+ }
50167
+ const overrides = readEnvOverridesFile$1(options.envVars);
50168
+ const cdkPath = readCdkPathOrUndefined(resolved.resource);
50169
+ const envResult = resolveEnvVars(resolved.logicalId, cdkPath, templateEnv, overrides);
50170
+ for (const key of envResult.unresolved) {
50171
+ const overrideKeyExample = cdkPath?.replace(/\/Resource$/, "") ?? resolved.logicalId;
50172
+ logger.warn(`Environment variable ${key} contains a CloudFormation intrinsic and was dropped. Override it with --env-vars (e.g. {"${overrideKeyExample}":{"${key}":"<literal>"}}), or pass a state-source flag (e.g. --from-cfn-stack) to recover deployed values.`);
50173
+ }
50174
+ const dockerEnv = { ...envResult.resolved };
50175
+ const assumeRoleArn = resolveAssumeRoleArn(options, resolved, loaded);
50176
+ await applyAgentCoreCredentialEnv(dockerEnv, {
50177
+ ...assumeRoleArn !== void 0 && { assumeRoleArn },
50178
+ ...options.region !== void 0 && { region: options.region },
50179
+ ...profileCredentials !== void 0 && { profileCredentials },
50180
+ ...profileCredsFile !== void 0 && { profileCredsFile: {
50181
+ containerPath: profileCredsFile.containerPath,
50182
+ profileName: profileCredsFile.profileName
50183
+ } }
50184
+ });
50185
+ return {
50186
+ env: dockerEnv,
50187
+ sensitiveEnvKeys
50188
+ };
50189
+ }
50190
+ /**
50191
+ * Resolve a fromS3 bundle's intrinsic `Code.S3.Bucket` to a literal bucket
50192
+ * name in place on `resolved.codeArtifact.s3Source.bucket`. Uses the SAME
50193
+ * state-substitution machinery env vars use under `--from-cfn-stack`, so
50194
+ * every cross-stack intrinsic that path supports (`Ref` / `Fn::ImportValue` /
50195
+ * `Fn::GetStackOutput`) is supported transparently here.
50196
+ *
50197
+ * No-op when there is no intrinsic to resolve. Errors when no state is
50198
+ * available, or when the substitution returns a non-string / unresolved value.
50199
+ *
50200
+ * Exported so a unit test can drive the gate without the full Docker pipeline.
50201
+ */
50202
+ async function resolveFromS3BucketIntrinsic(resolved, stateProvider, loaded, imageContext) {
50203
+ const s3Source = resolved.codeArtifact?.s3Source;
50204
+ if (!s3Source || s3Source.bucketIntrinsic === void 0) return;
50205
+ if (s3Source.bucket !== void 0) return;
50206
+ if (!stateProvider || !loaded) throw new CdkdError(`AgentCore Runtime '${resolved.logicalId}' fromS3 bundle's Code.S3.Bucket is an unresolved intrinsic (${describeIntrinsic(s3Source.bucketIntrinsic)}). Pass --from-cfn-stack so its physical bucket name can be resolved against the deployed stack state.`, "LOCAL_INVOKE_AGENTCORE_FROMS3_BUCKET_INTRINSIC_NO_STATE");
50207
+ const subContext = {
50208
+ resources: imageContext?.stateResources ?? loaded.resources,
50209
+ consumerRegion: loaded.region
50210
+ };
50211
+ const pseudo = imageContext?.pseudoParameters ?? derivePseudoParametersFromRegion(loaded.region);
50212
+ if (pseudo) subContext.pseudoParameters = pseudo;
50213
+ const crossStackResolver = await stateProvider.buildCrossStackResolver(loaded.region);
50214
+ if (crossStackResolver) subContext.crossStackResolver = crossStackResolver;
50215
+ const result = await substituteAgainstStateAsync(s3Source.bucketIntrinsic, subContext);
50216
+ if (result.kind !== "literal") throw new CdkdError(`Could not resolve AgentCore Runtime '${resolved.logicalId}' fromS3 Code.S3.Bucket intrinsic (${describeIntrinsic(s3Source.bucketIntrinsic)}) against the --from-cfn-stack state: ${result.reason}. Confirm the referenced resource / export exists in the deployed stack.`, "LOCAL_INVOKE_AGENTCORE_FROMS3_BUCKET_INTRINSIC_UNRESOLVED");
50217
+ if (typeof result.value !== "string" || result.value.length === 0) throw new CdkdError(`AgentCore Runtime '${resolved.logicalId}' fromS3 Code.S3.Bucket intrinsic resolved to a ${typeof result.value} value, not a bucket name string. (${describeIntrinsic(s3Source.bucketIntrinsic)})`, "LOCAL_INVOKE_AGENTCORE_FROMS3_BUCKET_INTRINSIC_NOT_STRING");
50218
+ s3Source.bucket = result.value;
50219
+ getLogger().info(`Resolved fromS3 Code.S3.Bucket from state: ${describeIntrinsic(s3Source.bucketIntrinsic)} -> ${result.value}`);
50220
+ }
50221
+ /** Render the intrinsic key for an error / log message (e.g. `Ref:Bucket1`). */
50222
+ function describeIntrinsic(value) {
50223
+ if (!value || typeof value !== "object") return String(value);
50224
+ const obj = value;
50225
+ const key = Object.keys(obj)[0] ?? "?";
50226
+ const arg = obj[key];
50227
+ if (typeof arg === "string") return `${key}:${arg}`;
50228
+ return key;
50229
+ }
50230
+ /**
50231
+ * Build the `--from-cfn-stack` image-resolution context + return the loaded
50232
+ * state record (loaded once, reused by env substitution + role resolution).
50233
+ * Mirrors `run-task`'s `buildEcsImageResolutionContext`: pseudo parameters
50234
+ * (region + STS account id), the deployed resources, and SSM template
50235
+ * parameters (decrypted SecureString logical ids flagged sensitive).
50236
+ */
50237
+ async function buildAgentCoreImageContext(candidate, stateProvider, options) {
50238
+ const logger = getLogger();
50239
+ const region = options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"] ?? candidate.region;
50240
+ let accountId;
50241
+ try {
50242
+ accountId = await resolveCallerAccountId(region, options.profile);
50243
+ } catch (err) {
50244
+ logger.warn(`--from-cfn-stack: STS GetCallerIdentity failed: ${err instanceof Error ? err.message : String(err)}. A same-stack ECR image URI referencing \${AWS::AccountId} may not resolve.`);
50245
+ }
50246
+ const context = {};
50247
+ const pseudo = derivePseudoParametersFromRegion(region, accountId);
50248
+ if (pseudo) context.pseudoParameters = pseudo;
50249
+ const loaded = await stateProvider.load(candidate.stackName, candidate.region);
50250
+ if (loaded) {
50251
+ context.stateResources = loaded.resources;
50252
+ if (stateProvider.resolveTemplateSsmParameters) {
50253
+ const ssm = await stateProvider.resolveTemplateSsmParameters(candidate.template);
50254
+ if (Object.keys(ssm.values).length > 0) context.stateParameters = ssm.values;
50255
+ if (ssm.secureStringLogicalIds.length > 0) context.stateSensitiveParameters = ssm.secureStringLogicalIds;
50256
+ }
50257
+ }
50258
+ return {
50259
+ context,
50260
+ loaded: loaded ?? void 0
50261
+ };
50262
+ }
50263
+ /** STS `GetCallerIdentity` for the `${AWS::AccountId}` pseudo parameter (threads `--profile`). */
50264
+ async function resolveCallerAccountId(region, profile) {
50265
+ const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
50266
+ const sts = new STSClient({
50267
+ ...region && { region },
50268
+ ...profile && { profile }
50269
+ });
50270
+ try {
50271
+ return (await sts.send(new GetCallerIdentityCommand({}))).Account;
50272
+ } finally {
50273
+ sts.destroy();
50274
+ }
50275
+ }
50276
+ /**
50277
+ * Inject AWS credentials into the container env. Precedence:
50278
+ * 1. `--assume-role` → STS-issued temp creds for the resolved ARN (on
50279
+ * STS failure, warn + fall through to dev creds).
50280
+ * 2. dev shell creds (`forwardAwsEnv`) + `--profile` overlay
50281
+ * ({@link applyProfileCredentialsOverlay}) + the bind-mounted
50282
+ * credentials-file env so handler `fromIni({ profile })` resolves.
50283
+ *
50284
+ * Exported so a unit test can lock the binding (mock STS) without driving
50285
+ * the full synth + docker pipeline.
50286
+ */
50287
+ async function applyAgentCoreCredentialEnv(dockerEnv, args) {
50288
+ const logger = getLogger();
50289
+ let assumeSucceeded = false;
50290
+ if (args.assumeRoleArn) {
50291
+ const stsRegion = args.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"];
50292
+ try {
50293
+ const creds = await assumeAgentCoreExecutionRole(args.assumeRoleArn, stsRegion);
50294
+ dockerEnv["AWS_ACCESS_KEY_ID"] = creds.accessKeyId;
50295
+ dockerEnv["AWS_SECRET_ACCESS_KEY"] = creds.secretAccessKey;
50296
+ dockerEnv["AWS_SESSION_TOKEN"] = creds.sessionToken;
50297
+ if (stsRegion) dockerEnv["AWS_REGION"] = stsRegion;
50298
+ assumeSucceeded = true;
50299
+ } catch (err) {
50300
+ logger.warn(`--assume-role: STS AssumeRole(${args.assumeRoleArn}) failed: ${err instanceof Error ? err.message : String(err)}. Falling back to the developer's shell credentials.`);
50301
+ }
50302
+ }
50303
+ if (!assumeSucceeded) {
50304
+ forwardAwsEnv$1(dockerEnv);
50305
+ applyProfileCredentialsOverlay(dockerEnv, args.profileCredentials, false);
50306
+ if (args.profileCredsFile) {
50307
+ dockerEnv["AWS_SHARED_CREDENTIALS_FILE"] = args.profileCredsFile.containerPath;
50308
+ dockerEnv["AWS_PROFILE"] = args.profileCredsFile.profileName;
50309
+ }
50310
+ }
50311
+ }
50312
+ /**
50313
+ * Resolve the role ARN to assume, honoring the three `--assume-role` forms.
50314
+ * Bare `--assume-role` uses the runtime's literal `RoleArn`; when that is an
50315
+ * intrinsic (the common L2 case — `Fn::GetAtt` to an auto-created role) it
50316
+ * resolves the execution-role ARN from `--from-cfn-stack` state, and only
50317
+ * warns + falls back to dev creds when neither is available.
50318
+ */
50319
+ function resolveAssumeRoleArn(options, resolved, loaded) {
50320
+ if (typeof options.assumeRole === "string") return options.assumeRole;
50321
+ if (options.assumeRole === true) {
50322
+ if (resolved.roleArn) return resolved.roleArn;
50323
+ if (loaded) {
50324
+ const fromState = resolveExecutionRoleArnFromState(loaded, resolved.logicalId, "RoleArn");
50325
+ if (fromState) {
50326
+ getLogger().debug(`--assume-role: resolved RoleArn from state: ${fromState}`);
50327
+ return fromState;
50328
+ }
50329
+ }
50330
+ getLogger().warn("--assume-role passed without an ARN, but the runtime's RoleArn is not a literal ARN in the template " + (loaded ? "and could not be resolved from the deployed stack state. " : "and no --from-cfn-stack state is available to resolve it. ") + "Pass the ARN explicitly: --assume-role <arn>. Falling back to the developer's shell credentials.");
50331
+ }
50332
+ }
50333
+ function emitResult(result) {
50334
+ const logger = getLogger();
50335
+ if (result.status >= 400) {
50336
+ logger.warn(`Agent /invocations returned HTTP ${result.status}.`);
50337
+ process.exitCode = 1;
50338
+ }
50339
+ if (result.streamed) {
50340
+ process.stdout.write("\n");
50341
+ return;
50342
+ }
50343
+ process.stdout.write(`${result.raw}\n`);
50344
+ }
50345
+ /**
50346
+ * Finish a `/ws` exchange: the frames were already streamed to stdout via the
50347
+ * onMessage sink, so just terminate with a newline (so the shell prompt resumes
50348
+ * cleanly) and note the frame count at debug level.
50349
+ */
50350
+ function emitWsResult(result) {
50351
+ process.stdout.write("\n");
50352
+ getLogger().debug(`Agent /ws closed after ${result.frames} frame(s).`);
50353
+ }
50354
+ /**
50355
+ * Build the JSON-RPC request to send to an MCP runtime from `--event`:
50356
+ * - no `--event` (empty object) → `tools/list` (discover the server's tools),
50357
+ * - an object with a string `method` → that method + its `params`,
50358
+ * - anything else → a fail-fast error.
50359
+ *
50360
+ * Exported for unit testing.
50361
+ */
50362
+ function buildMcpRequest(event) {
50363
+ if (event === void 0 || event === null) return {
50364
+ method: "tools/list",
50365
+ params: {}
50366
+ };
50367
+ if (typeof event !== "object" || Array.isArray(event)) throw new CdkdError("MCP --event must be a JSON object describing a JSON-RPC request (e.g. {\"method\":\"tools/call\",\"params\":{\"name\":\"...\",\"arguments\":{...}}}).", "LOCAL_INVOKE_AGENTCORE_MCP_EVENT_INVALID");
50368
+ const obj = event;
50369
+ if (Object.keys(obj).length === 0) return {
50370
+ method: "tools/list",
50371
+ params: {}
50372
+ };
50373
+ if (typeof obj["method"] !== "string") throw new CdkdError(`MCP --event must include a string "method" (a JSON-RPC method such as "tools/list" or "tools/call"). Got keys: ${Object.keys(obj).join(", ")}.`, "LOCAL_INVOKE_AGENTCORE_MCP_EVENT_INVALID");
50374
+ return {
50375
+ method: obj["method"],
50376
+ ...obj["params"] !== void 0 && { params: obj["params"] }
50377
+ };
50378
+ }
50379
+ /** Print the MCP JSON-RPC response; exit 1 when it carried a JSON-RPC error. */
50380
+ function emitMcpResult(result) {
50381
+ if (!result.ok) {
50382
+ getLogger().warn("MCP server returned a JSON-RPC error.");
50383
+ process.exitCode = 1;
50384
+ }
50385
+ process.stdout.write(`${result.raw}\n`);
50386
+ }
50387
+ /**
50388
+ * Build the JSON-RPC request to send to an A2A runtime from `--event`:
50389
+ * - no `--event` (empty object) → `agent/getCard` (discover the agent's card),
50390
+ * - an object with a string `method` → that method + its `params`,
50391
+ * - anything else → a fail-fast error.
50392
+ *
50393
+ * Exported for unit testing.
50394
+ */
50395
+ function buildA2aRequest(event) {
50396
+ if (event === void 0 || event === null) return {
50397
+ method: "agent/getCard",
50398
+ params: {}
50399
+ };
50400
+ if (typeof event !== "object" || Array.isArray(event)) throw new CdkdError("A2A --event must be a JSON object describing a JSON-RPC request (e.g. {\"method\":\"tasks/send\",\"params\":{\"id\":\"...\",\"message\":{...}}}).", "LOCAL_INVOKE_AGENTCORE_A2A_EVENT_INVALID");
50401
+ const obj = event;
50402
+ if (Object.keys(obj).length === 0) return {
50403
+ method: "agent/getCard",
50404
+ params: {}
50405
+ };
50406
+ if (typeof obj["method"] !== "string") throw new CdkdError(`A2A --event must include a string "method" (a JSON-RPC method such as "agent/getCard" or "tasks/send"). Got keys: ${Object.keys(obj).join(", ")}.`, "LOCAL_INVOKE_AGENTCORE_A2A_EVENT_INVALID");
50407
+ return {
50408
+ method: obj["method"],
50409
+ ...obj["params"] !== void 0 && { params: obj["params"] }
50410
+ };
50411
+ }
50412
+ /** Print the A2A JSON-RPC response; exit 1 when it carried a JSON-RPC error. */
50413
+ function emitA2aResult(result) {
50414
+ if (!result.ok) {
50415
+ getLogger().warn("A2A server returned a JSON-RPC error.");
50416
+ process.exitCode = 1;
50417
+ }
50418
+ process.stdout.write(`${result.raw}\n`);
50419
+ }
50420
+ /** Map a `--platform` value to the architecture `buildContainerImage` expects. */
50421
+ function platformToArchitecture(platform) {
50422
+ return platform === "linux/amd64" ? "x86_64" : "arm64";
50423
+ }
50424
+ function forwardAwsEnv$1(env) {
50425
+ for (const key of [
50426
+ "AWS_ACCESS_KEY_ID",
50427
+ "AWS_SECRET_ACCESS_KEY",
50428
+ "AWS_SESSION_TOKEN",
50429
+ "AWS_REGION",
50430
+ "AWS_DEFAULT_REGION"
50431
+ ]) {
50432
+ const value = process.env[key];
50433
+ if (value !== void 0) env[key] = value;
50434
+ }
50435
+ }
50436
+ async function assumeAgentCoreExecutionRole(roleArn, region) {
50437
+ const { STSClient, AssumeRoleCommand } = await import("@aws-sdk/client-sts");
50438
+ const sts = new STSClient({ ...region && { region } });
50439
+ try {
50440
+ const creds = (await sts.send(new AssumeRoleCommand({
50441
+ RoleArn: roleArn,
50442
+ RoleSessionName: `${getEmbedConfig().resourceNamePrefix}-invoke-agentcore-${Date.now()}`,
50443
+ DurationSeconds: 3600
50444
+ }))).Credentials;
50445
+ if (!creds?.AccessKeyId || !creds.SecretAccessKey || !creds.SessionToken) throw new CdkdError(`AssumeRole(${roleArn}) returned no usable credentials.`, "LOCAL_INVOKE_AGENTCORE_ASSUMEROLE_NO_CREDS");
50446
+ return {
50447
+ accessKeyId: creds.AccessKeyId,
50448
+ secretAccessKey: creds.SecretAccessKey,
50449
+ sessionToken: creds.SessionToken
50450
+ };
50451
+ } finally {
50452
+ sts.destroy();
50453
+ }
50454
+ }
50455
+ async function readEvent$1(options) {
50456
+ if (options.event && options.eventStdin) throw new CdkdError("--event and --event-stdin are mutually exclusive.", "LOCAL_INVOKE_AGENTCORE_EVENT_FLAG_CONFLICT");
50457
+ if (options.eventStdin) return parseEvent$1(await readStdin$1(), "<stdin>");
50458
+ if (options.event) {
50459
+ let raw;
50460
+ try {
50461
+ raw = readFileSync(options.event, "utf-8");
50462
+ } catch (err) {
50463
+ throw new CdkdError(`Failed to read --event file '${options.event}': ${err instanceof Error ? err.message : String(err)}`, "LOCAL_INVOKE_AGENTCORE_EVENT_READ_FAILED");
50464
+ }
50465
+ return parseEvent$1(raw, options.event);
50466
+ }
50467
+ return {};
50468
+ }
50469
+ function parseEvent$1(raw, source) {
50470
+ try {
50471
+ return JSON.parse(raw);
50472
+ } catch (err) {
50473
+ throw new CdkdError(`Failed to parse event payload from ${source} as JSON: ${err instanceof Error ? err.message : String(err)}`, "LOCAL_INVOKE_AGENTCORE_EVENT_PARSE_FAILED");
50474
+ }
50475
+ }
50476
+ async function readStdin$1() {
50477
+ const chunks = [];
50478
+ for await (const chunk of process.stdin) chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
50479
+ return Buffer.concat(chunks).toString("utf-8");
50480
+ }
50481
+ /**
50482
+ * Read `process.stdin` line-buffered and yield each line as a string (trailing
50483
+ * `\r?\n` stripped). The async iterable completes when stdin EOFs (Ctrl-D /
50484
+ * end-of-pipe), and surrenders the underlying stream when its `return()` is
50485
+ * called — so the WS client can close down the source when the server closes
50486
+ * first without leaving stdin held open.
50487
+ *
50488
+ * Exported so a unit test can drive the iterable shape directly.
50489
+ */
50490
+ async function* readStdinLines() {
50491
+ const { createInterface } = await import("node:readline");
50492
+ const rl = createInterface({
50493
+ input: process.stdin,
50494
+ crlfDelay: Infinity
50495
+ });
50496
+ try {
50497
+ for await (const line of rl) yield line;
50498
+ } finally {
50499
+ rl.close();
50500
+ }
50501
+ }
50502
+ function readEnvOverridesFile$1(filePath) {
50503
+ if (!filePath) return void 0;
50504
+ let raw;
50505
+ try {
50506
+ raw = readFileSync(filePath, "utf-8");
50507
+ } catch (err) {
50508
+ throw new CdkdError(`Failed to read --env-vars file '${filePath}': ${err instanceof Error ? err.message : String(err)}`, "LOCAL_INVOKE_AGENTCORE_ENV_VARS_READ_FAILED");
50509
+ }
50510
+ let parsed;
50511
+ try {
50512
+ parsed = JSON.parse(raw);
50513
+ } catch (err) {
50514
+ throw new CdkdError(`Failed to parse --env-vars file '${filePath}' as JSON: ${err instanceof Error ? err.message : String(err)}`, "LOCAL_INVOKE_AGENTCORE_ENV_VARS_PARSE_FAILED");
50515
+ }
50516
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new CdkdError(`--env-vars file '${filePath}' must contain a JSON object at the top level.`, "LOCAL_INVOKE_AGENTCORE_ENV_VARS_NOT_OBJECT");
50517
+ return parsed;
50518
+ }
50519
+ function createLocalInvokeAgentCoreCommand() {
50520
+ 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. Ignored for an MCP runtime.").default(false)).addOption(new Option("--ws-interactive", "REPL mode for --ws: after the initial --event frame, read additional frames from stdin (one frame per line, trailing newline stripped) and send each as a text frame until stdin EOFs (Ctrl-D) or the agent closes. Only meaningful with --ws.").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) => {
50521
+ await localInvokeAgentCoreCommand(target, options);
50522
+ }));
50523
+ [
50524
+ ...commonOptions,
50525
+ ...appOptions,
50526
+ ...contextOptions,
50527
+ ...stateOptions
50528
+ ].forEach((opt) => cmd.addOption(opt));
50529
+ cmd.addOption(deprecatedRegionOption);
50530
+ return cmd;
50531
+ }
50532
+
49696
50533
  //#endregion
49697
50534
  //#region src/cli/commands/local-invoke.ts
49698
50535
  /**
@@ -50447,10 +51284,10 @@ function suggestAssumeRoleFromState(state, logicalId) {
50447
51284
  *
50448
51285
  * Exported for unit testing.
50449
51286
  */
50450
- function resolveExecutionRoleArnFromState(state, logicalId) {
51287
+ function resolveExecutionRoleArnFromState(state, logicalId, roleProperty = "Role") {
50451
51288
  const lambda = state.resources[logicalId];
50452
51289
  if (!lambda) return void 0;
50453
- const roleRef = lambda.properties?.["Role"] ?? lambda.observedProperties?.["Role"];
51290
+ const roleRef = lambda.properties?.[roleProperty] ?? lambda.observedProperties?.[roleProperty];
50454
51291
  if (typeof roleRef === "string" && roleRef.startsWith("arn:")) return roleRef;
50455
51292
  if (typeof roleRef === "object" && roleRef !== null) {
50456
51293
  const refLogicalId = pickReferencedLogicalId(roleRef);
@@ -50495,6 +51332,7 @@ function createLocalCommand() {
50495
51332
  local.addCommand(createLocalStartApiCommand());
50496
51333
  local.addCommand(createLocalRunTaskCommand());
50497
51334
  local.addCommand(createLocalStartServiceCommand());
51335
+ local.addCommand(createLocalInvokeAgentCoreCommand());
50498
51336
  return local;
50499
51337
  }
50500
51338
 
@@ -51607,7 +52445,7 @@ function reorderArgs(argv) {
51607
52445
  */
51608
52446
  async function main() {
51609
52447
  const program = new Command();
51610
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.190.0");
52448
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.192.0");
51611
52449
  program.addCommand(createBootstrapCommand());
51612
52450
  program.addCommand(createSynthCommand());
51613
52451
  program.addCommand(createListCommand());