@aws/nx-plugin 1.1.0 → 1.1.1

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/migrations.json CHANGED
@@ -7,6 +7,11 @@
7
7
  "description": "Add the strands-agents-tools pillow override to the workspace root pyproject.toml uv override-dependencies",
8
8
  "implementation": "./src/migrations/latest/py-agent-pillow-override/migration"
9
9
  },
10
+ "latest-ts-agent-guardrails-synth-input": {
11
+ "version": "1.1.1",
12
+ "description": "Add each CDK-guarded TypeScript agent's guardrail.json to the synth inputs of the CDK infrastructure, so a policy change is synthesised instead of served from the Nx cache",
13
+ "implementation": "./src/migrations/latest/ts-agent-guardrails-synth-input/migration"
14
+ },
10
15
  "v1.0.0-rc.50-0001-modernize-function-props-cast": {
11
16
  "version": "1.0.0-rc.50",
12
17
  "description": "Replace the legacy angle-bracket FunctionProps type assertion with the modern as syntax in generated API constructs",
@@ -423,7 +428,7 @@
423
428
  "implementation": "./src/migrations/v1.0.9/0001-py-dynamodb-bind-base-model-meta/migration"
424
429
  },
425
430
  "sync-vended-versions": {
426
- "version": "1.1.0",
431
+ "version": "1.1.1",
427
432
  "description": "Sync vended dependency versions and the tracked plugin version to those vended by this release",
428
433
  "implementation": "./src/utils/version-upgrade-migration/migration"
429
434
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws/nx-plugin",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/awslabs/nx-plugin-for-aws.git",
@@ -0,0 +1,3 @@
1
+ {
2
+ "description": "Add each CDK-guarded TypeScript agent's guardrail.json to the synth inputs of the CDK infrastructure, so a policy change is synthesised instead of served from the Nx cache"
3
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { type MigrationReturnObject, type Tree } from '@nx/devkit';
6
+ /**
7
+ * Add each CDK-guarded TypeScript agent's guardrail.json to the `synth` inputs
8
+ * of the CDK infrastructure projects.
9
+ *
10
+ * The CDK guardrail construct reads guardrail.json at synth time to build the
11
+ * guardrail's rules and version description. The file belongs to the agent's
12
+ * project and no task output the infrastructure's `synth` hashes includes it,
13
+ * so without an explicit input a policy change is served from the Nx cache
14
+ * and `deploy-ci` ships the stale template.
15
+ *
16
+ * Guarded agents are found from the `ts#agent#guardrails` components in
17
+ * project metadata, each paired with the `ts#agent` component of the same
18
+ * name, and kept when that agent's IaC is CDK. An infrastructure project
19
+ * whose `synth` has no `inputs` array, or no `synth` target, is left
20
+ * unchanged and reported via `nextSteps`.
21
+ */
22
+ export default function migration(tree: Tree): Promise<MigrationReturnObject>;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { getProjects, joinPathFragments } from "@nx/devkit";
5
+ import { TS_AGENT_GENERATOR_INFO } from "../../../ts/agent/generator.js";
6
+ import { TS_AGENT_GUARDRAILS_GENERATOR_INFO } from "../../../ts/agent/guardrails/generator.js";
7
+ import { addGuardrailPolicySynthInputs } from "../../../ts/agent/guardrails/synth-inputs.js";
8
+ import { formatFilesInSubtree } from "../../../utils/format.js";
9
+ /**
10
+ * Add each CDK-guarded TypeScript agent's guardrail.json to the `synth` inputs
11
+ * of the CDK infrastructure projects.
12
+ *
13
+ * The CDK guardrail construct reads guardrail.json at synth time to build the
14
+ * guardrail's rules and version description. The file belongs to the agent's
15
+ * project and no task output the infrastructure's `synth` hashes includes it,
16
+ * so without an explicit input a policy change is served from the Nx cache
17
+ * and `deploy-ci` ships the stale template.
18
+ *
19
+ * Guarded agents are found from the `ts#agent#guardrails` components in
20
+ * project metadata, each paired with the `ts#agent` component of the same
21
+ * name, and kept when that agent's IaC is CDK. An infrastructure project
22
+ * whose `synth` has no `inputs` array, or no `synth` target, is left
23
+ * unchanged and reported via `nextSteps`.
24
+ */ export default async function migration(tree) {
25
+ const policyPaths = [];
26
+ for (const project of getProjects(tree).values()){
27
+ const components = project.metadata?.components ?? [];
28
+ for (const guardrail of components.filter((c)=>c.generator === TS_AGENT_GUARDRAILS_GENERATOR_INFO.id)){
29
+ const agent = components.find((c)=>c.generator === TS_AGENT_GENERATOR_INFO.id && (c.name ?? 'agent') === guardrail.name);
30
+ if (agent?.iac === 'cdk') {
31
+ policyPaths.push(joinPathFragments(project.root, guardrail.path, 'guardrail.json'));
32
+ }
33
+ }
34
+ }
35
+ const nextSteps = addGuardrailPolicySynthInputs(tree, policyPaths);
36
+ await formatFilesInSubtree(tree);
37
+ return {
38
+ nextSteps
39
+ };
40
+ }
41
+
42
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/ts-agent-guardrails-synth-input/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { TS_AGENT_GENERATOR_INFO } from '../../../ts/agent/generator.js';\nimport { TS_AGENT_GUARDRAILS_GENERATOR_INFO } from '../../../ts/agent/guardrails/generator.js';\nimport { addGuardrailPolicySynthInputs } from '../../../ts/agent/guardrails/synth-inputs.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport type { ComponentMetadata } from '../../../utils/nx.js';\n\n/**\n * Add each CDK-guarded TypeScript agent's guardrail.json to the `synth` inputs\n * of the CDK infrastructure projects.\n *\n * The CDK guardrail construct reads guardrail.json at synth time to build the\n * guardrail's rules and version description. The file belongs to the agent's\n * project and no task output the infrastructure's `synth` hashes includes it,\n * so without an explicit input a policy change is served from the Nx cache\n * and `deploy-ci` ships the stale template.\n *\n * Guarded agents are found from the `ts#agent#guardrails` components in\n * project metadata, each paired with the `ts#agent` component of the same\n * name, and kept when that agent's IaC is CDK. An infrastructure project\n * whose `synth` has no `inputs` array, or no `synth` target, is left\n * unchanged and reported via `nextSteps`.\n */\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const policyPaths: string[] = [];\n for (const project of getProjects(tree).values()) {\n const components: ComponentMetadata[] =\n (project.metadata as { components?: ComponentMetadata[] } | undefined)\n ?.components ?? [];\n for (const guardrail of components.filter(\n (c) => c.generator === TS_AGENT_GUARDRAILS_GENERATOR_INFO.id,\n )) {\n const agent = components.find(\n (c) =>\n c.generator === TS_AGENT_GENERATOR_INFO.id &&\n (c.name ?? 'agent') === guardrail.name,\n );\n if (agent?.iac === 'cdk') {\n policyPaths.push(\n joinPathFragments(project.root, guardrail.path, 'guardrail.json'),\n );\n }\n }\n }\n\n const nextSteps = addGuardrailPolicySynthInputs(tree, policyPaths);\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","TS_AGENT_GENERATOR_INFO","TS_AGENT_GUARDRAILS_GENERATOR_INFO","addGuardrailPolicySynthInputs","formatFilesInSubtree","migration","tree","policyPaths","project","values","components","metadata","guardrail","filter","c","generator","id","agent","find","name","iac","push","root","path","nextSteps"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,QAGZ,aAAa;AACpB,SAASC,uBAAuB,QAAQ,iCAAiC;AACzE,SAASC,kCAAkC,QAAQ,4CAA4C;AAC/F,SAASC,6BAA6B,QAAQ,+CAA+C;AAC7F,SAASC,oBAAoB,QAAQ,2BAA2B;AAGhE;;;;;;;;;;;;;;;CAeC,GACD,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,cAAwB,EAAE;IAChC,KAAK,MAAMC,WAAWT,YAAYO,MAAMG,MAAM,GAAI;QAChD,MAAMC,aACJ,AAACF,QAAQG,QAAQ,EACbD,cAAc,EAAE;QACtB,KAAK,MAAME,aAAaF,WAAWG,MAAM,CACvC,CAACC,IAAMA,EAAEC,SAAS,KAAKb,mCAAmCc,EAAE,EAC3D;YACD,MAAMC,QAAQP,WAAWQ,IAAI,CAC3B,CAACJ,IACCA,EAAEC,SAAS,KAAKd,wBAAwBe,EAAE,IAC1C,AAACF,CAAAA,EAAEK,IAAI,IAAI,OAAM,MAAOP,UAAUO,IAAI;YAE1C,IAAIF,OAAOG,QAAQ,OAAO;gBACxBb,YAAYc,IAAI,CACdrB,kBAAkBQ,QAAQc,IAAI,EAAEV,UAAUW,IAAI,EAAE;YAEpD;QACF;IACF;IAEA,MAAMC,YAAYrB,8BAA8BG,MAAMC;IAEtD,MAAMH,qBAAqBE;IAE3B,OAAO;QAAEkB;IAAU;AACrB"}
@@ -12,6 +12,7 @@ import { kebabCase, toClassName } from "../../../utils/names.js";
12
12
  import { getNpmScope } from "../../../utils/npm-scope.js";
13
13
  import { addComponentGeneratorMetadata, getGeneratorInfo, readProjectConfigurationUnqualified } from "../../../utils/nx.js";
14
14
  import { TS_AGENT_GENERATOR_INFO } from "../generator.js";
15
+ import { addGuardrailPolicySynthInputs } from "./synth-inputs.js";
15
16
  export const TS_AGENT_GUARDRAILS_GENERATOR_INFO = getGeneratorInfo(import.meta.filename);
16
17
  /**
17
18
  * Find the `ts#agent` component to guard, by name when given, otherwise the
@@ -77,12 +78,20 @@ export const tsAgentGuardrailsGenerator = async (tree, options)=>{
77
78
  const iac = agent.iac;
78
79
  let wiringMessage;
79
80
  if (iac) {
81
+ const policyPath = joinPathFragments(agentDir, 'guardrail.json');
80
82
  await addGuardrailInfra(tree, {
81
83
  iac,
82
84
  nameClassName: agentNameClassName,
83
85
  nameKebabCase,
84
- policyPath: joinPathFragments(agentDir, 'guardrail.json')
86
+ policyPath
85
87
  });
88
+ if (iac === 'cdk') {
89
+ for (const message of addGuardrailPolicySynthInputs(tree, [
90
+ policyPath
91
+ ])){
92
+ logger.warn(message);
93
+ }
94
+ }
86
95
  wiringMessage = guardrailWiringMessage({
87
96
  iac,
88
97
  nameClassName: agentNameClassName,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/ts/agent/guardrails/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 logger,\n OverwriteStrategy,\n type Tree,\n} from '@nx/devkit';\nimport {\n addDestructuredImport,\n applyGritQL,\n matchGritQL,\n} from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { addGuardrailInfra } from '../../../utils/guardrail-constructs/guardrail-constructs.js';\nimport { guardrailWiringMessage } from '../../../utils/guardrail-constructs/guardrail-wiring.js';\nimport type { Iac } from '../../../utils/iac.js';\nimport { addGeneratorMetricsIfApplicable } from '../../../utils/metrics.js';\nimport { esmVars, isEsmWorkspace } from '../../../utils/module-format.js';\nimport { kebabCase, toClassName } from '../../../utils/names.js';\nimport { getNpmScope } from '../../../utils/npm-scope.js';\nimport {\n addComponentGeneratorMetadata,\n type ComponentMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../../utils/nx.js';\nimport { TS_AGENT_GENERATOR_INFO } from '../generator.js';\nimport type { TsAgentGuardrailsGeneratorSchema } from './schema';\n\nexport const TS_AGENT_GUARDRAILS_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\n/**\n * Find the `ts#agent` component to guard, by name when given, otherwise the\n * project's only one.\n */\nconst resolveAgent = (\n projectName: string,\n components: ComponentMetadata[],\n agent?: string,\n): ComponentMetadata => {\n const agents = components.filter(\n (c) => c.generator === TS_AGENT_GENERATOR_INFO.id,\n );\n const available = agents.map((c) => c.name).join(', ') || 'none';\n if (agent) {\n const match = agents.find((c) => c.name === agent);\n if (!match) {\n throw new Error(\n `No TypeScript Agent named ${agent} in project ${projectName}. Available agents: ${available}`,\n );\n }\n return match;\n }\n if (agents.length !== 1) {\n throw new Error(\n agents.length === 0\n ? `Project ${projectName} has no TypeScript Agent. Add one with the ts#agent generator first.`\n : `Project ${projectName} has more than one TypeScript Agent. Specify which to guard with --agent. Available agents: ${available}`,\n );\n }\n return agents[0];\n};\n\n/**\n * Add `model: getGuardrailedModel()` to the `new Agent({...})` call in\n * agent.ts. An agent that already sets its own model is left unchanged, and\n * the lines to add by hand are logged instead.\n */\nconst addGuardrailedModelToAgent = async (\n tree: Tree,\n agentFile: string,\n): Promise<void> => {\n const guardrailImport = isEsmWorkspace(tree)\n ? './guardrail.js'\n : './guardrail';\n\n if (tree.exists(agentFile)) {\n if (await matchGritQL(tree, agentFile, '`getGuardrailedModel()`')) {\n return;\n }\n if (\n await applyGritQL(\n tree,\n agentFile,\n '`new Agent({ $props })` => `new Agent({ model: getGuardrailedModel(), $props })` where { $props <: not some or { `model: $_`, `model` } }',\n )\n ) {\n await addDestructuredImport(\n tree,\n agentFile,\n ['getGuardrailedModel'],\n './guardrail.js',\n );\n return;\n }\n }\n\n logger.warn(\n `Could not add the guardrail to ${agentFile}, because ${tree.exists(agentFile) ? 'its new Agent({...}) call already sets a model or is not an inline object' : 'the file does not exist'}. Set the model of your Agent to the guardrailed model by hand:\n\n model: getGuardrailedModel(),\n\nand import it:\n\n import { getGuardrailedModel } from '${guardrailImport}';`,\n );\n};\n\nexport const tsAgentGuardrailsGenerator = async (\n tree: Tree,\n options: TsAgentGuardrailsGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n const agent = resolveAgent(\n project.name,\n (project.metadata as any)?.components ?? [],\n options.agent,\n );\n\n const agentTargetPrefix = agent.name ?? 'agent';\n const agentNameClassName = agent.rc ?? toClassName(agentTargetPrefix);\n const nameKebabCase = kebabCase(agentNameClassName);\n const agentPath = agent.path ?? joinPathFragments('src', agentTargetPrefix);\n const agentDir = joinPathFragments(project.root, agentPath);\n\n // The policy is the user's to edit, so a re-run never touches these files.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'agent'),\n agentDir,\n {\n ...esmVars(tree),\n agentConnectionImport: `@${getNpmScope(tree)}/agent-connection`,\n agentNameClassName,\n nameKebabCase,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n await addGuardrailedModelToAgent(\n tree,\n joinPathFragments(agentDir, 'agent.ts'),\n );\n\n const iac = agent.iac as Iac | undefined;\n let wiringMessage: string | undefined;\n if (iac) {\n await addGuardrailInfra(tree, {\n iac,\n nameClassName: agentNameClassName,\n nameKebabCase,\n policyPath: joinPathFragments(agentDir, 'guardrail.json'),\n });\n wiringMessage = guardrailWiringMessage({\n iac,\n nameClassName: agentNameClassName,\n nameKebabCase,\n npmScope: getNpmScope(tree),\n });\n } else {\n logger.warn(\n `Agent ${agentTargetPrefix} in project ${project.name} has no infrastructure, so no guardrail infrastructure was generated. Create the guardrail yourself and write its ID and version to runtime config at agentcore.guardrails.${agentNameClassName} as { guardrailId, guardrailVersion }.`,\n );\n }\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n TS_AGENT_GUARDRAILS_GENERATOR_INFO,\n agentPath,\n agentTargetPrefix,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [\n TS_AGENT_GUARDRAILS_GENERATOR_INFO,\n ]);\n\n await formatFilesInSubtree(tree);\n\n // Printed from the callback so it appears after Nx lists the changed\n // files, on every run, since the generator cannot tell whether the stack is\n // already wired.\n return () => {\n if (wiringMessage) {\n logger.info(wiringMessage);\n }\n };\n};\n\nexport default tsAgentGuardrailsGenerator;\n"],"names":["generateFiles","joinPathFragments","logger","OverwriteStrategy","addDestructuredImport","applyGritQL","matchGritQL","formatFilesInSubtree","addGuardrailInfra","guardrailWiringMessage","addGeneratorMetricsIfApplicable","esmVars","isEsmWorkspace","kebabCase","toClassName","getNpmScope","addComponentGeneratorMetadata","getGeneratorInfo","readProjectConfigurationUnqualified","TS_AGENT_GENERATOR_INFO","TS_AGENT_GUARDRAILS_GENERATOR_INFO","filename","resolveAgent","projectName","components","agent","agents","filter","c","generator","id","available","map","name","join","match","find","Error","length","addGuardrailedModelToAgent","tree","agentFile","guardrailImport","exists","warn","tsAgentGuardrailsGenerator","options","project","metadata","agentTargetPrefix","agentNameClassName","rc","nameKebabCase","agentPath","path","agentDir","root","dirname","agentConnectionImport","overwriteStrategy","KeepExisting","iac","wiringMessage","nameClassName","policyPath","npmScope","info"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/ts/agent/guardrails/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 logger,\n OverwriteStrategy,\n type Tree,\n} from '@nx/devkit';\nimport {\n addDestructuredImport,\n applyGritQL,\n matchGritQL,\n} from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { addGuardrailInfra } from '../../../utils/guardrail-constructs/guardrail-constructs.js';\nimport { guardrailWiringMessage } from '../../../utils/guardrail-constructs/guardrail-wiring.js';\nimport type { Iac } from '../../../utils/iac.js';\nimport { addGeneratorMetricsIfApplicable } from '../../../utils/metrics.js';\nimport { esmVars, isEsmWorkspace } from '../../../utils/module-format.js';\nimport { kebabCase, toClassName } from '../../../utils/names.js';\nimport { getNpmScope } from '../../../utils/npm-scope.js';\nimport {\n addComponentGeneratorMetadata,\n type ComponentMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../../utils/nx.js';\nimport { TS_AGENT_GENERATOR_INFO } from '../generator.js';\nimport type { TsAgentGuardrailsGeneratorSchema } from './schema';\nimport { addGuardrailPolicySynthInputs } from './synth-inputs.js';\n\nexport const TS_AGENT_GUARDRAILS_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\n/**\n * Find the `ts#agent` component to guard, by name when given, otherwise the\n * project's only one.\n */\nconst resolveAgent = (\n projectName: string,\n components: ComponentMetadata[],\n agent?: string,\n): ComponentMetadata => {\n const agents = components.filter(\n (c) => c.generator === TS_AGENT_GENERATOR_INFO.id,\n );\n const available = agents.map((c) => c.name).join(', ') || 'none';\n if (agent) {\n const match = agents.find((c) => c.name === agent);\n if (!match) {\n throw new Error(\n `No TypeScript Agent named ${agent} in project ${projectName}. Available agents: ${available}`,\n );\n }\n return match;\n }\n if (agents.length !== 1) {\n throw new Error(\n agents.length === 0\n ? `Project ${projectName} has no TypeScript Agent. Add one with the ts#agent generator first.`\n : `Project ${projectName} has more than one TypeScript Agent. Specify which to guard with --agent. Available agents: ${available}`,\n );\n }\n return agents[0];\n};\n\n/**\n * Add `model: getGuardrailedModel()` to the `new Agent({...})` call in\n * agent.ts. An agent that already sets its own model is left unchanged, and\n * the lines to add by hand are logged instead.\n */\nconst addGuardrailedModelToAgent = async (\n tree: Tree,\n agentFile: string,\n): Promise<void> => {\n const guardrailImport = isEsmWorkspace(tree)\n ? './guardrail.js'\n : './guardrail';\n\n if (tree.exists(agentFile)) {\n if (await matchGritQL(tree, agentFile, '`getGuardrailedModel()`')) {\n return;\n }\n if (\n await applyGritQL(\n tree,\n agentFile,\n '`new Agent({ $props })` => `new Agent({ model: getGuardrailedModel(), $props })` where { $props <: not some or { `model: $_`, `model` } }',\n )\n ) {\n await addDestructuredImport(\n tree,\n agentFile,\n ['getGuardrailedModel'],\n './guardrail.js',\n );\n return;\n }\n }\n\n logger.warn(\n `Could not add the guardrail to ${agentFile}, because ${tree.exists(agentFile) ? 'its new Agent({...}) call already sets a model or is not an inline object' : 'the file does not exist'}. Set the model of your Agent to the guardrailed model by hand:\n\n model: getGuardrailedModel(),\n\nand import it:\n\n import { getGuardrailedModel } from '${guardrailImport}';`,\n );\n};\n\nexport const tsAgentGuardrailsGenerator = async (\n tree: Tree,\n options: TsAgentGuardrailsGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n const agent = resolveAgent(\n project.name,\n (project.metadata as any)?.components ?? [],\n options.agent,\n );\n\n const agentTargetPrefix = agent.name ?? 'agent';\n const agentNameClassName = agent.rc ?? toClassName(agentTargetPrefix);\n const nameKebabCase = kebabCase(agentNameClassName);\n const agentPath = agent.path ?? joinPathFragments('src', agentTargetPrefix);\n const agentDir = joinPathFragments(project.root, agentPath);\n\n // The policy is the user's to edit, so a re-run never touches these files.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'agent'),\n agentDir,\n {\n ...esmVars(tree),\n agentConnectionImport: `@${getNpmScope(tree)}/agent-connection`,\n agentNameClassName,\n nameKebabCase,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n await addGuardrailedModelToAgent(\n tree,\n joinPathFragments(agentDir, 'agent.ts'),\n );\n\n const iac = agent.iac as Iac | undefined;\n let wiringMessage: string | undefined;\n if (iac) {\n const policyPath = joinPathFragments(agentDir, 'guardrail.json');\n await addGuardrailInfra(tree, {\n iac,\n nameClassName: agentNameClassName,\n nameKebabCase,\n policyPath,\n });\n if (iac === 'cdk') {\n for (const message of addGuardrailPolicySynthInputs(tree, [policyPath])) {\n logger.warn(message);\n }\n }\n wiringMessage = guardrailWiringMessage({\n iac,\n nameClassName: agentNameClassName,\n nameKebabCase,\n npmScope: getNpmScope(tree),\n });\n } else {\n logger.warn(\n `Agent ${agentTargetPrefix} in project ${project.name} has no infrastructure, so no guardrail infrastructure was generated. Create the guardrail yourself and write its ID and version to runtime config at agentcore.guardrails.${agentNameClassName} as { guardrailId, guardrailVersion }.`,\n );\n }\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n TS_AGENT_GUARDRAILS_GENERATOR_INFO,\n agentPath,\n agentTargetPrefix,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [\n TS_AGENT_GUARDRAILS_GENERATOR_INFO,\n ]);\n\n await formatFilesInSubtree(tree);\n\n // Printed from the callback so it appears after Nx lists the changed\n // files, on every run, since the generator cannot tell whether the stack is\n // already wired.\n return () => {\n if (wiringMessage) {\n logger.info(wiringMessage);\n }\n };\n};\n\nexport default tsAgentGuardrailsGenerator;\n"],"names":["generateFiles","joinPathFragments","logger","OverwriteStrategy","addDestructuredImport","applyGritQL","matchGritQL","formatFilesInSubtree","addGuardrailInfra","guardrailWiringMessage","addGeneratorMetricsIfApplicable","esmVars","isEsmWorkspace","kebabCase","toClassName","getNpmScope","addComponentGeneratorMetadata","getGeneratorInfo","readProjectConfigurationUnqualified","TS_AGENT_GENERATOR_INFO","addGuardrailPolicySynthInputs","TS_AGENT_GUARDRAILS_GENERATOR_INFO","filename","resolveAgent","projectName","components","agent","agents","filter","c","generator","id","available","map","name","join","match","find","Error","length","addGuardrailedModelToAgent","tree","agentFile","guardrailImport","exists","warn","tsAgentGuardrailsGenerator","options","project","metadata","agentTargetPrefix","agentNameClassName","rc","nameKebabCase","agentPath","path","agentDir","root","dirname","agentConnectionImport","overwriteStrategy","KeepExisting","iac","wiringMessage","policyPath","nameClassName","message","npmScope","info"],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { type Tree } from '@nx/devkit';
6
+ /** The Nx fileset input for a workspace-root-relative guardrail.json. */
7
+ export declare const guardrailPolicyInput: (policyPath: string) => string;
8
+ /**
9
+ * Add each guardrail.json to the `synth` inputs of every CDK infrastructure
10
+ * project. The CDK guardrail construct reads the file at synth time, but it
11
+ * belongs to the agent's project and no upstream task output includes it, so
12
+ * without an explicit input a policy change is served from the Nx cache.
13
+ *
14
+ * Existing inputs are kept and entries already present are not repeated. A
15
+ * project without a `synth` target, or whose `synth` has no `inputs` array, is
16
+ * left unchanged, since adding an array would replace Nx's implicit inputs;
17
+ * one message per such project is returned instead.
18
+ */
19
+ export declare const addGuardrailPolicySynthInputs: (tree: Tree, policyPaths: string[]) => string[];
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { getProjects, joinPathFragments, updateJson } from "@nx/devkit";
5
+ import { INFRA_APP_GENERATOR_INFO } from "../../../infra/app/generator.js";
6
+ /** The Nx fileset input for a workspace-root-relative guardrail.json. */ export const guardrailPolicyInput = (policyPath)=>`{workspaceRoot}/${policyPath}`;
7
+ /**
8
+ * Add each guardrail.json to the `synth` inputs of every CDK infrastructure
9
+ * project. The CDK guardrail construct reads the file at synth time, but it
10
+ * belongs to the agent's project and no upstream task output includes it, so
11
+ * without an explicit input a policy change is served from the Nx cache.
12
+ *
13
+ * Existing inputs are kept and entries already present are not repeated. A
14
+ * project without a `synth` target, or whose `synth` has no `inputs` array, is
15
+ * left unchanged, since adding an array would replace Nx's implicit inputs;
16
+ * one message per such project is returned instead.
17
+ */ export const addGuardrailPolicySynthInputs = (tree, policyPaths)=>{
18
+ const entries = [
19
+ ...new Set(policyPaths)
20
+ ].map(guardrailPolicyInput);
21
+ const messages = [];
22
+ if (entries.length === 0) {
23
+ return messages;
24
+ }
25
+ for (const [name, project] of getProjects(tree)){
26
+ if (project.metadata?.generator !== INFRA_APP_GENERATOR_INFO.id) {
27
+ continue;
28
+ }
29
+ const projectJson = joinPathFragments(project.root, 'project.json');
30
+ const synth = project.targets?.synth;
31
+ if (!synth || !Array.isArray(synth.inputs)) {
32
+ const problem = synth ? `the synth target in ${projectJson} has no inputs` : `${projectJson} has no synth target`;
33
+ messages.push(`${name}: ${problem} - left unchanged. Add ${entries.join(', ')} to its synth inputs so a change to the guardrail policy invalidates the cached synth.`);
34
+ continue;
35
+ }
36
+ const missing = entries.filter((entry)=>!synth.inputs.includes(entry));
37
+ if (missing.length > 0) {
38
+ updateJson(tree, projectJson, (config)=>{
39
+ config.targets.synth.inputs = [
40
+ ...config.targets.synth.inputs,
41
+ ...missing
42
+ ];
43
+ return config;
44
+ });
45
+ }
46
+ }
47
+ return messages;
48
+ };
49
+
50
+ //# sourceMappingURL=synth-inputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/ts/agent/guardrails/synth-inputs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport { INFRA_APP_GENERATOR_INFO } from '../../../infra/app/generator.js';\n\n/** The Nx fileset input for a workspace-root-relative guardrail.json. */\nexport const guardrailPolicyInput = (policyPath: string): string =>\n `{workspaceRoot}/${policyPath}`;\n\n/**\n * Add each guardrail.json to the `synth` inputs of every CDK infrastructure\n * project. The CDK guardrail construct reads the file at synth time, but it\n * belongs to the agent's project and no upstream task output includes it, so\n * without an explicit input a policy change is served from the Nx cache.\n *\n * Existing inputs are kept and entries already present are not repeated. A\n * project without a `synth` target, or whose `synth` has no `inputs` array, is\n * left unchanged, since adding an array would replace Nx's implicit inputs;\n * one message per such project is returned instead.\n */\nexport const addGuardrailPolicySynthInputs = (\n tree: Tree,\n policyPaths: string[],\n): string[] => {\n const entries = [...new Set(policyPaths)].map(guardrailPolicyInput);\n const messages: string[] = [];\n if (entries.length === 0) {\n return messages;\n }\n\n for (const [name, project] of getProjects(tree)) {\n if (project.metadata?.generator !== INFRA_APP_GENERATOR_INFO.id) {\n continue;\n }\n const projectJson = joinPathFragments(project.root, 'project.json');\n const synth = project.targets?.synth;\n if (!synth || !Array.isArray(synth.inputs)) {\n const problem = synth\n ? `the synth target in ${projectJson} has no inputs`\n : `${projectJson} has no synth target`;\n messages.push(\n `${name}: ${problem} - left unchanged. Add ${entries.join(', ')} to its synth inputs so a change to the guardrail policy invalidates the cached synth.`,\n );\n continue;\n }\n const missing = entries.filter((entry) => !synth.inputs.includes(entry));\n if (missing.length > 0) {\n updateJson(tree, projectJson, (config) => {\n config.targets.synth.inputs = [\n ...config.targets.synth.inputs,\n ...missing,\n ];\n return config;\n });\n }\n }\n\n return messages;\n};\n"],"names":["getProjects","joinPathFragments","updateJson","INFRA_APP_GENERATOR_INFO","guardrailPolicyInput","policyPath","addGuardrailPolicySynthInputs","tree","policyPaths","entries","Set","map","messages","length","name","project","metadata","generator","id","projectJson","root","synth","targets","Array","isArray","inputs","problem","push","join","missing","filter","entry","includes","config"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,EAEjBC,UAAU,QACL,aAAa;AACpB,SAASC,wBAAwB,QAAQ,kCAAkC;AAE3E,uEAAuE,GACvE,OAAO,MAAMC,uBAAuB,CAACC,aACnC,CAAC,gBAAgB,EAAEA,YAAY,CAAC;AAElC;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,gCAAgC,CAC3CC,MACAC;IAEA,MAAMC,UAAU;WAAI,IAAIC,IAAIF;KAAa,CAACG,GAAG,CAACP;IAC9C,MAAMQ,WAAqB,EAAE;IAC7B,IAAIH,QAAQI,MAAM,KAAK,GAAG;QACxB,OAAOD;IACT;IAEA,KAAK,MAAM,CAACE,MAAMC,QAAQ,IAAIf,YAAYO,MAAO;QAC/C,IAAIQ,QAAQC,QAAQ,EAAEC,cAAcd,yBAAyBe,EAAE,EAAE;YAC/D;QACF;QACA,MAAMC,cAAclB,kBAAkBc,QAAQK,IAAI,EAAE;QACpD,MAAMC,QAAQN,QAAQO,OAAO,EAAED;QAC/B,IAAI,CAACA,SAAS,CAACE,MAAMC,OAAO,CAACH,MAAMI,MAAM,GAAG;YAC1C,MAAMC,UAAUL,QACZ,CAAC,oBAAoB,EAAEF,YAAY,cAAc,CAAC,GAClD,GAAGA,YAAY,oBAAoB,CAAC;YACxCP,SAASe,IAAI,CACX,GAAGb,KAAK,EAAE,EAAEY,QAAQ,uBAAuB,EAAEjB,QAAQmB,IAAI,CAAC,MAAM,sFAAsF,CAAC;YAEzJ;QACF;QACA,MAAMC,UAAUpB,QAAQqB,MAAM,CAAC,CAACC,QAAU,CAACV,MAAMI,MAAM,CAACO,QAAQ,CAACD;QACjE,IAAIF,QAAQhB,MAAM,GAAG,GAAG;YACtBX,WAAWK,MAAMY,aAAa,CAACc;gBAC7BA,OAAOX,OAAO,CAACD,KAAK,CAACI,MAAM,GAAG;uBACzBQ,OAAOX,OAAO,CAACD,KAAK,CAACI,MAAM;uBAC3BI;iBACJ;gBACD,OAAOI;YACT;QACF;IACF;IAEA,OAAOrB;AACT,EAAE"}
@@ -24,6 +24,8 @@ export interface AddGuardrailInfraOptions {
24
24
  *
25
25
  * Files are written with `KeepExisting`, so a re-run leaves them unchanged.
26
26
  * No build dependency is added on the agent's project, since the
27
- * infrastructure reads a source file and imports none of the agent's code.
27
+ * infrastructure reads a source file and imports none of the agent's code;
28
+ * for CDK the generator lists that file as a `synth` input instead, so the
29
+ * infrastructure's cached synth follows it.
28
30
  */
29
31
  export declare const addGuardrailInfra: (tree: Tree, options: AddGuardrailInfraOptions) => Promise<void>;
@@ -14,7 +14,9 @@ import { terraformProviderVersions } from "../versions.js";
14
14
  *
15
15
  * Files are written with `KeepExisting`, so a re-run leaves them unchanged.
16
16
  * No build dependency is added on the agent's project, since the
17
- * infrastructure reads a source file and imports none of the agent's code.
17
+ * infrastructure reads a source file and imports none of the agent's code;
18
+ * for CDK the generator lists that file as a `synth` input instead, so the
19
+ * infrastructure's cached synth follows it.
18
20
  */ export const addGuardrailInfra = async (tree, options)=>{
19
21
  const templateContext = {
20
22
  nameClassName: options.nameClassName,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/guardrail-constructs/guardrail-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n} from '@nx/devkit';\nimport { addStarExport } from '../ast.js';\nimport type { Iac } from '../iac.js';\nimport { esmVars } from '../module-format.js';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants.js';\nimport { terraformProviderVersions } from '../versions.js';\n\nexport interface AddGuardrailInfraOptions {\n iac: Iac;\n /** Class name of the guarded agent, eg `MyAgent` gives `MyAgentGuardrail`. */\n nameClassName: string;\n /**\n * Kebab-case name of the guarded agent, used for the directory and, with a\n * `-guardrail` suffix, the file.\n */\n nameKebabCase: string;\n /** Workspace-root-relative path of the guardrail.json policy file. */\n policyPath: string;\n}\n\n/**\n * Add the Amazon Bedrock Guardrail infrastructure for the selected IaC\n * provider: a CDK construct in the shared constructs project, or a Terraform\n * module in the shared Terraform project. Both read the policy file at synth\n * or plan time.\n *\n * Files are written with `KeepExisting`, so a re-run leaves them unchanged.\n * No build dependency is added on the agent's project, since the\n * infrastructure reads a source file and imports none of the agent's code.\n */\nexport const addGuardrailInfra = async (\n tree: Tree,\n options: AddGuardrailInfraOptions,\n): Promise<void> => {\n const templateContext = {\n nameClassName: options.nameClassName,\n nameKebabCase: options.nameKebabCase,\n policyPath: options.policyPath,\n };\n\n switch (options.iac) {\n case 'cdk': {\n const appDir = joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n );\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'app',\n 'guardrails',\n ),\n joinPathFragments(appDir, 'guardrails'),\n { ...templateContext, ...esmVars(tree) },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n await addStarExport(\n tree,\n joinPathFragments(appDir, 'guardrails', 'index.ts'),\n `./${options.nameKebabCase}/${options.nameKebabCase}-guardrail.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(appDir, 'index.ts'),\n './guardrails/index.js',\n );\n break;\n }\n case 'terraform':\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'guardrails',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'guardrails',\n ),\n {\n ...templateContext,\n // Guardrail names are at most 50 characters: the prefix, a hyphen\n // and the 8 hex characters of the random suffix.\n guardrailNamePrefix: `${options.nameKebabCase}-guardrail`.slice(\n 0,\n 41,\n ),\n ...terraformProviderVersions(),\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n break;\n }\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","addStarExport","esmVars","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","terraformProviderVersions","addGuardrailInfra","tree","options","templateContext","nameClassName","nameKebabCase","policyPath","iac","appDir","dirname","overwriteStrategy","KeepExisting","guardrailNamePrefix","slice"],"mappings":"AAAA;;;CAGC,GACD,SACEA,aAAa,EACbC,iBAAiB,EACjBC,iBAAiB,QAEZ,aAAa;AACpB,SAASC,aAAa,QAAQ,YAAY;AAE1C,SAASC,OAAO,QAAQ,sBAAsB;AAC9C,SACEC,YAAY,EACZC,qBAAqB,EACrBC,oBAAoB,QACf,oCAAoC;AAC3C,SAASC,yBAAyB,QAAQ,iBAAiB;AAe3D;;;;;;;;;CASC,GACD,OAAO,MAAMC,oBAAoB,OAC/BC,MACAC;IAEA,MAAMC,kBAAkB;QACtBC,eAAeF,QAAQE,aAAa;QACpCC,eAAeH,QAAQG,aAAa;QACpCC,YAAYJ,QAAQI,UAAU;IAChC;IAEA,OAAQJ,QAAQK,GAAG;QACjB,KAAK;YAAO;gBACV,MAAMC,SAAShB,kBACbI,cACAC,uBACA,OACA;gBAEFN,cACEU,MACAT,kBACE,YAAYiB,OAAO,EACnB,SACA,OACA,OACA,eAEFjB,kBAAkBgB,QAAQ,eAC1B;oBAAE,GAAGL,eAAe;oBAAE,GAAGR,QAAQM,KAAK;gBAAC,GACvC;oBAAES,mBAAmBjB,kBAAkBkB,YAAY;gBAAC;gBAEtD,MAAMjB,cACJO,MACAT,kBAAkBgB,QAAQ,cAAc,aACxC,CAAC,EAAE,EAAEN,QAAQG,aAAa,CAAC,CAAC,EAAEH,QAAQG,aAAa,CAAC,aAAa,CAAC;gBAEpE,MAAMX,cACJO,MACAT,kBAAkBgB,QAAQ,aAC1B;gBAEF;YACF;QACA,KAAK;YACHjB,cACEU,MACAT,kBACE,YAAYiB,OAAO,EACnB,SACA,aACA,OACA,eAEFjB,kBACEI,cACAE,sBACA,OACA,OACA,eAEF;gBACE,GAAGK,eAAe;gBAClB,kEAAkE;gBAClE,iDAAiD;gBACjDS,qBAAqB,GAAGV,QAAQG,aAAa,CAAC,UAAU,CAAC,CAACQ,KAAK,CAC7D,GACA;gBAEF,GAAGd,2BAA2B;YAChC,GACA;gBAAEW,mBAAmBjB,kBAAkBkB,YAAY;YAAC;YAEtD;IACJ;AACF,EAAE"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/guardrail-constructs/guardrail-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n} from '@nx/devkit';\nimport { addStarExport } from '../ast.js';\nimport type { Iac } from '../iac.js';\nimport { esmVars } from '../module-format.js';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants.js';\nimport { terraformProviderVersions } from '../versions.js';\n\nexport interface AddGuardrailInfraOptions {\n iac: Iac;\n /** Class name of the guarded agent, eg `MyAgent` gives `MyAgentGuardrail`. */\n nameClassName: string;\n /**\n * Kebab-case name of the guarded agent, used for the directory and, with a\n * `-guardrail` suffix, the file.\n */\n nameKebabCase: string;\n /** Workspace-root-relative path of the guardrail.json policy file. */\n policyPath: string;\n}\n\n/**\n * Add the Amazon Bedrock Guardrail infrastructure for the selected IaC\n * provider: a CDK construct in the shared constructs project, or a Terraform\n * module in the shared Terraform project. Both read the policy file at synth\n * or plan time.\n *\n * Files are written with `KeepExisting`, so a re-run leaves them unchanged.\n * No build dependency is added on the agent's project, since the\n * infrastructure reads a source file and imports none of the agent's code;\n * for CDK the generator lists that file as a `synth` input instead, so the\n * infrastructure's cached synth follows it.\n */\nexport const addGuardrailInfra = async (\n tree: Tree,\n options: AddGuardrailInfraOptions,\n): Promise<void> => {\n const templateContext = {\n nameClassName: options.nameClassName,\n nameKebabCase: options.nameKebabCase,\n policyPath: options.policyPath,\n };\n\n switch (options.iac) {\n case 'cdk': {\n const appDir = joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n );\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'app',\n 'guardrails',\n ),\n joinPathFragments(appDir, 'guardrails'),\n { ...templateContext, ...esmVars(tree) },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n await addStarExport(\n tree,\n joinPathFragments(appDir, 'guardrails', 'index.ts'),\n `./${options.nameKebabCase}/${options.nameKebabCase}-guardrail.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(appDir, 'index.ts'),\n './guardrails/index.js',\n );\n break;\n }\n case 'terraform':\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'guardrails',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'guardrails',\n ),\n {\n ...templateContext,\n // Guardrail names are at most 50 characters: the prefix, a hyphen\n // and the 8 hex characters of the random suffix.\n guardrailNamePrefix: `${options.nameKebabCase}-guardrail`.slice(\n 0,\n 41,\n ),\n ...terraformProviderVersions(),\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n break;\n }\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","addStarExport","esmVars","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","terraformProviderVersions","addGuardrailInfra","tree","options","templateContext","nameClassName","nameKebabCase","policyPath","iac","appDir","dirname","overwriteStrategy","KeepExisting","guardrailNamePrefix","slice"],"mappings":"AAAA;;;CAGC,GACD,SACEA,aAAa,EACbC,iBAAiB,EACjBC,iBAAiB,QAEZ,aAAa;AACpB,SAASC,aAAa,QAAQ,YAAY;AAE1C,SAASC,OAAO,QAAQ,sBAAsB;AAC9C,SACEC,YAAY,EACZC,qBAAqB,EACrBC,oBAAoB,QACf,oCAAoC;AAC3C,SAASC,yBAAyB,QAAQ,iBAAiB;AAe3D;;;;;;;;;;;CAWC,GACD,OAAO,MAAMC,oBAAoB,OAC/BC,MACAC;IAEA,MAAMC,kBAAkB;QACtBC,eAAeF,QAAQE,aAAa;QACpCC,eAAeH,QAAQG,aAAa;QACpCC,YAAYJ,QAAQI,UAAU;IAChC;IAEA,OAAQJ,QAAQK,GAAG;QACjB,KAAK;YAAO;gBACV,MAAMC,SAAShB,kBACbI,cACAC,uBACA,OACA;gBAEFN,cACEU,MACAT,kBACE,YAAYiB,OAAO,EACnB,SACA,OACA,OACA,eAEFjB,kBAAkBgB,QAAQ,eAC1B;oBAAE,GAAGL,eAAe;oBAAE,GAAGR,QAAQM,KAAK;gBAAC,GACvC;oBAAES,mBAAmBjB,kBAAkBkB,YAAY;gBAAC;gBAEtD,MAAMjB,cACJO,MACAT,kBAAkBgB,QAAQ,cAAc,aACxC,CAAC,EAAE,EAAEN,QAAQG,aAAa,CAAC,CAAC,EAAEH,QAAQG,aAAa,CAAC,aAAa,CAAC;gBAEpE,MAAMX,cACJO,MACAT,kBAAkBgB,QAAQ,aAC1B;gBAEF;YACF;QACA,KAAK;YACHjB,cACEU,MACAT,kBACE,YAAYiB,OAAO,EACnB,SACA,aACA,OACA,eAEFjB,kBACEI,cACAE,sBACA,OACA,OACA,eAEF;gBACE,GAAGK,eAAe;gBAClB,kEAAkE;gBAClE,iDAAiD;gBACjDS,qBAAqB,GAAGV,QAAQG,aAAa,CAAC,UAAU,CAAC,CAACQ,KAAK,CAC7D,GACA;gBAEF,GAAGd,2BAA2B;YAChC,GACA;gBAAEW,mBAAmBjB,kBAAkBkB,YAAY;YAAC;YAEtD;IACJ;AACF,EAAE"}