@aws/nx-plugin 1.0.0-rc.73 → 1.0.0-rc.75

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 (39) hide show
  1. package/LICENSE-THIRD-PARTY +495 -1188
  2. package/README.md +7 -89
  3. package/migrations.json +11 -1
  4. package/package.json +1 -1
  5. package/src/internal/test-matrix/generator.js +15 -0
  6. package/src/internal/test-matrix/generator.js.map +1 -1
  7. package/src/license/dependency-check/collectors/python-collector.js +9 -3
  8. package/src/license/dependency-check/collectors/python-collector.js.map +1 -1
  9. package/src/migrations/latest/py-agent-session-id-middleware-extraction/metadata.json +3 -0
  10. package/src/migrations/latest/py-agent-session-id-middleware-extraction/migration.d.ts +2 -0
  11. package/src/migrations/latest/py-agent-session-id-middleware-extraction/migration.js +118 -0
  12. package/src/migrations/latest/py-agent-session-id-middleware-extraction/migration.js.map +1 -0
  13. package/src/migrations/latest/ts-agent-session-id-middleware-extraction/metadata.json +3 -0
  14. package/src/migrations/latest/ts-agent-session-id-middleware-extraction/migration.d.ts +2 -0
  15. package/src/migrations/latest/ts-agent-session-id-middleware-extraction/migration.js +124 -0
  16. package/src/migrations/latest/ts-agent-session-id-middleware-extraction/migration.js.map +1 -0
  17. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +3 -18
  18. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +2 -13
  19. package/src/py/agent/files/langchain/a2a/main.py.template +4 -15
  20. package/src/py/agent/files/langchain/ag-ui/main.py.template +2 -13
  21. package/src/py/agent/files/langchain/common/middleware/__init__.py.template +0 -0
  22. package/src/py/agent/files/langchain/common/middleware/session_id_middleware.py.template +17 -0
  23. package/src/py/agent/files/langchain/http/main.py.template +2 -14
  24. package/src/py/agent/files/strands/a2a/main.py.template +4 -15
  25. package/src/py/agent/files/strands/ag-ui/main.py.template +2 -13
  26. package/src/py/agent/files/strands/common/middleware/__init__.py.template +0 -0
  27. package/src/py/agent/files/strands/common/middleware/session_id_middleware.py.template +17 -0
  28. package/src/py/agent/files/strands/http/main.py.template +2 -17
  29. package/src/sdk/agentcore-harness.d.ts +6 -0
  30. package/src/sdk/agentcore-harness.js +7 -0
  31. package/src/sdk/agentcore-harness.js.map +1 -0
  32. package/src/sdk/smithy.d.ts +6 -0
  33. package/src/sdk/smithy.js +7 -0
  34. package/src/sdk/smithy.js.map +1 -0
  35. package/src/ts/agent/files/a2a/index.ts.template +4 -11
  36. package/src/ts/agent/files/ag-ui/index.ts.template +2 -12
  37. package/src/ts/agent/files/common-express/middleware/session-id-middleware.ts.template +16 -0
  38. package/src/ts/agent/generator.js +8 -0
  39. package/src/ts/agent/generator.js.map +1 -1
package/README.md CHANGED
@@ -26,106 +26,24 @@
26
26
 
27
27
  ---
28
28
 
29
- **@aws/nx-plugin** is a collection of code generators that scaffold full-stack, production-ready AWS applications inside an [Nx](https://nx.dev) monorepo. Every generator produces best-practice application code **and** the infrastructure to deploy it — type-safe, locally runnable, and ready to deploy.
29
+ **@aws/nx-plugin** is a collection of code generators that scaffold full-stack AWS applications inside an [Nx](https://nx.dev) monorepo. Every generator produces best-practice application code **and** the infrastructure to deploy it — type-safe, locally runnable, and deployable from the start, getting you closer to production.
30
30
 
31
31
  ## Quick Start
32
32
 
33
33
  ### Build with AI
34
34
 
35
- Add the MCP server to your AI assistant and let it build for you.
35
+ **1. Create a workspace**
36
36
 
37
37
  ```bash
38
- claude mcp add nx-plugin-for-aws -- npx -y @aws/nx-plugin-mcp
39
- ```
40
-
41
- <details>
42
- <summary><strong>Kiro</strong></summary>
43
-
44
- Install the [Kiro Power](https://kiro.dev/docs/powers/) for the best experience — no manual MCP configuration needed:
45
-
46
- 1. Open the Kiro Powers panel from the sidebar
47
- 2. Click `+` to add a custom power
48
- 3. Paste: `https://github.com/awslabs/nx-plugin-for-aws/tree/main/powers/nx-plugin-for-aws`
49
- 4. Click install
50
-
51
- Or add the MCP server manually in `.kiro/mcp.json`:
52
-
53
- ```json
54
- {
55
- "mcpServers": {
56
- "nx-plugin-for-aws": {
57
- "command": "npx",
58
- "args": ["-y", "@aws/nx-plugin-mcp"]
59
- }
60
- }
61
- }
62
- ```
63
-
64
- </details>
65
-
66
- <details>
67
- <summary><strong>Claude Code</strong></summary>
68
-
69
- ```bash
70
- claude mcp add nx-plugin-for-aws -- npx -y @aws/nx-plugin-mcp
71
- ```
72
-
73
- </details>
74
-
75
- <details>
76
- <summary><strong>Cursor</strong></summary>
77
-
78
- Add to `~/.cursor/mcp.json`:
79
-
80
- ```json
81
- {
82
- "mcpServers": {
83
- "nx-plugin-for-aws": {
84
- "command": "npx",
85
- "args": ["-y", "@aws/nx-plugin-mcp"]
86
- }
87
- }
88
- }
89
- ```
90
-
91
- </details>
92
-
93
- <details>
94
- <summary><strong>Codex</strong></summary>
95
-
96
- Add to `~/.codex/config.toml`:
97
-
98
- ```toml
99
- [mcp_servers.nx-plugin-for-aws]
100
- command = "npx"
101
- args = ["-y", "@aws/nx-plugin-mcp"]
102
- ```
103
-
104
- </details>
105
-
106
- <details>
107
- <summary><strong>Other assistants</strong></summary>
108
-
109
- Most MCP-compatible assistants use a JSON configuration file. Add the following entry:
110
-
111
- ```json
112
- {
113
- "mcpServers": {
114
- "nx-plugin-for-aws": {
115
- "command": "npx",
116
- "args": ["-y", "@aws/nx-plugin-mcp"]
117
- }
118
- }
119
- }
38
+ pnpm create @aws/nx-workspace my-project
39
+ cd my-project
120
40
  ```
121
41
 
122
- </details>
123
-
124
- Then just ask:
42
+ **2. Open your AI assistant in the created workspace and prompt it**
125
43
 
126
- > _"Use the Nx Plugin for AWS to build a full-stack app with a React website, a tRPC API, Cognito auth, and CDK infrastructure."_
44
+ > _"Use the Nx Plugin for AWS to build a full-stack application consisting of a React website with shadcn and Cognito authentication, connected to a TypeScript Strands agent via the AG-UI protocol, and infrastructure to deploy it."_
127
45
 
128
- Your AI assistant will use the MCP tools to scaffold, connect, and configure everything. See the [Building with AI guide](https://awslabs.github.io/nx-plugin-for-aws/en/get_started/building-with-ai/) for more details.
46
+ Your AI assistant will use the Nx Plugin for AWS MCP server, which is preconfigured in every workspace you create with the command above, to scaffold, connect, and configure everything. See the [Building with AI guide](https://awslabs.github.io/nx-plugin-for-aws/en/get_started/building-with-ai/) for more details.
129
47
 
130
48
  ### Build with the CLI
131
49
 
package/migrations.json CHANGED
@@ -12,6 +12,16 @@
12
12
  "description": "Apply the distribution's security updates in vended agent / MCP server container images",
13
13
  "implementation": "./src/migrations/latest/apt-security-updates-in-container-images/migration"
14
14
  },
15
+ "latest-py-agent-session-id-middleware-extraction": {
16
+ "version": "1.0.0-rc.74",
17
+ "description": "Extract the duplicated _SessionIdMiddleware class in py#agent's main.py into a shared middleware/session_id_middleware.py module",
18
+ "implementation": "./src/migrations/latest/py-agent-session-id-middleware-extraction/migration"
19
+ },
20
+ "latest-ts-agent-session-id-middleware-extraction": {
21
+ "version": "1.0.0-rc.75",
22
+ "description": "Extract the duplicated session-id Express middleware in ts#agent's ag-ui/a2a index.ts into a shared middleware/session-id-middleware.ts module",
23
+ "implementation": "./src/migrations/latest/ts-agent-session-id-middleware-extraction/migration"
24
+ },
15
25
  "v1.0.0-rc.50-0001-modernize-function-props-cast": {
16
26
  "version": "1.0.0-rc.50",
17
27
  "description": "Replace the legacy angle-bracket FunctionProps type assertion with the modern as syntax in generated API constructs",
@@ -133,7 +143,7 @@
133
143
  "implementation": "./src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/migration"
134
144
  },
135
145
  "sync-vended-versions": {
136
- "version": "1.0.0-rc.73",
146
+ "version": "1.0.0-rc.75",
137
147
  "description": "Sync vended dependency versions and the tracked plugin version to those vended by this release",
138
148
  "implementation": "./src/utils/version-upgrade-migration/migration"
139
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws/nx-plugin",
3
- "version": "1.0.0-rc.73",
3
+ "version": "1.0.0-rc.75",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/awslabs/nx-plugin-for-aws.git",
@@ -2,9 +2,11 @@
2
2
  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */ import { agentcoreGatewayGenerator } from "../../sdk/agentcore-gateway.js";
5
+ import { agentcoreHarnessGenerator } from "../../sdk/agentcore-harness.js";
5
6
  import { connectionGenerator } from "../../sdk/connection.js";
6
7
  import { licenseGenerator } from "../../sdk/license.js";
7
8
  import { pyAgentGenerator, pyApiGenerator, pyDynamoDBGenerator, pyLambdaFunctionGenerator, pyMcpServerGenerator, pyProjectGenerator, pyRdbGenerator } from "../../sdk/py.js";
9
+ import { smithyProjectGenerator } from "../../sdk/smithy.js";
8
10
  import { terraformProjectGenerator } from "../../sdk/terraform.js";
9
11
  import { tsAgentGenerator, tsApiGenerator, tsAstroDocsGenerator, tsDcrProxyGenerator, tsDynamoDBGenerator, tsInfraGenerator, tsLambdaFunctionGenerator, tsMcpServerGenerator, tsNxGeneratorGenerator, tsNxMigrationGenerator, tsNxPluginGenerator, tsProjectGenerator, tsRdbGenerator, tsWebsiteAuthGenerator, tsWebsiteGenerator } from "../../sdk/ts.js";
10
12
  import { installDependencies } from "../../utils/install.js";
@@ -135,6 +137,12 @@ import { getNpmScope, getNpmScopePrefix } from "../../utils/npm-scope.js";
135
137
  ...projectDefaults
136
138
  });
137
139
  }
140
+ // A Smithy shape library; `my-smithy-api` covers consuming one.
141
+ await smithyProjectGenerator(tree, {
142
+ name: 'my-shapes',
143
+ type: 'shapes',
144
+ ...projectDefaults
145
+ });
138
146
  // Python FastAPI — REST + HTTP, with Cognito and custom auth.
139
147
  const pyApis = [
140
148
  {
@@ -353,6 +361,13 @@ import { getNpmScope, getNpmScopePrefix } from "../../utils/npm-scope.js";
353
361
  iac: 'inherit',
354
362
  ...projectDefaults
355
363
  });
364
+ // AgentCore Harness — a standalone invocation project.
365
+ await agentcoreHarnessGenerator(tree, {
366
+ name: 'my-harness',
367
+ infra: 'agentcore',
368
+ iac: 'inherit',
369
+ ...projectDefaults
370
+ });
356
371
  // Databases — DynamoDB, plus Aurora across both engines and ORMs.
357
372
  await tsDynamoDBGenerator(tree, {
358
373
  name: 'my-table',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/internal/test-matrix/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { GeneratorCallback, Tree } from '@nx/devkit';\nimport { agentcoreGatewayGenerator } from '../../sdk/agentcore-gateway';\nimport {\n type ConnectionGeneratorSchema,\n connectionGenerator,\n} from '../../sdk/connection';\nimport { licenseGenerator } from '../../sdk/license';\nimport {\n type PyAgentGeneratorSchema,\n type PyApiGeneratorSchema,\n type PyRdbGeneratorSchema,\n pyAgentGenerator,\n pyApiGenerator,\n pyDynamoDBGenerator,\n pyLambdaFunctionGenerator,\n pyMcpServerGenerator,\n pyProjectGenerator,\n pyRdbGenerator,\n} from '../../sdk/py';\nimport { terraformProjectGenerator } from '../../sdk/terraform';\nimport {\n type TsAgentGeneratorSchema,\n type TsApiGeneratorSchema,\n type TsNxMigrationGeneratorSchema,\n type TsRdbGeneratorSchema,\n tsAgentGenerator,\n tsApiGenerator,\n tsAstroDocsGenerator,\n tsDcrProxyGenerator,\n tsDynamoDBGenerator,\n tsInfraGenerator,\n tsLambdaFunctionGenerator,\n tsMcpServerGenerator,\n tsNxGeneratorGenerator,\n tsNxMigrationGenerator,\n tsNxPluginGenerator,\n tsProjectGenerator,\n tsRdbGenerator,\n tsWebsiteAuthGenerator,\n tsWebsiteGenerator,\n} from '../../sdk/ts';\nimport { installDependencies } from '../../utils/install';\nimport { toSnakeCase } from '../../utils/names';\nimport { getNpmScope, getNpmScopePrefix } from '../../utils/npm-scope';\nimport type { InternalTestMatrixGeneratorSchema } from './schema';\n\n/**\n * Scaffolds every generator, component and connection permutation the e2e tests\n * cover, by composing the generators in-process on a single tree.\n *\n * This ships with the plugin so each released version carries the matrix of the\n * generators *it* had. A test upgrading an old workspace scaffolds with the\n * released version's own matrix and never has to reason about which generators\n * existed when — driving the CLI from the test repo instead would couple the\n * test to a generator list that only describes today's plugin.\n *\n * Hidden and undocumented: it exists for the e2e suite, not for users.\n *\n * Options are typed against each generator's schema, so adding a required option\n * or changing an enum breaks the build here rather than silently reducing\n * coverage.\n *\n * Projects are generated with `preferInstallDependencies: false` by default and\n * the returned callback installs once. Nothing composed here reads the project\n * graph (only `ts#sync` does, which is not part of the matrix), so no\n * intermediate install is needed.\n */\nexport const internalTestMatrixGenerator = async (\n tree: Tree,\n options: InternalTestMatrixGeneratorSchema = {},\n): Promise<GeneratorCallback> => {\n const preferInstallDependencies = options.preferInstallDependencies ?? false;\n const defaults = { preferInstallDependencies };\n const projectDefaults = { ...defaults, directory: 'packages' };\n // Fully-qualified project names, which differ per language: TypeScript\n // projects are scope-prefixed, Python ones are dotted snake_case. Derived from\n // the workspace rather than hardcoded, so the matrix works in any workspace.\n const ts = (name: string) => `${getNpmScopePrefix(tree)}${name}`;\n const py = (name: string) =>\n `${toSnakeCase(getNpmScope(tree))}.${toSnakeCase(name)}`;\n\n // The infrastructure project every other generator deploys into. Which\n // generator owns it depends on the workspace's IaC provider, so the caller\n // asks for the one matching the workspace it created.\n if (options.infra === 'terraform') {\n await terraformProjectGenerator(tree, {\n name: 'infra',\n type: 'application',\n ...projectDefaults,\n });\n } else {\n await tsInfraGenerator(tree, { name: 'infra', ...projectDefaults });\n // A second CDK app with stage config, which only ts#infra offers.\n await tsInfraGenerator(tree, {\n name: 'infra-with-stages',\n stageConfig: true,\n ...projectDefaults,\n });\n }\n\n // Websites (with and without TanStack Router), a docs site, and auth on each.\n await tsWebsiteGenerator(tree, {\n name: 'website',\n iac: 'inherit',\n ...projectDefaults,\n });\n await tsWebsiteGenerator(tree, {\n name: 'website-no-router',\n tanstackRouter: false,\n iac: 'inherit',\n ...projectDefaults,\n });\n await tsAstroDocsGenerator(tree, { name: 'docs-site', ...defaults });\n await tsWebsiteAuthGenerator(tree, {\n project: ts('website'),\n cognitoDomain: 'test',\n allowSignup: true,\n iac: 'inherit',\n ...defaults,\n });\n await tsWebsiteAuthGenerator(tree, {\n project: ts('website-no-router'),\n cognitoDomain: 'test-no-router',\n allowSignup: true,\n iac: 'inherit',\n ...defaults,\n });\n\n // tRPC APIs — REST + HTTP, with Cognito and custom auth.\n const tsApis: TsApiGeneratorSchema[] = [\n { name: 'my-api', infra: 'rest-lambda', auth: 'iam', iac: 'inherit' },\n { name: 'my-api-http', infra: 'http-lambda', auth: 'iam', iac: 'inherit' },\n {\n name: 'my-api-custom',\n infra: 'rest-lambda',\n auth: 'custom',\n iac: 'inherit',\n },\n {\n name: 'my-api-custom-http',\n infra: 'http-lambda',\n auth: 'custom',\n iac: 'inherit',\n },\n {\n name: 'my-smithy-api',\n framework: 'smithy',\n infra: 'rest-lambda',\n auth: 'iam',\n iac: 'inherit',\n },\n ];\n for (const api of tsApis) {\n await tsApiGenerator(tree, { ...api, ...projectDefaults });\n }\n\n // Python FastAPI — REST + HTTP, with Cognito and custom auth.\n const pyApis: PyApiGeneratorSchema[] = [\n { name: 'py-api', infra: 'rest-lambda', auth: 'iam', iac: 'inherit' },\n { name: 'py-api-http', infra: 'http-lambda', auth: 'iam', iac: 'inherit' },\n {\n name: 'py-api-custom',\n infra: 'rest-lambda',\n auth: 'custom',\n iac: 'inherit',\n },\n {\n name: 'py-api-custom-http',\n infra: 'http-lambda',\n auth: 'custom',\n iac: 'inherit',\n },\n ];\n for (const api of pyApis) {\n await pyApiGenerator(tree, { ...api, ...projectDefaults });\n }\n\n // Library projects hosting the components below, each with a lambda function.\n await pyProjectGenerator(tree, {\n name: 'py-project',\n type: 'application',\n ...projectDefaults,\n });\n await tsProjectGenerator(tree, { name: 'ts-project', ...projectDefaults });\n await pyLambdaFunctionGenerator(tree, {\n project: py('py-project'),\n name: 'my-function',\n event: 'Any',\n iac: 'inherit',\n ...defaults,\n });\n await tsLambdaFunctionGenerator(tree, {\n project: 'ts-project',\n name: 'my-function',\n event: 'Any',\n iac: 'inherit',\n ...defaults,\n });\n\n // MCP servers — uninfra'd and hosted on AgentCore.\n await pyMcpServerGenerator(tree, {\n project: 'py_project',\n name: 'my-mcp-server',\n infra: 'agentcore',\n iac: 'inherit',\n ...defaults,\n });\n await tsMcpServerGenerator(tree, {\n project: 'ts-project',\n name: 'my-mcp-server',\n infra: 'none',\n iac: 'inherit',\n ...defaults,\n });\n await tsMcpServerGenerator(tree, {\n project: 'ts-project',\n name: 'hosted-mcp-server',\n infra: 'agentcore',\n iac: 'inherit',\n ...defaults,\n });\n\n // OAuth DCR proxy for Cognito-authenticated MCP servers.\n await tsDcrProxyGenerator(tree, {\n name: 'my-dcr-proxy',\n iac: 'inherit',\n ...projectDefaults,\n });\n\n // TypeScript agents across every protocol and auth permutation. The unnamed\n // one takes the generator's default name, which the connections below use.\n const tsAgents: TsAgentGeneratorSchema[] = [\n {\n project: 'ts-project',\n name: 'my-ts-agent',\n infra: 'none',\n iac: 'inherit',\n },\n { project: 'ts-project', infra: 'agentcore', iac: 'inherit' },\n {\n project: 'ts-project',\n name: 'my-ts-a2a-agent',\n protocol: 'a2a',\n infra: 'agentcore',\n iac: 'inherit',\n },\n {\n project: 'ts-project',\n name: 'my-ts-a2a-agent-cognito',\n protocol: 'a2a',\n auth: 'cognito',\n infra: 'agentcore',\n iac: 'inherit',\n },\n {\n project: 'ts-project',\n name: 'my-ts-agui-agent',\n protocol: 'ag-ui',\n infra: 'agentcore',\n iac: 'inherit',\n },\n ];\n for (const agent of tsAgents) {\n await tsAgentGenerator(tree, { ...agent, ...defaults });\n }\n\n // Python agents: Strands across every protocol, plus LangChain in its own\n // project — langchain's dependency closure would push the zip-bundled Lambda\n // in py-project past its unzipped size limit.\n const pyAgents: PyAgentGeneratorSchema[] = [\n {\n project: 'py_project',\n name: 'my-agent',\n infra: 'agentcore',\n iac: 'inherit',\n },\n {\n project: 'py_project',\n name: 'my-py-a2a-agent',\n protocol: 'a2a',\n infra: 'agentcore',\n iac: 'inherit',\n },\n {\n project: 'py_project',\n name: 'my-py-a2a-agent-cognito',\n protocol: 'a2a',\n auth: 'cognito',\n infra: 'agentcore',\n iac: 'inherit',\n },\n {\n project: 'py_project',\n name: 'my-py-agui-agent',\n protocol: 'ag-ui',\n infra: 'agentcore',\n iac: 'inherit',\n },\n ];\n for (const agent of pyAgents) {\n await pyAgentGenerator(tree, { ...agent, ...defaults });\n }\n await pyProjectGenerator(tree, {\n name: 'py-langchain-project',\n type: 'application',\n ...projectDefaults,\n });\n const langchainAgents: PyAgentGeneratorSchema[] = [\n {\n project: 'py_langchain_project',\n name: 'my-py-langchain-agent',\n protocol: 'ag-ui',\n iac: 'inherit',\n },\n {\n project: 'py_langchain_project',\n name: 'my-py-langchain-http-agent',\n protocol: 'http',\n iac: 'inherit',\n },\n {\n project: 'py_langchain_project',\n name: 'my-py-langchain-a2a-agent',\n protocol: 'a2a',\n iac: 'inherit',\n },\n ];\n for (const agent of langchainAgents) {\n await pyAgentGenerator(tree, {\n ...agent,\n framework: 'langchain',\n infra: 'agentcore',\n ...defaults,\n });\n }\n\n // AgentCore gateways, including a parent fronting the first (chained), and\n // an http-protocol gateway fronting agent runtime targets.\n await agentcoreGatewayGenerator(tree, {\n name: 'my-gateway',\n iac: 'inherit',\n ...projectDefaults,\n });\n await agentcoreGatewayGenerator(tree, {\n name: 'parent-gateway',\n iac: 'inherit',\n ...projectDefaults,\n });\n await agentcoreGatewayGenerator(tree, {\n name: 'agent-gateway',\n protocol: 'http',\n iac: 'inherit',\n ...projectDefaults,\n });\n\n // Databases — DynamoDB, plus Aurora across both engines and ORMs.\n await tsDynamoDBGenerator(tree, {\n name: 'my-table',\n framework: 'electrodb',\n infra: 'dynamodb',\n iac: 'inherit',\n ...projectDefaults,\n });\n await pyDynamoDBGenerator(tree, {\n name: 'my-py-table',\n framework: 'pynamodb',\n infra: 'dynamodb',\n iac: 'inherit',\n ...projectDefaults,\n });\n const tsRdbs: TsRdbGeneratorSchema[] = [\n {\n name: 'postgres-db',\n infra: 'aurora',\n engine: 'postgres',\n framework: 'prisma',\n iac: 'inherit',\n },\n {\n name: 'my-sql-db',\n infra: 'aurora',\n engine: 'mysql',\n framework: 'prisma',\n iac: 'inherit',\n },\n ];\n for (const rdb of tsRdbs) {\n await tsRdbGenerator(tree, { ...rdb, ...projectDefaults });\n }\n const pyRdbs: PyRdbGeneratorSchema[] = [\n {\n name: 'py-postgres-db',\n infra: 'aurora',\n engine: 'postgres',\n framework: 'sqlmodel',\n iac: 'inherit',\n },\n {\n name: 'py-mysql-db',\n infra: 'aurora',\n engine: 'mysql',\n framework: 'sqlmodel',\n iac: 'inherit',\n },\n ];\n for (const rdb of pyRdbs) {\n await pyRdbGenerator(tree, { ...rdb, ...projectDefaults });\n }\n\n // Every connection edge the matrix covers.\n const connections: ConnectionGeneratorSchema[] = [\n // Website -> API\n { sourceProject: ts('website'), targetProject: ts('my-api') },\n { sourceProject: ts('website-no-router'), targetProject: ts('my-api') },\n { sourceProject: 'website', targetProject: 'py_api' },\n { sourceProject: 'website', targetProject: 'my-smithy-api' },\n // Agent -> MCP server\n {\n sourceProject: 'ts-project',\n sourceComponent: 'agent',\n targetProject: 'ts-project',\n targetComponent: 'hosted-mcp-server',\n },\n {\n sourceProject: 'ts-project',\n sourceComponent: 'my-ts-agui-agent',\n targetProject: 'ts-project',\n targetComponent: 'hosted-mcp-server',\n },\n {\n sourceProject: 'ts-project',\n sourceComponent: 'agent',\n targetProject: 'py_project',\n targetComponent: 'my-mcp-server',\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: 'py_project',\n targetComponent: 'my-mcp-server',\n },\n {\n sourceProject: 'py_langchain_project',\n sourceComponent: 'my-py-langchain-agent',\n targetProject: 'py_project',\n targetComponent: 'my-mcp-server',\n },\n // HTTP agent <-> A2A agent\n {\n sourceProject: 'ts-project',\n sourceComponent: 'agent',\n targetProject: 'ts-project',\n targetComponent: 'my-ts-a2a-agent',\n },\n {\n sourceProject: 'ts-project',\n sourceComponent: 'agent',\n targetProject: 'py_project',\n targetComponent: 'my-py-a2a-agent',\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: 'ts-project',\n targetComponent: 'my-ts-a2a-agent',\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: 'py_project',\n targetComponent: 'my-py-a2a-agent',\n },\n {\n sourceProject: 'py_langchain_project',\n sourceComponent: 'my-py-langchain-agent',\n targetProject: 'py_project',\n targetComponent: 'my-py-a2a-agent',\n },\n // Agent -> gateway, gateway -> MCP server, gateway -> gateway\n {\n sourceProject: 'ts-project',\n sourceComponent: 'agent',\n targetProject: ts('my-gateway'),\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: ts('my-gateway'),\n },\n {\n sourceProject: 'py_langchain_project',\n sourceComponent: 'my-py-langchain-agent',\n targetProject: ts('my-gateway'),\n },\n {\n sourceProject: ts('my-gateway'),\n targetProject: 'ts-project',\n targetComponent: 'hosted-mcp-server',\n },\n {\n sourceProject: ts('my-gateway'),\n targetProject: 'py_project',\n targetComponent: 'my-mcp-server',\n },\n { sourceProject: ts('parent-gateway'), targetProject: ts('my-gateway') },\n // Gateway -> agent (http gateway fronting agent runtime targets: every\n // supported protocol permutation), then website -> gateway.\n {\n sourceProject: ts('agent-gateway'),\n targetProject: 'ts-project',\n targetComponent: 'my-ts-agui-agent',\n },\n {\n sourceProject: ts('agent-gateway'),\n targetProject: 'ts-project',\n targetComponent: 'my-ts-a2a-agent',\n },\n {\n sourceProject: ts('agent-gateway'),\n targetProject: 'py_project',\n targetComponent: 'my-py-agui-agent',\n },\n {\n sourceProject: ts('agent-gateway'),\n targetProject: 'py_project',\n targetComponent: 'my-agent',\n },\n {\n sourceProject: ts('agent-gateway'),\n targetProject: 'py_project',\n targetComponent: 'my-py-a2a-agent',\n },\n {\n sourceProject: ts('website-no-router'),\n targetProject: ts('agent-gateway'),\n },\n // Website -> agent\n {\n sourceProject: ts('website'),\n targetProject: 'ts-project',\n targetComponent: 'agent',\n },\n {\n sourceProject: ts('website'),\n targetProject: 'ts-project',\n targetComponent: 'my-ts-agui-agent',\n },\n {\n sourceProject: ts('website'),\n targetProject: 'py_project',\n targetComponent: 'my-agent',\n },\n {\n sourceProject: ts('website'),\n targetProject: 'py_project',\n targetComponent: 'my-py-agui-agent',\n },\n {\n sourceProject: ts('website'),\n targetProject: 'py_langchain_project',\n targetComponent: 'my-py-langchain-agent',\n },\n {\n sourceProject: ts('website'),\n targetProject: 'py_langchain_project',\n targetComponent: 'my-py-langchain-http-agent',\n },\n // DynamoDB\n { sourceProject: 'my-api', targetProject: ts('my-table') },\n { sourceProject: 'my-smithy-api', targetProject: ts('my-table') },\n {\n sourceProject: 'ts-project',\n sourceComponent: 'my-ts-agent',\n targetProject: ts('my-table'),\n },\n {\n sourceProject: 'ts-project',\n sourceComponent: 'my-mcp-server',\n targetProject: ts('my-table'),\n },\n { sourceProject: 'py_api', targetProject: 'my_py_table' },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: 'my_py_table',\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-mcp-server',\n targetProject: 'my_py_table',\n },\n {\n sourceProject: 'py_langchain_project',\n sourceComponent: 'my-py-langchain-http-agent',\n targetProject: 'my_py_table',\n },\n // Relational databases\n { sourceProject: 'py_api', targetProject: 'py_postgres_db' },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: 'py_postgres_db',\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-mcp-server',\n targetProject: 'py_postgres_db',\n },\n ];\n for (const connection of connections) {\n await connectionGenerator(tree, { ...connection, ...defaults });\n }\n\n // Licensing, then an Nx plugin with a custom generator.\n await licenseGenerator(tree, {\n license: 'Apache-2.0',\n copyrightHolder: 'Amazon.com, Inc. or its affiliates',\n ...defaults,\n });\n await tsNxPluginGenerator(tree, {\n ...projectDefaults,\n name: 'plugin',\n directory: 'tools',\n });\n await tsNxGeneratorGenerator(tree, {\n project: ts('plugin'),\n name: 'my#generator',\n ...defaults,\n });\n\n // A migration of each kind, so the scaffolded codemods compile and the\n // plugin's migrations.json (created by the first run) registers all three.\n const migrations: Omit<TsNxMigrationGeneratorSchema, 'project'>[] = [\n {\n name: 'rename-foo-target',\n description: 'Rename the foo target to bar',\n },\n {\n name: 'migrate-custom-handlers',\n description: 'Update custom handlers for the new API',\n kind: 'agentic',\n },\n {\n name: 'upgrade-framework',\n description: 'Upgrade the framework and reconcile call sites',\n kind: 'hybrid',\n },\n ];\n for (const migration of migrations) {\n await tsNxMigrationGenerator(tree, {\n ...migration,\n project: ts('plugin'),\n ...defaults,\n });\n }\n\n return () =>\n installDependencies(tree, preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default internalTestMatrixGenerator;\n"],"names":["agentcoreGatewayGenerator","connectionGenerator","licenseGenerator","pyAgentGenerator","pyApiGenerator","pyDynamoDBGenerator","pyLambdaFunctionGenerator","pyMcpServerGenerator","pyProjectGenerator","pyRdbGenerator","terraformProjectGenerator","tsAgentGenerator","tsApiGenerator","tsAstroDocsGenerator","tsDcrProxyGenerator","tsDynamoDBGenerator","tsInfraGenerator","tsLambdaFunctionGenerator","tsMcpServerGenerator","tsNxGeneratorGenerator","tsNxMigrationGenerator","tsNxPluginGenerator","tsProjectGenerator","tsRdbGenerator","tsWebsiteAuthGenerator","tsWebsiteGenerator","installDependencies","toSnakeCase","getNpmScope","getNpmScopePrefix","internalTestMatrixGenerator","tree","options","preferInstallDependencies","defaults","projectDefaults","directory","ts","name","py","infra","type","stageConfig","iac","tanstackRouter","project","cognitoDomain","allowSignup","tsApis","auth","framework","api","pyApis","event","tsAgents","protocol","agent","pyAgents","langchainAgents","tsRdbs","engine","rdb","pyRdbs","connections","sourceProject","targetProject","sourceComponent","targetComponent","connection","license","copyrightHolder","migrations","description","kind","migration","languages"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/internal/test-matrix/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { GeneratorCallback, Tree } from '@nx/devkit';\nimport { agentcoreGatewayGenerator } from '../../sdk/agentcore-gateway';\nimport { agentcoreHarnessGenerator } from '../../sdk/agentcore-harness';\nimport {\n type ConnectionGeneratorSchema,\n connectionGenerator,\n} from '../../sdk/connection';\nimport { licenseGenerator } from '../../sdk/license';\nimport {\n type PyAgentGeneratorSchema,\n type PyApiGeneratorSchema,\n type PyRdbGeneratorSchema,\n pyAgentGenerator,\n pyApiGenerator,\n pyDynamoDBGenerator,\n pyLambdaFunctionGenerator,\n pyMcpServerGenerator,\n pyProjectGenerator,\n pyRdbGenerator,\n} from '../../sdk/py';\nimport { smithyProjectGenerator } from '../../sdk/smithy';\nimport { terraformProjectGenerator } from '../../sdk/terraform';\nimport {\n type TsAgentGeneratorSchema,\n type TsApiGeneratorSchema,\n type TsNxMigrationGeneratorSchema,\n type TsRdbGeneratorSchema,\n tsAgentGenerator,\n tsApiGenerator,\n tsAstroDocsGenerator,\n tsDcrProxyGenerator,\n tsDynamoDBGenerator,\n tsInfraGenerator,\n tsLambdaFunctionGenerator,\n tsMcpServerGenerator,\n tsNxGeneratorGenerator,\n tsNxMigrationGenerator,\n tsNxPluginGenerator,\n tsProjectGenerator,\n tsRdbGenerator,\n tsWebsiteAuthGenerator,\n tsWebsiteGenerator,\n} from '../../sdk/ts';\nimport { installDependencies } from '../../utils/install';\nimport { toSnakeCase } from '../../utils/names';\nimport { getNpmScope, getNpmScopePrefix } from '../../utils/npm-scope';\nimport type { InternalTestMatrixGeneratorSchema } from './schema';\n\n/**\n * Scaffolds every generator, component and connection permutation the e2e tests\n * cover, by composing the generators in-process on a single tree.\n *\n * This ships with the plugin so each released version carries the matrix of the\n * generators *it* had. A test upgrading an old workspace scaffolds with the\n * released version's own matrix and never has to reason about which generators\n * existed when — driving the CLI from the test repo instead would couple the\n * test to a generator list that only describes today's plugin.\n *\n * Hidden and undocumented: it exists for the e2e suite, not for users.\n *\n * Options are typed against each generator's schema, so adding a required option\n * or changing an enum breaks the build here rather than silently reducing\n * coverage.\n *\n * Projects are generated with `preferInstallDependencies: false` by default and\n * the returned callback installs once. Nothing composed here reads the project\n * graph (only `ts#sync` does, which is not part of the matrix), so no\n * intermediate install is needed.\n */\nexport const internalTestMatrixGenerator = async (\n tree: Tree,\n options: InternalTestMatrixGeneratorSchema = {},\n): Promise<GeneratorCallback> => {\n const preferInstallDependencies = options.preferInstallDependencies ?? false;\n const defaults = { preferInstallDependencies };\n const projectDefaults = { ...defaults, directory: 'packages' };\n // Fully-qualified project names, which differ per language: TypeScript\n // projects are scope-prefixed, Python ones are dotted snake_case. Derived from\n // the workspace rather than hardcoded, so the matrix works in any workspace.\n const ts = (name: string) => `${getNpmScopePrefix(tree)}${name}`;\n const py = (name: string) =>\n `${toSnakeCase(getNpmScope(tree))}.${toSnakeCase(name)}`;\n\n // The infrastructure project every other generator deploys into. Which\n // generator owns it depends on the workspace's IaC provider, so the caller\n // asks for the one matching the workspace it created.\n if (options.infra === 'terraform') {\n await terraformProjectGenerator(tree, {\n name: 'infra',\n type: 'application',\n ...projectDefaults,\n });\n } else {\n await tsInfraGenerator(tree, { name: 'infra', ...projectDefaults });\n // A second CDK app with stage config, which only ts#infra offers.\n await tsInfraGenerator(tree, {\n name: 'infra-with-stages',\n stageConfig: true,\n ...projectDefaults,\n });\n }\n\n // Websites (with and without TanStack Router), a docs site, and auth on each.\n await tsWebsiteGenerator(tree, {\n name: 'website',\n iac: 'inherit',\n ...projectDefaults,\n });\n await tsWebsiteGenerator(tree, {\n name: 'website-no-router',\n tanstackRouter: false,\n iac: 'inherit',\n ...projectDefaults,\n });\n await tsAstroDocsGenerator(tree, { name: 'docs-site', ...defaults });\n await tsWebsiteAuthGenerator(tree, {\n project: ts('website'),\n cognitoDomain: 'test',\n allowSignup: true,\n iac: 'inherit',\n ...defaults,\n });\n await tsWebsiteAuthGenerator(tree, {\n project: ts('website-no-router'),\n cognitoDomain: 'test-no-router',\n allowSignup: true,\n iac: 'inherit',\n ...defaults,\n });\n\n // tRPC APIs — REST + HTTP, with Cognito and custom auth.\n const tsApis: TsApiGeneratorSchema[] = [\n { name: 'my-api', infra: 'rest-lambda', auth: 'iam', iac: 'inherit' },\n { name: 'my-api-http', infra: 'http-lambda', auth: 'iam', iac: 'inherit' },\n {\n name: 'my-api-custom',\n infra: 'rest-lambda',\n auth: 'custom',\n iac: 'inherit',\n },\n {\n name: 'my-api-custom-http',\n infra: 'http-lambda',\n auth: 'custom',\n iac: 'inherit',\n },\n {\n name: 'my-smithy-api',\n framework: 'smithy',\n infra: 'rest-lambda',\n auth: 'iam',\n iac: 'inherit',\n },\n ];\n for (const api of tsApis) {\n await tsApiGenerator(tree, { ...api, ...projectDefaults });\n }\n\n // A Smithy shape library; `my-smithy-api` covers consuming one.\n await smithyProjectGenerator(tree, {\n name: 'my-shapes',\n type: 'shapes',\n ...projectDefaults,\n });\n\n // Python FastAPI — REST + HTTP, with Cognito and custom auth.\n const pyApis: PyApiGeneratorSchema[] = [\n { name: 'py-api', infra: 'rest-lambda', auth: 'iam', iac: 'inherit' },\n { name: 'py-api-http', infra: 'http-lambda', auth: 'iam', iac: 'inherit' },\n {\n name: 'py-api-custom',\n infra: 'rest-lambda',\n auth: 'custom',\n iac: 'inherit',\n },\n {\n name: 'py-api-custom-http',\n infra: 'http-lambda',\n auth: 'custom',\n iac: 'inherit',\n },\n ];\n for (const api of pyApis) {\n await pyApiGenerator(tree, { ...api, ...projectDefaults });\n }\n\n // Library projects hosting the components below, each with a lambda function.\n await pyProjectGenerator(tree, {\n name: 'py-project',\n type: 'application',\n ...projectDefaults,\n });\n await tsProjectGenerator(tree, { name: 'ts-project', ...projectDefaults });\n await pyLambdaFunctionGenerator(tree, {\n project: py('py-project'),\n name: 'my-function',\n event: 'Any',\n iac: 'inherit',\n ...defaults,\n });\n await tsLambdaFunctionGenerator(tree, {\n project: 'ts-project',\n name: 'my-function',\n event: 'Any',\n iac: 'inherit',\n ...defaults,\n });\n\n // MCP servers — uninfra'd and hosted on AgentCore.\n await pyMcpServerGenerator(tree, {\n project: 'py_project',\n name: 'my-mcp-server',\n infra: 'agentcore',\n iac: 'inherit',\n ...defaults,\n });\n await tsMcpServerGenerator(tree, {\n project: 'ts-project',\n name: 'my-mcp-server',\n infra: 'none',\n iac: 'inherit',\n ...defaults,\n });\n await tsMcpServerGenerator(tree, {\n project: 'ts-project',\n name: 'hosted-mcp-server',\n infra: 'agentcore',\n iac: 'inherit',\n ...defaults,\n });\n\n // OAuth DCR proxy for Cognito-authenticated MCP servers.\n await tsDcrProxyGenerator(tree, {\n name: 'my-dcr-proxy',\n iac: 'inherit',\n ...projectDefaults,\n });\n\n // TypeScript agents across every protocol and auth permutation. The unnamed\n // one takes the generator's default name, which the connections below use.\n const tsAgents: TsAgentGeneratorSchema[] = [\n {\n project: 'ts-project',\n name: 'my-ts-agent',\n infra: 'none',\n iac: 'inherit',\n },\n { project: 'ts-project', infra: 'agentcore', iac: 'inherit' },\n {\n project: 'ts-project',\n name: 'my-ts-a2a-agent',\n protocol: 'a2a',\n infra: 'agentcore',\n iac: 'inherit',\n },\n {\n project: 'ts-project',\n name: 'my-ts-a2a-agent-cognito',\n protocol: 'a2a',\n auth: 'cognito',\n infra: 'agentcore',\n iac: 'inherit',\n },\n {\n project: 'ts-project',\n name: 'my-ts-agui-agent',\n protocol: 'ag-ui',\n infra: 'agentcore',\n iac: 'inherit',\n },\n ];\n for (const agent of tsAgents) {\n await tsAgentGenerator(tree, { ...agent, ...defaults });\n }\n\n // Python agents: Strands across every protocol, plus LangChain in its own\n // project — langchain's dependency closure would push the zip-bundled Lambda\n // in py-project past its unzipped size limit.\n const pyAgents: PyAgentGeneratorSchema[] = [\n {\n project: 'py_project',\n name: 'my-agent',\n infra: 'agentcore',\n iac: 'inherit',\n },\n {\n project: 'py_project',\n name: 'my-py-a2a-agent',\n protocol: 'a2a',\n infra: 'agentcore',\n iac: 'inherit',\n },\n {\n project: 'py_project',\n name: 'my-py-a2a-agent-cognito',\n protocol: 'a2a',\n auth: 'cognito',\n infra: 'agentcore',\n iac: 'inherit',\n },\n {\n project: 'py_project',\n name: 'my-py-agui-agent',\n protocol: 'ag-ui',\n infra: 'agentcore',\n iac: 'inherit',\n },\n ];\n for (const agent of pyAgents) {\n await pyAgentGenerator(tree, { ...agent, ...defaults });\n }\n await pyProjectGenerator(tree, {\n name: 'py-langchain-project',\n type: 'application',\n ...projectDefaults,\n });\n const langchainAgents: PyAgentGeneratorSchema[] = [\n {\n project: 'py_langchain_project',\n name: 'my-py-langchain-agent',\n protocol: 'ag-ui',\n iac: 'inherit',\n },\n {\n project: 'py_langchain_project',\n name: 'my-py-langchain-http-agent',\n protocol: 'http',\n iac: 'inherit',\n },\n {\n project: 'py_langchain_project',\n name: 'my-py-langchain-a2a-agent',\n protocol: 'a2a',\n iac: 'inherit',\n },\n ];\n for (const agent of langchainAgents) {\n await pyAgentGenerator(tree, {\n ...agent,\n framework: 'langchain',\n infra: 'agentcore',\n ...defaults,\n });\n }\n\n // AgentCore gateways, including a parent fronting the first (chained), and\n // an http-protocol gateway fronting agent runtime targets.\n await agentcoreGatewayGenerator(tree, {\n name: 'my-gateway',\n iac: 'inherit',\n ...projectDefaults,\n });\n await agentcoreGatewayGenerator(tree, {\n name: 'parent-gateway',\n iac: 'inherit',\n ...projectDefaults,\n });\n await agentcoreGatewayGenerator(tree, {\n name: 'agent-gateway',\n protocol: 'http',\n iac: 'inherit',\n ...projectDefaults,\n });\n\n // AgentCore Harness — a standalone invocation project.\n await agentcoreHarnessGenerator(tree, {\n name: 'my-harness',\n infra: 'agentcore',\n iac: 'inherit',\n ...projectDefaults,\n });\n\n // Databases — DynamoDB, plus Aurora across both engines and ORMs.\n await tsDynamoDBGenerator(tree, {\n name: 'my-table',\n framework: 'electrodb',\n infra: 'dynamodb',\n iac: 'inherit',\n ...projectDefaults,\n });\n await pyDynamoDBGenerator(tree, {\n name: 'my-py-table',\n framework: 'pynamodb',\n infra: 'dynamodb',\n iac: 'inherit',\n ...projectDefaults,\n });\n const tsRdbs: TsRdbGeneratorSchema[] = [\n {\n name: 'postgres-db',\n infra: 'aurora',\n engine: 'postgres',\n framework: 'prisma',\n iac: 'inherit',\n },\n {\n name: 'my-sql-db',\n infra: 'aurora',\n engine: 'mysql',\n framework: 'prisma',\n iac: 'inherit',\n },\n ];\n for (const rdb of tsRdbs) {\n await tsRdbGenerator(tree, { ...rdb, ...projectDefaults });\n }\n const pyRdbs: PyRdbGeneratorSchema[] = [\n {\n name: 'py-postgres-db',\n infra: 'aurora',\n engine: 'postgres',\n framework: 'sqlmodel',\n iac: 'inherit',\n },\n {\n name: 'py-mysql-db',\n infra: 'aurora',\n engine: 'mysql',\n framework: 'sqlmodel',\n iac: 'inherit',\n },\n ];\n for (const rdb of pyRdbs) {\n await pyRdbGenerator(tree, { ...rdb, ...projectDefaults });\n }\n\n // Every connection edge the matrix covers.\n const connections: ConnectionGeneratorSchema[] = [\n // Website -> API\n { sourceProject: ts('website'), targetProject: ts('my-api') },\n { sourceProject: ts('website-no-router'), targetProject: ts('my-api') },\n { sourceProject: 'website', targetProject: 'py_api' },\n { sourceProject: 'website', targetProject: 'my-smithy-api' },\n // Agent -> MCP server\n {\n sourceProject: 'ts-project',\n sourceComponent: 'agent',\n targetProject: 'ts-project',\n targetComponent: 'hosted-mcp-server',\n },\n {\n sourceProject: 'ts-project',\n sourceComponent: 'my-ts-agui-agent',\n targetProject: 'ts-project',\n targetComponent: 'hosted-mcp-server',\n },\n {\n sourceProject: 'ts-project',\n sourceComponent: 'agent',\n targetProject: 'py_project',\n targetComponent: 'my-mcp-server',\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: 'py_project',\n targetComponent: 'my-mcp-server',\n },\n {\n sourceProject: 'py_langchain_project',\n sourceComponent: 'my-py-langchain-agent',\n targetProject: 'py_project',\n targetComponent: 'my-mcp-server',\n },\n // HTTP agent <-> A2A agent\n {\n sourceProject: 'ts-project',\n sourceComponent: 'agent',\n targetProject: 'ts-project',\n targetComponent: 'my-ts-a2a-agent',\n },\n {\n sourceProject: 'ts-project',\n sourceComponent: 'agent',\n targetProject: 'py_project',\n targetComponent: 'my-py-a2a-agent',\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: 'ts-project',\n targetComponent: 'my-ts-a2a-agent',\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: 'py_project',\n targetComponent: 'my-py-a2a-agent',\n },\n {\n sourceProject: 'py_langchain_project',\n sourceComponent: 'my-py-langchain-agent',\n targetProject: 'py_project',\n targetComponent: 'my-py-a2a-agent',\n },\n // Agent -> gateway, gateway -> MCP server, gateway -> gateway\n {\n sourceProject: 'ts-project',\n sourceComponent: 'agent',\n targetProject: ts('my-gateway'),\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: ts('my-gateway'),\n },\n {\n sourceProject: 'py_langchain_project',\n sourceComponent: 'my-py-langchain-agent',\n targetProject: ts('my-gateway'),\n },\n {\n sourceProject: ts('my-gateway'),\n targetProject: 'ts-project',\n targetComponent: 'hosted-mcp-server',\n },\n {\n sourceProject: ts('my-gateway'),\n targetProject: 'py_project',\n targetComponent: 'my-mcp-server',\n },\n { sourceProject: ts('parent-gateway'), targetProject: ts('my-gateway') },\n // Gateway -> agent (http gateway fronting agent runtime targets: every\n // supported protocol permutation), then website -> gateway.\n {\n sourceProject: ts('agent-gateway'),\n targetProject: 'ts-project',\n targetComponent: 'my-ts-agui-agent',\n },\n {\n sourceProject: ts('agent-gateway'),\n targetProject: 'ts-project',\n targetComponent: 'my-ts-a2a-agent',\n },\n {\n sourceProject: ts('agent-gateway'),\n targetProject: 'py_project',\n targetComponent: 'my-py-agui-agent',\n },\n {\n sourceProject: ts('agent-gateway'),\n targetProject: 'py_project',\n targetComponent: 'my-agent',\n },\n {\n sourceProject: ts('agent-gateway'),\n targetProject: 'py_project',\n targetComponent: 'my-py-a2a-agent',\n },\n {\n sourceProject: ts('website-no-router'),\n targetProject: ts('agent-gateway'),\n },\n // Website -> agent\n {\n sourceProject: ts('website'),\n targetProject: 'ts-project',\n targetComponent: 'agent',\n },\n {\n sourceProject: ts('website'),\n targetProject: 'ts-project',\n targetComponent: 'my-ts-agui-agent',\n },\n {\n sourceProject: ts('website'),\n targetProject: 'py_project',\n targetComponent: 'my-agent',\n },\n {\n sourceProject: ts('website'),\n targetProject: 'py_project',\n targetComponent: 'my-py-agui-agent',\n },\n {\n sourceProject: ts('website'),\n targetProject: 'py_langchain_project',\n targetComponent: 'my-py-langchain-agent',\n },\n {\n sourceProject: ts('website'),\n targetProject: 'py_langchain_project',\n targetComponent: 'my-py-langchain-http-agent',\n },\n // DynamoDB\n { sourceProject: 'my-api', targetProject: ts('my-table') },\n { sourceProject: 'my-smithy-api', targetProject: ts('my-table') },\n {\n sourceProject: 'ts-project',\n sourceComponent: 'my-ts-agent',\n targetProject: ts('my-table'),\n },\n {\n sourceProject: 'ts-project',\n sourceComponent: 'my-mcp-server',\n targetProject: ts('my-table'),\n },\n { sourceProject: 'py_api', targetProject: 'my_py_table' },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: 'my_py_table',\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-mcp-server',\n targetProject: 'my_py_table',\n },\n {\n sourceProject: 'py_langchain_project',\n sourceComponent: 'my-py-langchain-http-agent',\n targetProject: 'my_py_table',\n },\n // Relational databases\n { sourceProject: 'py_api', targetProject: 'py_postgres_db' },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-agent',\n targetProject: 'py_postgres_db',\n },\n {\n sourceProject: 'py_project',\n sourceComponent: 'my-mcp-server',\n targetProject: 'py_postgres_db',\n },\n ];\n for (const connection of connections) {\n await connectionGenerator(tree, { ...connection, ...defaults });\n }\n\n // Licensing, then an Nx plugin with a custom generator.\n await licenseGenerator(tree, {\n license: 'Apache-2.0',\n copyrightHolder: 'Amazon.com, Inc. or its affiliates',\n ...defaults,\n });\n await tsNxPluginGenerator(tree, {\n ...projectDefaults,\n name: 'plugin',\n directory: 'tools',\n });\n await tsNxGeneratorGenerator(tree, {\n project: ts('plugin'),\n name: 'my#generator',\n ...defaults,\n });\n\n // A migration of each kind, so the scaffolded codemods compile and the\n // plugin's migrations.json (created by the first run) registers all three.\n const migrations: Omit<TsNxMigrationGeneratorSchema, 'project'>[] = [\n {\n name: 'rename-foo-target',\n description: 'Rename the foo target to bar',\n },\n {\n name: 'migrate-custom-handlers',\n description: 'Update custom handlers for the new API',\n kind: 'agentic',\n },\n {\n name: 'upgrade-framework',\n description: 'Upgrade the framework and reconcile call sites',\n kind: 'hybrid',\n },\n ];\n for (const migration of migrations) {\n await tsNxMigrationGenerator(tree, {\n ...migration,\n project: ts('plugin'),\n ...defaults,\n });\n }\n\n return () =>\n installDependencies(tree, preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default internalTestMatrixGenerator;\n"],"names":["agentcoreGatewayGenerator","agentcoreHarnessGenerator","connectionGenerator","licenseGenerator","pyAgentGenerator","pyApiGenerator","pyDynamoDBGenerator","pyLambdaFunctionGenerator","pyMcpServerGenerator","pyProjectGenerator","pyRdbGenerator","smithyProjectGenerator","terraformProjectGenerator","tsAgentGenerator","tsApiGenerator","tsAstroDocsGenerator","tsDcrProxyGenerator","tsDynamoDBGenerator","tsInfraGenerator","tsLambdaFunctionGenerator","tsMcpServerGenerator","tsNxGeneratorGenerator","tsNxMigrationGenerator","tsNxPluginGenerator","tsProjectGenerator","tsRdbGenerator","tsWebsiteAuthGenerator","tsWebsiteGenerator","installDependencies","toSnakeCase","getNpmScope","getNpmScopePrefix","internalTestMatrixGenerator","tree","options","preferInstallDependencies","defaults","projectDefaults","directory","ts","name","py","infra","type","stageConfig","iac","tanstackRouter","project","cognitoDomain","allowSignup","tsApis","auth","framework","api","pyApis","event","tsAgents","protocol","agent","pyAgents","langchainAgents","tsRdbs","engine","rdb","pyRdbs","connections","sourceProject","targetProject","sourceComponent","targetComponent","connection","license","copyrightHolder","migrations","description","kind","migration","languages"],"mappings":"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"}
@@ -8,6 +8,11 @@ import { existsSync, readFileSync } from "fs";
8
8
  import { join } from "path";
9
9
  import { uvxCommand } from "../../../utils/py.js";
10
10
  const isUsable = (value)=>!!value && value !== 'UNKNOWN';
11
+ // Package names and interpreter paths are interpolated into a shell command, so
12
+ // only accept the characters PEP 508 permits in a name, and paths without shell
13
+ // metacharacters.
14
+ const isSafePackageName = (name)=>/^[A-Za-z0-9]([A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(name);
15
+ const isSafePath = (path)=>!/[^\w./\\:@+-]/.test(path);
11
16
  // Priority: License-Expression (PEP 639) > License-Metadata (legacy) > License-Classifier (deprecated classifiers)
12
17
  const pickLicense = (entry)=>{
13
18
  if (isUsable(entry['License-Expression'])) return entry['License-Expression'];
@@ -38,7 +43,7 @@ const pickLicense = (entry)=>{
38
43
  const content = readFileSync(join(start, tomlFile), 'utf-8');
39
44
  const parsed = TOML.parse(content);
40
45
  const name = parsed.project?.name;
41
- if (typeof name === 'string') names.push(name);
46
+ if (typeof name === 'string' && isSafePackageName(name)) names.push(name);
42
47
  } catch {
43
48
  // skip unreadable or malformed files
44
49
  }
@@ -71,7 +76,7 @@ const findVenvPythons = async (start)=>{
71
76
  pythons.push(envPython);
72
77
  }
73
78
  }
74
- return pythons.filter((p)=>existsSync(p));
79
+ return pythons.filter((p)=>existsSync(p) && isSafePath(p));
75
80
  };
76
81
  /**
77
82
  * Collect Python dependency licenses by invoking `uvx pip-licenses` against
@@ -80,7 +85,8 @@ const findVenvPythons = async (start)=>{
80
85
  const pythons = await findVenvPythons(options.start);
81
86
  if (pythons.length === 0) return [];
82
87
  const seen = new Map();
83
- const ignoreFlag = options.excludePackages?.length ? ` --ignore-packages ${options.excludePackages.join(' ')}` : '';
88
+ const excluded = options.excludePackages?.filter(isSafePackageName) ?? [];
89
+ const ignoreFlag = excluded.length ? ` --ignore-packages ${excluded.join(' ')}` : '';
84
90
  const cmd = uvxCommand('pip-licenses', `--format json --from all${ignoreFlag}`);
85
91
  for (const python of pythons){
86
92
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/license/dependency-check/collectors/python-collector.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport TOML from '@iarna/toml';\nimport { execSync } from 'child_process';\nimport fastGlob from 'fast-glob';\nimport { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { uvxCommand } from '../../../utils/py';\n\nexport interface PythonDependency {\n name: string;\n version: string;\n rawLicense: string;\n}\n\nexport interface PythonCollectorOptions {\n start: string;\n excludePackages?: string[];\n}\n\ninterface PipLicensesEntry {\n Name: string;\n Version: string;\n 'License-Expression': string;\n 'License-Metadata': string;\n 'License-Classifier': string;\n}\n\nconst isUsable = (value: string | undefined): value is string =>\n !!value && value !== 'UNKNOWN';\n\n// Priority: License-Expression (PEP 639) > License-Metadata (legacy) > License-Classifier (deprecated classifiers)\nconst pickLicense = (entry: PipLicensesEntry): string => {\n if (isUsable(entry['License-Expression'])) return entry['License-Expression'];\n if (isUsable(entry['License-Metadata'])) return entry['License-Metadata'];\n if (isUsable(entry['License-Classifier'])) return entry['License-Classifier'];\n return '';\n};\n\n/**\n * Discover Python project names in the workspace (from pyproject.toml files)\n * so they can be excluded from the license check.\n */\nexport const findWorkspacePyProjectNames = async (\n start: string,\n): Promise<string[]> => {\n const tomlFiles = await fastGlob(['**/pyproject.toml'], {\n cwd: start,\n ignore: ['**/node_modules/**', '**/.venv/**', '**/venv/**', '**/dist/**'],\n deep: 4,\n suppressErrors: true,\n });\n const names: string[] = [];\n for (const tomlFile of tomlFiles) {\n try {\n const content = readFileSync(join(start, tomlFile), 'utf-8');\n const parsed = TOML.parse(content);\n const name = (parsed.project as TOML.JsonMap | undefined)?.name;\n if (typeof name === 'string') names.push(name);\n } catch {\n // skip unreadable or malformed files\n }\n }\n return names;\n};\n\nconst findVenvPythons = async (start: string): Promise<string[]> => {\n const patterns = [\n '**/.venv/bin/python',\n '**/venv/bin/python',\n '**/.venv/Scripts/python.exe',\n '**/venv/Scripts/python.exe',\n ];\n\n const candidates = await fastGlob(patterns, {\n cwd: start,\n ignore: [\n '**/node_modules/**',\n '**/.nx/**',\n '**/dist/**',\n '**/build/**',\n '**/.git/**',\n ],\n deep: 6,\n suppressErrors: true,\n });\n\n const pythons = candidates.map((c) => join(start, c));\n\n if (process.env.UV_PROJECT_ENVIRONMENT) {\n const envPython = join(\n process.env.UV_PROJECT_ENVIRONMENT,\n process.platform === 'win32' ? 'Scripts/python.exe' : 'bin/python',\n );\n if (existsSync(envPython)) {\n pythons.push(envPython);\n }\n }\n\n return pythons.filter((p) => existsSync(p));\n};\n\n/**\n * Collect Python dependency licenses by invoking `uvx pip-licenses` against\n * each discovered virtual environment.\n */\nexport const collectPythonDependencies = async (\n options: PythonCollectorOptions,\n): Promise<PythonDependency[]> => {\n const pythons = await findVenvPythons(options.start);\n if (pythons.length === 0) return [];\n\n const seen = new Map<string, PythonDependency>();\n const ignoreFlag = options.excludePackages?.length\n ? ` --ignore-packages ${options.excludePackages.join(' ')}`\n : '';\n const cmd = uvxCommand(\n 'pip-licenses',\n `--format json --from all${ignoreFlag}`,\n );\n\n for (const python of pythons) {\n try {\n const output = execSync(`${cmd} --python ${python}`, {\n cwd: options.start,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: 60_000,\n });\n\n const entries: PipLicensesEntry[] = JSON.parse(output);\n for (const entry of entries) {\n const key = `${entry.Name}@${entry.Version}`;\n if (seen.has(key)) continue;\n seen.set(key, {\n name: entry.Name,\n version: entry.Version,\n rawLicense: pickLicense(entry),\n });\n }\n } catch {\n // If pip-licenses fails for this venv, skip it\n }\n }\n\n return Array.from(seen.values());\n};\n"],"names":["TOML","execSync","fastGlob","existsSync","readFileSync","join","uvxCommand","isUsable","value","pickLicense","entry","findWorkspacePyProjectNames","start","tomlFiles","cwd","ignore","deep","suppressErrors","names","tomlFile","content","parsed","parse","name","project","push","findVenvPythons","patterns","candidates","pythons","map","c","process","env","UV_PROJECT_ENVIRONMENT","envPython","platform","filter","p","collectPythonDependencies","options","length","seen","Map","ignoreFlag","excludePackages","cmd","python","output","encoding","stdio","timeout","entries","JSON","key","Name","Version","has","set","version","rawLicense","Array","from","values"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/license/dependency-check/collectors/python-collector.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport TOML from '@iarna/toml';\nimport { execSync } from 'child_process';\nimport fastGlob from 'fast-glob';\nimport { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { uvxCommand } from '../../../utils/py';\n\nexport interface PythonDependency {\n name: string;\n version: string;\n rawLicense: string;\n}\n\nexport interface PythonCollectorOptions {\n start: string;\n excludePackages?: string[];\n}\n\ninterface PipLicensesEntry {\n Name: string;\n Version: string;\n 'License-Expression': string;\n 'License-Metadata': string;\n 'License-Classifier': string;\n}\n\nconst isUsable = (value: string | undefined): value is string =>\n !!value && value !== 'UNKNOWN';\n\n// Package names and interpreter paths are interpolated into a shell command, so\n// only accept the characters PEP 508 permits in a name, and paths without shell\n// metacharacters.\nconst isSafePackageName = (name: string): boolean =>\n /^[A-Za-z0-9]([A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(name);\n\nconst isSafePath = (path: string): boolean => !/[^\\w./\\\\:@+-]/.test(path);\n\n// Priority: License-Expression (PEP 639) > License-Metadata (legacy) > License-Classifier (deprecated classifiers)\nconst pickLicense = (entry: PipLicensesEntry): string => {\n if (isUsable(entry['License-Expression'])) return entry['License-Expression'];\n if (isUsable(entry['License-Metadata'])) return entry['License-Metadata'];\n if (isUsable(entry['License-Classifier'])) return entry['License-Classifier'];\n return '';\n};\n\n/**\n * Discover Python project names in the workspace (from pyproject.toml files)\n * so they can be excluded from the license check.\n */\nexport const findWorkspacePyProjectNames = async (\n start: string,\n): Promise<string[]> => {\n const tomlFiles = await fastGlob(['**/pyproject.toml'], {\n cwd: start,\n ignore: ['**/node_modules/**', '**/.venv/**', '**/venv/**', '**/dist/**'],\n deep: 4,\n suppressErrors: true,\n });\n const names: string[] = [];\n for (const tomlFile of tomlFiles) {\n try {\n const content = readFileSync(join(start, tomlFile), 'utf-8');\n const parsed = TOML.parse(content);\n const name = (parsed.project as TOML.JsonMap | undefined)?.name;\n if (typeof name === 'string' && isSafePackageName(name)) names.push(name);\n } catch {\n // skip unreadable or malformed files\n }\n }\n return names;\n};\n\nconst findVenvPythons = async (start: string): Promise<string[]> => {\n const patterns = [\n '**/.venv/bin/python',\n '**/venv/bin/python',\n '**/.venv/Scripts/python.exe',\n '**/venv/Scripts/python.exe',\n ];\n\n const candidates = await fastGlob(patterns, {\n cwd: start,\n ignore: [\n '**/node_modules/**',\n '**/.nx/**',\n '**/dist/**',\n '**/build/**',\n '**/.git/**',\n ],\n deep: 6,\n suppressErrors: true,\n });\n\n const pythons = candidates.map((c) => join(start, c));\n\n if (process.env.UV_PROJECT_ENVIRONMENT) {\n const envPython = join(\n process.env.UV_PROJECT_ENVIRONMENT,\n process.platform === 'win32' ? 'Scripts/python.exe' : 'bin/python',\n );\n if (existsSync(envPython)) {\n pythons.push(envPython);\n }\n }\n\n return pythons.filter((p) => existsSync(p) && isSafePath(p));\n};\n\n/**\n * Collect Python dependency licenses by invoking `uvx pip-licenses` against\n * each discovered virtual environment.\n */\nexport const collectPythonDependencies = async (\n options: PythonCollectorOptions,\n): Promise<PythonDependency[]> => {\n const pythons = await findVenvPythons(options.start);\n if (pythons.length === 0) return [];\n\n const seen = new Map<string, PythonDependency>();\n const excluded = options.excludePackages?.filter(isSafePackageName) ?? [];\n const ignoreFlag = excluded.length\n ? ` --ignore-packages ${excluded.join(' ')}`\n : '';\n const cmd = uvxCommand(\n 'pip-licenses',\n `--format json --from all${ignoreFlag}`,\n );\n\n for (const python of pythons) {\n try {\n const output = execSync(`${cmd} --python ${python}`, {\n cwd: options.start,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: 60_000,\n });\n\n const entries: PipLicensesEntry[] = JSON.parse(output);\n for (const entry of entries) {\n const key = `${entry.Name}@${entry.Version}`;\n if (seen.has(key)) continue;\n seen.set(key, {\n name: entry.Name,\n version: entry.Version,\n rawLicense: pickLicense(entry),\n });\n }\n } catch {\n // If pip-licenses fails for this venv, skip it\n }\n }\n\n return Array.from(seen.values());\n};\n"],"names":["TOML","execSync","fastGlob","existsSync","readFileSync","join","uvxCommand","isUsable","value","isSafePackageName","name","test","isSafePath","path","pickLicense","entry","findWorkspacePyProjectNames","start","tomlFiles","cwd","ignore","deep","suppressErrors","names","tomlFile","content","parsed","parse","project","push","findVenvPythons","patterns","candidates","pythons","map","c","process","env","UV_PROJECT_ENVIRONMENT","envPython","platform","filter","p","collectPythonDependencies","options","length","seen","Map","excluded","excludePackages","ignoreFlag","cmd","python","output","encoding","stdio","timeout","entries","JSON","key","Name","Version","has","set","version","rawLicense","Array","from","values"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "description": "Extract the duplicated _SessionIdMiddleware class in py#agent's main.py into a shared middleware/session_id_middleware.py module"
3
+ }
@@ -0,0 +1,2 @@
1
+ import { type MigrationReturnObject, type Tree } from '@nx/devkit';
2
+ export default function migration(tree: Tree): Promise<MigrationReturnObject>;
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { readFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { getProjects, joinPathFragments } from "@nx/devkit";
7
+ import { PY_AGENT_GENERATOR_INFO } from "../../../py/agent/generator.js";
8
+ import { addPythonDestructuredImport, applyGritQL, captureGritQLVariable, matchGritQL } from "../../../utils/ast.js";
9
+ import { formatFilesInSubtree } from "../../../utils/format.js";
10
+ /**
11
+ * Extract the `_SessionIdMiddleware` class - previously duplicated verbatim
12
+ * in every py#agent `main.py` (one copy per framework/protocol combination) -
13
+ * into a shared `middleware/session_id_middleware.py` module sitting beside
14
+ * `main.py`, mirroring the http#/a2a#/ag-ui#'s own `common/agent.py` and
15
+ * `common/session.py` sharing pattern.
16
+ *
17
+ * The transform is protocol/framework-agnostic: every generated `main.py`
18
+ * duplicated the exact same `dispatch` body (only the docstring differs
19
+ * between AG-UI and HTTP/A2A), so one rewrite handles all six shapes. Imports
20
+ * that only existed to support the inlined class (`uuid`, `Request`,
21
+ * `BaseHTTPMiddleware`, `session_id_context`) are left for the trailing
22
+ * `formatFilesInSubtree` ruff pass to prune if they've gone unused - AG-UI's
23
+ * `main.py` still uses several of them directly, so nothing here can safely
24
+ * assume any one of them is dead.
25
+ */ const pyMatch = (snippet)=>`language python\n\`${snippet}\``;
26
+ const pyDelete = (snippet)=>`${pyMatch(snippet)} => .`;
27
+ const pyRewrite = (from, to)=>{
28
+ const replacement = to.includes('\n') ? `raw\`${to}\`` : `\`${to}\``;
29
+ return `${pyMatch(from)} => ${replacement}`;
30
+ };
31
+ // Both frameworks import `session_id_context` from the shared agent-connection
32
+ // module alongside other names, so this both confirms the old shape is
33
+ // present and recovers the module name to import the new middleware from.
34
+ const SESSION_ID_CONTEXT_MOD_CAPTURE = 'language python\n`from $mod import $names` where { $names <: contains `session_id_context` }';
35
+ const SESSION_ID_HEADER_LINE = 'SESSION_ID_HEADER = "x-amzn-bedrock-agentcore-runtime-session-id"';
36
+ const ADD_MIDDLEWARE_OLD = 'app.add_middleware(_SessionIdMiddleware)';
37
+ const ADD_MIDDLEWARE_NEW = 'app.add_middleware(SessionIdMiddleware)';
38
+ // HTTP and A2A share this docstring verbatim; AG-UI's differs (see below).
39
+ const OLD_CLASS_INBOUND = `class _SessionIdMiddleware(BaseHTTPMiddleware):
40
+ """Bind the inbound session (or a fresh UUID) to async context."""
41
+
42
+ async def dispatch(self, request: Request, call_next):
43
+ session_id = request.headers.get(SESSION_ID_HEADER) or str(uuid.uuid4())
44
+ with session_id_context(session_id):
45
+ return await call_next(request)`;
46
+ const OLD_CLASS_DOWNSTREAM = `class _SessionIdMiddleware(BaseHTTPMiddleware):
47
+ """Bind the session ID for this request so downstream MCP / A2A clients forward it on outbound calls."""
48
+
49
+ async def dispatch(self, request: Request, call_next):
50
+ session_id = request.headers.get(SESSION_ID_HEADER) or str(uuid.uuid4())
51
+ with session_id_context(session_id):
52
+ return await call_next(request)`;
53
+ // Both framework common/ dirs vend byte-identical middleware content (the
54
+ // LangChain copy would work equally well); this one is read as the single
55
+ // source of truth rather than hand-duplicating it here.
56
+ const SESSION_ID_MIDDLEWARE_TEMPLATE = readFileSync(join(import.meta.dirname, '../../../py/agent/files/strands/common/middleware/session_id_middleware.py.template'), 'utf-8');
57
+ const sessionIdMiddlewareContent = (agentConnectionModule)=>SESSION_ID_MIDDLEWARE_TEMPLATE.replace('<%- agentConnectionModuleName %>', agentConnectionModule);
58
+ const findAgentComponents = (components)=>(components ?? []).filter((component)=>component.generator === PY_AGENT_GENERATOR_INFO.id);
59
+ const migrateMain = async (tree, mainPath, component, nextSteps)=>{
60
+ if (!tree.exists(mainPath)) return;
61
+ const contents = tree.read(mainPath, 'utf-8') ?? '';
62
+ if (!contents.includes('class _SessionIdMiddleware(')) return;
63
+ const oldClass = contents.includes('Bind the session ID for this request so downstream MCP / A2A clients forward it on outbound calls.') ? OLD_CLASS_DOWNSTREAM : OLD_CLASS_INBOUND;
64
+ const ready = await matchGritQL(tree, mainPath, pyMatch(oldClass)) && await matchGritQL(tree, mainPath, pyMatch(SESSION_ID_HEADER_LINE)) && await matchGritQL(tree, mainPath, pyMatch(ADD_MIDDLEWARE_OLD)) && await matchGritQL(tree, mainPath, SESSION_ID_CONTEXT_MOD_CAPTURE);
65
+ const diverged = ()=>{
66
+ const shape = [
67
+ component.framework,
68
+ component.protocol
69
+ ].filter(Boolean).join('/');
70
+ nextSteps.push(`${mainPath}: diverged from the generated ${shape || 'py#agent'} shape - left untouched. Manually move \`_SessionIdMiddleware\` into a sibling \`middleware/session_id_middleware.py\` module and import it from there (see the py#agent generator's template).`);
71
+ };
72
+ if (!ready) {
73
+ diverged();
74
+ return;
75
+ }
76
+ const mod = await captureGritQLVariable(tree, mainPath, SESSION_ID_CONTEXT_MOD_CAPTURE, 'mod');
77
+ if (!mod) {
78
+ diverged();
79
+ return;
80
+ }
81
+ const dir = mainPath.split('/').slice(0, -1).join('/');
82
+ const middlewareInitPath = joinPathFragments(dir, 'middleware', '__init__.py');
83
+ const middlewarePath = joinPathFragments(dir, 'middleware', 'session_id_middleware.py');
84
+ if (!tree.exists(middlewareInitPath)) {
85
+ tree.write(middlewareInitPath, '');
86
+ }
87
+ if (!tree.exists(middlewarePath)) {
88
+ tree.write(middlewarePath, sessionIdMiddlewareContent(mod));
89
+ }
90
+ await applyGritQL(tree, mainPath, pyDelete(SESSION_ID_HEADER_LINE));
91
+ await applyGritQL(tree, mainPath, pyDelete(oldClass));
92
+ await applyGritQL(tree, mainPath, pyRewrite(ADD_MIDDLEWARE_OLD, ADD_MIDDLEWARE_NEW));
93
+ // Imported unconditionally - SESSION_ID_HEADER is only still referenced by
94
+ // AG-UI's main.py after the class is gone; the ruff pass below prunes it
95
+ // from HTTP/A2A's now-unused import list.
96
+ await addPythonDestructuredImport(tree, mainPath, [
97
+ 'SESSION_ID_HEADER',
98
+ 'SessionIdMiddleware'
99
+ ], '.middleware.session_id_middleware');
100
+ };
101
+ export default async function migration(tree) {
102
+ const nextSteps = [];
103
+ for (const project of getProjects(tree).values()){
104
+ const components = findAgentComponents(project.metadata?.components);
105
+ for (const component of components){
106
+ if (!component.path) continue;
107
+ const componentDir = component.path.endsWith('/agent.py') ? component.path.slice(0, -'/agent.py'.length) : component.path;
108
+ const mainPath = joinPathFragments(project.root, componentDir, 'main.py');
109
+ await migrateMain(tree, mainPath, component, nextSteps);
110
+ }
111
+ }
112
+ await formatFilesInSubtree(tree);
113
+ return {
114
+ nextSteps
115
+ };
116
+ }
117
+
118
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/py-agent-session-id-middleware-extraction/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { PY_AGENT_GENERATOR_INFO } from '../../../py/agent/generator';\nimport {\n addPythonDestructuredImport,\n applyGritQL,\n captureGritQLVariable,\n matchGritQL,\n} from '../../../utils/ast';\nimport { formatFilesInSubtree } from '../../../utils/format';\nimport type { ComponentMetadata } from '../../../utils/nx';\n\n/**\n * Extract the `_SessionIdMiddleware` class - previously duplicated verbatim\n * in every py#agent `main.py` (one copy per framework/protocol combination) -\n * into a shared `middleware/session_id_middleware.py` module sitting beside\n * `main.py`, mirroring the http#/a2a#/ag-ui#'s own `common/agent.py` and\n * `common/session.py` sharing pattern.\n *\n * The transform is protocol/framework-agnostic: every generated `main.py`\n * duplicated the exact same `dispatch` body (only the docstring differs\n * between AG-UI and HTTP/A2A), so one rewrite handles all six shapes. Imports\n * that only existed to support the inlined class (`uuid`, `Request`,\n * `BaseHTTPMiddleware`, `session_id_context`) are left for the trailing\n * `formatFilesInSubtree` ruff pass to prune if they've gone unused - AG-UI's\n * `main.py` still uses several of them directly, so nothing here can safely\n * assume any one of them is dead.\n */\nconst pyMatch = (snippet: string) => `language python\\n\\`${snippet}\\``;\n\nconst pyDelete = (snippet: string) => `${pyMatch(snippet)} => .`;\n\nconst pyRewrite = (from: string, to: string): string => {\n const replacement = to.includes('\\n') ? `raw\\`${to}\\`` : `\\`${to}\\``;\n return `${pyMatch(from)} => ${replacement}`;\n};\n\n// Both frameworks import `session_id_context` from the shared agent-connection\n// module alongside other names, so this both confirms the old shape is\n// present and recovers the module name to import the new middleware from.\nconst SESSION_ID_CONTEXT_MOD_CAPTURE =\n 'language python\\n`from $mod import $names` where { $names <: contains `session_id_context` }';\n\nconst SESSION_ID_HEADER_LINE =\n 'SESSION_ID_HEADER = \"x-amzn-bedrock-agentcore-runtime-session-id\"';\n\nconst ADD_MIDDLEWARE_OLD = 'app.add_middleware(_SessionIdMiddleware)';\nconst ADD_MIDDLEWARE_NEW = 'app.add_middleware(SessionIdMiddleware)';\n\n// HTTP and A2A share this docstring verbatim; AG-UI's differs (see below).\nconst OLD_CLASS_INBOUND = `class _SessionIdMiddleware(BaseHTTPMiddleware):\n \"\"\"Bind the inbound session (or a fresh UUID) to async context.\"\"\"\n\n async def dispatch(self, request: Request, call_next):\n session_id = request.headers.get(SESSION_ID_HEADER) or str(uuid.uuid4())\n with session_id_context(session_id):\n return await call_next(request)`;\n\nconst OLD_CLASS_DOWNSTREAM = `class _SessionIdMiddleware(BaseHTTPMiddleware):\n \"\"\"Bind the session ID for this request so downstream MCP / A2A clients forward it on outbound calls.\"\"\"\n\n async def dispatch(self, request: Request, call_next):\n session_id = request.headers.get(SESSION_ID_HEADER) or str(uuid.uuid4())\n with session_id_context(session_id):\n return await call_next(request)`;\n\n// Both framework common/ dirs vend byte-identical middleware content (the\n// LangChain copy would work equally well); this one is read as the single\n// source of truth rather than hand-duplicating it here.\nconst SESSION_ID_MIDDLEWARE_TEMPLATE = readFileSync(\n join(\n import.meta.dirname,\n '../../../py/agent/files/strands/common/middleware/session_id_middleware.py.template',\n ),\n 'utf-8',\n);\n\nconst sessionIdMiddlewareContent = (agentConnectionModule: string): string =>\n SESSION_ID_MIDDLEWARE_TEMPLATE.replace(\n '<%- agentConnectionModuleName %>',\n agentConnectionModule,\n );\n\nconst findAgentComponents = (\n components: ComponentMetadata[] | undefined,\n): ComponentMetadata[] =>\n (components ?? []).filter(\n (component) => component.generator === PY_AGENT_GENERATOR_INFO.id,\n );\n\nconst migrateMain = async (\n tree: Tree,\n mainPath: string,\n component: ComponentMetadata,\n nextSteps: string[],\n): Promise<void> => {\n if (!tree.exists(mainPath)) return;\n\n const contents = tree.read(mainPath, 'utf-8') ?? '';\n if (!contents.includes('class _SessionIdMiddleware(')) return;\n\n const oldClass = contents.includes(\n 'Bind the session ID for this request so downstream MCP / A2A clients forward it on outbound calls.',\n )\n ? OLD_CLASS_DOWNSTREAM\n : OLD_CLASS_INBOUND;\n\n const ready =\n (await matchGritQL(tree, mainPath, pyMatch(oldClass))) &&\n (await matchGritQL(tree, mainPath, pyMatch(SESSION_ID_HEADER_LINE))) &&\n (await matchGritQL(tree, mainPath, pyMatch(ADD_MIDDLEWARE_OLD))) &&\n (await matchGritQL(tree, mainPath, SESSION_ID_CONTEXT_MOD_CAPTURE));\n\n const diverged = () => {\n const shape = [component.framework, component.protocol]\n .filter(Boolean)\n .join('/');\n nextSteps.push(\n `${mainPath}: diverged from the generated ${shape || 'py#agent'} shape - left untouched. Manually move \\`_SessionIdMiddleware\\` into a sibling \\`middleware/session_id_middleware.py\\` module and import it from there (see the py#agent generator's template).`,\n );\n };\n\n if (!ready) {\n diverged();\n return;\n }\n\n const mod = await captureGritQLVariable(\n tree,\n mainPath,\n SESSION_ID_CONTEXT_MOD_CAPTURE,\n 'mod',\n );\n if (!mod) {\n diverged();\n return;\n }\n\n const dir = mainPath.split('/').slice(0, -1).join('/');\n const middlewareInitPath = joinPathFragments(\n dir,\n 'middleware',\n '__init__.py',\n );\n const middlewarePath = joinPathFragments(\n dir,\n 'middleware',\n 'session_id_middleware.py',\n );\n\n if (!tree.exists(middlewareInitPath)) {\n tree.write(middlewareInitPath, '');\n }\n if (!tree.exists(middlewarePath)) {\n tree.write(middlewarePath, sessionIdMiddlewareContent(mod));\n }\n\n await applyGritQL(tree, mainPath, pyDelete(SESSION_ID_HEADER_LINE));\n await applyGritQL(tree, mainPath, pyDelete(oldClass));\n await applyGritQL(\n tree,\n mainPath,\n pyRewrite(ADD_MIDDLEWARE_OLD, ADD_MIDDLEWARE_NEW),\n );\n // Imported unconditionally - SESSION_ID_HEADER is only still referenced by\n // AG-UI's main.py after the class is gone; the ruff pass below prunes it\n // from HTTP/A2A's now-unused import list.\n await addPythonDestructuredImport(\n tree,\n mainPath,\n ['SESSION_ID_HEADER', 'SessionIdMiddleware'],\n '.middleware.session_id_middleware',\n );\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const project of getProjects(tree).values()) {\n const components = findAgentComponents(\n (project.metadata as { components?: ComponentMetadata[] })?.components,\n );\n\n for (const component of components) {\n if (!component.path) continue;\n\n const componentDir = component.path.endsWith('/agent.py')\n ? component.path.slice(0, -'/agent.py'.length)\n : component.path;\n const mainPath = joinPathFragments(project.root, componentDir, 'main.py');\n\n await migrateMain(tree, mainPath, component, nextSteps);\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["readFileSync","join","getProjects","joinPathFragments","PY_AGENT_GENERATOR_INFO","addPythonDestructuredImport","applyGritQL","captureGritQLVariable","matchGritQL","formatFilesInSubtree","pyMatch","snippet","pyDelete","pyRewrite","from","to","replacement","includes","SESSION_ID_CONTEXT_MOD_CAPTURE","SESSION_ID_HEADER_LINE","ADD_MIDDLEWARE_OLD","ADD_MIDDLEWARE_NEW","OLD_CLASS_INBOUND","OLD_CLASS_DOWNSTREAM","SESSION_ID_MIDDLEWARE_TEMPLATE","dirname","sessionIdMiddlewareContent","agentConnectionModule","replace","findAgentComponents","components","filter","component","generator","id","migrateMain","tree","mainPath","nextSteps","exists","contents","read","oldClass","ready","diverged","shape","framework","protocol","Boolean","push","mod","dir","split","slice","middlewareInitPath","middlewarePath","write","migration","project","values","metadata","path","componentDir","endsWith","length","root"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "description": "Extract the duplicated session-id Express middleware in ts#agent's ag-ui/a2a index.ts into a shared middleware/session-id-middleware.ts module"
3
+ }
@@ -0,0 +1,2 @@
1
+ import { type MigrationReturnObject, type Tree } from '@nx/devkit';
2
+ export default function migration(tree: Tree): Promise<MigrationReturnObject>;