@aws/nx-plugin 1.0.1 → 1.0.3

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.
Files changed (60) hide show
  1. package/LICENSE-THIRD-PARTY +25 -9
  2. package/migrations.json +20 -10
  3. package/package.json +6 -6
  4. package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +3 -3
  5. package/src/agentcore-gateway/agent-connection/generator.js +6 -0
  6. package/src/agentcore-gateway/agent-connection/generator.js.map +1 -1
  7. package/src/connection/scaffold-catalog.d.ts +17 -0
  8. package/src/connection/scaffold-catalog.js +11 -0
  9. package/src/connection/scaffold-catalog.js.map +1 -1
  10. package/src/infra/app/__snapshots__/generator.spec.ts.snap +3 -3
  11. package/src/migrations/latest/terraform-init-target/metadata.json +3 -0
  12. package/src/migrations/latest/terraform-init-target/migration.js +153 -0
  13. package/src/migrations/latest/terraform-init-target/migration.js.map +1 -0
  14. package/src/migrations/v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks/migration.js.map +1 -0
  15. package/src/migrations/v1.0.0-rc.98/0002-shadcn-cn-package/migration.d.ts +6 -0
  16. package/src/migrations/v1.0.0-rc.98/0002-shadcn-cn-package/migration.js.map +1 -0
  17. package/src/migrations/v1.0.2/0001-terraform-harness-environment-variables/metadata.json +3 -0
  18. package/src/migrations/v1.0.2/0001-terraform-harness-environment-variables/migration.d.ts +6 -0
  19. package/src/migrations/v1.0.2/0001-terraform-harness-environment-variables/migration.js +54 -0
  20. package/src/migrations/v1.0.2/0001-terraform-harness-environment-variables/migration.js.map +1 -0
  21. package/src/preset/__snapshots__/generator.spec.ts.snap +2 -2
  22. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +7 -7
  23. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +9 -9
  24. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +8 -8
  25. package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +3 -3
  26. package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +27 -27
  27. package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +6 -6
  28. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +8 -8
  29. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +9 -9
  30. package/src/sdk/open-api.d.ts +2 -2
  31. package/src/sdk/open-api.js +1 -1
  32. package/src/sdk/open-api.js.map +1 -1
  33. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +5 -5
  34. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +19 -19
  35. package/src/terraform/project/generator.js +52 -44
  36. package/src/terraform/project/generator.js.map +1 -1
  37. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +27 -27
  38. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +7 -7
  39. package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +3 -3
  40. package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +3 -3
  41. package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +6 -6
  42. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +4 -4
  43. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +17 -17
  44. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +28 -28
  45. package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +3 -3
  46. package/src/utils/agent-core-constructs/files/terraform/app/agentcore-harness/__nameKebabCase__/__nameKebabCase__.tf.template +1 -1
  47. package/src/utils/test-migration.d.ts +20 -0
  48. package/src/utils/test-migration.js +32 -0
  49. package/src/utils/test-migration.js.map +1 -0
  50. package/src/utils/versions.d.ts +86 -86
  51. package/src/utils/versions.js +79 -79
  52. package/src/utils/versions.js.map +1 -1
  53. package/src/migrations/latest/sandbox-pattern-nested-stacks/migration.js.map +0 -1
  54. package/src/migrations/latest/shadcn-cn-package/migration.js.map +0 -1
  55. /package/src/migrations/latest/{sandbox-pattern-nested-stacks → terraform-init-target}/migration.d.ts +0 -0
  56. /package/src/migrations/{latest/sandbox-pattern-nested-stacks → v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks}/metadata.json +0 -0
  57. /package/src/migrations/{latest/shadcn-cn-package → v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks}/migration.d.ts +0 -0
  58. /package/src/migrations/{latest/sandbox-pattern-nested-stacks → v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks}/migration.js +0 -0
  59. /package/src/migrations/{latest/shadcn-cn-package → v1.0.0-rc.98/0002-shadcn-cn-package}/metadata.json +0 -0
  60. /package/src/migrations/{latest/shadcn-cn-package → v1.0.0-rc.98/0002-shadcn-cn-package}/migration.js +0 -0
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { getProjects, joinPathFragments, updateProjectConfiguration } from "@nx/devkit";
5
+ import { relative } from "path";
6
+ import { TERRAFORM_PROJECT_GENERATOR_INFO } from "../../../terraform/project/generator.js";
7
+ import { formatFilesInSubtree } from "../../../utils/format.js";
8
+ import { sortObjectKeys } from "../../../utils/object.js";
9
+ /**
10
+ * Give the shared Terraform provider plugin cache a single writer.
11
+ *
12
+ * `init`, `test` and `validate` each ran their own `terraform init` against one
13
+ * per-project cache, and Nx schedules them concurrently — `plan` depends on both
14
+ * `init` and `validate`. Two `terraform init` runs filling the cache at once each
15
+ * compute a different hash for the same provider, because the hash covers a
16
+ * directory the other is still writing, and terraform then rejects the mismatch
17
+ * against the lock file: "the cached package ... does not match any of the
18
+ * checksums recorded in the dependency lock file".
19
+ *
20
+ * The new `terraform-init` target runs that init once, and `test`, `validate` and
21
+ * `init` depend on it — `test` and `validate` now run against the `TF_DATA_DIR`
22
+ * it prepared rather than initialising their own.
23
+ */ const TERRAFORM_INIT = 'terraform-init';
24
+ /** `terraform init` as the pre-fix `test` and `validate` targets ran it. */ const BACKENDLESS_INIT = 'terraform init -backend=false';
25
+ const divergedStep = (projectName, targetName)=>`${projectName}: its '${targetName}' target no longer matches the shape the generator produced - left untouched. Point it at the \`TF_DATA_DIR\` of the new \`${TERRAFORM_INIT}\` target and add \`"dependsOn": ["${TERRAFORM_INIT}"]\`, so its \`terraform init\` no longer races the other targets over the provider cache.`;
26
+ /** Path from a target running in `{projectRoot}/src` back to the workspace root. */ const rootRelativePath = (projectRoot)=>relative(joinPathFragments(projectRoot, 'src'), '.').replace(/\\/g, '/');
27
+ const pluginCacheDirFor = (toRoot)=>joinPathFragments(toRoot, '.terraform', 'plugin-cache', '{projectRoot}');
28
+ const dataDirFor = (toRoot, name)=>joinPathFragments(toRoot, 'dist', '{projectRoot}', name);
29
+ /**
30
+ * The target as the generator vends it: `-backend=false` needs no credentials,
31
+ * so this runs on a fresh workspace before `bootstrap`, and its `TF_DATA_DIR`
32
+ * keeps the `.terraform` it initialises out of `src`.
33
+ */ const terraformInitTarget = (projectRoot)=>{
34
+ const toRoot = rootRelativePath(projectRoot);
35
+ const pluginCacheDir = pluginCacheDirFor(toRoot);
36
+ return {
37
+ executor: 'nx:run-commands',
38
+ options: {
39
+ commands: [
40
+ {
41
+ command: `shx mkdir -p ${pluginCacheDir}`,
42
+ forwardAllArgs: false
43
+ },
44
+ BACKENDLESS_INIT
45
+ ],
46
+ forwardAllArgs: true,
47
+ cwd: '{projectRoot}/src',
48
+ parallel: false,
49
+ env: {
50
+ TF_DATA_DIR: dataDirFor(toRoot, TERRAFORM_INIT),
51
+ TF_PLUGIN_CACHE_DIR: pluginCacheDir
52
+ }
53
+ }
54
+ };
55
+ };
56
+ /** Every command a target runs, across its options and its configurations. */ const commandsOf = (target)=>[
57
+ target.options,
58
+ ...Object.values(target.configurations ?? {})
59
+ ].flatMap((holder)=>[
60
+ holder?.command,
61
+ ...Array.isArray(holder?.commands) ? holder.commands : []
62
+ ]).map((command)=>typeof command === 'string' ? command : command?.command).filter((command)=>typeof command === 'string');
63
+ /**
64
+ * Whether the target still runs the `terraform init` this migration orders. A
65
+ * library's `init` runs it directly and an application's delegates to the vended
66
+ * script.
67
+ */ const runsTerraformInit = (target)=>commandsOf(target).some((command)=>command.includes('terraform init') || command.includes('scripts/init.ts'));
68
+ /** Creating the plugin cache directory, which `terraform-init` now does. */ const isMakeCacheDir = (command)=>/^(shx mkdir -p|make-dir)\s/.test(command) && command.includes('plugin-cache');
69
+ /**
70
+ * Rewrites `test` or `validate` to run against the `TF_DATA_DIR` `terraform-init`
71
+ * prepared. Only the exact shape the generator produced is rewritten: its own
72
+ * `terraform init` (with the cache directory the plugin-cache fix added ahead of
73
+ * it), then the one terraform command the target exists to run. Anything else is
74
+ * the user's, and is reported instead.
75
+ */ const migrateInitlessTarget = (target, verb, toRoot)=>{
76
+ const commands = commandsOf(target).filter((command)=>!isMakeCacheDir(command));
77
+ if (commands.length !== 2 || commands[0] !== BACKENDLESS_INIT || commands[1] !== `terraform ${verb}`) {
78
+ return false;
79
+ }
80
+ const options = target.options ?? {};
81
+ const env = options.env ?? {};
82
+ if (env.TF_DATA_DIR !== dataDirFor(toRoot, `terraform-${verb}`)) {
83
+ return false;
84
+ }
85
+ const { TF_DATA_DIR: _dataDir, TF_PLUGIN_CACHE_DIR: _cacheDir, ...rest } = env;
86
+ delete options.commands;
87
+ // `parallel: false` sequenced the init ahead of the command; one command left.
88
+ delete options.parallel;
89
+ target.options = {
90
+ ...options,
91
+ command: `terraform ${verb}`,
92
+ env: {
93
+ ...rest,
94
+ TF_DATA_DIR: dataDirFor(toRoot, TERRAFORM_INIT)
95
+ }
96
+ };
97
+ return true;
98
+ };
99
+ export default async function migration(tree) {
100
+ const nextSteps = [];
101
+ for (const [projectName, project] of getProjects(tree)){
102
+ const generator = project.metadata?.generator;
103
+ if (generator !== TERRAFORM_PROJECT_GENERATOR_INFO.id) continue;
104
+ let targets = project.targets ?? {};
105
+ const toRoot = rootRelativePath(project.root);
106
+ let changed = false;
107
+ // Guarded on the target being absent, so a re-run — and a project generated
108
+ // with it — is a no-op.
109
+ if (!targets[TERRAFORM_INIT]) {
110
+ targets = sortObjectKeys({
111
+ ...targets,
112
+ [TERRAFORM_INIT]: terraformInitTarget(project.root)
113
+ });
114
+ changed = true;
115
+ }
116
+ for (const targetName of [
117
+ 'init',
118
+ 'test',
119
+ 'validate'
120
+ ]){
121
+ const target = targets[targetName];
122
+ if (!target) continue;
123
+ if (target.dependsOn?.includes(TERRAFORM_INIT)) continue;
124
+ // `init` keeps its own backend-configured `terraform init`; `test` and
125
+ // `validate` hand theirs over to `terraform-init`, so nothing is ordered
126
+ // after a target whose shape is no longer recognised.
127
+ const migrated = targetName === 'init' ? runsTerraformInit(target) : migrateInitlessTarget(target, targetName, toRoot);
128
+ if (!migrated) {
129
+ nextSteps.push(divergedStep(projectName, targetName));
130
+ continue;
131
+ }
132
+ // Prepended rather than appended, so a migrated workspace matches a
133
+ // freshly generated one.
134
+ target.dependsOn = [
135
+ TERRAFORM_INIT,
136
+ ...target.dependsOn ?? []
137
+ ];
138
+ changed = true;
139
+ }
140
+ if (changed) {
141
+ updateProjectConfiguration(tree, projectName, {
142
+ ...project,
143
+ targets
144
+ });
145
+ }
146
+ }
147
+ await formatFilesInSubtree(tree);
148
+ return {
149
+ nextSteps
150
+ };
151
+ }
152
+
153
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/terraform-init-target/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { relative } from 'path';\nimport { TERRAFORM_PROJECT_GENERATOR_INFO } from '../../../terraform/project/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { sortObjectKeys } from '../../../utils/object.js';\n\n/**\n * Give the shared Terraform provider plugin cache a single writer.\n *\n * `init`, `test` and `validate` each ran their own `terraform init` against one\n * per-project cache, and Nx schedules them concurrently — `plan` depends on both\n * `init` and `validate`. Two `terraform init` runs filling the cache at once each\n * compute a different hash for the same provider, because the hash covers a\n * directory the other is still writing, and terraform then rejects the mismatch\n * against the lock file: \"the cached package ... does not match any of the\n * checksums recorded in the dependency lock file\".\n *\n * The new `terraform-init` target runs that init once, and `test`, `validate` and\n * `init` depend on it — `test` and `validate` now run against the `TF_DATA_DIR`\n * it prepared rather than initialising their own.\n */\n\nconst TERRAFORM_INIT = 'terraform-init';\n\n/** `terraform init` as the pre-fix `test` and `validate` targets ran it. */\nconst BACKENDLESS_INIT = 'terraform init -backend=false';\n\nconst divergedStep = (projectName: string, targetName: string) =>\n `${projectName}: its '${targetName}' target no longer matches the shape the generator produced - left untouched. Point it at the \\`TF_DATA_DIR\\` of the new \\`${TERRAFORM_INIT}\\` target and add \\`\"dependsOn\": [\"${TERRAFORM_INIT}\"]\\`, so its \\`terraform init\\` no longer races the other targets over the provider cache.`;\n\n/** Path from a target running in `{projectRoot}/src` back to the workspace root. */\nconst rootRelativePath = (projectRoot: string) =>\n relative(joinPathFragments(projectRoot, 'src'), '.').replace(/\\\\/g, '/');\n\nconst pluginCacheDirFor = (toRoot: string) =>\n joinPathFragments(toRoot, '.terraform', 'plugin-cache', '{projectRoot}');\n\nconst dataDirFor = (toRoot: string, name: string) =>\n joinPathFragments(toRoot, 'dist', '{projectRoot}', name);\n\n/**\n * The target as the generator vends it: `-backend=false` needs no credentials,\n * so this runs on a fresh workspace before `bootstrap`, and its `TF_DATA_DIR`\n * keeps the `.terraform` it initialises out of `src`.\n */\nconst terraformInitTarget = (projectRoot: string): TargetConfiguration => {\n const toRoot = rootRelativePath(projectRoot);\n const pluginCacheDir = pluginCacheDirFor(toRoot);\n return {\n executor: 'nx:run-commands',\n options: {\n commands: [\n { command: `shx mkdir -p ${pluginCacheDir}`, forwardAllArgs: false },\n BACKENDLESS_INIT,\n ],\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n parallel: false,\n env: {\n TF_DATA_DIR: dataDirFor(toRoot, TERRAFORM_INIT),\n TF_PLUGIN_CACHE_DIR: pluginCacheDir,\n },\n },\n };\n};\n\n/** Every command a target runs, across its options and its configurations. */\nconst commandsOf = (target: TargetConfiguration): string[] =>\n [target.options, ...Object.values(target.configurations ?? {})]\n .flatMap(\n (holder: { command?: unknown; commands?: unknown } | undefined) => [\n holder?.command,\n ...(Array.isArray(holder?.commands) ? holder.commands : []),\n ],\n )\n .map((command) =>\n typeof command === 'string'\n ? command\n : (command as { command?: unknown } | undefined)?.command,\n )\n .filter((command): command is string => typeof command === 'string');\n\n/**\n * Whether the target still runs the `terraform init` this migration orders. A\n * library's `init` runs it directly and an application's delegates to the vended\n * script.\n */\nconst runsTerraformInit = (target: TargetConfiguration): boolean =>\n commandsOf(target).some(\n (command) =>\n command.includes('terraform init') || command.includes('scripts/init.ts'),\n );\n\n/** Creating the plugin cache directory, which `terraform-init` now does. */\nconst isMakeCacheDir = (command: string) =>\n /^(shx mkdir -p|make-dir)\\s/.test(command) &&\n command.includes('plugin-cache');\n\n/**\n * Rewrites `test` or `validate` to run against the `TF_DATA_DIR` `terraform-init`\n * prepared. Only the exact shape the generator produced is rewritten: its own\n * `terraform init` (with the cache directory the plugin-cache fix added ahead of\n * it), then the one terraform command the target exists to run. Anything else is\n * the user's, and is reported instead.\n */\nconst migrateInitlessTarget = (\n target: TargetConfiguration,\n verb: 'test' | 'validate',\n toRoot: string,\n): boolean => {\n const commands = commandsOf(target).filter(\n (command) => !isMakeCacheDir(command),\n );\n if (\n commands.length !== 2 ||\n commands[0] !== BACKENDLESS_INIT ||\n commands[1] !== `terraform ${verb}`\n ) {\n return false;\n }\n const options = target.options ?? {};\n const env: Record<string, string> = options.env ?? {};\n if (env.TF_DATA_DIR !== dataDirFor(toRoot, `terraform-${verb}`)) {\n return false;\n }\n\n const {\n TF_DATA_DIR: _dataDir,\n TF_PLUGIN_CACHE_DIR: _cacheDir,\n ...rest\n } = env;\n delete options.commands;\n // `parallel: false` sequenced the init ahead of the command; one command left.\n delete options.parallel;\n target.options = {\n ...options,\n command: `terraform ${verb}`,\n env: { ...rest, TF_DATA_DIR: dataDirFor(toRoot, TERRAFORM_INIT) },\n };\n return true;\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [projectName, project] of getProjects(tree)) {\n const generator = (project.metadata as { generator?: string } | undefined)\n ?.generator;\n if (generator !== TERRAFORM_PROJECT_GENERATOR_INFO.id) continue;\n\n let targets = project.targets ?? {};\n const toRoot = rootRelativePath(project.root);\n let changed = false;\n\n // Guarded on the target being absent, so a re-run — and a project generated\n // with it — is a no-op.\n if (!targets[TERRAFORM_INIT]) {\n targets = sortObjectKeys({\n ...targets,\n [TERRAFORM_INIT]: terraformInitTarget(project.root),\n });\n changed = true;\n }\n\n for (const targetName of ['init', 'test', 'validate'] as const) {\n const target = targets[targetName];\n if (!target) continue;\n if (target.dependsOn?.includes(TERRAFORM_INIT)) continue;\n\n // `init` keeps its own backend-configured `terraform init`; `test` and\n // `validate` hand theirs over to `terraform-init`, so nothing is ordered\n // after a target whose shape is no longer recognised.\n const migrated =\n targetName === 'init'\n ? runsTerraformInit(target)\n : migrateInitlessTarget(target, targetName, toRoot);\n if (!migrated) {\n nextSteps.push(divergedStep(projectName, targetName));\n continue;\n }\n\n // Prepended rather than appended, so a migrated workspace matches a\n // freshly generated one.\n target.dependsOn = [TERRAFORM_INIT, ...(target.dependsOn ?? [])];\n changed = true;\n }\n\n if (changed) {\n updateProjectConfiguration(tree, projectName, { ...project, targets });\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","updateProjectConfiguration","relative","TERRAFORM_PROJECT_GENERATOR_INFO","formatFilesInSubtree","sortObjectKeys","TERRAFORM_INIT","BACKENDLESS_INIT","divergedStep","projectName","targetName","rootRelativePath","projectRoot","replace","pluginCacheDirFor","toRoot","dataDirFor","name","terraformInitTarget","pluginCacheDir","executor","options","commands","command","forwardAllArgs","cwd","parallel","env","TF_DATA_DIR","TF_PLUGIN_CACHE_DIR","commandsOf","target","Object","values","configurations","flatMap","holder","Array","isArray","map","filter","runsTerraformInit","some","includes","isMakeCacheDir","test","migrateInitlessTarget","verb","length","_dataDir","_cacheDir","rest","migration","tree","nextSteps","project","generator","metadata","id","targets","root","changed","dependsOn","migrated","push"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { INFRA_APP_GENERATOR_INFO } from '../../../infra/app/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * Widen the stage pattern of the sandbox targets of ts#infra projects from\n * `<stage>/*` to `<stage>/**`.\n *\n * A single `*` matches the stage's own stacks but nothing below them, so it\n * misses stacks a construct creates inside a stack - such as the `us-east-1`\n * WebACL stack a website creates for its CloudFront distribution.\n * `cdk destroy` only deletes the stacks its pattern selects, so\n * `destroy-sandbox` left that stack, and the WebACL it bills for, deployed.\n */\n\nconst SANDBOX_TARGETS = ['deploy-sandbox', 'destroy-sandbox'];\n\n/** A quoted or bare stage pattern ending in a single `*`, ie `\"my-sandbox/*\"`. */\nconst SINGLE_STAR_PATTERN = /^(\"?)\\S+\\/\\*\\1$/;\n\nconst widen = (token: string): string => token.replace(/\\/\\*(\"?)$/, '/**$1');\n\n/**\n * Whether the command is one of the deploy/destroy commands this generator\n * vends - either a direct `cdk deploy`/`cdk destroy`, or the stage-config\n * script that wraps it. Anything else has been hand-written and is reported\n * rather than rewritten.\n */\nconst isGeneratedCommand = (command: string): boolean =>\n /(^|\\s)cdk\\s+(deploy|destroy)(\\s|$)/.test(command) ||\n command.includes('infra-deploy.ts') ||\n command.includes('infra-destroy.ts');\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n let migrated = false;\n\n for (const [name, project] of getProjects(tree)) {\n if (\n (project.metadata as { generator?: string } | undefined)?.generator !==\n INFRA_APP_GENERATOR_INFO.id\n ) {\n continue;\n }\n\n let projectChanged = false;\n\n for (const targetName of SANDBOX_TARGETS) {\n const target: TargetConfiguration | undefined =\n project.targets?.[targetName];\n const command = target?.options?.command;\n if (!target || typeof command !== 'string') {\n continue;\n }\n\n const args = command.split(/\\s+/);\n // Nothing to widen: already `/**`, or the pattern has been removed. Keeps\n // re-runs - and a project generated after this change - a no-op.\n if (!args.some((arg) => SINGLE_STAR_PATTERN.test(arg))) {\n continue;\n }\n\n if (!isGeneratedCommand(command)) {\n nextSteps.push(\n `${name}: its ${targetName} target has been customised, so it was left as it is. Widen its stage pattern from \"<stage>/*\" to \"<stage>/**\" so it also matches stacks nested below the stage's stacks, such as a website's WebACL stack.`,\n );\n continue;\n }\n\n target.options.command = args\n .map((arg) => (SINGLE_STAR_PATTERN.test(arg) ? widen(arg) : arg))\n .join(' ');\n projectChanged = true;\n }\n\n if (projectChanged) {\n updateProjectConfiguration(tree, name, project);\n migrated = true;\n }\n }\n\n if (migrated) {\n await formatFilesInSubtree(tree);\n }\n\n return { nextSteps };\n}\n"],"names":["getProjects","updateProjectConfiguration","INFRA_APP_GENERATOR_INFO","formatFilesInSubtree","SANDBOX_TARGETS","SINGLE_STAR_PATTERN","widen","token","replace","isGeneratedCommand","command","test","includes","migration","tree","nextSteps","migrated","name","project","metadata","generator","id","projectChanged","targetName","target","targets","options","args","split","some","arg","push","map","join"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAIXC,0BAA0B,QACrB,aAAa;AACpB,SAASC,wBAAwB,QAAQ,kCAAkC;AAC3E,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE;;;;;;;;;CASC,GAED,MAAMC,kBAAkB;IAAC;IAAkB;CAAkB;AAE7D,gFAAgF,GAChF,MAAMC,sBAAsB;AAE5B,MAAMC,QAAQ,CAACC,QAA0BA,MAAMC,OAAO,CAAC,aAAa;AAEpE;;;;;CAKC,GACD,MAAMC,qBAAqB,CAACC,UAC1B,qCAAqCC,IAAI,CAACD,YAC1CA,QAAQE,QAAQ,CAAC,sBACjBF,QAAQE,QAAQ,CAAC;AAEnB,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAC9B,IAAIC,WAAW;IAEf,KAAK,MAAM,CAACC,MAAMC,QAAQ,IAAIlB,YAAYc,MAAO;QAC/C,IACE,AAACI,QAAQC,QAAQ,EAAyCC,cAC1DlB,yBAAyBmB,EAAE,EAC3B;YACA;QACF;QAEA,IAAIC,iBAAiB;QAErB,KAAK,MAAMC,cAAcnB,gBAAiB;YACxC,MAAMoB,SACJN,QAAQO,OAAO,EAAE,CAACF,WAAW;YAC/B,MAAMb,UAAUc,QAAQE,SAAShB;YACjC,IAAI,CAACc,UAAU,OAAOd,YAAY,UAAU;gBAC1C;YACF;YAEA,MAAMiB,OAAOjB,QAAQkB,KAAK,CAAC;YAC3B,0EAA0E;YAC1E,iEAAiE;YACjE,IAAI,CAACD,KAAKE,IAAI,CAAC,CAACC,MAAQzB,oBAAoBM,IAAI,CAACmB,OAAO;gBACtD;YACF;YAEA,IAAI,CAACrB,mBAAmBC,UAAU;gBAChCK,UAAUgB,IAAI,CACZ,GAAGd,KAAK,MAAM,EAAEM,WAAW,2MAA2M,CAAC;gBAEzO;YACF;YAEAC,OAAOE,OAAO,CAAChB,OAAO,GAAGiB,KACtBK,GAAG,CAAC,CAACF,MAASzB,oBAAoBM,IAAI,CAACmB,OAAOxB,MAAMwB,OAAOA,KAC3DG,IAAI,CAAC;YACRX,iBAAiB;QACnB;QAEA,IAAIA,gBAAgB;YAClBrB,2BAA2Ba,MAAMG,MAAMC;YACvCF,WAAW;QACb;IACF;IAEA,IAAIA,UAAU;QACZ,MAAMb,qBAAqBW;IAC7B;IAEA,OAAO;QAAEC;IAAU;AACrB"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { type MigrationReturnObject, type Tree } from '@nx/devkit';
6
+ export default function migration(tree: Tree): Promise<MigrationReturnObject>;
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.98/0002-shadcn-cn-package/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type MigrationReturnObject,\n readJson,\n type Tree,\n} from '@nx/devkit';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast.js';\nimport {\n addDependenciesToPackageJson,\n removeDependenciesFromPackageJson,\n} from '../../../utils/dependencies.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_SHADCN_DIR,\n} from '../../../utils/shared-constructs-constants.js';\nimport { TS_VERSIONS } from '../../../utils/versions.js';\n\n/**\n * Move the shared shadcn package onto the `cn` package.\n *\n * The shadcn registry now serves components importing `cn` from the `cn`\n * package and declares it as a registry dependency, so a component added by\n * `shadcn add` no longer resolves the package's own `#lib/utils` helper. This\n * carries an existing workspace onto that shape: the components import `cn`,\n * `src/lib/utils.ts` becomes the single-line re-export shadcn's own install\n * guide prescribes, which keeps every consumer importing `cn` through\n * `<scope>common-shadcn/lib/utils` working, and clsx / tailwind-merge are\n * dropped now that nothing imports them.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Only touches a `packages/common/shadcn` this plugin's generators produced,\n * guarded by `components.json`'s aliases still matching the generated shape.\n * - An import is only rewritten when `cn` is its sole binding, so a file also\n * pulling a user's own helper out of `#lib/utils` keeps resolving through the\n * re-export.\n * - `src/lib/utils.ts` is only rewritten while it still holds the generated\n * `twMerge(clsx(...))` helper; a customised one is reported instead.\n * - clsx / tailwind-merge are only dropped once nothing under `src` imports\n * them.\n * - Idempotent: every write is guarded by the old shape still being present.\n */\n\nconst libraryRoot = joinPathFragments(PACKAGES_DIR, SHARED_SHADCN_DIR);\nconst componentsJsonPath = joinPathFragments(libraryRoot, 'components.json');\nconst packageJsonPath = joinPathFragments(libraryRoot, 'package.json');\nconst srcRoot = joinPathFragments(libraryRoot, 'src');\nconst utilsPath = joinPathFragments(srcRoot, 'lib', 'utils.ts');\n\n/** The aliases today's generators write, which this migration leaves in place. */\nconst generatedAliases: Record<string, string> = {\n components: '#components',\n utils: '#lib/utils',\n hooks: '#hooks',\n lib: '#lib',\n ui: '#components/ui',\n};\n\nconst CN_IMPORT_REWRITE = `\\`import { cn } from '#lib/utils'\\` => \\`import { cn } from 'cn'\\``;\n\n/** The generated helper, whichever way the user's formatter has laid it out. */\nconst GENERATED_CN_HELPER = `\\`twMerge(clsx($_))\\``;\n\nconst importsPackage = (name: string): string => `\\`import $_ from '${name}'\\``;\n\nconst REEXPORT_UTILS = `export { cn } from 'cn';\\n`;\n\nconst DROPPED_PACKAGES = ['clsx', 'tailwind-merge'] as const;\n\n/** Every `.ts`/`.tsx` file in the package's source tree. */\nconst sourceFiles = (tree: Tree, dir: string): string[] => {\n if (!tree.exists(dir)) {\n return [];\n }\n return tree.children(dir).flatMap((entry) => {\n const path = joinPathFragments(dir, entry);\n if (!tree.isFile(path)) {\n return sourceFiles(tree, path);\n }\n return path.endsWith('.ts') || path.endsWith('.tsx') ? [path] : [];\n });\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (!tree.exists(componentsJsonPath) || !tree.exists(packageJsonPath)) {\n return { nextSteps };\n }\n\n const aliases =\n readJson<{ aliases?: Record<string, string> }>(tree, componentsJsonPath)\n .aliases ?? {};\n if (Object.entries(generatedAliases).some(([k, v]) => aliases[k] !== v)) {\n return { nextSteps };\n }\n\n const files = sourceFiles(tree, srcRoot);\n\n for (const file of files) {\n await applyGritQL(tree, file, CN_IMPORT_REWRITE);\n }\n\n if (tree.exists(utilsPath)) {\n if (await matchGritQL(tree, utilsPath, GENERATED_CN_HELPER)) {\n tree.write(utilsPath, REEXPORT_UTILS);\n } else if (tree.read(utilsPath, 'utf-8') !== REEXPORT_UTILS) {\n nextSteps.push(\n `${utilsPath}: no longer holds the generated cn helper - left untouched. Re-export cn from the 'cn' package by hand so consumers importing it from here keep working.`,\n );\n }\n }\n\n addDependenciesToPackageJson(\n tree,\n { cn: TS_VERSIONS.cn },\n {},\n packageJsonPath,\n );\n\n const stillImported = new Set<string>();\n for (const file of sourceFiles(tree, srcRoot)) {\n for (const name of DROPPED_PACKAGES) {\n if (await matchGritQL(tree, file, importsPackage(name))) {\n stillImported.add(name);\n }\n }\n }\n\n const dropped = DROPPED_PACKAGES.filter((name) => !stillImported.has(name));\n removeDependenciesFromPackageJson(tree, dropped, dropped, packageJsonPath);\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["joinPathFragments","readJson","applyGritQL","matchGritQL","addDependenciesToPackageJson","removeDependenciesFromPackageJson","formatFilesInSubtree","PACKAGES_DIR","SHARED_SHADCN_DIR","TS_VERSIONS","libraryRoot","componentsJsonPath","packageJsonPath","srcRoot","utilsPath","generatedAliases","components","utils","hooks","lib","ui","CN_IMPORT_REWRITE","GENERATED_CN_HELPER","importsPackage","name","REEXPORT_UTILS","DROPPED_PACKAGES","sourceFiles","tree","dir","exists","children","flatMap","entry","path","isFile","endsWith","migration","nextSteps","aliases","Object","entries","some","k","v","files","file","write","read","push","cn","stillImported","Set","add","dropped","filter","has"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "description": "Send an empty map rather than null for a vended Terraform AgentCore Harness module's environment_variables, so the first apply does not fail after creating the Harness"
3
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { type MigrationReturnObject, type Tree } from '@nx/devkit';
6
+ export default function migration(tree: Tree): Promise<MigrationReturnObject>;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { joinPathFragments } from "@nx/devkit";
5
+ import { formatFilesInSubtree } from "../../../utils/format.js";
6
+ import { PACKAGES_DIR, SHARED_TERRAFORM_DIR } from "../../../utils/shared-constructs-constants.js";
7
+ /**
8
+ * Stop each vended Terraform AgentCore Harness app module
9
+ * (`app/harnesses/<name>/<name>.tf`) sending a null `environment_variables`.
10
+ *
11
+ * The service stores no environment variables as an empty map and returns one,
12
+ * so a null fails the apply with "inconsistent values for sensitive attribute"
13
+ * once the Harness has already been created, leaving it tainted. Every
14
+ * subsequent apply fails the same way.
15
+ *
16
+ * Modules whose assignment has been edited are left untouched and reported via
17
+ * `nextSteps`.
18
+ */ const TERRAFORM_HARNESS_APP_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/harnesses`;
19
+ /** The assignment the generator used to write. */ const NULLABLE_ASSIGNMENT = 'environment_variables = var.environment_variables';
20
+ /** What it becomes, so the value sent matches what the service returns. */ const COALESCED_ASSIGNMENT = 'environment_variables = coalesce(var.environment_variables, {})';
21
+ const divergedMessage = (filePath)=>`${filePath}: its environment_variables assignment has been edited, so it was left as it is. Change it to \`${COALESCED_ASSIGNMENT}\` — the AgentCore service returns an empty map when a Harness has no environment variables, and sending null fails the apply after the Harness has been created.`;
22
+ export default async function migration(tree) {
23
+ const nextSteps = [];
24
+ let migrated = false;
25
+ if (!tree.exists(TERRAFORM_HARNESS_APP_DIR)) {
26
+ return {
27
+ nextSteps
28
+ }; // This workspace has no Terraform harness modules.
29
+ }
30
+ for (const dirName of tree.children(TERRAFORM_HARNESS_APP_DIR)){
31
+ const filePath = joinPathFragments(TERRAFORM_HARNESS_APP_DIR, dirName, `${dirName}.tf`);
32
+ if (!tree.exists(filePath)) {
33
+ continue; // Not a harness app module directory.
34
+ }
35
+ const contents = tree.read(filePath, 'utf-8') ?? '';
36
+ if (contents.includes(COALESCED_ASSIGNMENT)) {
37
+ continue; // Already migrated, so a re-run is a no-op.
38
+ }
39
+ if (!contents.includes(NULLABLE_ASSIGNMENT)) {
40
+ nextSteps.push(divergedMessage(filePath));
41
+ continue;
42
+ }
43
+ tree.write(filePath, contents.replace(NULLABLE_ASSIGNMENT, COALESCED_ASSIGNMENT));
44
+ migrated = true;
45
+ }
46
+ if (migrated) {
47
+ await formatFilesInSubtree(tree, TERRAFORM_HARNESS_APP_DIR);
48
+ }
49
+ return {
50
+ nextSteps
51
+ };
52
+ }
53
+
54
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.2/0001-terraform-harness-environment-variables/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../../../utils/shared-constructs-constants.js';\n\n/**\n * Stop each vended Terraform AgentCore Harness app module\n * (`app/harnesses/<name>/<name>.tf`) sending a null `environment_variables`.\n *\n * The service stores no environment variables as an empty map and returns one,\n * so a null fails the apply with \"inconsistent values for sensitive attribute\"\n * once the Harness has already been created, leaving it tainted. Every\n * subsequent apply fails the same way.\n *\n * Modules whose assignment has been edited are left untouched and reported via\n * `nextSteps`.\n */\n\nconst TERRAFORM_HARNESS_APP_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/harnesses`;\n\n/** The assignment the generator used to write. */\nconst NULLABLE_ASSIGNMENT = 'environment_variables = var.environment_variables';\n\n/** What it becomes, so the value sent matches what the service returns. */\nconst COALESCED_ASSIGNMENT =\n 'environment_variables = coalesce(var.environment_variables, {})';\n\nconst divergedMessage = (filePath: string) =>\n `${filePath}: its environment_variables assignment has been edited, so it was left as it is. Change it to \\`${COALESCED_ASSIGNMENT}\\` — the AgentCore service returns an empty map when a Harness has no environment variables, and sending null fails the apply after the Harness has been created.`;\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n let migrated = false;\n\n if (!tree.exists(TERRAFORM_HARNESS_APP_DIR)) {\n return { nextSteps }; // This workspace has no Terraform harness modules.\n }\n\n for (const dirName of tree.children(TERRAFORM_HARNESS_APP_DIR)) {\n const filePath = joinPathFragments(\n TERRAFORM_HARNESS_APP_DIR,\n dirName,\n `${dirName}.tf`,\n );\n if (!tree.exists(filePath)) {\n continue; // Not a harness app module directory.\n }\n\n const contents = tree.read(filePath, 'utf-8') ?? '';\n\n if (contents.includes(COALESCED_ASSIGNMENT)) {\n continue; // Already migrated, so a re-run is a no-op.\n }\n\n if (!contents.includes(NULLABLE_ASSIGNMENT)) {\n nextSteps.push(divergedMessage(filePath));\n continue;\n }\n\n tree.write(\n filePath,\n contents.replace(NULLABLE_ASSIGNMENT, COALESCED_ASSIGNMENT),\n );\n migrated = true;\n }\n\n if (migrated) {\n await formatFilesInSubtree(tree, TERRAFORM_HARNESS_APP_DIR);\n }\n\n return { nextSteps };\n}\n"],"names":["joinPathFragments","formatFilesInSubtree","PACKAGES_DIR","SHARED_TERRAFORM_DIR","TERRAFORM_HARNESS_APP_DIR","NULLABLE_ASSIGNMENT","COALESCED_ASSIGNMENT","divergedMessage","filePath","migration","tree","nextSteps","migrated","exists","dirName","children","contents","read","includes","push","write","replace"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,oBAAoB,QACf,gDAAgD;AAEvD;;;;;;;;;;;CAWC,GAED,MAAMC,4BAA4B,GAAGF,aAAa,CAAC,EAAEC,qBAAqB,kBAAkB,CAAC;AAE7F,gDAAgD,GAChD,MAAME,sBAAsB;AAE5B,yEAAyE,GACzE,MAAMC,uBACJ;AAEF,MAAMC,kBAAkB,CAACC,WACvB,GAAGA,SAAS,gGAAgG,EAAEF,qBAAqB,iKAAiK,CAAC;AAEvS,eAAe,eAAeG,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAC9B,IAAIC,WAAW;IAEf,IAAI,CAACF,KAAKG,MAAM,CAACT,4BAA4B;QAC3C,OAAO;YAAEO;QAAU,GAAG,mDAAmD;IAC3E;IAEA,KAAK,MAAMG,WAAWJ,KAAKK,QAAQ,CAACX,2BAA4B;QAC9D,MAAMI,WAAWR,kBACfI,2BACAU,SACA,GAAGA,QAAQ,GAAG,CAAC;QAEjB,IAAI,CAACJ,KAAKG,MAAM,CAACL,WAAW;YAC1B,UAAU,sCAAsC;QAClD;QAEA,MAAMQ,WAAWN,KAAKO,IAAI,CAACT,UAAU,YAAY;QAEjD,IAAIQ,SAASE,QAAQ,CAACZ,uBAAuB;YAC3C,UAAU,4CAA4C;QACxD;QAEA,IAAI,CAACU,SAASE,QAAQ,CAACb,sBAAsB;YAC3CM,UAAUQ,IAAI,CAACZ,gBAAgBC;YAC/B;QACF;QAEAE,KAAKU,KAAK,CACRZ,UACAQ,SAASK,OAAO,CAAChB,qBAAqBC;QAExCM,WAAW;IACb;IAEA,IAAIA,UAAU;QACZ,MAAMX,qBAAqBS,MAAMN;IACnC;IAEA,OAAO;QAAEO;IAAU;AACrB"}
@@ -253,7 +253,7 @@ export default {
253
253
 
254
254
  exports[`preset generator > should run successfully > biome.json 1`] = `
255
255
  "{
256
- "$schema": "https://biomejs.dev/schemas/2.5.12/schema.json",
256
+ "$schema": "https://biomejs.dev/schemas/2.5.14/schema.json",
257
257
  "root": true,
258
258
  "formatter": {
259
259
  "enabled": true,
@@ -422,7 +422,7 @@ catalog:
422
422
  '@nx/js': 23.2.1
423
423
  '@nx/workspace': 23.2.1
424
424
  typescript: ~6.0.3
425
- '@biomejs/biome': 2.5.12
425
+ '@biomejs/biome': 2.5.14
426
426
  '@aws/nx-plugin': ^0.0.0
427
427
  '@aws/nx-plugin-mcp': ^0.0.0
428
428
  "
@@ -763,15 +763,15 @@ name = "proj.test_project"
763
763
  version = "0.1.0"
764
764
  dependencies = [
765
765
  "proj-agent-connection",
766
- "aws-lambda-powertools==3.34.0",
767
- "aws-opentelemetry-distro==0.19.0",
768
- "bedrock-agentcore==1.22.0",
769
- "boto3==1.43.89",
766
+ "aws-lambda-powertools==3.35.0",
767
+ "aws-opentelemetry-distro==0.20.0",
768
+ "bedrock-agentcore==1.23.1",
769
+ "boto3==1.43.98",
770
770
  "fastapi==0.141.1",
771
771
  "mcp==1.28.1",
772
- "strands-agents==1.54.0",
773
- "strands-agents-tools==0.8.8",
774
- "uvicorn==0.52.4"
772
+ "strands-agents==1.56.0",
773
+ "strands-agents-tools==0.8.9",
774
+ "uvicorn==0.53.0"
775
775
  ]
776
776
 
777
777
  [dependency-groups]
@@ -701,20 +701,20 @@ name = "proj.test_project"
701
701
  version = "0.1.0"
702
702
  dependencies = [
703
703
  "proj-agent-connection",
704
- "aws-lambda-powertools==3.34.0",
705
- "aws-opentelemetry-distro==0.19.0",
706
- "bedrock-agentcore==1.22.0",
707
- "boto3==1.43.89",
704
+ "aws-lambda-powertools==3.35.0",
705
+ "aws-opentelemetry-distro==0.20.0",
706
+ "bedrock-agentcore==1.23.1",
707
+ "boto3==1.43.98",
708
708
  "fastapi==0.141.1",
709
709
  "mcp==1.28.1",
710
- "langchain==1.4.0",
711
- "langchain-aws==1.7.5",
712
- "langgraph==1.2.11",
710
+ "langchain==1.4.2",
711
+ "langchain-aws==1.7.8",
712
+ "langgraph==1.2.12",
713
713
  "langgraph-checkpoint-sqlite==3.1.1",
714
714
  "aiosqlite==0.22.1",
715
715
  "ag-ui-protocol==0.1.22",
716
- "ag-ui-langgraph==0.0.44",
717
- "uvicorn==0.52.4"
716
+ "ag-ui-langgraph==0.0.45",
717
+ "uvicorn==0.53.0"
718
718
  ]
719
719
 
720
720
  [dependency-groups]
@@ -5,11 +5,11 @@ exports[`py#agent generator > should create DynamoDB checkpoint table and S3 off
5
5
  required_providers {
6
6
  aws = {
7
7
  source = "hashicorp/aws"
8
- version = "6.63.0"
8
+ version = "6.66.0"
9
9
  }
10
10
  random = {
11
11
  source = "hashicorp/random"
12
- version = "3.9.0"
12
+ version = "3.9.1"
13
13
  }
14
14
  }
15
15
  }
@@ -381,11 +381,11 @@ exports[`py#agent generator > should match snapshot for Terraform generated file
381
381
  required_providers {
382
382
  aws = {
383
383
  source = "hashicorp/aws"
384
- version = "6.63.0"
384
+ version = "6.66.0"
385
385
  }
386
386
  random = {
387
387
  source = "hashicorp/random"
388
- version = "3.9.0"
388
+ version = "3.9.1"
389
389
  }
390
390
  }
391
391
  }
@@ -704,15 +704,15 @@ exports[`py#agent generator > should match snapshot for Terraform generated file
704
704
  required_providers {
705
705
  aws = {
706
706
  source = "hashicorp/aws"
707
- version = "6.63.0"
707
+ version = "6.66.0"
708
708
  }
709
709
  null = {
710
710
  source = "hashicorp/null"
711
- version = "3.3.1"
711
+ version = "3.3.2"
712
712
  }
713
713
  random = {
714
714
  source = "hashicorp/random"
715
- version = "3.9.0"
715
+ version = "3.9.1"
716
716
  }
717
717
  }
718
718
  }
@@ -1063,7 +1063,7 @@ resource "null_resource" "runtime_ready" {
1063
1063
 
1064
1064
  provisioner "local-exec" {
1065
1065
  command = <<-EOT
1066
- uv run --with boto3==1.43.89 python -c "
1066
+ uv run --with boto3==1.43.98 python -c "
1067
1067
  import boto3
1068
1068
  import json
1069
1069
  import os
@@ -35,7 +35,7 @@ exports[`py#dynamodb generator > should generate terraform modules when iac is t
35
35
  required_providers {
36
36
  aws = {
37
37
  source = "hashicorp/aws"
38
- version = "6.63.0"
38
+ version = "6.66.0"
39
39
  }
40
40
  }
41
41
  }
@@ -232,11 +232,11 @@ exports[`py#dynamodb generator > should generate terraform modules when iac is t
232
232
  required_providers {
233
233
  aws = {
234
234
  source = "hashicorp/aws"
235
- version = "6.63.0"
235
+ version = "6.66.0"
236
236
  }
237
237
  random = {
238
238
  source = "hashicorp/random"
239
- version = "3.9.0"
239
+ version = "3.9.1"
240
240
  }
241
241
  }
242
242
  }
@@ -11,7 +11,7 @@ terraform {
11
11
  required_providers {
12
12
  aws = {
13
13
  source = "hashicorp/aws"
14
- version = "6.63.0"
14
+ version = "6.66.0"
15
15
  }
16
16
  }
17
17
  }
@@ -258,15 +258,15 @@ output "api_log_group_arn" {
258
258
  required_providers {
259
259
  archive = {
260
260
  source = "hashicorp/archive"
261
- version = "2.8.0"
261
+ version = "2.8.1"
262
262
  }
263
263
  aws = {
264
264
  source = "hashicorp/aws"
265
- version = "6.63.0"
265
+ version = "6.66.0"
266
266
  }
267
267
  random = {
268
268
  source = "hashicorp/random"
269
- version = "3.9.0"
269
+ version = "3.9.1"
270
270
  }
271
271
  }
272
272
  }
@@ -846,7 +846,7 @@ terraform {
846
846
  required_providers {
847
847
  aws = {
848
848
  source = "hashicorp/aws"
849
- version = "6.63.0"
849
+ version = "6.66.0"
850
850
  }
851
851
  }
852
852
  }
@@ -1093,15 +1093,15 @@ output "api_log_group_arn" {
1093
1093
  required_providers {
1094
1094
  archive = {
1095
1095
  source = "hashicorp/archive"
1096
- version = "2.8.0"
1096
+ version = "2.8.1"
1097
1097
  }
1098
1098
  aws = {
1099
1099
  source = "hashicorp/aws"
1100
- version = "6.63.0"
1100
+ version = "6.66.0"
1101
1101
  }
1102
1102
  random = {
1103
1103
  source = "hashicorp/random"
1104
- version = "3.9.0"
1104
+ version = "3.9.1"
1105
1105
  }
1106
1106
  }
1107
1107
  }
@@ -1754,7 +1754,7 @@ terraform {
1754
1754
  required_providers {
1755
1755
  aws = {
1756
1756
  source = "hashicorp/aws"
1757
- version = "6.63.0"
1757
+ version = "6.66.0"
1758
1758
  }
1759
1759
  }
1760
1760
  }
@@ -2001,15 +2001,15 @@ output "api_log_group_arn" {
2001
2001
  required_providers {
2002
2002
  archive = {
2003
2003
  source = "hashicorp/archive"
2004
- version = "2.8.0"
2004
+ version = "2.8.1"
2005
2005
  }
2006
2006
  aws = {
2007
2007
  source = "hashicorp/aws"
2008
- version = "6.63.0"
2008
+ version = "6.66.0"
2009
2009
  }
2010
2010
  random = {
2011
2011
  source = "hashicorp/random"
2012
- version = "3.9.0"
2012
+ version = "3.9.1"
2013
2013
  }
2014
2014
  }
2015
2015
  }
@@ -2566,11 +2566,11 @@ terraform {
2566
2566
  required_providers {
2567
2567
  aws = {
2568
2568
  source = "hashicorp/aws"
2569
- version = "6.63.0"
2569
+ version = "6.66.0"
2570
2570
  }
2571
2571
  random = {
2572
2572
  source = "hashicorp/random"
2573
- version = "3.9.0"
2573
+ version = "3.9.1"
2574
2574
  }
2575
2575
  }
2576
2576
  }
@@ -2875,15 +2875,15 @@ output "waf_web_acl_arn" {
2875
2875
  required_providers {
2876
2876
  archive = {
2877
2877
  source = "hashicorp/archive"
2878
- version = "2.8.0"
2878
+ version = "2.8.1"
2879
2879
  }
2880
2880
  aws = {
2881
2881
  source = "hashicorp/aws"
2882
- version = "6.63.0"
2882
+ version = "6.66.0"
2883
2883
  }
2884
2884
  random = {
2885
2885
  source = "hashicorp/random"
2886
- version = "3.9.0"
2886
+ version = "3.9.1"
2887
2887
  }
2888
2888
  }
2889
2889
  }
@@ -3914,11 +3914,11 @@ terraform {
3914
3914
  required_providers {
3915
3915
  aws = {
3916
3916
  source = "hashicorp/aws"
3917
- version = "6.63.0"
3917
+ version = "6.66.0"
3918
3918
  }
3919
3919
  random = {
3920
3920
  source = "hashicorp/random"
3921
- version = "3.9.0"
3921
+ version = "3.9.1"
3922
3922
  }
3923
3923
  }
3924
3924
  }
@@ -4223,15 +4223,15 @@ output "waf_web_acl_arn" {
4223
4223
  required_providers {
4224
4224
  archive = {
4225
4225
  source = "hashicorp/archive"
4226
- version = "2.8.0"
4226
+ version = "2.8.1"
4227
4227
  }
4228
4228
  aws = {
4229
4229
  source = "hashicorp/aws"
4230
- version = "6.63.0"
4230
+ version = "6.66.0"
4231
4231
  }
4232
4232
  random = {
4233
4233
  source = "hashicorp/random"
4234
- version = "3.9.0"
4234
+ version = "3.9.1"
4235
4235
  }
4236
4236
  }
4237
4237
  }
@@ -5251,11 +5251,11 @@ terraform {
5251
5251
  required_providers {
5252
5252
  aws = {
5253
5253
  source = "hashicorp/aws"
5254
- version = "6.63.0"
5254
+ version = "6.66.0"
5255
5255
  }
5256
5256
  random = {
5257
5257
  source = "hashicorp/random"
5258
- version = "3.9.0"
5258
+ version = "3.9.1"
5259
5259
  }
5260
5260
  }
5261
5261
  }
@@ -5560,15 +5560,15 @@ output "waf_web_acl_arn" {
5560
5560
  required_providers {
5561
5561
  archive = {
5562
5562
  source = "hashicorp/archive"
5563
- version = "2.8.0"
5563
+ version = "2.8.1"
5564
5564
  }
5565
5565
  aws = {
5566
5566
  source = "hashicorp/aws"
5567
- version = "6.63.0"
5567
+ version = "6.66.0"
5568
5568
  }
5569
5569
  random = {
5570
5570
  source = "hashicorp/random"
5571
- version = "3.9.0"
5571
+ version = "3.9.1"
5572
5572
  }
5573
5573
  }
5574
5574
  }