@go-to-k/cdkd 0.17.1 → 0.18.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
@@ -458,10 +458,16 @@ cdkd state resources MyStack --json # full JSON array
458
458
  cdkd state show MyStack
459
459
  cdkd state show MyStack --json # raw {state, lock} JSON
460
460
 
461
- # Remove cdkd's state record for a stack (does NOT delete AWS resources)
462
- cdkd state rm MyStack # confirmation prompt (y/N)
463
- cdkd state rm MyStack --yes # skip confirmation
464
- cdkd state rm StackA StackB --force # also bypass the locked-stack refusal
461
+ # Orphan a stack from cdkd's state (does NOT delete AWS resources).
462
+ # Synth-driven needs --app / cdk.json — same stack-pattern routing as deploy.
463
+ cdkd orphan MyStack # confirmation prompt (y/N)
464
+ cdkd orphan MyStack --yes
465
+ cdkd orphan 'MyStage/*' --yes # display-path wildcard
466
+
467
+ # State-driven counterpart (no CDK app needed — works against the bucket).
468
+ cdkd state orphan MyStack # confirmation prompt (y/N)
469
+ cdkd state orphan MyStack --yes # skip confirmation
470
+ cdkd state orphan StackA StackB --force # also bypass the locked-stack refusal
465
471
 
466
472
  # Destroy a stack's AWS resources AND remove its state record, without
467
473
  # requiring the CDK app (no synth — works from any working directory).
@@ -471,10 +477,12 @@ cdkd state destroy --all -y # every stack in the bucket
471
477
  cdkd state destroy MyStack --region us-east-1
472
478
  ```
473
479
 
474
- > `cdkd state destroy` vs `cdkd state rm`: `state destroy` deletes both the
475
- > AWS resources and the state record (the equivalent of `cdkd destroy` minus
476
- > the CDK-app dependency). `state rm` only forgets the state record and
477
- > leaves the AWS resources intact.
480
+ > **`destroy` vs `orphan`** (matches aws-cdk-cli's new `cdk orphan`):
481
+ > `destroy` deletes the AWS resources AND the state record. `orphan` deletes
482
+ > ONLY the state record AWS resources remain intact, just no longer
483
+ > tracked by cdkd. Each has a synth-driven form (`cdkd destroy` / `cdkd
484
+ > orphan`, needs the CDK app) and a state-driven form (`cdkd state destroy`
485
+ > / `cdkd state orphan`, works on the bucket alone).
478
486
 
479
487
  ### Concurrency Options
480
488
 
@@ -561,14 +569,60 @@ s3://{state-bucket}/
561
569
  > `env.region` between deploys silently overwrote the prior region's state
562
570
  > and `cdkd destroy` ran against the wrong region. cdkd now treats the two
563
571
  > regions as independent. Use `cdkd state list` to see both, and
564
- > `cdkd state rm <stack> --stack-region <region>` to prune one without
572
+ > `cdkd state orphan <stack> --stack-region <region>` to prune one without
565
573
  > touching the other.
566
574
  >
567
- > **Legacy layout migration:** state files written by cdkd before this
568
- > layout (`version: 1`, flat `cdkd/{stackName}/state.json`) are still
569
- > readable. The next cdkd write auto-migrates to the new key and removes
570
- > the legacy file. An older cdkd binary reading a `version: 2` file fails
571
- > with a clear "upgrade cdkd" error rather than silently mishandling it.
575
+ > **Legacy key-layout migration (within the same bucket):** state files
576
+ > written by cdkd before this layout (`version: 1`, flat
577
+ > `cdkd/{stackName}/state.json`) are still readable. The next cdkd write
578
+ > auto-migrates to the new region-prefixed key
579
+ > (`cdkd/{stackName}/{region}/state.json`) and removes the legacy file
580
+ > no manual action required. An older cdkd binary reading a `version: 2`
581
+ > file fails with a clear "upgrade cdkd" error rather than silently
582
+ > mishandling it.
583
+ >
584
+ > Note: this only covers the **key layout inside an existing state
585
+ > bucket**. The separate **bucket-name migration** (legacy
586
+ > `cdkd-state-{accountId}-{region}` → new `cdkd-state-{accountId}`)
587
+ > is described below and does NOT auto-migrate.
588
+
589
+ ### Bucket migration
590
+
591
+ The default state-bucket name changed in v0.11.0 from the region-suffixed
592
+ `cdkd-state-{accountId}-{region}` to the region-free
593
+ `cdkd-state-{accountId}`. The bucket name is region-free because S3 names
594
+ are globally unique, so teammates with different profile regions all
595
+ converge on the same bucket; the bucket's actual region is auto-detected
596
+ via `GetBucketLocation`.
597
+
598
+ Existing users keep working without doing anything: when only the legacy
599
+ bucket exists, cdkd transparently falls back to it and emits a
600
+ deprecation warning. To stop the warning (and consolidate state into the
601
+ new bucket) run:
602
+
603
+ ```bash
604
+ # Per-region: copies all objects from cdkd-state-{accountId}-{region}
605
+ # into cdkd-state-{accountId}. Source bucket is kept by default.
606
+ cdkd state migrate --region us-east-1
607
+
608
+ # Optional: delete the legacy bucket once the copy is verified.
609
+ cdkd state migrate --region us-east-1 --remove-legacy
610
+ ```
611
+
612
+ This migration is **account-wide / per-region**, not per-stack — running
613
+ it once per region clears the legacy bucket for that region in one shot.
614
+ For multi-region accounts, run it once per region (each invocation copies
615
+ into the same destination bucket).
616
+
617
+ `cdkd state migrate` refuses to run while any stack has an active
618
+ `lock.json` (an in-flight `cdkd deploy` / `destroy` would race the copy),
619
+ verifies object-count parity between source and destination before any
620
+ source cleanup, and only deletes the legacy bucket when
621
+ `--remove-legacy` is passed.
622
+
623
+ See the [Configuration](#configuration) table below for the full
624
+ precedence rules of the `--state-bucket` flag and its env-var / cdk.json
625
+ fallbacks.
572
626
 
573
627
  ### Configuration
574
628
 
package/dist/cli.js CHANGED
@@ -447,7 +447,7 @@ var init_aws_clients = __esm({
447
447
  });
448
448
 
449
449
  // src/cli/index.ts
450
- import { Command as Command12 } from "commander";
450
+ import { Command as Command13 } from "commander";
451
451
 
452
452
  // src/cli/commands/bootstrap.ts
453
453
  import { Command, Option as Option2 } from "commander";
@@ -3488,7 +3488,7 @@ var S3StateBackend = class {
3488
3488
  *
3489
3489
  * Returns true for either layout: the new region-scoped key, or the legacy
3490
3490
  * key when its embedded `region` matches the requested region. This lets
3491
- * `cdkd state rm <stack> --region X` and `cdkd destroy <stack>` see legacy
3491
+ * `cdkd state orphan <stack> --region X` and `cdkd destroy <stack>` see legacy
3492
3492
  * state without forcing a write-through migration first.
3493
3493
  */
3494
3494
  async stateExists(stackName, region) {
@@ -30630,7 +30630,7 @@ Preparing to destroy stack: ${stackName}`);
30630
30630
  } else {
30631
30631
  const regions = refs.map((r) => r.region ?? "(legacy)").join(", ");
30632
30632
  throw new Error(
30633
- `Stack '${stackName}' has state in multiple regions: ${regions}. Use 'cdkd state rm ${stackName} --region <region>' to remove cdkd's record for one region, or run destroy from a CDK app whose env.region matches one of them.`
30633
+ `Stack '${stackName}' has state in multiple regions: ${regions}. Use 'cdkd state orphan ${stackName} --region <region>' to remove cdkd's record for one region, or run destroy from a CDK app whose env.region matches one of them.`
30634
30634
  );
30635
30635
  }
30636
30636
  const stateResult = await stateBackend.getState(stackName, stackTargetRegion);
@@ -30670,8 +30670,192 @@ function createDestroyCommand() {
30670
30670
  return cmd;
30671
30671
  }
30672
30672
 
30673
+ // src/cli/commands/orphan.ts
30674
+ import * as readline2 from "node:readline/promises";
30675
+ import { Command as Command7 } from "commander";
30676
+ init_aws_clients();
30677
+ async function orphanCommand(stackArgs, options) {
30678
+ const logger = getLogger();
30679
+ if (options.verbose)
30680
+ logger.setLevel("debug");
30681
+ warnIfDeprecatedRegion(options);
30682
+ const region = options.region || process.env["AWS_REGION"] || "us-east-1";
30683
+ const stateBucket = await resolveStateBucketWithDefault(options.stateBucket, region);
30684
+ logger.info("Starting stack orphan...");
30685
+ logger.debug("Options:", options);
30686
+ if (options.region) {
30687
+ process.env["AWS_REGION"] = options.region;
30688
+ process.env["AWS_DEFAULT_REGION"] = options.region;
30689
+ }
30690
+ const awsClients = new AwsClients({
30691
+ ...options.region && { region: options.region },
30692
+ ...options.profile && { profile: options.profile }
30693
+ });
30694
+ setAwsClients(awsClients);
30695
+ try {
30696
+ const stateConfig = {
30697
+ bucket: stateBucket,
30698
+ prefix: options.statePrefix
30699
+ };
30700
+ const stateBackend = new S3StateBackend(awsClients.s3, stateConfig, {
30701
+ ...options.region && { region: options.region },
30702
+ ...options.profile && { profile: options.profile }
30703
+ });
30704
+ await stateBackend.verifyBucketExists();
30705
+ const lockManager = new LockManager(awsClients.s3, stateConfig);
30706
+ const appCmd = options.app || resolveApp();
30707
+ let appStacks = [];
30708
+ if (appCmd) {
30709
+ try {
30710
+ const synthesizer = new Synthesizer();
30711
+ const context = parseContextOptions(options.context);
30712
+ const result = await synthesizer.synthesize({
30713
+ app: appCmd,
30714
+ output: options.output || "cdk.out",
30715
+ ...Object.keys(context).length > 0 && { context }
30716
+ });
30717
+ appStacks = result.stacks.map((s) => ({
30718
+ stackName: s.stackName,
30719
+ displayName: s.displayName,
30720
+ ...s.region && { region: s.region }
30721
+ }));
30722
+ } catch {
30723
+ logger.debug("Could not synthesize app, falling back to state-based stack list");
30724
+ }
30725
+ }
30726
+ const allStateRefs = await stateBackend.listStacks();
30727
+ let candidateStacks;
30728
+ if (appStacks.length > 0) {
30729
+ const stateNames = new Set(allStateRefs.map((r) => r.stackName));
30730
+ candidateStacks = appStacks.filter((s) => stateNames.has(s.stackName));
30731
+ } else if (stackArgs.length > 0 || options.stack || options.all) {
30732
+ const seen = /* @__PURE__ */ new Set();
30733
+ candidateStacks = [];
30734
+ for (const ref of allStateRefs) {
30735
+ if (seen.has(ref.stackName))
30736
+ continue;
30737
+ seen.add(ref.stackName);
30738
+ candidateStacks.push({ stackName: ref.stackName });
30739
+ }
30740
+ } else {
30741
+ throw new Error(
30742
+ "Could not determine which stacks belong to this app. Specify stack names explicitly, use --all, or ensure --app / cdk.json is configured."
30743
+ );
30744
+ }
30745
+ const stackPatterns = stackArgs.length > 0 ? stackArgs : options.stack ? [options.stack] : [];
30746
+ let stackNames;
30747
+ if (options.all) {
30748
+ stackNames = candidateStacks.map((s) => s.stackName);
30749
+ } else if (stackPatterns.length > 0) {
30750
+ stackNames = matchStacks(candidateStacks, stackPatterns).map((s) => s.stackName);
30751
+ } else if (candidateStacks.length === 1) {
30752
+ stackNames = candidateStacks.map((s) => s.stackName);
30753
+ } else if (candidateStacks.length === 0) {
30754
+ logger.info("No stacks found in state");
30755
+ return;
30756
+ } else {
30757
+ throw new Error(
30758
+ `Multiple stacks found: ${candidateStacks.map(describeStack).join(", ")}. Specify stack name(s) or use --all`
30759
+ );
30760
+ }
30761
+ if (stackNames.length === 0) {
30762
+ logger.info("No matching stacks found in state");
30763
+ return;
30764
+ }
30765
+ logger.info(`Found ${stackNames.length} stack(s) to orphan: ${stackNames.join(", ")}`);
30766
+ const stateRefsByName = /* @__PURE__ */ new Map();
30767
+ for (const ref of allStateRefs) {
30768
+ const arr = stateRefsByName.get(ref.stackName) ?? [];
30769
+ arr.push(ref);
30770
+ stateRefsByName.set(ref.stackName, arr);
30771
+ }
30772
+ const skipConfirmation = options.yes || options.force;
30773
+ for (const stackName of stackNames) {
30774
+ const refs = stateRefsByName.get(stackName) ?? [];
30775
+ if (refs.length === 0) {
30776
+ logger.info(`No state found for stack: ${stackName}, skipping`);
30777
+ continue;
30778
+ }
30779
+ const targets = options.stackRegion ? refs.filter((r) => r.region === options.stackRegion) : refs;
30780
+ if (targets.length === 0) {
30781
+ const seen = refs.map((r) => r.region ?? "(legacy)").join(", ");
30782
+ throw new Error(
30783
+ `No state found for stack '${stackName}' in region '${options.stackRegion}'. Available regions: ${seen}.`
30784
+ );
30785
+ }
30786
+ if (!options.force) {
30787
+ for (const target of targets) {
30788
+ const locked = await lockManager.isLocked(stackName, target.region);
30789
+ if (locked) {
30790
+ const where = target.region ?? "(legacy)";
30791
+ throw new Error(
30792
+ `Stack '${stackName}' (${where}) is locked. Run 'cdkd force-unlock ${stackName}${target.region ? ` --stack-region ${target.region}` : ""}' first, or pass --force to orphan anyway.`
30793
+ );
30794
+ }
30795
+ }
30796
+ }
30797
+ if (!skipConfirmation) {
30798
+ const targetList = targets.map((t) => t.region ? `${stackName} (${t.region})` : stackName).join(", ");
30799
+ process.stdout.write(
30800
+ `
30801
+ WARNING: This removes cdkd's state record for [${targetList}] only. AWS resources will NOT be deleted.
30802
+ Use 'cdkd destroy ${stackName}' if you want to delete the actual resources.
30803
+
30804
+ `
30805
+ );
30806
+ const rl = readline2.createInterface({
30807
+ input: process.stdin,
30808
+ output: process.stdout
30809
+ });
30810
+ const answer = await rl.question(
30811
+ `Orphan state for ${targetList} from s3://${stateBucket}/${options.statePrefix}/? (y/N): `
30812
+ );
30813
+ rl.close();
30814
+ const trimmed = answer.trim().toLowerCase();
30815
+ if (trimmed !== "y" && trimmed !== "yes") {
30816
+ logger.info(`Cancelled orphan of stack: ${stackName}`);
30817
+ continue;
30818
+ }
30819
+ }
30820
+ for (const target of targets) {
30821
+ if (target.region) {
30822
+ await stateBackend.deleteState(stackName, target.region);
30823
+ await lockManager.forceReleaseLock(stackName, target.region);
30824
+ } else {
30825
+ await lockManager.forceReleaseLock(stackName, void 0);
30826
+ }
30827
+ const label = target.region ? `${stackName} (${target.region})` : stackName;
30828
+ logger.info(`\u2713 Orphaned state for stack: ${label}`);
30829
+ }
30830
+ }
30831
+ } finally {
30832
+ awsClients.destroy();
30833
+ }
30834
+ }
30835
+ function createOrphanCommand() {
30836
+ const cmd = new Command7("orphan").description(
30837
+ "Remove cdkd's state record for one or more stacks (does NOT delete AWS resources). Synth-driven; for the CDK-app-free version use 'cdkd state orphan'."
30838
+ ).argument(
30839
+ "[stacks...]",
30840
+ "Stack name(s) to orphan. Accepts physical CloudFormation names (e.g. 'MyStage-Api') or CDK display paths (e.g. 'MyStage/Api'). Supports wildcards (e.g. 'MyStage/*')."
30841
+ ).option("--all", "Orphan all stacks in the current app", false).option(
30842
+ "--stack-region <region>",
30843
+ "Region of the stack record to operate on. Required when the same stack name has state in multiple regions."
30844
+ ).action(withErrorHandling(orphanCommand));
30845
+ [
30846
+ ...commonOptions,
30847
+ ...appOptions,
30848
+ ...stateOptions,
30849
+ ...stackOptions,
30850
+ ...destroyOptions,
30851
+ ...contextOptions
30852
+ ].forEach((opt) => cmd.addOption(opt));
30853
+ cmd.addOption(deprecatedRegionOption);
30854
+ return cmd;
30855
+ }
30856
+
30673
30857
  // src/cli/commands/publish-assets.ts
30674
- import { Option as Option3, Command as Command7 } from "commander";
30858
+ import { Option as Option3, Command as Command8 } from "commander";
30675
30859
  async function publishAssetsCommand(options) {
30676
30860
  const logger = getLogger();
30677
30861
  if (options.verbose) {
@@ -30690,7 +30874,7 @@ async function publishAssetsCommand(options) {
30690
30874
  logger.info("\u2705 Asset publishing complete");
30691
30875
  }
30692
30876
  function createPublishAssetsCommand() {
30693
- const cmd = new Command7("publish-assets").description("Publish assets to S3/ECR from asset manifest").requiredOption("--path <path>", "Path to asset manifest file or directory").addOption(
30877
+ const cmd = new Command8("publish-assets").description("Publish assets to S3/ECR from asset manifest").requiredOption("--path <path>", "Path to asset manifest file or directory").addOption(
30694
30878
  new Option3(
30695
30879
  "--asset-publish-concurrency <number>",
30696
30880
  "Maximum concurrent asset publish operations"
@@ -30704,7 +30888,7 @@ function createPublishAssetsCommand() {
30704
30888
  }
30705
30889
 
30706
30890
  // src/cli/commands/force-unlock.ts
30707
- import { Command as Command8, Option as Option4 } from "commander";
30891
+ import { Command as Command9, Option as Option4 } from "commander";
30708
30892
  init_aws_clients();
30709
30893
  async function forceUnlockCommand(stackArgs, options) {
30710
30894
  const logger = getLogger();
@@ -30764,7 +30948,7 @@ async function forceUnlockCommand(stackArgs, options) {
30764
30948
  }
30765
30949
  }
30766
30950
  function createForceUnlockCommand() {
30767
- const cmd = new Command8("force-unlock").description("Force-release a stale lock on a stack").argument("[stacks...]", "Stack name(s) to unlock").addOption(
30951
+ const cmd = new Command9("force-unlock").description("Force-release a stale lock on a stack").argument("[stacks...]", "Stack name(s) to unlock").addOption(
30768
30952
  new Option4(
30769
30953
  "--stack-region <region>",
30770
30954
  "Stack region whose lock to release (use when the same stack name has locks in multiple regions). Defaults to all regions where the stack has state."
@@ -30776,8 +30960,8 @@ function createForceUnlockCommand() {
30776
30960
  }
30777
30961
 
30778
30962
  // src/cli/commands/state.ts
30779
- import * as readline3 from "node:readline/promises";
30780
- import { Command as Command10, Option as Option5 } from "commander";
30963
+ import * as readline4 from "node:readline/promises";
30964
+ import { Command as Command11, Option as Option5 } from "commander";
30781
30965
  import {
30782
30966
  GetBucketLocationCommand as GetBucketLocationCommand2,
30783
30967
  GetObjectCommand as GetObjectCommand4,
@@ -30786,8 +30970,8 @@ import {
30786
30970
  init_aws_clients();
30787
30971
 
30788
30972
  // src/cli/commands/state-migrate.ts
30789
- import * as readline2 from "node:readline/promises";
30790
- import { Command as Command9 } from "commander";
30973
+ import * as readline3 from "node:readline/promises";
30974
+ import { Command as Command10 } from "commander";
30791
30975
  import {
30792
30976
  CopyObjectCommand,
30793
30977
  CreateBucketCommand as CreateBucketCommand4,
@@ -31061,7 +31245,7 @@ async function emptyBucketAllVersions(s3, bucket) {
31061
31245
  } while (keyMarker || versionIdMarker);
31062
31246
  }
31063
31247
  async function confirmPrompt(prompt) {
31064
- const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
31248
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
31065
31249
  try {
31066
31250
  const ans = await rl.question(`${prompt} [y/N] `);
31067
31251
  return /^y(es)?$/i.test(ans.trim());
@@ -31070,7 +31254,7 @@ async function confirmPrompt(prompt) {
31070
31254
  }
31071
31255
  }
31072
31256
  function createStateMigrateCommand() {
31073
- const cmd = new Command9("migrate").description(
31257
+ const cmd = new Command10("migrate").description(
31074
31258
  "Migrate state from the legacy region-suffixed bucket (cdkd-state-{account}-{region}) to the new region-free default (cdkd-state-{account}). Source bucket is kept by default; pass --remove-legacy to delete it after a successful migration."
31075
31259
  ).option(
31076
31260
  "--region <region>",
@@ -31228,7 +31412,7 @@ async function stateListCommand(options) {
31228
31412
  }
31229
31413
  }
31230
31414
  function createStateListCommand() {
31231
- const cmd = new Command10("list").alias("ls").description("List stacks registered in the cdkd state bucket").option("-l, --long", "Show resource count, last-modified time, and lock status", false).option("--json", "Output as JSON", false).action(withErrorHandling(stateListCommand));
31415
+ const cmd = new Command11("list").alias("ls").description("List stacks registered in the cdkd state bucket").option("-l, --long", "Show resource count, last-modified time, and lock status", false).option("--json", "Output as JSON", false).action(withErrorHandling(stateListCommand));
31232
31416
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
31233
31417
  cmd.addOption(deprecatedRegionOption);
31234
31418
  return cmd;
@@ -31332,7 +31516,7 @@ function formatLockSummary(lockInfo) {
31332
31516
  return `locked by ${lockInfo.owner}${opStr}, ${expiresStr}`;
31333
31517
  }
31334
31518
  function createStateResourcesCommand() {
31335
- const cmd = new Command10("resources").description("List resources recorded in a stack's state").argument("<stack>", "Stack name (physical CloudFormation name)").option("-l, --long", "Include dependencies and attributes per resource", false).option("--json", "Output as JSON", false).addOption(stackRegionOption()).action(withErrorHandling(stateResourcesCommand));
31519
+ const cmd = new Command11("resources").description("List resources recorded in a stack's state").argument("<stack>", "Stack name (physical CloudFormation name)").option("-l, --long", "Include dependencies and attributes per resource", false).option("--json", "Output as JSON", false).addOption(stackRegionOption()).action(withErrorHandling(stateResourcesCommand));
31336
31520
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
31337
31521
  cmd.addOption(deprecatedRegionOption);
31338
31522
  return cmd;
@@ -31420,17 +31604,17 @@ async function stateShowCommand(stackName, options) {
31420
31604
  }
31421
31605
  }
31422
31606
  function createStateShowCommand() {
31423
- const cmd = new Command10("show").description("Show the full cdkd state record for a stack (metadata, outputs, resources)").argument("<stack>", "Stack name (physical CloudFormation name)").option("--json", "Output the raw state and lock as JSON", false).addOption(stackRegionOption()).action(withErrorHandling(stateShowCommand));
31607
+ const cmd = new Command11("show").description("Show the full cdkd state record for a stack (metadata, outputs, resources)").argument("<stack>", "Stack name (physical CloudFormation name)").option("--json", "Output the raw state and lock as JSON", false).addOption(stackRegionOption()).action(withErrorHandling(stateShowCommand));
31424
31608
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
31425
31609
  cmd.addOption(deprecatedRegionOption);
31426
31610
  return cmd;
31427
31611
  }
31428
- async function stateRmCommand(stackArgs, options) {
31612
+ async function stateOrphanCommand(stackArgs, options) {
31429
31613
  const logger = getLogger();
31430
31614
  if (options.verbose)
31431
31615
  logger.setLevel("debug");
31432
31616
  if (stackArgs.length === 0) {
31433
- throw new Error("Stack name is required. Usage: cdkd state rm <stack> [<stack>...]");
31617
+ throw new Error("Stack name is required. Usage: cdkd state orphan <stack> [<stack>...]");
31434
31618
  }
31435
31619
  const setup = await setupStateBackend(options);
31436
31620
  try {
@@ -31468,7 +31652,7 @@ Use 'cdkd destroy ${stackName}' if you want to delete the actual resources.
31468
31652
 
31469
31653
  `
31470
31654
  );
31471
- const rl = readline3.createInterface({
31655
+ const rl = readline4.createInterface({
31472
31656
  input: process.stdin,
31473
31657
  output: process.stdout
31474
31658
  });
@@ -31502,8 +31686,10 @@ function stackRegionOption() {
31502
31686
  "Region of the stack record to operate on. Required when the same stack name has state in multiple regions."
31503
31687
  );
31504
31688
  }
31505
- function createStateRmCommand() {
31506
- const cmd = new Command10("rm").description("Remove cdkd state for one or more stacks (does NOT delete AWS resources)").argument("<stacks...>", "Stack name(s) to remove from state").option("-f, --force", "Skip confirmation and remove even if the stack is locked", false).addOption(stackRegionOption()).action(withErrorHandling(stateRmCommand));
31689
+ function createStateOrphanCommand() {
31690
+ const cmd = new Command11("orphan").description(
31691
+ "Orphan one or more stacks from cdkd state (removes the state record; does NOT delete AWS resources)"
31692
+ ).argument("<stacks...>", "Stack name(s) to orphan from state").option("-f, --force", "Skip confirmation and remove even if the stack is locked", false).addOption(stackRegionOption()).action(withErrorHandling(stateOrphanCommand));
31507
31693
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
31508
31694
  cmd.addOption(deprecatedRegionOption);
31509
31695
  return cmd;
@@ -31553,7 +31739,7 @@ WARNING: This destroys ${stackNames.length} stack(s) and removes their state rec
31553
31739
  `);
31554
31740
  }
31555
31741
  process.stdout.write("\n");
31556
- const rl = readline3.createInterface({
31742
+ const rl = readline4.createInterface({
31557
31743
  input: process.stdin,
31558
31744
  output: process.stdout
31559
31745
  });
@@ -31628,8 +31814,8 @@ Preparing to destroy stack: ${stackName}${ref.region ? ` (${ref.region})` : ""}`
31628
31814
  }
31629
31815
  }
31630
31816
  function createStateDestroyCommand() {
31631
- const cmd = new Command10("destroy").description(
31632
- "Destroy a stack's AWS resources and remove its state record without requiring the CDK app. For removing only the state record (keeping AWS resources intact), use 'cdkd state rm'."
31817
+ const cmd = new Command11("destroy").description(
31818
+ "Destroy a stack's AWS resources and remove its state record without requiring the CDK app. For removing only the state record (keeping AWS resources intact), use 'cdkd state orphan'."
31633
31819
  ).argument("[stacks...]", "Stack name(s) to destroy (physical CloudFormation names)").option("--all", "Destroy every stack in the state bucket", false).addOption(stackRegionOption()).addHelpText(
31634
31820
  "after",
31635
31821
  [
@@ -31641,7 +31827,7 @@ function createStateDestroyCommand() {
31641
31827
  " cdkd state destroy MyStack --state-bucket cdkd-state-test",
31642
31828
  " cdkd state destroy MyStack --stack-region us-west-2",
31643
31829
  "",
31644
- "For removing only the state record (keeping AWS resources intact), use 'cdkd state rm'."
31830
+ "For removing only the state record (keeping AWS resources intact), use 'cdkd state orphan'."
31645
31831
  ].join("\n")
31646
31832
  ).action(withErrorHandling(stateDestroyCommand));
31647
31833
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
@@ -31760,19 +31946,19 @@ async function stateInfoCommand(options) {
31760
31946
  }
31761
31947
  }
31762
31948
  function createStateInfoCommand() {
31763
- const cmd = new Command10("info").description(
31949
+ const cmd = new Command11("info").description(
31764
31950
  "Show cdkd state bucket info (bucket name, region, source, schema version, stack count)"
31765
31951
  ).option("--json", "Output as JSON", false).action(withErrorHandling(stateInfoCommand));
31766
31952
  [...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
31767
31953
  return cmd;
31768
31954
  }
31769
31955
  function createStateCommand() {
31770
- const cmd = new Command10("state").description("Manage cdkd state stored in S3");
31956
+ const cmd = new Command11("state").description("Manage cdkd state stored in S3");
31771
31957
  cmd.addCommand(createStateInfoCommand());
31772
31958
  cmd.addCommand(createStateListCommand());
31773
31959
  cmd.addCommand(createStateResourcesCommand());
31774
31960
  cmd.addCommand(createStateShowCommand());
31775
- cmd.addCommand(createStateRmCommand());
31961
+ cmd.addCommand(createStateOrphanCommand());
31776
31962
  cmd.addCommand(createStateDestroyCommand());
31777
31963
  cmd.addCommand(createStateMigrateCommand());
31778
31964
  return cmd;
@@ -31780,8 +31966,8 @@ function createStateCommand() {
31780
31966
 
31781
31967
  // src/cli/commands/import.ts
31782
31968
  import { readFileSync as readFileSync5 } from "node:fs";
31783
- import * as readline4 from "node:readline/promises";
31784
- import { Command as Command11 } from "commander";
31969
+ import * as readline5 from "node:readline/promises";
31970
+ import { Command as Command12 } from "commander";
31785
31971
  init_aws_clients();
31786
31972
  async function importCommand(stackArg, options) {
31787
31973
  const logger = getLogger();
@@ -32077,7 +32263,7 @@ function formatOutcome(outcome) {
32077
32263
  }
32078
32264
  }
32079
32265
  async function confirmPrompt2(prompt) {
32080
- const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
32266
+ const rl = readline5.createInterface({ input: process.stdin, output: process.stdout });
32081
32267
  try {
32082
32268
  const ans = await rl.question(`${prompt} [y/N] `);
32083
32269
  return /^y(es)?$/i.test(ans.trim());
@@ -32086,7 +32272,7 @@ async function confirmPrompt2(prompt) {
32086
32272
  }
32087
32273
  }
32088
32274
  function createImportCommand() {
32089
- const cmd = new Command11("import").description(
32275
+ const cmd = new Command12("import").description(
32090
32276
  "Adopt already-deployed AWS resources into cdkd state. Reads the CDK app to find logical IDs, resource types, and dependencies; uses the aws:cdk:path tag (or explicit --resource overrides) to find each resource in AWS."
32091
32277
  ).argument(
32092
32278
  "[stack]",
@@ -32122,6 +32308,7 @@ var SUBCOMMANDS = /* @__PURE__ */ new Set([
32122
32308
  "deploy",
32123
32309
  "diff",
32124
32310
  "destroy",
32311
+ "orphan",
32125
32312
  "import",
32126
32313
  "publish-assets",
32127
32314
  "force-unlock",
@@ -32138,14 +32325,15 @@ function reorderArgs(argv) {
32138
32325
  return [...prefix, ...cmdAndAfter, ...beforeCmd];
32139
32326
  }
32140
32327
  async function main() {
32141
- const program = new Command12();
32142
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.17.1");
32328
+ const program = new Command13();
32329
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.18.0");
32143
32330
  program.addCommand(createBootstrapCommand());
32144
32331
  program.addCommand(createSynthCommand());
32145
32332
  program.addCommand(createListCommand());
32146
32333
  program.addCommand(createDeployCommand());
32147
32334
  program.addCommand(createDiffCommand());
32148
32335
  program.addCommand(createDestroyCommand());
32336
+ program.addCommand(createOrphanCommand());
32149
32337
  program.addCommand(createImportCommand());
32150
32338
  program.addCommand(createPublishAssetsCommand());
32151
32339
  program.addCommand(createForceUnlockCommand());