@aws/nx-plugin 1.0.0-rc.72 → 1.0.0-rc.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-THIRD-PARTY +210 -730
- package/migrations.json +34 -24
- package/package.json +4 -4
- package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +3 -3
- package/src/license/config.d.ts +9 -0
- package/src/license/config.js +28 -0
- package/src/license/config.js.map +1 -1
- package/src/license/dependency-check/collectors/collector.js.map +1 -1
- package/src/license/generator.js +3 -17
- package/src/license/generator.js.map +1 -1
- package/src/license/known-exceptions.d.ts +0 -1
- package/src/license/known-exceptions.js +1 -23
- package/src/license/known-exceptions.js.map +1 -1
- package/src/migrations/latest/apt-security-updates-in-container-images/__snapshots__/migration.spec.ts.snap +90 -0
- package/src/migrations/latest/apt-security-updates-in-container-images/metadata.json +3 -0
- package/src/migrations/latest/apt-security-updates-in-container-images/migration.js +90 -0
- package/src/migrations/latest/apt-security-updates-in-container-images/migration.js.map +1 -0
- package/src/migrations/latest/remove-mcp-inspector-license-exceptions/metadata.json +3 -0
- package/src/migrations/latest/remove-mcp-inspector-license-exceptions/migration.d.ts +6 -0
- package/src/migrations/latest/remove-mcp-inspector-license-exceptions/migration.js +38 -0
- package/src/migrations/latest/remove-mcp-inspector-license-exceptions/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.67/0001-smithy-server-package-rename/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/migration.js.map +1 -0
- package/src/migrations/{latest/py-agent-a2a-lifespan-construction → v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction}/migration.js +14 -2
- package/src/migrations/v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/migration.js.map +1 -0
- package/src/preset/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +11 -4
- package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +8 -8
- package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +2 -2
- package/src/py/agent/a2a-connection/generator.js +5 -11
- package/src/py/agent/a2a-connection/generator.js.map +1 -1
- package/src/py/agent/files/deploy/Dockerfile.template +7 -0
- package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +5 -5
- package/src/py/mcp-server/files/deploy/Dockerfile.template +7 -0
- package/src/py/mcp-server/generator.js +8 -3
- package/src/py/mcp-server/generator.js.map +1 -1
- package/src/py/rdb/__snapshots__/generator.spec.ts.snap +7 -5
- package/src/py/rdb/generator.js +36 -2
- package/src/py/rdb/generator.js.map +1 -1
- package/src/smithy/project/__snapshots__/generator.spec.ts.snap +14 -14
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +9 -2
- package/src/ts/agent/a2a-connection/generator.js +4 -2
- package/src/ts/agent/a2a-connection/generator.js.map +1 -1
- package/src/ts/agent/files/deploy/Dockerfile.template +7 -0
- package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/ts/mcp-server/files/Dockerfile.template +7 -0
- package/src/ts/mcp-server/generator.js +8 -3
- package/src/ts/mcp-server/generator.js.map +1 -1
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +8 -6
- package/src/ts/rdb/generator.js +29 -2
- package/src/ts/rdb/generator.js.map +1 -1
- package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +15 -15
- package/src/ts/react-website/app/generator.js +4 -2
- package/src/ts/react-website/app/generator.js.map +1 -1
- package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +1 -1
- package/src/utils/agent-connection/agent-connection.js +5 -9
- package/src/utils/agent-connection/agent-connection.js.map +1 -1
- package/src/utils/ast.d.ts +29 -0
- package/src/utils/ast.js +31 -0
- package/src/utils/ast.js.map +1 -1
- package/src/utils/metrics.js +2 -2
- package/src/utils/metrics.js.map +1 -1
- package/src/utils/versions.d.ts +73 -73
- package/src/utils/versions.js +70 -70
- package/src/utils/versions.js.map +1 -1
- package/src/migrations/latest/py-agent-a2a-httpx-client-per-call/migration.js.map +0 -1
- package/src/migrations/latest/py-agent-a2a-lifespan-construction/migration.js.map +0 -1
- package/src/migrations/latest/py-agent-session-management-support/migration.js.map +0 -1
- package/src/migrations/latest/smithy-server-package-rename/migration.js.map +0 -1
- package/src/migrations/latest/translate-script-whole-file-writes/migration.js.map +0 -1
- package/src/py/rdb/files/__name__/__init__.py.template +0 -3
- package/src/py/rdb/files/config.json.template +0 -14
- package/src/ts/rdb/files/config.json.template +0 -14
- package/src/ts/rdb/files/src/index.ts.template +0 -1
- /package/src/migrations/latest/{py-agent-a2a-httpx-client-per-call → apt-security-updates-in-container-images}/migration.d.ts +0 -0
- /package/src/migrations/{latest/smithy-server-package-rename → v1.0.0-rc.67/0001-smithy-server-package-rename}/metadata.json +0 -0
- /package/src/migrations/{latest/py-agent-a2a-lifespan-construction → v1.0.0-rc.67/0001-smithy-server-package-rename}/migration.d.ts +0 -0
- /package/src/migrations/{latest/smithy-server-package-rename → v1.0.0-rc.67/0001-smithy-server-package-rename}/migration.js +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/build-system-prompt.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/build-user-prompt.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/config-path.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/file-to-translate.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/get-files-to-translate.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/header.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/log.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/main-call.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/main.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/project-root.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/run-with-concurrency.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/scripts-dir.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/translate-file-for-language.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/already-migrated.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/build-system-prompt.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/build-user-prompt.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/config-path.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/file-to-translate.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/get-files-to-translate.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/log.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/main-call.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/main.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/project-root.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/run-with-concurrency.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/translate-file-for-language.grit +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/metadata.json +0 -0
- /package/src/migrations/{latest/py-agent-session-management-support → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/migration.d.ts +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/migration.js +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/test-fixtures/released-script-first.ts.fixture +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/test-fixtures/released-script.ts.fixture +0 -0
- /package/src/migrations/{latest/py-agent-a2a-lifespan-construction → v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction}/metadata.json +0 -0
- /package/src/migrations/{latest/smithy-server-package-rename → v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction}/migration.d.ts +0 -0
- /package/src/migrations/{latest/py-agent-a2a-httpx-client-per-call → v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call}/metadata.json +0 -0
- /package/src/migrations/{latest/py-agent-a2a-httpx-client-per-call → v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call}/migration.js +0 -0
- /package/src/migrations/{latest/py-agent-session-management-support → v1.0.0-rc.72/0001-py-agent-session-management-support}/metadata.json +0 -0
- /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.72/0001-py-agent-session-management-support}/migration.d.ts +0 -0
- /package/src/migrations/{latest/py-agent-session-management-support → v1.0.0-rc.72/0001-py-agent-session-management-support}/migration.js +0 -0
|
@@ -712,20 +712,20 @@ name = "proj.test_project"
|
|
|
712
712
|
version = "0.1.0"
|
|
713
713
|
dependencies = [
|
|
714
714
|
"proj-agent-connection",
|
|
715
|
-
"aws-lambda-powertools==3.
|
|
715
|
+
"aws-lambda-powertools==3.34.0",
|
|
716
716
|
"aws-opentelemetry-distro==0.19.0",
|
|
717
717
|
"bedrock-agentcore==1.21.0",
|
|
718
|
-
"boto3==1.43.
|
|
718
|
+
"boto3==1.43.72",
|
|
719
719
|
"fastapi==0.141.1",
|
|
720
720
|
"mcp==1.28.1",
|
|
721
|
-
"langchain==1.3.
|
|
722
|
-
"langchain-aws==1.7.
|
|
723
|
-
"langgraph==1.2.
|
|
721
|
+
"langchain==1.3.15",
|
|
722
|
+
"langchain-aws==1.7.1",
|
|
723
|
+
"langgraph==1.2.11",
|
|
724
724
|
"langgraph-checkpoint-sqlite==3.1.1",
|
|
725
725
|
"aiosqlite==0.22.1",
|
|
726
|
-
"ag-ui-protocol==0.1.
|
|
727
|
-
"ag-ui-langgraph==0.0.
|
|
728
|
-
"uvicorn==0.52.
|
|
726
|
+
"ag-ui-protocol==0.1.20",
|
|
727
|
+
"ag-ui-langgraph==0.0.43",
|
|
728
|
+
"uvicorn==0.52.3"
|
|
729
729
|
]
|
|
730
730
|
|
|
731
731
|
[dependency-groups]
|
|
@@ -676,7 +676,7 @@ exports[`py#agent generator > should match snapshot for Terraform generated file
|
|
|
676
676
|
}
|
|
677
677
|
null = {
|
|
678
678
|
source = "hashicorp/null"
|
|
679
|
-
version = "3.3.
|
|
679
|
+
version = "3.3.1"
|
|
680
680
|
}
|
|
681
681
|
random = {
|
|
682
682
|
source = "hashicorp/random"
|
|
@@ -1088,7 +1088,7 @@ resource "null_resource" "runtime_ready" {
|
|
|
1088
1088
|
|
|
1089
1089
|
provisioner "local-exec" {
|
|
1090
1090
|
command = <<-EOT
|
|
1091
|
-
uv run --with boto3==1.43.
|
|
1091
|
+
uv run --with boto3==1.43.72 python -c "
|
|
1092
1092
|
import boto3
|
|
1093
1093
|
import json
|
|
1094
1094
|
import os
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/ import { generateFiles, joinPathFragments, OverwriteStrategy, updateProjectConfiguration } from "@nx/devkit";
|
|
5
5
|
import { addPyDependencies } from "../../../utils/add-dependencies.js";
|
|
6
6
|
import { AGENT_CONNECTION_PY_DEPENDENCIES, addPythonCoreClient, addPythonReExport, ensurePythonAgentConnectionProject, getPythonAgentConnectionModuleName, getPythonAgentConnectionProject, getPythonAgentConnectionProjectDir, PY_CLIENT_NAMING, resolveAgentFramework } from "../../../utils/agent-connection/agent-connection.js";
|
|
7
|
-
import { addPythonDestructuredImport, applyGritQL, matchGritQL } from "../../../utils/ast.js";
|
|
7
|
+
import { addPythonDestructuredImport, appendToArrayViaGritQL, applyGritQL, matchGritQL } from "../../../utils/ast.js";
|
|
8
8
|
import { declareDependencies, ownedElsewhere } from "../../../utils/declared-dependencies.js";
|
|
9
9
|
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
10
10
|
import { installDependencies } from "../../../utils/install.js";
|
|
@@ -169,16 +169,10 @@ export const pyAgentA2aConnectionGenerator = async (tree, options)=>{
|
|
|
169
169
|
* Scoped to the framework's agent constructor so unrelated `tools=` keyword
|
|
170
170
|
* arguments elsewhere in the file are not touched.
|
|
171
171
|
*/ const addToolToAgent = async (tree, filePath, toolName, framework)=>{
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if ($old <: \`[]\`) {
|
|
177
|
-
$old => \`[${toolName}]\`
|
|
178
|
-
} else {
|
|
179
|
-
$old <: \`[$items]\` where { $items += \`, ${toolName}\` }
|
|
180
|
-
}
|
|
181
|
-
}`));
|
|
172
|
+
await appendToArrayViaGritQL(tree, filePath, 'tools=', toolName, {
|
|
173
|
+
scope: AGENT_CONSTRUCTOR[framework],
|
|
174
|
+
language: 'py'
|
|
175
|
+
});
|
|
182
176
|
};
|
|
183
177
|
/**
|
|
184
178
|
* Wrap the get_agent body so the remote A2A client is created and exposed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/py/agent/a2a-connection/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addPyDependencies } from '../../../utils/add-dependencies';\nimport {\n AGENT_CONNECTION_PY_DEPENDENCIES,\n type AgentFramework,\n addPythonCoreClient,\n addPythonReExport,\n ensurePythonAgentConnectionProject,\n getPythonAgentConnectionModuleName,\n getPythonAgentConnectionProject,\n getPythonAgentConnectionProjectDir,\n PY_CLIENT_NAMING,\n resolveAgentFramework,\n} from '../../../utils/agent-connection/agent-connection';\nimport {\n addPythonDestructuredImport,\n applyGritQL,\n matchGritQL,\n} from '../../../utils/ast';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../../utils/declared-dependencies';\nimport { formatFilesInSubtree } from '../../../utils/format';\nimport { installDependencies } from '../../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../../utils/metrics';\nimport { snakeCase } from '../../../utils/names';\nimport {\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../../utils/nx';\nimport { toProjectRelativePath } from '../../../utils/paths';\nimport { addWorkspaceDependencyToPyProject } from '../../../utils/py';\nimport type { PyAgentA2aConnectionGeneratorSchema } from './schema';\n\n/** Prefix a GritQL pattern with `language python` */\nconst py = (pattern: string) => `language python\\n${pattern}`;\n\n/** The module each framework imports the `tool` decorator from. */\nconst TOOL_IMPORT_MODULE: Record<AgentFramework, string> = {\n strands: 'strands',\n langchain: 'langchain_core.tools',\n};\n\n/** The GritQL pattern matching each framework's agent constructor. */\nconst AGENT_CONSTRUCTOR: Record<AgentFramework, string> = {\n strands: 'yield Agent($_)',\n langchain: 'create_agent($_)',\n};\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyAgentA2aConnectionMetadata {\n readonly framework: AgentFramework;\n}\n\n// Each framework's Layer-2 client needs its own A2A transport: Strands wraps\n// strands' `A2AAgent` (strands-agents[a2a]); LangChain drives the a2a SDK\n// directly (a2a-sdk) and must not pull Strands in.\nexport const DEPENDENCIES = declareDependencies<PyAgentA2aConnectionMetadata>()(\n {\n py: [\n { name: 'boto3' },\n { name: 'httpx' },\n { name: 'strands-agents[a2a]', when: (m) => m.framework === 'strands' },\n { name: 'a2a-sdk', when: (m) => m.framework === 'langchain' },\n ...ownedElsewhere(AGENT_CONNECTION_PY_DEPENDENCIES),\n ],\n },\n);\n\nexport const PY_AGENT_A2A_CONNECTION_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\nexport const pyAgentA2aConnectionGenerator = async (\n tree: Tree,\n options: PyAgentA2aConnectionGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const sourceProject = readProjectConfigurationUnqualified(\n tree,\n options.sourceProject,\n );\n const targetProject = readProjectConfigurationUnqualified(\n tree,\n options.targetProject,\n );\n\n const agentComponent = options.sourceComponent;\n const targetAgentComponent = options.targetComponent;\n\n if (!agentComponent || !targetAgentComponent) {\n throw new Error(\n 'Both sourceComponent and targetComponent must be provided for py#agent -> a2a connections',\n );\n }\n\n if ((targetAgentComponent.protocol ?? '').toLowerCase() !== 'a2a') {\n throw new Error(\n `Target agent '${targetAgentComponent.name}' uses the ${targetAgentComponent.protocol ?? 'http'} protocol — only A2A agents can be connected as tools.`,\n );\n }\n\n if (\n targetAgentComponent.auth &&\n targetAgentComponent.auth.toLowerCase() !== 'iam'\n ) {\n throw new Error(\n `A2A agent connection currently only supports IAM authentication, but '${targetAgentComponent.name}' uses '${targetAgentComponent.auth}' authentication.`,\n );\n }\n\n const targetAgentComponentName = targetAgentComponent.name ?? 'agent';\n const targetAgentClassName = targetAgentComponent.rc as string;\n const targetAgentSnakeCase = snakeCase(targetAgentClassName);\n const targetAgentPort = targetAgentComponent.port ?? 9000;\n\n // The source agent's framework drives everything that varies: the client\n // naming + app template (shared with the mcp/gateway generators via\n // PY_CLIENT_NAMING), the A2A transport dep (see DEPENDENCIES), and the\n // agent.py transform below. Each framework wraps its own A2A Layer-2 client\n // (Strands' A2AAgent vs an a2a-sdk-only client) over the shared,\n // framework-agnostic A2A client config. Keyed on the framework, not a\n // boolean, so a third framework stays additive.\n const framework = resolveAgentFramework(agentComponent.framework);\n const naming = PY_CLIENT_NAMING[framework];\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyAgentA2aConnectionMetadata = { framework };\n\n // 1. Ensure the shared Python agent-connection project exists + has the\n // A2A core client (framework Layer-2) and its shared SigV4 auth helper.\n await ensurePythonAgentConnectionProject(tree, DEPENDENCIES);\n await addPythonCoreClient(tree, 'a2a', DEPENDENCIES, framework);\n\n const agentConnectionProjectDir = getPythonAgentConnectionProjectDir(tree);\n const agentConnectionModuleName = getPythonAgentConnectionModuleName(tree);\n\n // A2A client config + shared auth helper deps, plus the framework's A2A\n // transport dep. These belong to the shared agent-connection project, which\n // holds the client.\n addPyDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: agentConnectionProjectDir,\n });\n\n // 2. Generate the per-connection client into the shared agent-connection project\n const appDir = joinPathFragments(\n agentConnectionProjectDir,\n agentConnectionModuleName,\n 'app',\n );\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', naming.appTemplateSubdir),\n appDir,\n {\n targetAgentSnakeCase,\n targetAgentClassName,\n targetAgentPort,\n agentConnectionModuleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n // Ensure app/__init__.py exists\n const appInitPath = joinPathFragments(appDir, '__init__.py');\n if (!tree.exists(appInitPath)) {\n tree.write(appInitPath, '');\n }\n\n // Add re-export to module __init__.py\n const moduleInitPath = joinPathFragments(\n agentConnectionProjectDir,\n agentConnectionModuleName,\n '__init__.py',\n );\n await addPythonReExport(\n tree,\n moduleInitPath,\n `.app.${targetAgentSnakeCase}_client_${naming.clientModuleSuffix}`,\n `${targetAgentClassName}Client${naming.clientClassSuffix}`,\n );\n\n // 3. Transform agent.py to add the A2A client import + wrap it as a tool\n const agentSourceDir = joinPathFragments(\n sourceProject.root,\n agentComponent.path ?? 'src',\n );\n const agentFilePath = joinPathFragments(agentSourceDir, 'agent.py');\n\n if (tree.exists(agentFilePath)) {\n const clientClassName = `${targetAgentClassName}Client${naming.clientClassSuffix}`;\n const clientVarName = targetAgentSnakeCase;\n const toolName = `ask_${targetAgentSnakeCase}`;\n\n await addImportToAgentFile(\n tree,\n agentFilePath,\n agentConnectionModuleName,\n clientClassName,\n framework,\n );\n await addToolToAgent(tree, agentFilePath, toolName, framework);\n await addClientToolToGetAgent(\n tree,\n agentFilePath,\n clientClassName,\n clientVarName,\n toolName,\n targetAgentClassName,\n framework,\n );\n }\n\n // 4. Add workspace dependency from agent project to agent-connection project\n addWorkspaceDependencyToPyProject(\n tree,\n sourceProject,\n getPythonAgentConnectionProject(tree),\n );\n\n // 5. Set up dev target dependencies — chain onto the target agent\n const agentName = agentComponent.name ?? 'agent';\n const devTargetName = `${agentName}-dev`;\n const targetDevTargetName = `${targetAgentComponentName}-dev`;\n\n if (sourceProject.targets?.[devTargetName]) {\n addDependencyToTargetIfNotPresent(sourceProject, devTargetName, {\n projects: [targetProject.name],\n target: targetDevTargetName,\n });\n updateProjectConfiguration(tree, sourceProject.name, sourceProject);\n }\n\n // Recorded so the version sync knows this connection's dependencies are ours.\n addComponentGeneratorMetadata(\n tree,\n sourceProject.name,\n PY_AGENT_A2A_CONNECTION_GENERATOR_INFO,\n toProjectRelativePath(sourceProject, agentFilePath),\n targetAgentClassName,\n // `sourcePath` names the source component this connection is made from, so\n // the pair is identifiable rather than just the two projects.\n { ...metadata, sourcePath: options.sourceComponent?.path },\n );\n\n await addGeneratorMetricsIfApplicable(tree, [\n PY_AGENT_A2A_CONNECTION_GENERATOR_INFO,\n ]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\n/**\n * Add imports to agent.py:\n * - `tool` (from `strands`, or `langchain_core.tools` for LangChain agents)\n * - the per-connection client class from the shared agent-connection module\n */\nconst addImportToAgentFile = async (\n tree: Tree,\n filePath: string,\n agentConnectionModuleName: string,\n clientClassName: string,\n framework: AgentFramework,\n): Promise<void> => {\n await addPythonDestructuredImport(\n tree,\n filePath,\n ['tool'],\n TOOL_IMPORT_MODULE[framework],\n );\n await addPythonDestructuredImport(\n tree,\n filePath,\n [clientClassName],\n agentConnectionModuleName,\n );\n};\n\n/**\n * Add the A2A tool to the Agent's tools array using GritQL.\n *\n * Scoped to the framework's agent constructor so unrelated `tools=` keyword\n * arguments elsewhere in the file are not touched.\n */\nconst addToolToAgent = async (\n tree: Tree,\n filePath: string,\n toolName: string,\n framework: AgentFramework,\n): Promise<void> => {\n const scope = AGENT_CONSTRUCTOR[framework];\n await applyGritQL(\n tree,\n filePath,\n py(`\\`tools=$old\\` where {\n $old <: within \\`${scope}\\`,\n $old <: not contains \\`${toolName}\\`,\n if ($old <: \\`[]\\`) {\n $old => \\`[${toolName}]\\`\n } else {\n $old <: \\`[$items]\\` where { $items += \\`, ${toolName}\\` }\n }\n}`),\n );\n};\n\n/**\n * Wrap the get_agent body so the remote A2A client is created and exposed\n * as a `@tool`-decorated closure before constructing the Agent.\n *\n * Unlike MCP clients, A2A clients aren't context managers — we don't need\n * a `with` block around them. Creation + tool definition happen at the\n * top of the function body, anchored on the framework's agent constructor.\n */\nconst addClientToolToGetAgent = async (\n tree: Tree,\n filePath: string,\n clientClassName: string,\n clientVarName: string,\n toolName: string,\n targetAgentClassName: string,\n framework: AgentFramework,\n): Promise<void> => {\n if (await matchGritQL(tree, filePath, py(`\\`${clientClassName}.create\\``))) {\n return;\n }\n\n // Both frameworks' tools are @tool-decorated callables (the decorator's\n // import differs, handled in addImportToAgentFile), defined inline in\n // get_agent. The client is directly callable, returning the remote's reply.\n const toolBlock = `${clientVarName} = ${clientClassName}.create()\n\n @tool\n def ${toolName}(prompt: str) -> str:\n \"\"\"Delegate a question to the remote ${targetAgentClassName} A2A agent and return its reply.\"\"\"\n return str(${clientVarName}(prompt))\n`;\n\n // Prepend client creation + tool definition to the function body, anchored on\n // the framework's agent constructor. This works whether or not a prior MCP\n // block is present since we insert before any existing statements.\n const anchor = AGENT_CONSTRUCTOR[framework];\n await applyGritQL(\n tree,\n filePath,\n py(`\\`def get_agent($params):\n $body\\` where {\n $body <: contains \\`${anchor}\\`,\n $body <: not contains \\`${clientClassName}.create\\`\n} => \\`def get_agent($params):\n ${toolBlock}\n $body\\``),\n );\n};\n\nexport default pyAgentA2aConnectionGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","addPyDependencies","AGENT_CONNECTION_PY_DEPENDENCIES","addPythonCoreClient","addPythonReExport","ensurePythonAgentConnectionProject","getPythonAgentConnectionModuleName","getPythonAgentConnectionProject","getPythonAgentConnectionProjectDir","PY_CLIENT_NAMING","resolveAgentFramework","addPythonDestructuredImport","applyGritQL","matchGritQL","declareDependencies","ownedElsewhere","formatFilesInSubtree","installDependencies","addGeneratorMetricsIfApplicable","snakeCase","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","toProjectRelativePath","addWorkspaceDependencyToPyProject","py","pattern","TOOL_IMPORT_MODULE","strands","langchain","AGENT_CONSTRUCTOR","DEPENDENCIES","name","when","m","framework","PY_AGENT_A2A_CONNECTION_GENERATOR_INFO","filename","pyAgentA2aConnectionGenerator","tree","options","sourceProject","targetProject","agentComponent","sourceComponent","targetAgentComponent","targetComponent","Error","protocol","toLowerCase","auth","targetAgentComponentName","targetAgentClassName","rc","targetAgentSnakeCase","targetAgentPort","port","naming","metadata","agentConnectionProjectDir","agentConnectionModuleName","projectRoot","appDir","dirname","appTemplateSubdir","overwriteStrategy","KeepExisting","appInitPath","exists","write","moduleInitPath","clientModuleSuffix","clientClassSuffix","agentSourceDir","root","path","agentFilePath","clientClassName","clientVarName","toolName","addImportToAgentFile","addToolToAgent","addClientToolToGetAgent","agentName","devTargetName","targetDevTargetName","targets","projects","target","sourcePath","preferInstallDependencies","languages","filePath","scope","toolBlock","anchor"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/py/agent/a2a-connection/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addPyDependencies } from '../../../utils/add-dependencies';\nimport {\n AGENT_CONNECTION_PY_DEPENDENCIES,\n type AgentFramework,\n addPythonCoreClient,\n addPythonReExport,\n ensurePythonAgentConnectionProject,\n getPythonAgentConnectionModuleName,\n getPythonAgentConnectionProject,\n getPythonAgentConnectionProjectDir,\n PY_CLIENT_NAMING,\n resolveAgentFramework,\n} from '../../../utils/agent-connection/agent-connection';\nimport {\n addPythonDestructuredImport,\n appendToArrayViaGritQL,\n applyGritQL,\n matchGritQL,\n} from '../../../utils/ast';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../../utils/declared-dependencies';\nimport { formatFilesInSubtree } from '../../../utils/format';\nimport { installDependencies } from '../../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../../utils/metrics';\nimport { snakeCase } from '../../../utils/names';\nimport {\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../../utils/nx';\nimport { toProjectRelativePath } from '../../../utils/paths';\nimport { addWorkspaceDependencyToPyProject } from '../../../utils/py';\nimport type { PyAgentA2aConnectionGeneratorSchema } from './schema';\n\n/** Prefix a GritQL pattern with `language python` */\nconst py = (pattern: string) => `language python\\n${pattern}`;\n\n/** The module each framework imports the `tool` decorator from. */\nconst TOOL_IMPORT_MODULE: Record<AgentFramework, string> = {\n strands: 'strands',\n langchain: 'langchain_core.tools',\n};\n\n/** The GritQL pattern matching each framework's agent constructor. */\nconst AGENT_CONSTRUCTOR: Record<AgentFramework, string> = {\n strands: 'yield Agent($_)',\n langchain: 'create_agent($_)',\n};\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyAgentA2aConnectionMetadata {\n readonly framework: AgentFramework;\n}\n\n// Each framework's Layer-2 client needs its own A2A transport: Strands wraps\n// strands' `A2AAgent` (strands-agents[a2a]); LangChain drives the a2a SDK\n// directly (a2a-sdk) and must not pull Strands in.\nexport const DEPENDENCIES = declareDependencies<PyAgentA2aConnectionMetadata>()(\n {\n py: [\n { name: 'boto3' },\n { name: 'httpx' },\n { name: 'strands-agents[a2a]', when: (m) => m.framework === 'strands' },\n { name: 'a2a-sdk', when: (m) => m.framework === 'langchain' },\n ...ownedElsewhere(AGENT_CONNECTION_PY_DEPENDENCIES),\n ],\n },\n);\n\nexport const PY_AGENT_A2A_CONNECTION_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\nexport const pyAgentA2aConnectionGenerator = async (\n tree: Tree,\n options: PyAgentA2aConnectionGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const sourceProject = readProjectConfigurationUnqualified(\n tree,\n options.sourceProject,\n );\n const targetProject = readProjectConfigurationUnqualified(\n tree,\n options.targetProject,\n );\n\n const agentComponent = options.sourceComponent;\n const targetAgentComponent = options.targetComponent;\n\n if (!agentComponent || !targetAgentComponent) {\n throw new Error(\n 'Both sourceComponent and targetComponent must be provided for py#agent -> a2a connections',\n );\n }\n\n if ((targetAgentComponent.protocol ?? '').toLowerCase() !== 'a2a') {\n throw new Error(\n `Target agent '${targetAgentComponent.name}' uses the ${targetAgentComponent.protocol ?? 'http'} protocol — only A2A agents can be connected as tools.`,\n );\n }\n\n if (\n targetAgentComponent.auth &&\n targetAgentComponent.auth.toLowerCase() !== 'iam'\n ) {\n throw new Error(\n `A2A agent connection currently only supports IAM authentication, but '${targetAgentComponent.name}' uses '${targetAgentComponent.auth}' authentication.`,\n );\n }\n\n const targetAgentComponentName = targetAgentComponent.name ?? 'agent';\n const targetAgentClassName = targetAgentComponent.rc as string;\n const targetAgentSnakeCase = snakeCase(targetAgentClassName);\n const targetAgentPort = targetAgentComponent.port ?? 9000;\n\n // The source agent's framework drives everything that varies: the client\n // naming + app template (shared with the mcp/gateway generators via\n // PY_CLIENT_NAMING), the A2A transport dep (see DEPENDENCIES), and the\n // agent.py transform below. Each framework wraps its own A2A Layer-2 client\n // (Strands' A2AAgent vs an a2a-sdk-only client) over the shared,\n // framework-agnostic A2A client config. Keyed on the framework, not a\n // boolean, so a third framework stays additive.\n const framework = resolveAgentFramework(agentComponent.framework);\n const naming = PY_CLIENT_NAMING[framework];\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyAgentA2aConnectionMetadata = { framework };\n\n // 1. Ensure the shared Python agent-connection project exists + has the\n // A2A core client (framework Layer-2) and its shared SigV4 auth helper.\n await ensurePythonAgentConnectionProject(tree, DEPENDENCIES);\n await addPythonCoreClient(tree, 'a2a', DEPENDENCIES, framework);\n\n const agentConnectionProjectDir = getPythonAgentConnectionProjectDir(tree);\n const agentConnectionModuleName = getPythonAgentConnectionModuleName(tree);\n\n // A2A client config + shared auth helper deps, plus the framework's A2A\n // transport dep. These belong to the shared agent-connection project, which\n // holds the client.\n addPyDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: agentConnectionProjectDir,\n });\n\n // 2. Generate the per-connection client into the shared agent-connection project\n const appDir = joinPathFragments(\n agentConnectionProjectDir,\n agentConnectionModuleName,\n 'app',\n );\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', naming.appTemplateSubdir),\n appDir,\n {\n targetAgentSnakeCase,\n targetAgentClassName,\n targetAgentPort,\n agentConnectionModuleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n // Ensure app/__init__.py exists\n const appInitPath = joinPathFragments(appDir, '__init__.py');\n if (!tree.exists(appInitPath)) {\n tree.write(appInitPath, '');\n }\n\n // Add re-export to module __init__.py\n const moduleInitPath = joinPathFragments(\n agentConnectionProjectDir,\n agentConnectionModuleName,\n '__init__.py',\n );\n await addPythonReExport(\n tree,\n moduleInitPath,\n `.app.${targetAgentSnakeCase}_client_${naming.clientModuleSuffix}`,\n `${targetAgentClassName}Client${naming.clientClassSuffix}`,\n );\n\n // 3. Transform agent.py to add the A2A client import + wrap it as a tool\n const agentSourceDir = joinPathFragments(\n sourceProject.root,\n agentComponent.path ?? 'src',\n );\n const agentFilePath = joinPathFragments(agentSourceDir, 'agent.py');\n\n if (tree.exists(agentFilePath)) {\n const clientClassName = `${targetAgentClassName}Client${naming.clientClassSuffix}`;\n const clientVarName = targetAgentSnakeCase;\n const toolName = `ask_${targetAgentSnakeCase}`;\n\n await addImportToAgentFile(\n tree,\n agentFilePath,\n agentConnectionModuleName,\n clientClassName,\n framework,\n );\n await addToolToAgent(tree, agentFilePath, toolName, framework);\n await addClientToolToGetAgent(\n tree,\n agentFilePath,\n clientClassName,\n clientVarName,\n toolName,\n targetAgentClassName,\n framework,\n );\n }\n\n // 4. Add workspace dependency from agent project to agent-connection project\n addWorkspaceDependencyToPyProject(\n tree,\n sourceProject,\n getPythonAgentConnectionProject(tree),\n );\n\n // 5. Set up dev target dependencies — chain onto the target agent\n const agentName = agentComponent.name ?? 'agent';\n const devTargetName = `${agentName}-dev`;\n const targetDevTargetName = `${targetAgentComponentName}-dev`;\n\n if (sourceProject.targets?.[devTargetName]) {\n addDependencyToTargetIfNotPresent(sourceProject, devTargetName, {\n projects: [targetProject.name],\n target: targetDevTargetName,\n });\n updateProjectConfiguration(tree, sourceProject.name, sourceProject);\n }\n\n // Recorded so the version sync knows this connection's dependencies are ours.\n addComponentGeneratorMetadata(\n tree,\n sourceProject.name,\n PY_AGENT_A2A_CONNECTION_GENERATOR_INFO,\n toProjectRelativePath(sourceProject, agentFilePath),\n targetAgentClassName,\n // `sourcePath` names the source component this connection is made from, so\n // the pair is identifiable rather than just the two projects.\n { ...metadata, sourcePath: options.sourceComponent?.path },\n );\n\n await addGeneratorMetricsIfApplicable(tree, [\n PY_AGENT_A2A_CONNECTION_GENERATOR_INFO,\n ]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\n/**\n * Add imports to agent.py:\n * - `tool` (from `strands`, or `langchain_core.tools` for LangChain agents)\n * - the per-connection client class from the shared agent-connection module\n */\nconst addImportToAgentFile = async (\n tree: Tree,\n filePath: string,\n agentConnectionModuleName: string,\n clientClassName: string,\n framework: AgentFramework,\n): Promise<void> => {\n await addPythonDestructuredImport(\n tree,\n filePath,\n ['tool'],\n TOOL_IMPORT_MODULE[framework],\n );\n await addPythonDestructuredImport(\n tree,\n filePath,\n [clientClassName],\n agentConnectionModuleName,\n );\n};\n\n/**\n * Add the A2A tool to the Agent's tools array using GritQL.\n *\n * Scoped to the framework's agent constructor so unrelated `tools=` keyword\n * arguments elsewhere in the file are not touched.\n */\nconst addToolToAgent = async (\n tree: Tree,\n filePath: string,\n toolName: string,\n framework: AgentFramework,\n): Promise<void> => {\n await appendToArrayViaGritQL(tree, filePath, 'tools=', toolName, {\n scope: AGENT_CONSTRUCTOR[framework],\n language: 'py',\n });\n};\n\n/**\n * Wrap the get_agent body so the remote A2A client is created and exposed\n * as a `@tool`-decorated closure before constructing the Agent.\n *\n * Unlike MCP clients, A2A clients aren't context managers — we don't need\n * a `with` block around them. Creation + tool definition happen at the\n * top of the function body, anchored on the framework's agent constructor.\n */\nconst addClientToolToGetAgent = async (\n tree: Tree,\n filePath: string,\n clientClassName: string,\n clientVarName: string,\n toolName: string,\n targetAgentClassName: string,\n framework: AgentFramework,\n): Promise<void> => {\n if (await matchGritQL(tree, filePath, py(`\\`${clientClassName}.create\\``))) {\n return;\n }\n\n // Both frameworks' tools are @tool-decorated callables (the decorator's\n // import differs, handled in addImportToAgentFile), defined inline in\n // get_agent. The client is directly callable, returning the remote's reply.\n const toolBlock = `${clientVarName} = ${clientClassName}.create()\n\n @tool\n def ${toolName}(prompt: str) -> str:\n \"\"\"Delegate a question to the remote ${targetAgentClassName} A2A agent and return its reply.\"\"\"\n return str(${clientVarName}(prompt))\n`;\n\n // Prepend client creation + tool definition to the function body, anchored on\n // the framework's agent constructor. This works whether or not a prior MCP\n // block is present since we insert before any existing statements.\n const anchor = AGENT_CONSTRUCTOR[framework];\n await applyGritQL(\n tree,\n filePath,\n py(`\\`def get_agent($params):\n $body\\` where {\n $body <: contains \\`${anchor}\\`,\n $body <: not contains \\`${clientClassName}.create\\`\n} => \\`def get_agent($params):\n ${toolBlock}\n $body\\``),\n );\n};\n\nexport default pyAgentA2aConnectionGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","addPyDependencies","AGENT_CONNECTION_PY_DEPENDENCIES","addPythonCoreClient","addPythonReExport","ensurePythonAgentConnectionProject","getPythonAgentConnectionModuleName","getPythonAgentConnectionProject","getPythonAgentConnectionProjectDir","PY_CLIENT_NAMING","resolveAgentFramework","addPythonDestructuredImport","appendToArrayViaGritQL","applyGritQL","matchGritQL","declareDependencies","ownedElsewhere","formatFilesInSubtree","installDependencies","addGeneratorMetricsIfApplicable","snakeCase","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","toProjectRelativePath","addWorkspaceDependencyToPyProject","py","pattern","TOOL_IMPORT_MODULE","strands","langchain","AGENT_CONSTRUCTOR","DEPENDENCIES","name","when","m","framework","PY_AGENT_A2A_CONNECTION_GENERATOR_INFO","filename","pyAgentA2aConnectionGenerator","tree","options","sourceProject","targetProject","agentComponent","sourceComponent","targetAgentComponent","targetComponent","Error","protocol","toLowerCase","auth","targetAgentComponentName","targetAgentClassName","rc","targetAgentSnakeCase","targetAgentPort","port","naming","metadata","agentConnectionProjectDir","agentConnectionModuleName","projectRoot","appDir","dirname","appTemplateSubdir","overwriteStrategy","KeepExisting","appInitPath","exists","write","moduleInitPath","clientModuleSuffix","clientClassSuffix","agentSourceDir","root","path","agentFilePath","clientClassName","clientVarName","toolName","addImportToAgentFile","addToolToAgent","addClientToolToGetAgent","agentName","devTargetName","targetDevTargetName","targets","projects","target","sourcePath","preferInstallDependencies","languages","filePath","scope","language","toolBlock","anchor"],"mappings":"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"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
FROM <%- pythonBaseImage %>
|
|
2
2
|
|
|
3
|
+
# Apply the distribution's security updates: base image tags lag behind the
|
|
4
|
+
# security suite, so its OS packages carry fixed HIGH/CRITICAL vulnerabilities
|
|
5
|
+
# flagged by the image scan.
|
|
6
|
+
RUN apt-get update && \
|
|
7
|
+
apt-get upgrade -y --no-install-recommends && \
|
|
8
|
+
rm -rf /var/lib/apt/lists/*
|
|
9
|
+
|
|
3
10
|
# Remove the base image's pip: the agent runs from the bundled environment and
|
|
4
11
|
# never needs it at runtime, and pip's vendored packages carry known
|
|
5
12
|
# HIGH/CRITICAL vulnerabilities flagged by the image scan.
|
|
@@ -159,7 +159,7 @@ exports[`py#mcp-server generator > should match snapshot for Terraform generated
|
|
|
159
159
|
}
|
|
160
160
|
null = {
|
|
161
161
|
source = "hashicorp/null"
|
|
162
|
-
version = "3.3.
|
|
162
|
+
version = "3.3.1"
|
|
163
163
|
}
|
|
164
164
|
random = {
|
|
165
165
|
source = "hashicorp/random"
|
|
@@ -571,7 +571,7 @@ resource "null_resource" "runtime_ready" {
|
|
|
571
571
|
|
|
572
572
|
provisioner "local-exec" {
|
|
573
573
|
command = <<-EOT
|
|
574
|
-
uv run --with boto3==1.43.
|
|
574
|
+
uv run --with boto3==1.43.72 python -c "
|
|
575
575
|
import boto3
|
|
576
576
|
import json
|
|
577
577
|
import os
|
|
@@ -846,10 +846,10 @@ exports[`py#mcp-server generator > should match snapshot for generated files > u
|
|
|
846
846
|
name = "proj.test_project"
|
|
847
847
|
version = "0.1.0"
|
|
848
848
|
dependencies = [
|
|
849
|
-
"aws-lambda-powertools==3.
|
|
849
|
+
"aws-lambda-powertools==3.34.0",
|
|
850
850
|
"mcp==1.28.1",
|
|
851
|
-
"uvicorn==0.52.
|
|
852
|
-
"boto3==1.43.
|
|
851
|
+
"uvicorn==0.52.3",
|
|
852
|
+
"boto3==1.43.72",
|
|
853
853
|
"aws-opentelemetry-distro==0.19.0"
|
|
854
854
|
]
|
|
855
855
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
FROM <%- pythonBaseImage %>
|
|
2
2
|
|
|
3
|
+
# Apply the distribution's security updates: base image tags lag behind the
|
|
4
|
+
# security suite, so its OS packages carry fixed HIGH/CRITICAL vulnerabilities
|
|
5
|
+
# flagged by the image scan.
|
|
6
|
+
RUN apt-get update && \
|
|
7
|
+
apt-get upgrade -y --no-install-recommends && \
|
|
8
|
+
rm -rf /var/lib/apt/lists/*
|
|
9
|
+
|
|
3
10
|
# Remove the base image's pip: the server runs from the bundled environment and
|
|
4
11
|
# never needs it at runtime, and pip's vendored packages carry known
|
|
5
12
|
# HIGH/CRITICAL vulnerabilities flagged by the image scan.
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/ import { generateFiles, joinPathFragments, OverwriteStrategy, updateProjectConfiguration } from "@nx/devkit";
|
|
5
|
-
import { ensureLicenseExceptions } from "../../license/config.js";
|
|
6
|
-
import { MCP_INSPECTOR_EXCEPTIONS } from "../../license/known-exceptions.js";
|
|
7
5
|
import { addPyDependencies, addTsDependencies } from "../../utils/add-dependencies.js";
|
|
8
6
|
import { addMcpServerInfra } from "../../utils/agent-core-constructs/agent-core-constructs.js";
|
|
9
7
|
import { addPythonBundleTarget } from "../../utils/bundle/bundle.js";
|
|
@@ -19,6 +17,7 @@ import { kebabCase, toClassName, toSnakeCase } from "../../utils/names.js";
|
|
|
19
17
|
import { getNpmScope } from "../../utils/npm-scope.js";
|
|
20
18
|
import { addComponentDevTarget, addComponentGeneratorMetadata, addDependencyToTargetIfNotPresent, getGeneratorInfo, readProjectConfigurationUnqualified } from "../../utils/nx.js";
|
|
21
19
|
import { toProjectRelativePath } from "../../utils/paths.js";
|
|
20
|
+
import { registerPnpmBuiltDependencies } from "../../utils/pnpm-workspace.js";
|
|
22
21
|
import { assignPort } from "../../utils/port.js";
|
|
23
22
|
import { SHARED_CONSTRUCTS_DEPENDENCIES, sharedConstructsGenerator } from "../../utils/shared-constructs.js";
|
|
24
23
|
import { BASE_IMAGES } from "../../utils/versions.js";
|
|
@@ -169,6 +168,13 @@ export const pyMcpServerGenerator = async (tree, options)=>{
|
|
|
169
168
|
iac
|
|
170
169
|
} : {}
|
|
171
170
|
};
|
|
171
|
+
// The MCP inspector has a postinstall script that cascades installs into its
|
|
172
|
+
// client packages, which no-ops when the package is installed as a dependency.
|
|
173
|
+
// Register it as an explicitly-rejected build so pnpm 11's default
|
|
174
|
+
// `strictDepBuilds=true` skips it instead of failing the install.
|
|
175
|
+
registerPnpmBuiltDependencies(tree, {
|
|
176
|
+
'@modelcontextprotocol/inspector': false
|
|
177
|
+
});
|
|
172
178
|
addPyDependencies(tree, DEPENDENCIES, {
|
|
173
179
|
metadata,
|
|
174
180
|
projectRoot: project.root
|
|
@@ -253,7 +259,6 @@ export const pyMcpServerGenerator = async (tree, options)=>{
|
|
|
253
259
|
await addGeneratorMetricsIfApplicable(tree, [
|
|
254
260
|
PY_MCP_SERVER_GENERATOR_INFO
|
|
255
261
|
]);
|
|
256
|
-
await ensureLicenseExceptions(tree, MCP_INSPECTOR_EXCEPTIONS);
|
|
257
262
|
await formatFilesInSubtree(tree);
|
|
258
263
|
return ()=>installDependencies(tree, options.preferInstallDependencies, {
|
|
259
264
|
languages: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/mcp-server/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { ensureLicenseExceptions } from '../../license/config';\nimport { MCP_INSPECTOR_EXCEPTIONS } from '../../license/known-exceptions';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies';\nimport { addMcpServerInfra } from '../../utils/agent-core-constructs/agent-core-constructs';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies';\nimport { addDockerScanTarget, DOCKER_DEPENDENCIES } from '../../utils/docker';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx';\nimport { toProjectRelativePath } from '../../utils/paths';\nimport { assignPort } from '../../utils/port';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs';\nimport type { IacMetadata } from '../../utils/shared-constructs-constants';\nimport { BASE_IMAGES } from '../../utils/versions';\nimport type { PyMcpServerGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyMcpServerMetadata extends IacMetadata {\n readonly port: number;\n readonly rc: string;\n readonly auth: string;\n}\n\nexport const DEPENDENCIES = declareDependencies<PyMcpServerMetadata>()({\n ts: [\n // The MCP inspector is shared tooling.\n { name: '@modelcontextprotocol/inspector', dev: true, root: true },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: [\n { name: 'aws-lambda-powertools' },\n { name: 'mcp' },\n { name: 'uvicorn' },\n { name: 'boto3' },\n { name: 'aws-opentelemetry-distro' },\n ],\n});\n\nexport const PY_MCP_SERVER_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyMcpServerGenerator = async (\n tree: Tree,\n options: PyMcpServerGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-mcp-server`,\n );\n const mcpTargetPrefix = options.name ? name : 'mcp-server';\n\n const mcpServerNameSnakeCase = toSnakeCase(options.name || 'mcp-server');\n const mcpServerNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n mcpServerNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n\n // Recorded in the metadata below so the version sync can tell a CDK\n // project from a Terraform one; undefined when no infrastructure was\n // generated, in which case neither provider's packages were added.\n const iac =\n infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Generate example server\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'app'),\n targetSourceDir,\n {\n name,\n mcpServerNameSnakeCase,\n mcpServerNameClassName,\n moduleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n mcpServerNameSnakeCase,\n moduleName,\n bundleOutputDir,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${mcpTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree, DEPENDENCIES);\n project.targets[dockerTargetName] = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addDependencyToTargetIfNotPresent(project, 'build', 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project,\n containerEngine: containers,\n trivyTargetName: `${mcpTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n },\n DEPENDENCIES,\n );\n\n // Add shared constructs\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n\n // Add the construct to deploy the mcp server\n await addMcpServerInfra(tree, {\n mcpServerNameKebabCase: name,\n mcpServerNameClassName,\n projectName: project.name,\n dockerImageTag,\n dockerOutputDir,\n iac,\n auth,\n containers,\n });\n }\n\n const localDevPort = assignPort(tree, project, 8000, {\n component: { info: PY_MCP_SERVER_GENERATOR_INFO, name: mcpTargetPrefix },\n });\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyMcpServerMetadata = {\n port: localDevPort,\n rc: mcpServerNameClassName,\n auth,\n ...(iac ? { iac } : {}),\n };\n\n addPyDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: project.root,\n });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n const mcpTargets = {\n ...project.targets,\n // Add targets for running the MCP server\n [`${mcpTargetPrefix}-serve-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [`uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${mcpTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n [`${mcpTargetPrefix}-inspect`]: {\n executor: 'nx:run-commands',\n continuous: true,\n // Launch the inspector against the locally served HTTP server. The dev\n // target starts the server and any connected dependencies (e.g. a local\n // database).\n dependsOn: [`${mcpTargetPrefix}-dev`],\n options: {\n commands: [\n `mcp-inspector --transport http --server-url http://localhost:${localDevPort}/mcp`,\n ],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-inspect-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `mcp-inspector -- uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`,\n ],\n cwd: '{projectRoot}',\n },\n },\n };\n\n // Aggregate `<mcp>-dev` under the project-level `dev` target.\n addComponentDevTarget(mcpTargets, `${mcpTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: mcpTargets,\n });\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_MCP_SERVER_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n mcpTargetPrefix,\n metadata,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_MCP_SERVER_GENERATOR_INFO]);\n\n await ensureLicenseExceptions(tree, MCP_INSPECTOR_EXCEPTIONS);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyMcpServerGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","ensureLicenseExceptions","MCP_INSPECTOR_EXCEPTIONS","addPyDependencies","addTsDependencies","addMcpServerInfra","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","toProjectRelativePath","assignPort","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","BASE_IMAGES","DEPENDENCIES","ts","name","dev","root","py","PY_MCP_SERVER_GENERATOR_INFO","filename","pyMcpServerGenerator","tree","options","project","pyProjectPath","Error","sourceRoot","sourceParts","split","moduleName","length","pop","mcpTargetPrefix","mcpServerNameSnakeCase","mcpServerNameClassName","targetSourceDir","infra","iac","undefined","auth","console","warn","dirname","overwriteStrategy","KeepExisting","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","mcpServerNameKebabCase","projectName","localDevPort","component","info","metadata","port","rc","projectRoot","mcpTargets","continuous","cwd","env","PORT","LOCAL_DEV","preferInstallDependencies","languages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/mcp-server/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies';\nimport { addMcpServerInfra } from '../../utils/agent-core-constructs/agent-core-constructs';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies';\nimport { addDockerScanTarget, DOCKER_DEPENDENCIES } from '../../utils/docker';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx';\nimport { toProjectRelativePath } from '../../utils/paths';\nimport { registerPnpmBuiltDependencies } from '../../utils/pnpm-workspace';\nimport { assignPort } from '../../utils/port';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs';\nimport type { IacMetadata } from '../../utils/shared-constructs-constants';\nimport { BASE_IMAGES } from '../../utils/versions';\nimport type { PyMcpServerGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyMcpServerMetadata extends IacMetadata {\n readonly port: number;\n readonly rc: string;\n readonly auth: string;\n}\n\nexport const DEPENDENCIES = declareDependencies<PyMcpServerMetadata>()({\n ts: [\n // The MCP inspector is shared tooling.\n { name: '@modelcontextprotocol/inspector', dev: true, root: true },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: [\n { name: 'aws-lambda-powertools' },\n { name: 'mcp' },\n { name: 'uvicorn' },\n { name: 'boto3' },\n { name: 'aws-opentelemetry-distro' },\n ],\n});\n\nexport const PY_MCP_SERVER_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyMcpServerGenerator = async (\n tree: Tree,\n options: PyMcpServerGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-mcp-server`,\n );\n const mcpTargetPrefix = options.name ? name : 'mcp-server';\n\n const mcpServerNameSnakeCase = toSnakeCase(options.name || 'mcp-server');\n const mcpServerNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n mcpServerNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n\n // Recorded in the metadata below so the version sync can tell a CDK\n // project from a Terraform one; undefined when no infrastructure was\n // generated, in which case neither provider's packages were added.\n const iac =\n infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Generate example server\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'app'),\n targetSourceDir,\n {\n name,\n mcpServerNameSnakeCase,\n mcpServerNameClassName,\n moduleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n mcpServerNameSnakeCase,\n moduleName,\n bundleOutputDir,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${mcpTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree, DEPENDENCIES);\n project.targets[dockerTargetName] = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addDependencyToTargetIfNotPresent(project, 'build', 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project,\n containerEngine: containers,\n trivyTargetName: `${mcpTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n },\n DEPENDENCIES,\n );\n\n // Add shared constructs\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n\n // Add the construct to deploy the mcp server\n await addMcpServerInfra(tree, {\n mcpServerNameKebabCase: name,\n mcpServerNameClassName,\n projectName: project.name,\n dockerImageTag,\n dockerOutputDir,\n iac,\n auth,\n containers,\n });\n }\n\n const localDevPort = assignPort(tree, project, 8000, {\n component: { info: PY_MCP_SERVER_GENERATOR_INFO, name: mcpTargetPrefix },\n });\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyMcpServerMetadata = {\n port: localDevPort,\n rc: mcpServerNameClassName,\n auth,\n ...(iac ? { iac } : {}),\n };\n\n // The MCP inspector has a postinstall script that cascades installs into its\n // client packages, which no-ops when the package is installed as a dependency.\n // Register it as an explicitly-rejected build so pnpm 11's default\n // `strictDepBuilds=true` skips it instead of failing the install.\n registerPnpmBuiltDependencies(tree, {\n '@modelcontextprotocol/inspector': false,\n });\n\n addPyDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: project.root,\n });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n const mcpTargets = {\n ...project.targets,\n // Add targets for running the MCP server\n [`${mcpTargetPrefix}-serve-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [`uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${mcpTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n [`${mcpTargetPrefix}-inspect`]: {\n executor: 'nx:run-commands',\n continuous: true,\n // Launch the inspector against the locally served HTTP server. The dev\n // target starts the server and any connected dependencies (e.g. a local\n // database).\n dependsOn: [`${mcpTargetPrefix}-dev`],\n options: {\n commands: [\n `mcp-inspector --transport http --server-url http://localhost:${localDevPort}/mcp`,\n ],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-inspect-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `mcp-inspector -- uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`,\n ],\n cwd: '{projectRoot}',\n },\n },\n };\n\n // Aggregate `<mcp>-dev` under the project-level `dev` target.\n addComponentDevTarget(mcpTargets, `${mcpTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: mcpTargets,\n });\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_MCP_SERVER_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n mcpTargetPrefix,\n metadata,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_MCP_SERVER_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyMcpServerGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","addPyDependencies","addTsDependencies","addMcpServerInfra","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","toProjectRelativePath","registerPnpmBuiltDependencies","assignPort","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","BASE_IMAGES","DEPENDENCIES","ts","name","dev","root","py","PY_MCP_SERVER_GENERATOR_INFO","filename","pyMcpServerGenerator","tree","options","project","pyProjectPath","Error","sourceRoot","sourceParts","split","moduleName","length","pop","mcpTargetPrefix","mcpServerNameSnakeCase","mcpServerNameClassName","targetSourceDir","infra","iac","undefined","auth","console","warn","dirname","overwriteStrategy","KeepExisting","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","mcpServerNameKebabCase","projectName","localDevPort","component","info","metadata","port","rc","projectRoot","mcpTargets","continuous","cwd","env","PORT","LOCAL_DEV","preferInstallDependencies","languages"],"mappings":"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"}
|
|
@@ -218,7 +218,7 @@ exports[`py#rdb generator > should generate Terraform modules 1`] = `
|
|
|
218
218
|
}
|
|
219
219
|
null = {
|
|
220
220
|
source = "hashicorp/null"
|
|
221
|
-
version = "3.3.
|
|
221
|
+
version = "3.3.1"
|
|
222
222
|
}
|
|
223
223
|
random = {
|
|
224
224
|
source = "hashicorp/random"
|
|
@@ -1054,7 +1054,9 @@ def downgrade() -> None:
|
|
|
1054
1054
|
exports[`py#rdb generator > should generate a PostgreSQL SQLModel project with Alembic > packages/db/migrations/versions/.gitkeep 1`] = `""`;
|
|
1055
1055
|
|
|
1056
1056
|
exports[`py#rdb generator > should generate a PostgreSQL SQLModel project with Alembic > packages/db/proj_db/__init__.py 1`] = `
|
|
1057
|
-
"
|
|
1057
|
+
""""Automatically generated by Nx."""
|
|
1058
|
+
|
|
1059
|
+
from .connection import get_engine, is_local_dev, session_context
|
|
1058
1060
|
|
|
1059
1061
|
__all__ = ["get_engine", "is_local_dev", "session_context"]
|
|
1060
1062
|
"
|
|
@@ -1499,10 +1501,10 @@ readme = "README.md"
|
|
|
1499
1501
|
dependencies = [
|
|
1500
1502
|
"sqlmodel==0.0.39",
|
|
1501
1503
|
"alembic==1.19.1",
|
|
1502
|
-
"greenlet==3.5.
|
|
1504
|
+
"greenlet==3.5.5",
|
|
1503
1505
|
"asyncpg==0.31.0",
|
|
1504
|
-
"boto3==1.43.
|
|
1505
|
-
"aws-lambda-powertools==3.
|
|
1506
|
+
"boto3==1.43.72",
|
|
1507
|
+
"aws-lambda-powertools==3.34.0"
|
|
1506
1508
|
]
|
|
1507
1509
|
|
|
1508
1510
|
[build-system]
|
package/src/py/rdb/generator.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/ import { relative } from "node:path";
|
|
5
|
-
import { generateFiles, joinPathFragments, readProjectConfiguration, updateProjectConfiguration } from "@nx/devkit";
|
|
5
|
+
import { generateFiles, joinPathFragments, OverwriteStrategy, readProjectConfiguration, updateProjectConfiguration, writeJson } from "@nx/devkit";
|
|
6
6
|
import { addPyDependencies, addTsDependencies } from "../../utils/add-dependencies.js";
|
|
7
|
+
import { addPythonReExport } from "../../utils/agent-connection/agent-connection.js";
|
|
7
8
|
import { addPythonBundleTarget } from "../../utils/bundle/bundle.js";
|
|
8
9
|
import { resolveContainers } from "../../utils/containers.js";
|
|
9
10
|
import { declareDependencies, ownedElsewhere } from "../../utils/declared-dependencies.js";
|
|
@@ -138,7 +139,40 @@ export const pyRdbGenerator = async (tree, options)=>{
|
|
|
138
139
|
boto3Version: PY_VERSIONS.boto3,
|
|
139
140
|
awsLambdaPowertoolsVersion: PY_VERSIONS['aws-lambda-powertools']
|
|
140
141
|
};
|
|
141
|
-
|
|
142
|
+
// Models, the connection module, the Alembic config and the migration env are
|
|
143
|
+
// user-editable, so a re-run (to add infrastructure, or after a failed run)
|
|
144
|
+
// must not clobber the user's schema and edits.
|
|
145
|
+
generateFiles(tree, joinPathFragments(import.meta.dirname, 'files'), dir, templateOptions, {
|
|
146
|
+
overwriteStrategy: OverwriteStrategy.KeepExisting
|
|
147
|
+
});
|
|
148
|
+
// The package barrel re-exports connection.py. `pyProjectGenerator` writes a
|
|
149
|
+
// stub __init__.py when it creates the project, so the re-exports are added to
|
|
150
|
+
// whatever is there rather than replacing it — which also leaves a user's own
|
|
151
|
+
// additions to the barrel alone on a re-run.
|
|
152
|
+
const initFilePath = joinPathFragments(dir, normalizedModuleName, '__init__.py');
|
|
153
|
+
for (const importName of [
|
|
154
|
+
'get_engine',
|
|
155
|
+
'is_local_dev',
|
|
156
|
+
'session_context'
|
|
157
|
+
]){
|
|
158
|
+
await addPythonReExport(tree, initFilePath, '.connection', importName);
|
|
159
|
+
}
|
|
160
|
+
// config.json is framework-owned: it carries values derived from the
|
|
161
|
+
// generator's options, so it converges on a re-run with changed options.
|
|
162
|
+
writeJson(tree, joinPathFragments(dir, 'config.json'), {
|
|
163
|
+
runtimeConfigKey: nameClassName,
|
|
164
|
+
localDev: {
|
|
165
|
+
containerEngine,
|
|
166
|
+
containerName,
|
|
167
|
+
image: dockerImage,
|
|
168
|
+
port: localDbPort,
|
|
169
|
+
host: localDbHost,
|
|
170
|
+
dbName: databaseName,
|
|
171
|
+
dbUser: localDbUser,
|
|
172
|
+
dbPassword: localDbPassword,
|
|
173
|
+
dbEngine: engine
|
|
174
|
+
}
|
|
175
|
+
});
|
|
142
176
|
await sharedRdbScriptsGenerator(tree, engine, DEPENDENCIES);
|
|
143
177
|
const scriptsDir = relative(dir, joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'src', 'rdb'));
|
|
144
178
|
const fs = new FsCommands(tree, DEPENDENCIES);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/rdb/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { relative } from 'node:path';\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n readProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies';\nimport { addDockerScanTarget, DOCKER_DEPENDENCIES } from '../../utils/docker';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, snakeCase, toClassName } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx';\nimport { assignPort } from '../../utils/port';\nimport { addRdbInfra } from '../../utils/rdb-constructs/rdb-constructs';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs';\nimport {\n type IacMetadata,\n PACKAGES_DIR,\n SHARED_SCRIPTS_DIR,\n} from '../../utils/shared-constructs-constants';\nimport {\n SHARED_RDB_SCRIPTS_DEPENDENCIES,\n sharedRdbScriptsGenerator,\n} from '../../utils/shared-rdb-scripts';\nimport { PY_VERSIONS } from '../../utils/versions';\nimport pyProjectGenerator, { getPyProjectDetails } from '../project/generator';\nimport type { PyRdbGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyRdbMetadata extends IacMetadata {\n readonly engine: PyRdbGeneratorSchema['engine'];\n}\n\n/** The Postgres engine, which MySQL takes none of. */\nconst isPostgres = (m: PyRdbMetadata) => m.engine !== 'mysql';\n\n// Each entry names the engine branch it belongs to, so the same declaration\n// drives both adding and the version sync.\nexport const DEPENDENCIES = declareDependencies<PyRdbMetadata>()({\n ts: [\n // The engine client the local dev script wait-for-*-db.ts imports.\n { name: 'mariadb', when: (m) => m.engine === 'mysql', root: true },\n { name: 'pg', when: isPostgres, root: true },\n { name: '@types/pg', when: isPostgres, dev: true, root: true },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ...ownedElsewhere(SHARED_RDB_SCRIPTS_DEPENDENCIES),\n ],\n py: [\n { name: 'sqlmodel' },\n { name: 'alembic' },\n // SQLAlchemy's async engine (used by connection.py for both engines)\n // requires greenlet at runtime. Vend it explicitly at a pinned version so\n // the dependency graph is fully determined and doesn't float to an\n // unpublished-wheel release at install time.\n { name: 'greenlet' },\n { name: 'aiomysql', when: (m) => m.engine === 'mysql' },\n { name: 'asyncpg', when: (m) => m.engine !== 'mysql' },\n { name: 'boto3' },\n { name: 'aws-lambda-powertools' },\n ],\n});\n\nexport const PY_RDB_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyRdbGenerator = async (\n tree: Tree,\n options: PyRdbGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const nameClassName = toClassName(options.name);\n const databaseUser = options.databaseUser ?? 'dbadmin';\n const databaseName = snakeCase(options.databaseName ?? options.name);\n const containerEngine = await resolveContainers(tree, 'inherit');\n\n const { fullyQualifiedName, dir, normalizedModuleName } = getPyProjectDetails(\n tree,\n {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n },\n );\n\n if (!projectExists(tree, fullyQualifiedName)) {\n await pyProjectGenerator(tree, {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n type: 'library',\n });\n }\n\n const projectConfig = readProjectConfiguration(tree, fullyQualifiedName);\n\n const { engine } = options;\n // Recorded in the metadata below so the version sync can tell a CDK project\n // from a Terraform one; undefined when no infrastructure was generated.\n const iac =\n options.infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyRdbMetadata = { engine, ...(iac ? { iac } : {}) };\n const localDbPort = assignPort(\n tree,\n projectConfig,\n engine === 'mysql' ? 3306 : 5432,\n );\n const localDbHost = 'localhost';\n const localDbUser = engine === 'mysql' ? 'root' : 'dbadmin';\n const localDbPassword = 'password';\n const containerName = `${getNpmScope(tree)}-${databaseName}`;\n const dockerImage =\n engine === 'mysql'\n ? 'public.ecr.aws/docker/library/mysql:8.0.44'\n : 'public.ecr.aws/docker/library/postgres:17.7';\n\n const templateOptions = {\n name: normalizedModuleName,\n runtimeConfigKey: nameClassName,\n engine,\n localDbPort,\n localDbHost,\n localDbName: databaseName,\n localDbUser,\n localDbPassword,\n containerEngine,\n containerName,\n dockerImage,\n sqlmodelVersion: PY_VERSIONS.sqlmodel,\n alembicVersion: PY_VERSIONS.alembic,\n aiomysqlVersion: PY_VERSIONS.aiomysql,\n asyncpgVersion: PY_VERSIONS.asyncpg,\n boto3Version: PY_VERSIONS.boto3,\n awsLambdaPowertoolsVersion: PY_VERSIONS['aws-lambda-powertools'],\n };\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files'),\n dir,\n templateOptions,\n );\n\n await sharedRdbScriptsGenerator(tree, engine, DEPENDENCIES);\n const scriptsDir = relative(\n dir,\n joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'src', 'rdb'),\n );\n const fs = new FsCommands(tree, DEPENDENCIES);\n\n const migrationBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'migration',\n );\n const createDbUserBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'create-db-user',\n );\n const migrationDockerImageTag = `${getNpmScope(tree)}-${kebabCase(options.name)}-migration:latest`;\n const createDbUserDockerImageTag = `${getNpmScope(tree)}-${kebabCase(\n options.name,\n )}-create-db-user:latest`;\n\n if (options.infra !== 'none') {\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n projectConfig,\n { pythonPlatform: 'aarch64-manylinux_2_28' },\n );\n\n projectConfig.targets['bundle-migration'] = {\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/migration'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(migrationBundleDir),\n fs.mkdir(migrationBundleDir),\n fs.cp(bundleOutputDir, migrationBundleDir),\n fs.cp(\n joinPathFragments(dir, 'migrations'),\n joinPathFragments(migrationBundleDir, 'migrations'),\n ),\n fs.cp(\n joinPathFragments(dir, 'alembic.ini'),\n joinPathFragments(migrationBundleDir, 'alembic.ini'),\n ),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.migration'),\n joinPathFragments(migrationBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n projectConfig.targets['bundle-create-db-user'] = {\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/create-db-user'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(createDbUserBundleDir),\n fs.mkdir(createDbUserBundleDir),\n fs.cp(bundleOutputDir, createDbUserBundleDir),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.create-db-user'),\n joinPathFragments(createDbUserBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-create-db-user',\n );\n }\n\n projectConfig.targets['pull-image'] = {\n executor: 'nx:run-commands',\n options: {\n command: `tsx ${scriptsDir}/pull-image.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets['dev'] = {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n command: `tsx ${scriptsDir}/start-container.ts`,\n cwd: '{projectRoot}',\n },\n dependsOn: ['pull-image'],\n };\n projectConfig.targets['wait-for-db'] = {\n executor: 'nx:run-commands',\n dependsOn: ['dev'],\n options: {\n command: `tsx ${scriptsDir}/wait-for-${engine}-db.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets.migrate = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic upgrade head',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n projectConfig.targets.alembic = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n\n if (options.infra !== 'none') {\n if (iac === 'terraform') {\n projectConfig.targets.docker = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${migrationDockerImageTag} ${migrationBundleDir}`,\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${createDbUserDockerImageTag} ${createDbUserBundleDir}`,\n ],\n parallel: false,\n },\n dependsOn: ['bundle-migration', 'bundle-create-db-user'],\n };\n addDependencyToTargetIfNotPresent(projectConfig, 'build', 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project: projectConfig,\n containerEngine,\n trivyTargetName: 'trivy',\n dockerTargetName: 'docker',\n imageTags: [migrationDockerImageTag, createDbUserDockerImageTag],\n },\n DEPENDENCIES,\n );\n }\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-create-db-user',\n );\n }\n\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfig);\n addGeneratorMetadata(\n tree,\n fullyQualifiedName,\n PY_RDB_GENERATOR_INFO,\n metadata,\n );\n\n if (options.infra !== 'none') {\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n await addRdbInfra(tree, {\n iac,\n projectName: fullyQualifiedName,\n projectRoot: dir,\n nameClassName,\n nameKebabCase: kebabCase(options.name),\n databasePackageAlias: normalizedModuleName,\n databaseName,\n adminUser: databaseUser,\n engine,\n migrationBundleDir,\n createDbUserBundleDir,\n framework: 'sqlmodel',\n createDbUserDockerImageTag,\n migrationDockerImageTag,\n containerEngine,\n });\n }\n\n addPyDependencies(tree, DEPENDENCIES, { metadata, projectRoot: dir });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n await addGeneratorMetricsIfApplicable(tree, [PY_RDB_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyRdbGenerator;\n"],"names":["relative","generateFiles","joinPathFragments","readProjectConfiguration","updateProjectConfiguration","addPyDependencies","addTsDependencies","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","snakeCase","toClassName","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","assignPort","addRdbInfra","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","PACKAGES_DIR","SHARED_SCRIPTS_DIR","SHARED_RDB_SCRIPTS_DEPENDENCIES","sharedRdbScriptsGenerator","PY_VERSIONS","pyProjectGenerator","getPyProjectDetails","isPostgres","m","engine","DEPENDENCIES","ts","name","when","root","dev","py","PY_RDB_GENERATOR_INFO","filename","pyRdbGenerator","tree","options","nameClassName","databaseUser","databaseName","containerEngine","fullyQualifiedName","dir","normalizedModuleName","directory","subDirectory","type","projectConfig","iac","infra","undefined","metadata","localDbPort","localDbHost","localDbUser","localDbPassword","containerName","dockerImage","templateOptions","runtimeConfigKey","localDbName","sqlmodelVersion","sqlmodel","alembicVersion","alembic","aiomysqlVersion","aiomysql","asyncpgVersion","asyncpg","boto3Version","boto3","awsLambdaPowertoolsVersion","dirname","scriptsDir","fs","migrationBundleDir","createDbUserBundleDir","migrationDockerImageTag","createDbUserDockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","targets","cache","outputs","executor","commands","rm","mkdir","cp","parallel","dependsOn","command","cwd","continuous","migrate","env","LOCAL_DEV","docker","project","trivyTargetName","dockerTargetName","imageTags","projectName","projectRoot","nameKebabCase","databasePackageAlias","adminUser","framework","preferInstallDependencies","languages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/rdb/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { relative } from 'node:path';\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n readProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n writeJson,\n} from '@nx/devkit';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies';\nimport { addPythonReExport } from '../../utils/agent-connection/agent-connection';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies';\nimport { addDockerScanTarget, DOCKER_DEPENDENCIES } from '../../utils/docker';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, snakeCase, toClassName } from '../../utils/names';\nimport { getNpmScope } from '../../utils/npm-scope';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx';\nimport { assignPort } from '../../utils/port';\nimport { addRdbInfra } from '../../utils/rdb-constructs/rdb-constructs';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs';\nimport {\n type IacMetadata,\n PACKAGES_DIR,\n SHARED_SCRIPTS_DIR,\n} from '../../utils/shared-constructs-constants';\nimport {\n SHARED_RDB_SCRIPTS_DEPENDENCIES,\n sharedRdbScriptsGenerator,\n} from '../../utils/shared-rdb-scripts';\nimport { PY_VERSIONS } from '../../utils/versions';\nimport pyProjectGenerator, { getPyProjectDetails } from '../project/generator';\nimport type { PyRdbGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyRdbMetadata extends IacMetadata {\n readonly engine: PyRdbGeneratorSchema['engine'];\n}\n\n/** The Postgres engine, which MySQL takes none of. */\nconst isPostgres = (m: PyRdbMetadata) => m.engine !== 'mysql';\n\n// Each entry names the engine branch it belongs to, so the same declaration\n// drives both adding and the version sync.\nexport const DEPENDENCIES = declareDependencies<PyRdbMetadata>()({\n ts: [\n // The engine client the local dev script wait-for-*-db.ts imports.\n { name: 'mariadb', when: (m) => m.engine === 'mysql', root: true },\n { name: 'pg', when: isPostgres, root: true },\n { name: '@types/pg', when: isPostgres, dev: true, root: true },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ...ownedElsewhere(SHARED_RDB_SCRIPTS_DEPENDENCIES),\n ],\n py: [\n { name: 'sqlmodel' },\n { name: 'alembic' },\n // SQLAlchemy's async engine (used by connection.py for both engines)\n // requires greenlet at runtime. Vend it explicitly at a pinned version so\n // the dependency graph is fully determined and doesn't float to an\n // unpublished-wheel release at install time.\n { name: 'greenlet' },\n { name: 'aiomysql', when: (m) => m.engine === 'mysql' },\n { name: 'asyncpg', when: (m) => m.engine !== 'mysql' },\n { name: 'boto3' },\n { name: 'aws-lambda-powertools' },\n ],\n});\n\nexport const PY_RDB_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyRdbGenerator = async (\n tree: Tree,\n options: PyRdbGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const nameClassName = toClassName(options.name);\n const databaseUser = options.databaseUser ?? 'dbadmin';\n const databaseName = snakeCase(options.databaseName ?? options.name);\n const containerEngine = await resolveContainers(tree, 'inherit');\n\n const { fullyQualifiedName, dir, normalizedModuleName } = getPyProjectDetails(\n tree,\n {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n },\n );\n\n if (!projectExists(tree, fullyQualifiedName)) {\n await pyProjectGenerator(tree, {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n type: 'library',\n });\n }\n\n const projectConfig = readProjectConfiguration(tree, fullyQualifiedName);\n\n const { engine } = options;\n // Recorded in the metadata below so the version sync can tell a CDK project\n // from a Terraform one; undefined when no infrastructure was generated.\n const iac =\n options.infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyRdbMetadata = { engine, ...(iac ? { iac } : {}) };\n const localDbPort = assignPort(\n tree,\n projectConfig,\n engine === 'mysql' ? 3306 : 5432,\n );\n const localDbHost = 'localhost';\n const localDbUser = engine === 'mysql' ? 'root' : 'dbadmin';\n const localDbPassword = 'password';\n const containerName = `${getNpmScope(tree)}-${databaseName}`;\n const dockerImage =\n engine === 'mysql'\n ? 'public.ecr.aws/docker/library/mysql:8.0.44'\n : 'public.ecr.aws/docker/library/postgres:17.7';\n\n const templateOptions = {\n name: normalizedModuleName,\n runtimeConfigKey: nameClassName,\n engine,\n localDbPort,\n localDbHost,\n localDbName: databaseName,\n localDbUser,\n localDbPassword,\n containerEngine,\n containerName,\n dockerImage,\n sqlmodelVersion: PY_VERSIONS.sqlmodel,\n alembicVersion: PY_VERSIONS.alembic,\n aiomysqlVersion: PY_VERSIONS.aiomysql,\n asyncpgVersion: PY_VERSIONS.asyncpg,\n boto3Version: PY_VERSIONS.boto3,\n awsLambdaPowertoolsVersion: PY_VERSIONS['aws-lambda-powertools'],\n };\n\n // Models, the connection module, the Alembic config and the migration env are\n // user-editable, so a re-run (to add infrastructure, or after a failed run)\n // must not clobber the user's schema and edits.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files'),\n dir,\n templateOptions,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n // The package barrel re-exports connection.py. `pyProjectGenerator` writes a\n // stub __init__.py when it creates the project, so the re-exports are added to\n // whatever is there rather than replacing it — which also leaves a user's own\n // additions to the barrel alone on a re-run.\n const initFilePath = joinPathFragments(\n dir,\n normalizedModuleName,\n '__init__.py',\n );\n for (const importName of ['get_engine', 'is_local_dev', 'session_context']) {\n await addPythonReExport(tree, initFilePath, '.connection', importName);\n }\n\n // config.json is framework-owned: it carries values derived from the\n // generator's options, so it converges on a re-run with changed options.\n writeJson(tree, joinPathFragments(dir, 'config.json'), {\n runtimeConfigKey: nameClassName,\n localDev: {\n containerEngine,\n containerName,\n image: dockerImage,\n port: localDbPort,\n host: localDbHost,\n dbName: databaseName,\n dbUser: localDbUser,\n dbPassword: localDbPassword,\n dbEngine: engine,\n },\n });\n\n await sharedRdbScriptsGenerator(tree, engine, DEPENDENCIES);\n const scriptsDir = relative(\n dir,\n joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'src', 'rdb'),\n );\n const fs = new FsCommands(tree, DEPENDENCIES);\n\n const migrationBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'migration',\n );\n const createDbUserBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'create-db-user',\n );\n const migrationDockerImageTag = `${getNpmScope(tree)}-${kebabCase(options.name)}-migration:latest`;\n const createDbUserDockerImageTag = `${getNpmScope(tree)}-${kebabCase(\n options.name,\n )}-create-db-user:latest`;\n\n if (options.infra !== 'none') {\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n projectConfig,\n { pythonPlatform: 'aarch64-manylinux_2_28' },\n );\n\n projectConfig.targets['bundle-migration'] = {\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/migration'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(migrationBundleDir),\n fs.mkdir(migrationBundleDir),\n fs.cp(bundleOutputDir, migrationBundleDir),\n fs.cp(\n joinPathFragments(dir, 'migrations'),\n joinPathFragments(migrationBundleDir, 'migrations'),\n ),\n fs.cp(\n joinPathFragments(dir, 'alembic.ini'),\n joinPathFragments(migrationBundleDir, 'alembic.ini'),\n ),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.migration'),\n joinPathFragments(migrationBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n projectConfig.targets['bundle-create-db-user'] = {\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/create-db-user'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(createDbUserBundleDir),\n fs.mkdir(createDbUserBundleDir),\n fs.cp(bundleOutputDir, createDbUserBundleDir),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.create-db-user'),\n joinPathFragments(createDbUserBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-create-db-user',\n );\n }\n\n projectConfig.targets['pull-image'] = {\n executor: 'nx:run-commands',\n options: {\n command: `tsx ${scriptsDir}/pull-image.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets['dev'] = {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n command: `tsx ${scriptsDir}/start-container.ts`,\n cwd: '{projectRoot}',\n },\n dependsOn: ['pull-image'],\n };\n projectConfig.targets['wait-for-db'] = {\n executor: 'nx:run-commands',\n dependsOn: ['dev'],\n options: {\n command: `tsx ${scriptsDir}/wait-for-${engine}-db.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets.migrate = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic upgrade head',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n projectConfig.targets.alembic = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n\n if (options.infra !== 'none') {\n if (iac === 'terraform') {\n projectConfig.targets.docker = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${migrationDockerImageTag} ${migrationBundleDir}`,\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${createDbUserDockerImageTag} ${createDbUserBundleDir}`,\n ],\n parallel: false,\n },\n dependsOn: ['bundle-migration', 'bundle-create-db-user'],\n };\n addDependencyToTargetIfNotPresent(projectConfig, 'build', 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project: projectConfig,\n containerEngine,\n trivyTargetName: 'trivy',\n dockerTargetName: 'docker',\n imageTags: [migrationDockerImageTag, createDbUserDockerImageTag],\n },\n DEPENDENCIES,\n );\n }\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-create-db-user',\n );\n }\n\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfig);\n addGeneratorMetadata(\n tree,\n fullyQualifiedName,\n PY_RDB_GENERATOR_INFO,\n metadata,\n );\n\n if (options.infra !== 'none') {\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n await addRdbInfra(tree, {\n iac,\n projectName: fullyQualifiedName,\n projectRoot: dir,\n nameClassName,\n nameKebabCase: kebabCase(options.name),\n databasePackageAlias: normalizedModuleName,\n databaseName,\n adminUser: databaseUser,\n engine,\n migrationBundleDir,\n createDbUserBundleDir,\n framework: 'sqlmodel',\n createDbUserDockerImageTag,\n migrationDockerImageTag,\n containerEngine,\n });\n }\n\n addPyDependencies(tree, DEPENDENCIES, { metadata, projectRoot: dir });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n await addGeneratorMetricsIfApplicable(tree, [PY_RDB_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyRdbGenerator;\n"],"names":["relative","generateFiles","joinPathFragments","OverwriteStrategy","readProjectConfiguration","updateProjectConfiguration","writeJson","addPyDependencies","addTsDependencies","addPythonReExport","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","snakeCase","toClassName","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","assignPort","addRdbInfra","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","PACKAGES_DIR","SHARED_SCRIPTS_DIR","SHARED_RDB_SCRIPTS_DEPENDENCIES","sharedRdbScriptsGenerator","PY_VERSIONS","pyProjectGenerator","getPyProjectDetails","isPostgres","m","engine","DEPENDENCIES","ts","name","when","root","dev","py","PY_RDB_GENERATOR_INFO","filename","pyRdbGenerator","tree","options","nameClassName","databaseUser","databaseName","containerEngine","fullyQualifiedName","dir","normalizedModuleName","directory","subDirectory","type","projectConfig","iac","infra","undefined","metadata","localDbPort","localDbHost","localDbUser","localDbPassword","containerName","dockerImage","templateOptions","runtimeConfigKey","localDbName","sqlmodelVersion","sqlmodel","alembicVersion","alembic","aiomysqlVersion","aiomysql","asyncpgVersion","asyncpg","boto3Version","boto3","awsLambdaPowertoolsVersion","dirname","overwriteStrategy","KeepExisting","initFilePath","importName","localDev","image","port","host","dbName","dbUser","dbPassword","dbEngine","scriptsDir","fs","migrationBundleDir","createDbUserBundleDir","migrationDockerImageTag","createDbUserDockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","targets","cache","outputs","executor","commands","rm","mkdir","cp","parallel","dependsOn","command","cwd","continuous","migrate","env","LOCAL_DEV","docker","project","trivyTargetName","dockerTargetName","imageTags","projectName","projectRoot","nameKebabCase","databasePackageAlias","adminUser","framework","preferInstallDependencies","languages"],"mappings":"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"}
|