@go-to-k/cdkd 0.4.1 → 0.5.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
@@ -342,6 +342,9 @@ alias cdkd="node $(pwd)/dist/cli.js"
342
342
  # Bootstrap (creates S3 state bucket - only needed once per account/region)
343
343
  cdkd bootstrap
344
344
 
345
+ # List stacks in the CDK app
346
+ cdkd list
347
+
345
348
  # Deploy your CDK app
346
349
  cdkd deploy
347
350
 
@@ -367,6 +370,14 @@ cdkd bootstrap \
367
370
  # Synthesize only
368
371
  cdkd synth --app "npx ts-node app.ts"
369
372
 
373
+ # List all stacks in the CDK app (alias: ls)
374
+ cdkd list
375
+ cdkd ls
376
+ cdkd list --long # YAML records with id/name/environment
377
+ cdkd list --long --json # same, but JSON
378
+ cdkd list --show-dependencies # id + dependency list per stack
379
+ cdkd list 'MyStage/*' # filter by display path (CDK CLI parity)
380
+
370
381
  # Deploy from a pre-synthesized cloud assembly directory
371
382
  cdkd deploy --app cdk.out
372
383
 
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 Command8 } from "commander";
450
+ import { Command as Command9 } from "commander";
451
451
 
452
452
  // src/cli/commands/bootstrap.ts
453
453
  import { Command } from "commander";
@@ -2357,6 +2357,62 @@ function setsEqual(a, b) {
2357
2357
  return true;
2358
2358
  }
2359
2359
 
2360
+ // src/utils/yaml.ts
2361
+ function toYaml(obj, indent = 0) {
2362
+ const prefix = " ".repeat(indent);
2363
+ if (obj === null || obj === void 0)
2364
+ return "null\n";
2365
+ if (typeof obj === "boolean")
2366
+ return `${obj}
2367
+ `;
2368
+ if (typeof obj === "number")
2369
+ return `"${obj}"
2370
+ `;
2371
+ if (typeof obj === "string") {
2372
+ if (obj.includes("\n")) {
2373
+ return `'${obj.replace(/'/g, "''")}'
2374
+ `;
2375
+ }
2376
+ if (obj.startsWith("{") || obj.startsWith("[") || obj.startsWith('"')) {
2377
+ return `'${obj.replace(/'/g, "''")}'
2378
+ `;
2379
+ }
2380
+ if (obj.includes("#") || obj === "" || obj === "true" || obj === "false" || obj === "null") {
2381
+ return `"${obj}"
2382
+ `;
2383
+ }
2384
+ return `${obj}
2385
+ `;
2386
+ }
2387
+ if (Array.isArray(obj)) {
2388
+ if (obj.length === 0)
2389
+ return "[]\n";
2390
+ let result = "\n";
2391
+ for (const item of obj) {
2392
+ const value = toYaml(item, indent + 1).trimStart();
2393
+ result += `${prefix}- ${value}`;
2394
+ }
2395
+ return result;
2396
+ }
2397
+ if (typeof obj === "object") {
2398
+ const entries = Object.entries(obj);
2399
+ if (entries.length === 0)
2400
+ return "{}\n";
2401
+ let result = "\n";
2402
+ for (const [key, value] of entries) {
2403
+ const safeKey = key.includes(" ") ? `"${key}"` : key;
2404
+ if (typeof value === "object" && value !== null) {
2405
+ result += `${prefix}${safeKey}:${toYaml(value, indent + 1)}`;
2406
+ } else {
2407
+ result += `${prefix}${safeKey}: ${toYaml(value, indent + 1).trimStart()}`;
2408
+ }
2409
+ }
2410
+ return result;
2411
+ }
2412
+ return `${String(obj)}
2413
+ `;
2414
+ }
2415
+
2360
2416
  // src/cli/commands/synth.ts
2361
2417
  async function synthCommand(options) {
2362
2418
  const logger = getLogger();
@@ -2407,68 +2463,158 @@ async function synthCommand(options) {
2407
2463
  logger.info(`
2408
2464
  Output: ${assemblyDir}`);
2409
2465
  }
2410
- function toYaml(obj, indent = 0) {
2411
- const prefix = " ".repeat(indent);
2412
- if (obj === null || obj === void 0)
2413
- return "null\n";
2414
- if (typeof obj === "boolean")
2415
- return `${obj}
2416
- `;
2417
- if (typeof obj === "number")
2418
- return `"${obj}"
2419
- `;
2420
- if (typeof obj === "string") {
2421
- if (obj.includes("\n")) {
2422
- return `'${obj.replace(/'/g, "''")}'
2423
- `;
2424
- }
2425
- if (obj.startsWith("{") || obj.startsWith("[") || obj.startsWith('"')) {
2426
- return `'${obj.replace(/'/g, "''")}'
2427
- `;
2428
- }
2429
- if (obj.includes("#") || obj === "" || obj === "true" || obj === "false" || obj === "null") {
2430
- return `"${obj}"
2431
- `;
2466
+ function createSynthCommand() {
2467
+ const cmd = new Command2("synth").description("Synthesize CDK app to CloudFormation template").action(withErrorHandling(synthCommand));
2468
+ [...commonOptions, ...appOptions, ...contextOptions].forEach((opt) => cmd.addOption(opt));
2469
+ return cmd;
2470
+ }
2471
+
2472
+ // src/cli/commands/list.ts
2473
+ import { Command as Command3 } from "commander";
2474
+
2475
+ // src/cli/stack-matcher.ts
2476
+ function matchStacks(stacks, patterns) {
2477
+ if (patterns.length === 0)
2478
+ return [];
2479
+ const seen = /* @__PURE__ */ new Set();
2480
+ const result = [];
2481
+ for (const stack of stacks) {
2482
+ const matched = patterns.some((pattern) => stackMatchesPattern(stack, pattern));
2483
+ if (matched && !seen.has(stack.stackName)) {
2484
+ seen.add(stack.stackName);
2485
+ result.push(stack);
2432
2486
  }
2433
- return `${obj}
2434
- `;
2435
2487
  }
2436
- if (Array.isArray(obj)) {
2437
- if (obj.length === 0)
2438
- return "[]\n";
2439
- let result = "\n";
2440
- for (const item of obj) {
2441
- const value = toYaml(item, indent + 1).trimStart();
2442
- result += `${prefix}- ${value}`;
2488
+ return result;
2489
+ }
2490
+ function describeStack(stack) {
2491
+ if (stack.displayName && stack.displayName !== stack.stackName) {
2492
+ return `${stack.stackName} (${stack.displayName})`;
2493
+ }
2494
+ return stack.stackName;
2495
+ }
2496
+ function stackMatchesPattern(stack, pattern) {
2497
+ const target = pattern.includes("/") ? stack.displayName ?? stack.stackName : stack.stackName;
2498
+ if (pattern.includes("*")) {
2499
+ const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
2500
+ return regex.test(target);
2501
+ }
2502
+ return target === pattern;
2503
+ }
2504
+
2505
+ // src/cli/commands/list.ts
2506
+ function sortByDependency(stacks) {
2507
+ const byName = new Map(stacks.map((s) => [s.stackName, s]));
2508
+ const visited = /* @__PURE__ */ new Set();
2509
+ const result = [];
2510
+ const visit = (stack, ancestors) => {
2511
+ if (visited.has(stack.stackName))
2512
+ return;
2513
+ if (ancestors.has(stack.stackName))
2514
+ return;
2515
+ ancestors.add(stack.stackName);
2516
+ for (const depName of stack.dependencyNames) {
2517
+ const dep = byName.get(depName);
2518
+ if (dep)
2519
+ visit(dep, ancestors);
2520
+ }
2521
+ ancestors.delete(stack.stackName);
2522
+ if (!visited.has(stack.stackName)) {
2523
+ visited.add(stack.stackName);
2524
+ result.push(stack);
2443
2525
  }
2444
- return result;
2526
+ };
2527
+ for (const stack of stacks) {
2528
+ visit(stack, /* @__PURE__ */ new Set());
2445
2529
  }
2446
- if (typeof obj === "object") {
2447
- const entries = Object.entries(obj);
2448
- if (entries.length === 0)
2449
- return "{}\n";
2450
- let result = "\n";
2451
- for (const [key, value] of entries) {
2452
- const safeKey = key.includes(" ") ? `"${key}"` : key;
2453
- if (typeof value === "object" && value !== null) {
2454
- result += `${prefix}${safeKey}:${toYaml(value, indent + 1)}`;
2455
- } else {
2456
- result += `${prefix}${safeKey}: ${toYaml(value, indent + 1).trimStart()}`;
2457
- }
2530
+ return result;
2531
+ }
2532
+ function toLongRecord(stack, includeDeps) {
2533
+ const record = {
2534
+ id: stack.displayName,
2535
+ name: stack.stackName,
2536
+ environment: {
2537
+ account: stack.account ?? "unknown-account",
2538
+ region: stack.region ?? "unknown-region"
2458
2539
  }
2459
- return result;
2540
+ };
2541
+ if (includeDeps) {
2542
+ record.dependencies = [...stack.dependencyNames];
2460
2543
  }
2461
- return `${String(obj)}
2462
- `;
2544
+ return record;
2463
2545
  }
2464
- function createSynthCommand() {
2465
- const cmd = new Command2("synth").description("Synthesize CDK app to CloudFormation template").action(withErrorHandling(synthCommand));
2546
+ async function listCommand(patterns, options) {
2547
+ const logger = getLogger();
2548
+ if (options.verbose) {
2549
+ logger.setLevel("debug");
2550
+ }
2551
+ const app = resolveApp(options.app);
2552
+ if (!app) {
2553
+ throw new Error(
2554
+ 'No app command specified. Use --app, set CDKD_APP env var, or add "app" to cdk.json'
2555
+ );
2556
+ }
2557
+ logger.debug("Listing stacks...");
2558
+ logger.debug("App command:", app);
2559
+ const synthesizer = new Synthesizer();
2560
+ const context = parseContextOptions(options.context);
2561
+ const synthOptions = {
2562
+ app,
2563
+ output: options.output,
2564
+ ...options.region && { region: options.region },
2565
+ ...options.profile && { profile: options.profile },
2566
+ ...Object.keys(context).length > 0 && { context }
2567
+ };
2568
+ const result = await synthesizer.synthesize(synthOptions);
2569
+ const allStacks = result.stacks;
2570
+ if (allStacks.length === 0) {
2571
+ throw new Error("No stacks found in assembly");
2572
+ }
2573
+ const selected = patterns.length > 0 ? matchStacks(allStacks, patterns) : allStacks;
2574
+ if (selected.length === 0) {
2575
+ throw new Error(
2576
+ `No stacks matching ${patterns.join(", ")} found in assembly. Available: ${allStacks.map(describeStack).join(", ")}`
2577
+ );
2578
+ }
2579
+ const sorted = sortByDependency(selected);
2580
+ if (options.long) {
2581
+ const records = sorted.map((s) => toLongRecord(s, options.showDependencies));
2582
+ emitStructured(records, options.json);
2583
+ return;
2584
+ }
2585
+ if (options.showDependencies) {
2586
+ const records = sorted.map((s) => ({
2587
+ id: s.displayName,
2588
+ dependencies: [...s.dependencyNames]
2589
+ }));
2590
+ emitStructured(records, options.json);
2591
+ return;
2592
+ }
2593
+ for (const stack of sorted) {
2594
+ process.stdout.write(`${stack.displayName}
2595
+ `);
2596
+ }
2597
+ }
2598
+ function emitStructured(payload, asJson) {
2599
+ if (asJson) {
2600
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}
2601
+ `);
2602
+ return;
2603
+ }
2604
+ const yaml = toYaml(payload).replace(/^\n/, "");
2605
+ process.stdout.write(yaml);
2606
+ }
2607
+ function createListCommand() {
2608
+ const cmd = new Command3("list").alias("ls").description("List all stacks in the CDK app").argument(
2609
+ "[stacks...]",
2610
+ "Stack name pattern(s). Accepts physical CloudFormation names (e.g. 'MyStage-Api') or CDK display paths (e.g. 'MyStage/Api'). Supports wildcards (e.g. 'MyStage/*')."
2611
+ ).option("-l, --long", "Display environment information for each stack", false).option("-d, --show-dependencies", "Display stack dependency information for each stack", false).option("--json", "Output as JSON instead of YAML for --long / --show-dependencies", false).action(withErrorHandling(listCommand));
2466
2612
  [...commonOptions, ...appOptions, ...contextOptions].forEach((opt) => cmd.addOption(opt));
2467
2613
  return cmd;
2468
2614
  }
2469
2615
 
2470
2616
  // src/cli/commands/deploy.ts
2471
- import { Command as Command3 } from "commander";
2617
+ import { Command as Command4 } from "commander";
2472
2618
 
2473
2619
  // src/assets/asset-publisher.ts
2474
2620
  import { readFileSync as readFileSync4 } from "node:fs";
@@ -27082,38 +27228,6 @@ var DeployEngine = class {
27082
27228
 
27083
27229
  // src/cli/commands/deploy.ts
27084
27230
  init_aws_clients();
27085
-
27086
- // src/cli/stack-matcher.ts
27087
- function matchStacks(stacks, patterns) {
27088
- if (patterns.length === 0)
27089
- return [];
27090
- const seen = /* @__PURE__ */ new Set();
27091
- const result = [];
27092
- for (const stack of stacks) {
27093
- const matched = patterns.some((pattern) => stackMatchesPattern(stack, pattern));
27094
- if (matched && !seen.has(stack.stackName)) {
27095
- seen.add(stack.stackName);
27096
- result.push(stack);
27097
- }
27098
- }
27099
- return result;
27100
- }
27101
- function describeStack(stack) {
27102
- if (stack.displayName && stack.displayName !== stack.stackName) {
27103
- return `${stack.stackName} (${stack.displayName})`;
27104
- }
27105
- return stack.stackName;
27106
- }
27107
- function stackMatchesPattern(stack, pattern) {
27108
- const target = pattern.includes("/") ? stack.displayName ?? stack.stackName : stack.stackName;
27109
- if (pattern.includes("*")) {
27110
- const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
27111
- return regex.test(target);
27112
- }
27113
- return target === pattern;
27114
- }
27115
-
27116
- // src/cli/commands/deploy.ts
27117
27231
  async function deployCommand(stacks, options) {
27118
27232
  const logger = getLogger();
27119
27233
  if (options.verbose) {
@@ -27347,7 +27461,7 @@ Deploying stack: ${stackInfo.stackName}${stackRegion !== baseRegion ? ` (region:
27347
27461
  }
27348
27462
  }
27349
27463
  function createDeployCommand() {
27350
- const cmd = new Command3("deploy").description("Deploy CDK app using SDK/Cloud Control API").argument(
27464
+ const cmd = new Command4("deploy").description("Deploy CDK app using SDK/Cloud Control API").argument(
27351
27465
  "[stacks...]",
27352
27466
  "Stack name(s) to deploy. Accepts physical CloudFormation names (e.g. 'MyStage-Api') or CDK display paths (e.g. 'MyStage/Api'). Supports wildcards (e.g. 'MyStage/*')."
27353
27467
  ).option("--all", "Deploy all stacks", false).action(withErrorHandling(deployCommand));
@@ -27363,7 +27477,7 @@ function createDeployCommand() {
27363
27477
  }
27364
27478
 
27365
27479
  // src/cli/commands/diff.ts
27366
- import { Command as Command4 } from "commander";
27480
+ import { Command as Command5 } from "commander";
27367
27481
  init_aws_clients();
27368
27482
  var INTRINSIC_KEYS = /* @__PURE__ */ new Set([
27369
27483
  "Ref",
@@ -27561,7 +27675,7 @@ ${createCount} to create, ${updateCount} to update, ${deleteCount} to delete`);
27561
27675
  }
27562
27676
  }
27563
27677
  function createDiffCommand() {
27564
- const cmd = new Command4("diff").description("Show difference between current state and desired state").argument(
27678
+ const cmd = new Command5("diff").description("Show difference between current state and desired state").argument(
27565
27679
  "[stacks...]",
27566
27680
  "Stack name(s) to diff. Accepts physical CloudFormation names (e.g. 'MyStage-Api') or CDK display paths (e.g. 'MyStage/Api'). Supports wildcards (e.g. 'MyStage/*')."
27567
27681
  ).option("--all", "Diff all stacks", false).action(withErrorHandling(diffCommand));
@@ -27572,7 +27686,7 @@ function createDiffCommand() {
27572
27686
  }
27573
27687
 
27574
27688
  // src/cli/commands/destroy.ts
27575
- import { Command as Command5 } from "commander";
27689
+ import { Command as Command6 } from "commander";
27576
27690
  init_aws_clients();
27577
27691
  import * as readline from "node:readline/promises";
27578
27692
  async function destroyCommand(stackArgs, options) {
@@ -27854,7 +27968,7 @@ Acquiring lock for stack ${stackName}...`);
27854
27968
  }
27855
27969
  }
27856
27970
  function createDestroyCommand() {
27857
- const cmd = new Command5("destroy").description("Destroy all resources in the stack").argument(
27971
+ const cmd = new Command6("destroy").description("Destroy all resources in the stack").argument(
27858
27972
  "[stacks...]",
27859
27973
  "Stack name(s) to destroy. Accepts physical CloudFormation names (e.g. 'MyStage-Api') or CDK display paths (e.g. 'MyStage/Api'). Supports wildcards (e.g. 'MyStage/*')."
27860
27974
  ).option("--all", "Destroy all stacks", false).action(withErrorHandling(destroyCommand));
@@ -27870,7 +27984,7 @@ function createDestroyCommand() {
27870
27984
  }
27871
27985
 
27872
27986
  // src/cli/commands/publish-assets.ts
27873
- import { Option as Option2, Command as Command6 } from "commander";
27987
+ import { Option as Option2, Command as Command7 } from "commander";
27874
27988
  async function publishAssetsCommand(options) {
27875
27989
  const logger = getLogger();
27876
27990
  if (options.verbose) {
@@ -27888,7 +28002,7 @@ async function publishAssetsCommand(options) {
27888
28002
  logger.info("\u2705 Asset publishing complete");
27889
28003
  }
27890
28004
  function createPublishAssetsCommand() {
27891
- const cmd = new Command6("publish-assets").description("Publish assets to S3/ECR from asset manifest").requiredOption("--path <path>", "Path to asset manifest file or directory").addOption(
28005
+ 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(
27892
28006
  new Option2(
27893
28007
  "--asset-publish-concurrency <number>",
27894
28008
  "Maximum concurrent asset publish operations"
@@ -27901,7 +28015,7 @@ function createPublishAssetsCommand() {
27901
28015
  }
27902
28016
 
27903
28017
  // src/cli/commands/force-unlock.ts
27904
- import { Command as Command7 } from "commander";
28018
+ import { Command as Command8 } from "commander";
27905
28019
  init_aws_clients();
27906
28020
  async function forceUnlockCommand(stackArgs, options) {
27907
28021
  const logger = getLogger();
@@ -27944,7 +28058,7 @@ async function forceUnlockCommand(stackArgs, options) {
27944
28058
  }
27945
28059
  }
27946
28060
  function createForceUnlockCommand() {
27947
- const cmd = new Command7("force-unlock").description("Force-release a stale lock on a stack").argument("[stacks...]", "Stack name(s) to unlock").action(withErrorHandling(forceUnlockCommand));
28061
+ const cmd = new Command8("force-unlock").description("Force-release a stale lock on a stack").argument("[stacks...]", "Stack name(s) to unlock").action(withErrorHandling(forceUnlockCommand));
27948
28062
  [...commonOptions, ...stateOptions, ...stackOptions].forEach((opt) => cmd.addOption(opt));
27949
28063
  return cmd;
27950
28064
  }
@@ -27953,6 +28067,8 @@ function createForceUnlockCommand() {
27953
28067
  var SUBCOMMANDS = /* @__PURE__ */ new Set([
27954
28068
  "bootstrap",
27955
28069
  "synth",
28070
+ "list",
28071
+ "ls",
27956
28072
  "deploy",
27957
28073
  "diff",
27958
28074
  "destroy",
@@ -27970,10 +28086,11 @@ function reorderArgs(argv) {
27970
28086
  return [...prefix, ...cmdAndAfter, ...beforeCmd];
27971
28087
  }
27972
28088
  async function main() {
27973
- const program = new Command8();
27974
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.4.1");
28089
+ const program = new Command9();
28090
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.5.0");
27975
28091
  program.addCommand(createBootstrapCommand());
27976
28092
  program.addCommand(createSynthCommand());
28093
+ program.addCommand(createListCommand());
27977
28094
  program.addCommand(createDeployCommand());
27978
28095
  program.addCommand(createDiffCommand());
27979
28096
  program.addCommand(createDestroyCommand());