@go-to-k/cdkd 0.201.1 → 0.203.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -296,18 +296,25 @@ with the AWS-published ECS metadata sidecar.
296
296
  ```bash
297
297
  cdkd local start-service MyStack/Orders MyStack/Web # multiple services in one invocation
298
298
  cdkd local start-service MyStack/Orders --from-state # OR --from-cfn-stack
299
+ cdkd local start-service MyStack/Web --watch # hot reload (sub-second on interpreted handlers)
299
300
  ```
300
301
 
301
302
  Long-running ECS Service emulator: `DesiredCount` replicas with
302
303
  restart-on-exit, cross-service Service Connect / Cloud Map DNS
303
304
  discovery (peer containers reach each other by `<discoveryName>.<namespace>`).
304
- No local load-balancer in v1.
305
+ No local load-balancer in v1. `--watch` re-synths on every CDK source edit
306
+ and reloads one replica at a time — source-only edits on
307
+ interpreted-language handlers (Node / Python / Ruby / shell) take a
308
+ bind-mount fast path (`docker cp` + `docker restart`; no rebuild);
309
+ Dockerfile / dependency manifest / compiled-language source edits fall
310
+ through to a full rebuild + shadow boot + atomic swap.
305
311
 
306
312
  ### `local start-alb`
307
313
 
308
314
  ```bash
309
315
  cdkd local start-alb MyStack/MyAlb --lb-port 80=8080 # remap privileged listener port
310
316
  cdkd local start-alb MyStack/MyAlb --from-state # OR --from-cfn-stack
317
+ cdkd local start-alb MyStack/MyAlb --watch # hot reload (sub-second on interpreted handlers)
311
318
  ```
312
319
 
313
320
  Long-running local ALB front-door: names an `AWS::ElasticLoadBalancingV2::LoadBalancer`,
@@ -316,7 +323,10 @@ HTTP / HTTPS front-door on each listener port that round-robins across
316
323
  the running replicas and routes its listener rules across the backing
317
324
  services. Forward / redirect / fixed-response actions; ECS or Lambda
318
325
  targets; authenticate-cognito / authenticate-oidc via a local Bearer-JWT
319
- check.
326
+ check. `--watch` reloads one backing-replica at a time across edits —
327
+ interpreted-handler source edits go through the bind-mount fast path
328
+ (no rebuild); Dockerfile / dependency / compiled-source edits fall
329
+ through to a rebuild + atomic front-door pool swap.
320
330
 
321
331
  See **[docs/local-emulation.md](docs/local-emulation.md)** for the
322
332
  full reference — runtimes, target resolution, every flag, integration
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-DWUnLza1.js";
3
- import { $ as uploadCfnTemplate, A as S3StateBackend, At as PATTERN_B_NAME_PROPERTIES, B as Synthesizer, C as assertRegionMatch, Ct as normalizeAwsError, D as DagBuilder, E as DiffCalculator, Et as getLogger, F as buildDockerImage, Ft as withStackName, G as resolveSkipPrefix, H as getLegacyStateBucketName, I as formatDockerLoginError, J as warnDeprecatedNoPrefixCliFlag, K as resolveStateBucketWithDefault, L as getDockerCmd, M as AssetPublisher, Mt as generateResourceName, N as stringifyValue, Nt as generateResourceNameWithFallback, O as TemplateParser, Ot as runStackBuffered, P as WorkGraph, Pt as withSkipPrefix, Q as findLargeInlineResources, R as runDockerForeground, S as CloudControlProvider, T as applyRoleArnIfSet, U as resolveApp, V as getDefaultStateBucketName, W as resolveCaptureObservedState, X as CFN_TEMPLATE_URL_LIMIT, Y as CFN_TEMPLATE_BODY_LIMIT, Z as MIGRATE_TMP_PREFIX, _ as matchesCdkPath, _t as StackHasActiveImportsError, a as withRetry, b as ProviderRegistry, c as bold, ct as LocalMigrateError, d as green, dt as MissingCdkCliError, et as AssemblyReader, f as red, ft as NestedStackChildDirectDestroyError, g as CDK_PATH_TAG, gt as ResourceUpdateNotSupportedError, h as collectInlinePolicyNamesManagedBySiblings, ht as ResourceTimeoutError, i as withResourceDeadline, it as CdkdError, j as shouldRetainResource, jt as PATTERN_B_RESOURCE_TYPES, k as LockManager, kt as getLiveRenderer, l as cyan, lt as LocalStartServiceError, m as IAMRoleProvider, mt as ProvisioningError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as resolveBucketRegion, o as IMPLICIT_DELETE_DEPENDENCIES, p as yellow, pt as PartialFailureError, q as resolveStateBucketWithDefaultAndSource, r as DeployEngine, s as formatResourceLine, st as LocalInvokeBuildError$1, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, v as normalizeAwsTagsToCfn, vt as StackTerminationProtectionError, w as IntrinsicFunctionResolver, wt as withErrorHandling, x as findActionableSilentDrops, y as resolveExplicitPhysicalId, z as runDockerStreaming } from "./deploy-engine-5CVA5VWR.js";
3
+ import { $ as uploadCfnTemplate, A as S3StateBackend, At as PATTERN_B_NAME_PROPERTIES, B as Synthesizer, C as assertRegionMatch, Ct as normalizeAwsError, D as DagBuilder, E as DiffCalculator, Et as getLogger, F as buildDockerImage, Ft as withStackName, G as resolveSkipPrefix, H as getLegacyStateBucketName, I as formatDockerLoginError, J as warnDeprecatedNoPrefixCliFlag, K as resolveStateBucketWithDefault, L as getDockerCmd, M as AssetPublisher, Mt as generateResourceName, N as stringifyValue, Nt as generateResourceNameWithFallback, O as TemplateParser, Ot as runStackBuffered, P as WorkGraph, Pt as withSkipPrefix, Q as findLargeInlineResources, R as runDockerForeground, S as CloudControlProvider, T as applyRoleArnIfSet, U as resolveApp, V as getDefaultStateBucketName, W as resolveCaptureObservedState, X as CFN_TEMPLATE_URL_LIMIT, Y as CFN_TEMPLATE_BODY_LIMIT, Z as MIGRATE_TMP_PREFIX, _ as matchesCdkPath, _t as StackHasActiveImportsError, a as withRetry, b as ProviderRegistry, c as bold, ct as LocalMigrateError, d as green, dt as MissingCdkCliError, et as AssemblyReader, f as red, ft as NestedStackChildDirectDestroyError, g as CDK_PATH_TAG, gt as ResourceUpdateNotSupportedError, h as collectInlinePolicyNamesManagedBySiblings, ht as ResourceTimeoutError, i as withResourceDeadline, it as CdkdError, j as shouldRetainResource, jt as PATTERN_B_RESOURCE_TYPES, k as LockManager, kt as getLiveRenderer, l as cyan, lt as LocalStartServiceError, m as IAMRoleProvider, mt as ProvisioningError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as resolveBucketRegion, o as IMPLICIT_DELETE_DEPENDENCIES, p as yellow, pt as PartialFailureError, q as resolveStateBucketWithDefaultAndSource, r as DeployEngine, s as formatResourceLine, st as LocalInvokeBuildError$1, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, v as normalizeAwsTagsToCfn, vt as StackTerminationProtectionError, w as IntrinsicFunctionResolver, wt as withErrorHandling, x as findActionableSilentDrops, y as resolveExplicitPhysicalId, z as runDockerStreaming } from "./deploy-engine-CuJDHhTs.js";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
5
  import { randomBytes, randomUUID } from "node:crypto";
6
6
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListBucketsCommand, ListDirectoryBucketsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -62,7 +62,7 @@ import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as
62
62
  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";
63
63
  import { Document, Pair, Scalar, YAMLMap, YAMLSeq, parse as parse$1, stringify } from "yaml";
64
64
  import { createLocalStateProvider, getEmbedConfig, isCfnFlagPresent, listTargets, rejectExplicitCfnStackWithMultipleStacks, resolveCfnFallbackRegion, setEmbedConfig, substituteAgainstState, substituteAgainstStateAsync, substituteEnvVarsFromState, substituteEnvVarsFromStateAsync } from "cdk-local";
65
- import { A2A_CONTAINER_PORT, A2A_PATH, AGENTCORE_A2A_PROTOCOL, AGENTCORE_AGUI_PROTOCOL, AGENTCORE_MCP_PROTOCOL, ConnectionRegistry, EcsTaskResolutionError, HOST_GATEWAY_MIN_VERSION, LocalInvokeBuildError, MCP_CONTAINER_PORT, MCP_PATH, a2aInvokeOnce, addAlbSpecificOptions, addCommonEcsServiceOptions, albStrategy, architectureToPlatform, attachAuthorizers, attachStageContext, availableApiIdentifiers, bufferToBody, buildAgentCoreCodeImage, buildCognitoJwksUrl, buildConnectEvent, buildContainerImage, buildCorsConfigByApiId, buildCorsConfigFromCloudFrontChain, buildDisconnectEvent, buildJwksUrlFromIssuer, buildMessageEvent, buildMgmtEndpointEnvUrl, buildStageMap, createAuthorizerCache, createFileWatcher, createJwksCache, createWatchPredicates, defaultCredentialsLoader, derivePseudoParametersFromRegion, discoverRoutes, discoverWebSocketApis, downloadAndExtractS3Bundle, filterRoutesByApiIdentifier, groupRoutesByServer, handleConnectionsRequest, invokeAgentCore, invokeAgentCoreWs, materializeLayerFromArn, mcpInvokeOnce, parseConnectionsPath, parseSelectionExpressionPath, pickAgentCoreCandidateStack, probeHostGatewaySupport, readMtlsMaterialsFromDisk, resolveAgentCoreTarget, resolveEnvVars, resolveRuntimeCodeMountPath, resolveRuntimeFileExtension, resolveRuntimeImage, resolveSingleTarget, resolveWatchConfig, runEcsServiceEmulator, signAgentCoreInvocation, startApiServer, substituteImagePlaceholders, tryResolveImageFnJoin, verifyJwtViaDiscovery, waitForAgentCorePing } from "cdk-local/internal";
65
+ import { A2A_CONTAINER_PORT, A2A_PATH, AGENTCORE_A2A_PROTOCOL, AGENTCORE_AGUI_PROTOCOL, AGENTCORE_MCP_PROTOCOL, ConnectionRegistry, EcsTaskResolutionError, HOST_GATEWAY_MIN_VERSION, LocalInvokeBuildError, MCP_CONTAINER_PORT, MCP_PATH, a2aInvokeOnce, addAlbSpecificOptions, addCommonEcsServiceOptions, addStartServiceSpecificOptions, albStrategy, architectureToPlatform, attachAuthorizers, attachStageContext, availableApiIdentifiers, bufferToBody, buildAgentCoreCodeImage, buildCognitoJwksUrl, buildConnectEvent, buildContainerImage, buildCorsConfigByApiId, buildCorsConfigFromCloudFrontChain, buildDisconnectEvent, buildJwksUrlFromIssuer, buildMessageEvent, buildMgmtEndpointEnvUrl, buildStageMap, createAuthorizerCache, createFileWatcher, createJwksCache, createWatchPredicates, defaultCredentialsLoader, derivePseudoParametersFromRegion, discoverRoutes, discoverWebSocketApis, downloadAndExtractS3Bundle, filterRoutesByApiIdentifier, groupRoutesByServer, handleConnectionsRequest, invokeAgentCore, invokeAgentCoreWs, materializeLayerFromArn, mcpInvokeOnce, parseConnectionsPath, parseSelectionExpressionPath, pickAgentCoreCandidateStack, probeHostGatewaySupport, readMtlsMaterialsFromDisk, resolveAgentCoreTarget, resolveEnvVars, resolveRuntimeCodeMountPath, resolveRuntimeFileExtension, resolveRuntimeImage, resolveSingleTarget, resolveWatchConfig, runEcsServiceEmulator, signAgentCoreInvocation, startApiServer, substituteImagePlaceholders, tryResolveImageFnJoin, verifyJwtViaDiscovery, waitForAgentCorePing } from "cdk-local/internal";
66
66
  import { createServer } from "node:net";
67
67
  import { promisify } from "node:util";
68
68
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
@@ -32011,7 +32011,7 @@ var S3TablesProvider = class {
32011
32011
  providerRegion = process.env["AWS_REGION"];
32012
32012
  logger = getLogger().child("S3TablesProvider");
32013
32013
  handledProperties = new Map([
32014
- ["AWS::S3Tables::TableBucket", new Set(["TableBucketName"])],
32014
+ ["AWS::S3Tables::TableBucket", new Set(["TableBucketName", "Tags"])],
32015
32015
  ["AWS::S3Tables::Namespace", new Set(["TableBucketARN", "Namespace"])],
32016
32016
  ["AWS::S3Tables::Table", new Set([
32017
32017
  "TableBucketARN",
@@ -32037,6 +32037,7 @@ var S3TablesProvider = class {
32037
32037
  }
32038
32038
  async update(logicalId, physicalId, resourceType, properties, previousProperties) {
32039
32039
  if (resourceType === "AWS::S3Tables::Table") await this.applyTableTagsDiff(logicalId, physicalId, resourceType, previousProperties["Tags"], properties["Tags"]);
32040
+ else if (resourceType === "AWS::S3Tables::TableBucket") await this.applyTableBucketTagsDiff(logicalId, physicalId, resourceType, previousProperties["Tags"], properties["Tags"]);
32040
32041
  else this.logger.debug(`Update is no-op for ${resourceType} ${logicalId}`);
32041
32042
  return {
32042
32043
  physicalId,
@@ -32055,8 +32056,12 @@ var S3TablesProvider = class {
32055
32056
  this.logger.debug(`Creating S3 Table Bucket ${logicalId}`);
32056
32057
  const tableBucketName = properties["TableBucketName"];
32057
32058
  if (!tableBucketName) throw new ProvisioningError(`TableBucketName is required for S3 Table Bucket ${logicalId}`, resourceType, logicalId);
32059
+ const tags = this.cfnTagsToSdkMap(properties["Tags"]);
32058
32060
  try {
32059
- const tableBucketARN = (await this.getClient().send(new CreateTableBucketCommand({ name: tableBucketName }))).arn;
32061
+ const tableBucketARN = (await this.getClient().send(new CreateTableBucketCommand({
32062
+ name: tableBucketName,
32063
+ ...tags !== void 0 && { tags }
32064
+ }))).arn;
32060
32065
  this.logger.debug(`Successfully created S3 Table Bucket ${logicalId}: ${tableBucketARN}`);
32061
32066
  return {
32062
32067
  physicalId: tableBucketARN,
@@ -32248,6 +32253,7 @@ var S3TablesProvider = class {
32248
32253
  }
32249
32254
  const result = {};
32250
32255
  if (bucket.name !== void 0) result["TableBucketName"] = bucket.name;
32256
+ result["Tags"] = await this.readTagsBestEffort(physicalId);
32251
32257
  return result;
32252
32258
  }
32253
32259
  async readNamespaceCurrentState(physicalId) {
@@ -32567,6 +32573,47 @@ var S3TablesProvider = class {
32567
32573
  throw new ProvisioningError(`applyTableTagsDiff: TagResource failed for ${resourceArn} (keys: ${Object.keys(upserts).join(", ")}): ${err instanceof Error ? err.message : String(err)}. State has NOT been updated so the next deploy will retry the tag-diff.`, resourceType, logicalId, physicalId, cause);
32568
32574
  }
32569
32575
  }
32576
+ /**
32577
+ * Apply a tag-diff against a TableBucket resource ARN. Mirrors
32578
+ * `applyTableTagsDiff` for the Table case, but simpler: TableBucket's
32579
+ * `physicalId` IS the bucket ARN, so no `GetTableBucket` lookup hop
32580
+ * is needed (the Table version needs `GetTable` to recover the real
32581
+ * ARN from the cdkd-compound `<bucketArn>|<namespace>|<name>` physical id).
32582
+ *
32583
+ * Same throw semantics as `applyTableTagsDiff` (per issue #740 / PR
32584
+ * #741): tag-side failures THROW `ProvisioningError` so state is NOT
32585
+ * written, and the next deploy retries against the still-old state.
32586
+ * `update()` for AWS::S3Tables::TableBucket is otherwise a no-op (the
32587
+ * bucket itself is immutable), so a tag-side throw cleanly turns the
32588
+ * whole update into a clean retry with no side-effects.
32589
+ */
32590
+ async applyTableBucketTagsDiff(logicalId, physicalId, resourceType, previousTags, newTags) {
32591
+ const prev = this.cfnTagsToSdkMap(previousTags) ?? {};
32592
+ const next = this.cfnTagsToSdkMap(newTags) ?? {};
32593
+ const removedKeys = Object.keys(prev).filter((k) => !(k in next));
32594
+ const upserts = {};
32595
+ for (const [k, v] of Object.entries(next)) if (prev[k] !== v) upserts[k] = v;
32596
+ if (removedKeys.length === 0 && Object.keys(upserts).length === 0) return;
32597
+ const resourceArn = physicalId;
32598
+ if (removedKeys.length > 0) try {
32599
+ await this.getClient().send(new UntagResourceCommand$15({
32600
+ resourceArn,
32601
+ tagKeys: removedKeys
32602
+ }));
32603
+ } catch (err) {
32604
+ const cause = err instanceof Error ? err : void 0;
32605
+ throw new ProvisioningError(`applyTableBucketTagsDiff: UntagResource failed for ${resourceArn} (keys: ${removedKeys.join(", ")}): ${err instanceof Error ? err.message : String(err)}. State has NOT been updated so the next deploy will retry the tag-diff.`, resourceType, logicalId, physicalId, cause);
32606
+ }
32607
+ if (Object.keys(upserts).length > 0) try {
32608
+ await this.getClient().send(new TagResourceCommand$16({
32609
+ resourceArn,
32610
+ tags: upserts
32611
+ }));
32612
+ } catch (err) {
32613
+ const cause = err instanceof Error ? err : void 0;
32614
+ throw new ProvisioningError(`applyTableBucketTagsDiff: TagResource failed for ${resourceArn} (keys: ${Object.keys(upserts).join(", ")}): ${err instanceof Error ? err.message : String(err)}. State has NOT been updated so the next deploy will retry the tag-diff.`, resourceType, logicalId, physicalId, cause);
32615
+ }
32616
+ }
32570
32617
  };
32571
32618
 
32572
32619
  //#endregion
@@ -49118,7 +49165,8 @@ function serviceStrategy(_options) {
49118
49165
  boots: chosenTargets.map((target) => ({ target })),
49119
49166
  warnings: []
49120
49167
  }),
49121
- lbPortOverrides: {}
49168
+ lbPortOverrides: {},
49169
+ supportsWatch: true
49122
49170
  };
49123
49171
  }
49124
49172
  /**
@@ -49133,9 +49181,11 @@ function serviceStrategy(_options) {
49133
49181
  * --add-host overlay (Issue #460).
49134
49182
  */
49135
49183
  function createLocalStartServiceCommand() {
49136
- return addCommonEcsServiceOptions(new Command("start-service").description("Run one or more AWS::ECS::Service resources locally as a long-running emulator. Spins up DesiredCount task replicas per service (clamped by --max-tasks) using the same per-task docker network + metadata sidecar pattern as `cdkd local run-task`, then keeps each replica running and restarts it on exit per --restart-policy. ^C tears every replica + sidecar + network down. Each <target> accepts a CDK display path (MyStack/MyService) or stack-qualified logical ID (MyStack:MyServiceXYZ); single-stack apps may omit the stack prefix. When two or more <target>s are supplied, every service is booted into a shared Cloud Map / Service Connect registry so peer services discover each other via docker --add-host overlay (Issue #460). Omit <targets> in an interactive terminal to multi-select the ECS services from a list.").argument("[targets...]", "One or more CDK display paths or stack-qualified logical IDs of the AWS::ECS::Service resources to run (omit to multi-select interactively in a TTY)").addOption(new Option("--from-state", "Read cdkd's S3 state for the target stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::ImportValue / Fn::GetStackOutput intrinsics in container images, environment variables, secrets, role ARNs, and volumes. Mutually exclusive with --from-cfn-stack.").default(false)).addOption(new Option("--state-bucket <bucket>", "S3 bucket for --from-state. Falls back to CDKD_STATE_BUCKET env or cdk.json context.cdkd.stateBucket.")).addOption(new Option("--state-prefix <prefix>", "S3 key prefix for --from-state state files.").default("cdkd")).action(withErrorHandling(async (targets, options) => {
49184
+ const cmd = new Command("start-service").description("Run one or more AWS::ECS::Service resources locally as a long-running emulator. Spins up DesiredCount task replicas per service (clamped by --max-tasks) using the same per-task docker network + metadata sidecar pattern as `cdkd local run-task`, then keeps each replica running and restarts it on exit per --restart-policy. ^C tears every replica + sidecar + network down. Each <target> accepts a CDK display path (MyStack/MyService) or stack-qualified logical ID (MyStack:MyServiceXYZ); single-stack apps may omit the stack prefix. When two or more <target>s are supplied, every service is booted into a shared Cloud Map / Service Connect registry so peer services discover each other via docker --add-host overlay (Issue #460). Omit <targets> in an interactive terminal to multi-select the ECS services from a list.").argument("[targets...]", "One or more CDK display paths or stack-qualified logical IDs of the AWS::ECS::Service resources to run (omit to multi-select interactively in a TTY)").addOption(new Option("--from-state", "Read cdkd's S3 state for the target stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::ImportValue / Fn::GetStackOutput intrinsics in container images, environment variables, secrets, role ARNs, and volumes. Mutually exclusive with --from-cfn-stack.").default(false)).addOption(new Option("--state-bucket <bucket>", "S3 bucket for --from-state. Falls back to CDKD_STATE_BUCKET env or cdk.json context.cdkd.stateBucket.")).addOption(new Option("--state-prefix <prefix>", "S3 key prefix for --from-state state files.").default("cdkd")).action(withErrorHandling(async (targets, options) => {
49137
49185
  await runEcsServiceEmulator(targets, options, serviceStrategy(options), cdkdExtraStateProviders);
49138
- })));
49186
+ }));
49187
+ addStartServiceSpecificOptions(cmd);
49188
+ return addCommonEcsServiceOptions(cmd);
49139
49189
  }
49140
49190
 
49141
49191
  //#endregion
@@ -51877,7 +51927,7 @@ function reorderArgs(argv) {
51877
51927
  */
51878
51928
  async function main() {
51879
51929
  const program = new Command();
51880
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.201.1");
51930
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.203.0");
51881
51931
  program.addCommand(createBootstrapCommand());
51882
51932
  program.addCommand(createSynthCommand());
51883
51933
  program.addCommand(createListCommand());