@aws/nx-plugin 1.0.0-rc.37 → 1.0.0-rc.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/generators.json +7 -0
  2. package/package.json +1 -1
  3. package/src/init/generator.d.ts +18 -0
  4. package/src/init/generator.js +35 -0
  5. package/src/init/generator.js.map +1 -0
  6. package/src/init/schema.d.js +6 -0
  7. package/src/init/schema.d.js.map +1 -0
  8. package/src/init/schema.d.ts +16 -0
  9. package/src/init/schema.json +35 -0
  10. package/src/mcp-server/generator-info.js +27 -13
  11. package/src/mcp-server/generator-info.js.map +1 -1
  12. package/src/mcp-server/guide-pipeline.js +16 -1
  13. package/src/mcp-server/guide-pipeline.js.map +1 -1
  14. package/src/mcp-server/server.js +2 -0
  15. package/src/mcp-server/server.js.map +1 -1
  16. package/src/mcp-server/tools/add-to-existing-project.d.ts +12 -0
  17. package/src/mcp-server/tools/add-to-existing-project.js +36 -0
  18. package/src/mcp-server/tools/add-to-existing-project.js.map +1 -0
  19. package/src/mcp-server/tools/general-guidance.d.ts +1 -1
  20. package/src/mcp-server/tools/general-guidance.js +1 -0
  21. package/src/mcp-server/tools/general-guidance.js.map +1 -1
  22. package/src/preset/__snapshots__/generator.spec.ts.snap +3 -0
  23. package/src/preset/generator.js +19 -129
  24. package/src/preset/generator.js.map +1 -1
  25. package/src/ts/lib/ts-project-utils.js +0 -7
  26. package/src/ts/lib/ts-project-utils.js.map +1 -1
  27. package/src/utils/base-tsconfig.d.ts +30 -0
  28. package/src/utils/base-tsconfig.js +32 -0
  29. package/src/utils/base-tsconfig.js.map +1 -0
  30. package/src/utils/commands.d.ts +9 -2
  31. package/src/utils/commands.js +19 -9
  32. package/src/utils/commands.js.map +1 -1
  33. package/src/utils/init.d.ts +53 -0
  34. package/src/utils/init.js +251 -0
  35. package/src/utils/init.js.map +1 -0
package/generators.json CHANGED
@@ -3,6 +3,13 @@
3
3
  "name": "@aws/nx-plugin",
4
4
  "version": "0.0.1",
5
5
  "generators": {
6
+ "init": {
7
+ "factory": "./src/init/generator",
8
+ "schema": "./src/init/schema.json",
9
+ "description": "Configure an existing Nx workspace to use the @aws/nx-plugin",
10
+ "metric": "g57",
11
+ "guidePages": ["existing-project"]
12
+ },
6
13
  "agentcore-gateway": {
7
14
  "factory": "./src/agentcore-gateway/generator",
8
15
  "schema": "./src/agentcore-gateway/schema.json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws/nx-plugin",
3
- "version": "1.0.0-rc.37",
3
+ "version": "1.0.0-rc.38",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/awslabs/nx-plugin-for-aws.git",
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import type { GeneratorCallback, Tree } from '@nx/devkit';
6
+ import { type NxGeneratorInfo } from '../utils/nx';
7
+ import type { InitGeneratorSchema } from './schema';
8
+ export declare const INIT_GENERATOR_INFO: NxGeneratorInfo;
9
+ /**
10
+ * Configure an existing Nx workspace to use the @aws/nx-plugin.
11
+ *
12
+ * Runs the same deterministic setup the workspace preset performs, so teams
13
+ * with an established Nx workspace can adopt the plugin without recreating
14
+ * their workspace. Every step is idempotent — re-running against an
15
+ * already-initialised workspace is a safe no-op.
16
+ */
17
+ export declare const initGenerator: (tree: Tree, { iac, mcp, containers, preferInstallDependencies }: InitGeneratorSchema) => Promise<GeneratorCallback>;
18
+ export default initGenerator;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { formatFilesInSubtree } from "../utils/format.js";
5
+ import { applyWorkspaceInit } from "../utils/init.js";
6
+ import { installDependencies } from "../utils/install.js";
7
+ import { addGeneratorMetricsIfApplicable } from "../utils/metrics.js";
8
+ import { getGeneratorInfo } from "../utils/nx.js";
9
+ export const INIT_GENERATOR_INFO = getGeneratorInfo(import.meta.filename);
10
+ /**
11
+ * Configure an existing Nx workspace to use the @aws/nx-plugin.
12
+ *
13
+ * Runs the same deterministic setup the workspace preset performs, so teams
14
+ * with an established Nx workspace can adopt the plugin without recreating
15
+ * their workspace. Every step is idempotent — re-running against an
16
+ * already-initialised workspace is a safe no-op.
17
+ */ export const initGenerator = async (tree, { iac, mcp, containers, preferInstallDependencies })=>{
18
+ await applyWorkspaceInit(tree, {
19
+ iac,
20
+ containers,
21
+ mcp
22
+ });
23
+ await addGeneratorMetricsIfApplicable(tree, [
24
+ INIT_GENERATOR_INFO
25
+ ]);
26
+ await formatFilesInSubtree(tree);
27
+ return ()=>installDependencies(tree, preferInstallDependencies, {
28
+ languages: [
29
+ 'typescript'
30
+ ]
31
+ });
32
+ };
33
+ export default initGenerator;
34
+
35
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/init/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { GeneratorCallback, Tree } from '@nx/devkit';\nimport { formatFilesInSubtree } from '../utils/format';\nimport { applyWorkspaceInit } from '../utils/init';\nimport { installDependencies } from '../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../utils/metrics';\nimport { getGeneratorInfo, type NxGeneratorInfo } from '../utils/nx';\nimport type { InitGeneratorSchema } from './schema';\n\nexport const INIT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\n/**\n * Configure an existing Nx workspace to use the @aws/nx-plugin.\n *\n * Runs the same deterministic setup the workspace preset performs, so teams\n * with an established Nx workspace can adopt the plugin without recreating\n * their workspace. Every step is idempotent — re-running against an\n * already-initialised workspace is a safe no-op.\n */\nexport const initGenerator = async (\n tree: Tree,\n { iac, mcp, containers, preferInstallDependencies }: InitGeneratorSchema,\n): Promise<GeneratorCallback> => {\n await applyWorkspaceInit(tree, { iac, containers, mcp });\n\n await addGeneratorMetricsIfApplicable(tree, [INIT_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\nexport default initGenerator;\n"],"names":["formatFilesInSubtree","applyWorkspaceInit","installDependencies","addGeneratorMetricsIfApplicable","getGeneratorInfo","INIT_GENERATOR_INFO","filename","initGenerator","tree","iac","mcp","containers","preferInstallDependencies","languages"],"mappings":"AAAA;;;CAGC,GAED,SAASA,oBAAoB,QAAQ,qBAAkB;AACvD,SAASC,kBAAkB,QAAQ,mBAAgB;AACnD,SAASC,mBAAmB,QAAQ,sBAAmB;AACvD,SAASC,+BAA+B,QAAQ,sBAAmB;AACnE,SAASC,gBAAgB,QAA8B,iBAAc;AAGrE,OAAO,MAAMC,sBAAuCD,iBAClD,YAAYE,QAAQ,EACpB;AAEF;;;;;;;CAOC,GACD,OAAO,MAAMC,gBAAgB,OAC3BC,MACA,EAAEC,GAAG,EAAEC,GAAG,EAAEC,UAAU,EAAEC,yBAAyB,EAAuB;IAExE,MAAMX,mBAAmBO,MAAM;QAAEC;QAAKE;QAAYD;IAAI;IAEtD,MAAMP,gCAAgCK,MAAM;QAACH;KAAoB;IAEjE,MAAML,qBAAqBQ;IAC3B,OAAO,IACLN,oBAAoBM,MAAMI,2BAA2B;YACnDC,WAAW;gBAAC;aAAa;QAC3B;AACJ,EAAE;AAEF,eAAeN,cAAc"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ export { };
5
+
6
+ //# sourceMappingURL=schema.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/init/schema.d.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Containers } from '../utils/containers';\nimport { Iac } from '../utils/iac';\n\nexport type InitContainersOption = Containers | 'infer';\n\nexport interface InitGeneratorSchema {\n readonly iac: Iac;\n readonly mcp?: boolean;\n readonly containers?: InitContainersOption;\n readonly preferInstallDependencies?: boolean;\n}\n"],"names":[],"mappings":"AAAA;;;CAGC,GAOD,WAKC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import { Containers } from '../utils/containers';
7
+ import { Iac } from '../utils/iac';
8
+
9
+ export type InitContainersOption = Containers | 'infer';
10
+
11
+ export interface InitGeneratorSchema {
12
+ readonly iac: Iac;
13
+ readonly mcp?: boolean;
14
+ readonly containers?: InitContainersOption;
15
+ readonly preferInstallDependencies?: boolean;
16
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "init",
4
+ "title": "init",
5
+ "description": "Configure an existing Nx workspace to use the @aws/nx-plugin.",
6
+ "type": "object",
7
+ "properties": {
8
+ "iac": {
9
+ "type": "string",
10
+ "description": "The preferred IaC provider.",
11
+ "enum": ["cdk", "terraform"],
12
+ "default": "cdk",
13
+ "x-priority": "important",
14
+ "x-prompt": "Which provider would you like to manage your infrastructure?"
15
+ },
16
+ "mcp": {
17
+ "type": "boolean",
18
+ "description": "Whether to configure the Nx Plugin for AWS MCP server for use by coding agents.",
19
+ "default": true
20
+ },
21
+ "containers": {
22
+ "type": "string",
23
+ "description": "The container engine to use for build/push/login. 'infer' picks docker if installed, otherwise finch (falling back to docker when neither is installed).",
24
+ "enum": ["infer", "docker", "finch"],
25
+ "default": "infer",
26
+ "x-priority": "important",
27
+ "x-prompt": "Which container engine would you like to use? (default: infer)"
28
+ },
29
+ "preferInstallDependencies": {
30
+ "type": "boolean",
31
+ "description": "Whether to prefer installing dependencies after the generator runs. Set to false to defer installing when batching multiple generators (an install still runs if needed so subsequent generators can compute the Nx project graph); install once at the end.",
32
+ "default": true
33
+ }
34
+ }
35
+ }
@@ -252,27 +252,41 @@ const formatFilterableOptions = (_info, filterable)=>{
252
252
  };
253
253
  };
254
254
  /**
255
- * Probe paths for finding guide MDX files locally. Checked in order:
255
+ * Base directories to probe for guide MDX files, relative to this module.
256
+ * Each is checked in order:
256
257
  * 1. Bundled docs in the published @aws/nx-plugin-mcp package
257
258
  * 2. Source checkout when running from the monorepo (dev/test)
258
259
  * 3. Rolldown-bundled binary in dist/ (monorepo layout)
259
- */ const GUIDES_RELATIVE_PROBES = [
260
- // Bundled docs inside published @aws/nx-plugin-mcp package (bin/ → ../docs/guides)
261
- '../docs/guides',
260
+ */ const GUIDE_BASE_PROBES = [
261
+ // Bundled docs inside published @aws/nx-plugin-mcp package (bin/ → ../docs)
262
+ '../docs',
262
263
  // nx-plugin package compiled from source (src/mcp-server/…)
263
- '../../../docs/src/content/docs/en/guides',
264
+ '../../../docs/src/content/docs/en',
264
265
  // rolldown-bundled `@aws/nx-plugin-mcp` binary in dist (monorepo layout)
265
- '../../../../docs/src/content/docs/en/guides'
266
+ '../../../../docs/src/content/docs/en'
267
+ ];
268
+ /**
269
+ * Content sub-directories that hold pages a generator may reference via
270
+ * `guidePages`. Both the per-generator reference guides (`guides/`) and the
271
+ * getting-started pages (`get_started/`) are fetchable, so a page can live in
272
+ * whichever section reads best for humans while still being served by the MCP
273
+ * tools. Bare `guidePages` names may also include a sub-path (e.g.
274
+ * `connection/react-trpc`).
275
+ */ const GUIDE_SECTIONS = [
276
+ 'guides',
277
+ 'get_started'
266
278
  ];
267
279
  const fetchLocalGuide = (guide)=>{
268
- for (const rel of GUIDES_RELATIVE_PROBES){
269
- const candidate = path.resolve(import.meta.dirname, rel, `${guide}.mdx`);
270
- try {
271
- if (fs.existsSync(candidate)) {
272
- return fs.readFileSync(candidate, 'utf-8');
280
+ for (const base of GUIDE_BASE_PROBES){
281
+ for (const section of GUIDE_SECTIONS){
282
+ const candidate = path.resolve(import.meta.dirname, base, section, `${guide}.mdx`);
283
+ try {
284
+ if (fs.existsSync(candidate)) {
285
+ return fs.readFileSync(candidate, 'utf-8');
286
+ }
287
+ } catch {
288
+ // Probe failure → keep looking.
273
289
  }
274
- } catch {
275
- // Probe failure → keep looking.
276
290
  }
277
291
  }
278
292
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/mcp-server/generator-info.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport type { NxGeneratorInfo } from '../utils/generators';\nimport { kebabCase } from '../utils/names';\nimport { parseMdx, postProcessGuideWithRemark } from './guide-pipeline';\nimport {\n buildNxCommand,\n renderGeneratorCommand,\n renderSchema,\n} from './guide-render';\nimport { collectFilterableKeysFromJsx, extractFrontmatter } from './mdx-ast';\nimport { evaluatePredicate } from './option-filter';\nimport {\n filterableOptionsFromSchema,\n type GeneratorSchema,\n} from './schema-registry';\n\n// Re-export so existing callers of `generator-info` continue working.\nexport { buildNxCommand } from './guide-render';\n\n/**\n * Render summary information about a generator\n */\nexport const renderGeneratorInfo = (\n packageManager: string,\n info: NxGeneratorInfo,\n): string => {\n const schema = JSON.parse(fs.readFileSync(info.resolvedSchemaPath, 'utf-8'));\n\n return `${info.id}\n\nDescription: ${info.description}\n\nAvailable Parameters:\n${renderSchema(schema)}\n\nCommand:\n${renderGeneratorCommand(info.id, schema, packageManager)}\n`;\n};\n\nexport type FilterableOption = import('./schema-registry').FilterableOption;\n\n/**\n * Enum properties from the generator's JSON schema — the options a user\n * could pass on the CLI. Agents use this list to pick `options` values\n * when calling `generator-guide`.\n *\n * Multi-variant generators (e.g. `connection`) layer additional keys on\n * top via each guide page's `when:` frontmatter — merged in by\n * `collectFrontmatterFilterableOptions` / `renderFilterableOptionsAsync`.\n */\nexport const loadFilterableOptionsFromSchema = (\n info: NxGeneratorInfo,\n): FilterableOption[] => {\n try {\n const schema = JSON.parse(\n fs.readFileSync(info.resolvedSchemaPath, 'utf-8'),\n ) as GeneratorSchema;\n return filterableOptionsFromSchema(schema);\n } catch {\n return [];\n }\n};\n\n/**\n * Look at the `when:` frontmatter of every guide page belonging to a\n * generator and add any keys not already surfaced via the JSON schema.\n * This lets the `connection` generator advertise `sourceType` /\n * `targetType` / `protocol` without touching `generators.json`.\n */\nconst collectFrontmatterFilterableOptions = (\n fetched: FetchedGuide[],\n fromSchema: FilterableOption[],\n): FilterableOption[] => {\n const extras = new Map<string, Set<string>>();\n for (const guide of fetched) {\n const when = guide.frontmatter.when;\n if (!when) continue;\n for (const [key, rawValues] of Object.entries(when)) {\n const bucket = extras.get(key) ?? new Set<string>();\n for (const v of rawValues) bucket.add(v);\n extras.set(key, bucket);\n }\n }\n const out: FilterableOption[] = [];\n const seen = new Set(fromSchema.map((o) => o.key));\n for (const [key, values] of extras) {\n if (seen.has(key)) continue;\n out.push({ key, enum: [...values] });\n }\n return out;\n};\n\n/**\n * Decide whether the agent-supplied `options` describe a combination the\n * generator actually supports. Returns undefined when the combination is\n * fine (including when the agent hasn't narrowed enough to decide) and a\n * human-readable explanation otherwise.\n *\n * Supported combinations are inferred from the union of `when:` predicates\n * across a generator's guide pages. A generator with no `when:` predicates\n * on any of its pages (the common case — `ts#trpc-api`, `py#fast-api` …)\n * opts out of the check automatically.\n */\nconst describeUnsupportedCombinationFromFetched = (\n info: NxGeneratorInfo,\n fetched: FetchedGuide[],\n options: Record<string, string> | undefined,\n): string | undefined => {\n if (!options) return undefined;\n\n const predicates = fetched\n .map((g) => g.frontmatter.when)\n .filter((w): w is Record<string, string[]> => w !== undefined);\n if (predicates.length === 0) return undefined;\n\n // Consider only the option keys that actually participate in at least\n // one predicate — other options (e.g. schema enums) are orthogonal.\n const predicateKeys = new Set<string>();\n for (const p of predicates)\n for (const k of Object.keys(p)) predicateKeys.add(k);\n const suppliedPredicateKeys = [...predicateKeys].filter(\n (k) => options[k] !== undefined,\n );\n if (suppliedPredicateKeys.length === 0) return undefined;\n\n // If any predicate is still reachable given the keys the agent has\n // committed to so far, treat this as a partial (valid) selection and\n // skip the warning — the agent can keep narrowing.\n const stillReachable = predicates.some((pred) =>\n suppliedPredicateKeys.every((k) => {\n const values = pred[k];\n if (values === undefined) return true; // predicate doesn't care about this key\n return values.includes(options[k]);\n }),\n );\n if (stillReachable) return undefined;\n\n return renderUnsupportedMessage(info, options, predicates);\n};\n\nconst renderUnsupportedMessage = (\n info: NxGeneratorInfo,\n requested: Record<string, string>,\n predicates: Record<string, string[]>[],\n): string => {\n const requestedDesc = Object.entries(requested)\n .map(([k, v]) => `${k} = ${v}`)\n .join(', ');\n const supportedList = predicates\n .map((pred) => {\n const parts = Object.entries(pred).map(\n ([k, vs]) => `${k} = ${vs.join(' | ')}`,\n );\n return `- ${parts.join(', ')}`;\n })\n .join('\\n');\n return `## ${info.id}\n\n> [!WARNING] Unsupported combination: ${requestedDesc}. The \\`${info.id}\\` generator has no guide variant matching this combination — running it will likely fail.\n\nSupported combinations:\n${supportedList}\n\nPick a combination from the list above, or choose a different generator.`;\n};\n\n/**\n * Render the \"Filterable options\" block that list-generators emits for each\n * generator. Only keys the guide pages actually branch on are included —\n * enum properties the schema exposes but no guide filters on are omitted\n * so agents don't waste tokens setting options that won't affect the\n * returned content.\n *\n * Keys come from two sources:\n * - Schema enums, intersected with keys referenced by\n * `<OptionFilter when>` / `<TabItem _filter>` across the generator's\n * guide pages.\n * - Per-page `when:` frontmatter blocks (multi-variant generators like\n * `connection`).\n */\nexport const renderFilterableOptionsAsync = async (\n info: NxGeneratorInfo,\n): Promise<string> => {\n const fetched = await fetchGuideFrontmatters(info);\n\n const referenced = new Set<string>();\n for (const g of fetched) {\n for (const k of g.referencedKeys) referenced.add(k);\n }\n\n const schemaOptions = loadFilterableOptionsFromSchema(info).filter((o) =>\n referenced.has(o.key),\n );\n const frontmatterOptions = collectFrontmatterFilterableOptions(\n fetched,\n schemaOptions,\n );\n return formatFilterableOptions(info, [\n ...schemaOptions,\n ...frontmatterOptions,\n ]);\n};\n\nconst formatFilterableOptions = (\n _info: NxGeneratorInfo,\n filterable: FilterableOption[],\n): string => {\n if (filterable.length === 0) return '';\n const entries = filterable\n .map((opt) => {\n const def = opt.default ? ` (default: ${opt.default})` : '';\n return `- ${opt.key}: ${opt.enum.join(' | ')}${def}`;\n })\n .join('\\n');\n return `\\`generator-guide\\` options:\\n${entries}`;\n};\n\n/**\n * A guide page after its raw MDX has been fetched and the YAML frontmatter\n * parsed. The body excludes the frontmatter delimiter; the parsed\n * `frontmatter.when` predicate drives guide-level filtering.\n */\ninterface FetchedGuide {\n page: string;\n raw: string;\n body: string;\n frontmatter: {\n when?: Record<string, string[]>;\n title?: string;\n };\n /** Option keys referenced by `<OptionFilter when>` / `<TabItem _filter>` in the body. */\n referencedKeys: Set<string>;\n}\n\n/**\n * Result of `fetchGuidePagesForGenerator`. When the agent's options pick\n * a combination no variant page matches, `kind` is `'unsupported'` and\n * `content` holds an explanatory warning the tool should surface on its\n * own (without wrapping it in the usual `## <id>` summary). Otherwise\n * `content` is the rendered guide text.\n */\nexport type GuideFetchResult =\n | { kind: 'ok'; content: string }\n | { kind: 'unsupported'; content: string };\n\n/**\n * Retrieve the markdown guide pages for a generator.\n *\n * Every page listed in `guidePages` (or the kebab-cased generator id when\n * that field is absent) is fetched in parallel — local files first, GitHub\n * fallback — and its YAML frontmatter is parsed to pick up any `when:`\n * predicate. Pages without a `when:` are always included; pages with a\n * `when:` are included when either:\n * - `options` is absent (agent hasn't narrowed yet — keep every variant),\n * or\n * - the predicate matches `options` using the same semantics as\n * `<OptionFilter when={{…}}>` (AND across keys, OR within a key).\n *\n * If the agent has supplied enough options to identify a combination and\n * no variant page matches, the result is `{ kind: 'unsupported' }` and the\n * caller surfaces the warning directly.\n */\nexport const fetchGuidePagesForGenerator = async (\n info: NxGeneratorInfo,\n generators: NxGeneratorInfo[],\n packageManager?: string,\n snippetContentProvider?: SnippetContentProvider,\n options?: Record<string, string>,\n): Promise<GuideFetchResult> => {\n const fetched = await fetchGuideFrontmatters(info);\n\n const unsupported = describeUnsupportedCombinationFromFetched(\n info,\n fetched,\n options,\n );\n if (unsupported !== undefined) {\n return { kind: 'unsupported', content: unsupported };\n }\n\n const kept = fetched.filter((g) => {\n if (!g.frontmatter.when) return true;\n if (!options) return true;\n return evaluatePredicate(g.frontmatter.when, false, options);\n });\n\n const processed = await Promise.all(\n kept.map((g) =>\n postProcessGuide(\n g.body,\n generators,\n packageManager,\n snippetContentProvider,\n options,\n ),\n ),\n );\n return { kind: 'ok', content: processed.join('\\n\\n') };\n};\n\n/**\n * Fetch every guide page referenced by a generator, in parallel, and\n * return { page, raw, body, frontmatter } for each one. Used by both\n * `fetchGuidePagesForGenerator` (to filter + render) and\n * `renderFilterableOptionsAsync` (to build the filterable-options list\n * from the union of frontmatter `when:` keys).\n */\nexport const fetchGuideFrontmatters = async (\n info: NxGeneratorInfo,\n): Promise<FetchedGuide[]> => {\n const pages: string[] = [...(info.guidePages ?? [kebabCase(info.id)])];\n const results = await Promise.allSettled(\n pages.map(async (page) => ({ page, raw: await fetchGuideRaw(page) })),\n );\n const fulfilled: { page: string; raw: string }[] = [];\n for (const r of results) {\n if (r.status === 'fulfilled' && r.value.raw) fulfilled.push(r.value);\n }\n return Promise.all(\n fulfilled.map(async ({ page, raw }) => {\n const parsed = await parseGuide(raw);\n return { page, raw, ...parsed };\n }),\n );\n};\n\n/**\n * Read a guide's raw MDX from the local filesystem (bundled or monorepo).\n */\nconst fetchGuideRaw = async (page: string): Promise<string> => {\n const local = fetchLocalGuide(page);\n if (local !== undefined) return local;\n return '';\n};\n\n/**\n * Parse a guide's MDX once and return the body, the frontmatter, and the\n * set of option keys its `<OptionFilter>` / `<TabItem _filter>` blocks\n * actually reference. The yaml node's `position.end.offset` gives us the\n * body slice without re-stringifying the tree.\n */\nconst parseGuide = async (\n raw: string,\n): Promise<Omit<FetchedGuide, 'page' | 'raw'>> => {\n const tree = await parseMdx(raw);\n const { data, bodyOffset } = extractFrontmatter(tree);\n const body = raw.slice(bodyOffset).replace(/^\\r?\\n/, '');\n const frontmatter: { when?: Record<string, string[]>; title?: string } = {};\n if (typeof data.title === 'string') frontmatter.title = data.title;\n if (data.when && typeof data.when === 'object' && !Array.isArray(data.when)) {\n const when: Record<string, string[]> = {};\n for (const [key, value] of Object.entries(\n data.when as Record<string, unknown>,\n )) {\n when[key] = Array.isArray(value) ? value.map(String) : [String(value)];\n }\n frontmatter.when = when;\n }\n return {\n body,\n frontmatter,\n referencedKeys: collectFilterableKeysFromJsx(tree),\n };\n};\n\n/**\n * Probe paths for finding guide MDX files locally. Checked in order:\n * 1. Bundled docs in the published @aws/nx-plugin-mcp package\n * 2. Source checkout when running from the monorepo (dev/test)\n * 3. Rolldown-bundled binary in dist/ (monorepo layout)\n */\nconst GUIDES_RELATIVE_PROBES = [\n // Bundled docs inside published @aws/nx-plugin-mcp package (bin/ → ../docs/guides)\n '../docs/guides',\n // nx-plugin package compiled from source (src/mcp-server/…)\n '../../../docs/src/content/docs/en/guides',\n // rolldown-bundled `@aws/nx-plugin-mcp` binary in dist (monorepo layout)\n '../../../../docs/src/content/docs/en/guides',\n];\n\nconst fetchLocalGuide = (guide: string): string | undefined => {\n for (const rel of GUIDES_RELATIVE_PROBES) {\n const candidate = path.resolve(import.meta.dirname, rel, `${guide}.mdx`);\n try {\n if (fs.existsSync(candidate)) {\n return fs.readFileSync(candidate, 'utf-8');\n }\n } catch {\n // Probe failure → keep looking.\n }\n }\n return undefined;\n};\n\n/**\n * Fetch markdown guide pages from the local filesystem (bundled or monorepo).\n */\nexport const fetchGuidePages = async (\n guidePages: string[],\n generators: NxGeneratorInfo[],\n packageManager?: string,\n snippetContentProvider?: SnippetContentProvider,\n options?: Record<string, string>,\n): Promise<string> => {\n const guides = guidePages\n .map((guide) => fetchLocalGuide(guide))\n .filter((content): content is string => content !== undefined);\n const processed = await Promise.all(\n guides.map((content) =>\n postProcessGuide(\n content,\n generators,\n packageManager,\n snippetContentProvider,\n options,\n ),\n ),\n );\n return processed.join('\\n\\n');\n};\n\n/**\n * A function which retrieves snippet content given a snippet name.\n */\nexport type SnippetContentProvider = (\n snippetName: string,\n) => Promise<string> | string;\n\nconst SNIPPETS_RELATIVE_PROBES = [\n // Bundled docs inside published @aws/nx-plugin-mcp package (bin/ → ../docs/snippets)\n '../docs/snippets',\n '../../../docs/src/content/docs/en/snippets',\n '../../../../docs/src/content/docs/en/snippets',\n];\n\n/**\n * Fetch a snippet's content from the local filesystem (bundled or monorepo).\n */\nexport const fetchSnippet: SnippetContentProvider = async (\n snippetName: string,\n): Promise<string> => {\n for (const rel of SNIPPETS_RELATIVE_PROBES) {\n const candidate = path.resolve(\n import.meta.dirname,\n rel,\n `${snippetName}.mdx`,\n );\n try {\n if (fs.existsSync(candidate)) {\n return fs.readFileSync(candidate, 'utf-8');\n }\n } catch {\n // Probe failure — try next path.\n }\n }\n return '';\n};\n\n/**\n * Post-process a guide page. Thin wrapper around the unified/remark-mdx\n * pipeline in `guide-pipeline.ts` — the real work (snippet inlining,\n * OptionFilter/Infrastructure/TabItem filtering, command/schema rendering)\n * happens there. Kept under the same name so other packages\n * (e.g. the docs site's `markdown-content.astro`) can continue importing\n * `postProcessGuide` with the same signature.\n */\nexport const postProcessGuide = async (\n guide: string,\n generators: NxGeneratorInfo[],\n packageManager?: string,\n snippetContentProvider?: SnippetContentProvider,\n options?: Record<string, string>,\n): Promise<string> => {\n return postProcessGuideWithRemark(guide, {\n generators,\n packageManager,\n snippetContentProvider: snippetContentProvider ?? fetchSnippet,\n options,\n });\n};\n"],"names":["fs","path","kebabCase","parseMdx","postProcessGuideWithRemark","renderGeneratorCommand","renderSchema","collectFilterableKeysFromJsx","extractFrontmatter","evaluatePredicate","filterableOptionsFromSchema","buildNxCommand","renderGeneratorInfo","packageManager","info","schema","JSON","parse","readFileSync","resolvedSchemaPath","id","description","loadFilterableOptionsFromSchema","collectFrontmatterFilterableOptions","fetched","fromSchema","extras","Map","guide","when","frontmatter","key","rawValues","Object","entries","bucket","get","Set","v","add","set","out","seen","map","o","values","has","push","enum","describeUnsupportedCombinationFromFetched","options","undefined","predicates","g","filter","w","length","predicateKeys","p","k","keys","suppliedPredicateKeys","stillReachable","some","pred","every","includes","renderUnsupportedMessage","requested","requestedDesc","join","supportedList","parts","vs","renderFilterableOptionsAsync","fetchGuideFrontmatters","referenced","referencedKeys","schemaOptions","frontmatterOptions","formatFilterableOptions","_info","filterable","opt","def","default","fetchGuidePagesForGenerator","generators","snippetContentProvider","unsupported","kind","content","kept","processed","Promise","all","postProcessGuide","body","pages","guidePages","results","allSettled","page","raw","fetchGuideRaw","fulfilled","r","status","value","parsed","parseGuide","local","fetchLocalGuide","tree","data","bodyOffset","slice","replace","title","Array","isArray","String","GUIDES_RELATIVE_PROBES","rel","candidate","resolve","dirname","existsSync","fetchGuidePages","guides","SNIPPETS_RELATIVE_PROBES","fetchSnippet","snippetName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/mcp-server/generator-info.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport type { NxGeneratorInfo } from '../utils/generators';\nimport { kebabCase } from '../utils/names';\nimport { parseMdx, postProcessGuideWithRemark } from './guide-pipeline';\nimport {\n buildNxCommand,\n renderGeneratorCommand,\n renderSchema,\n} from './guide-render';\nimport { collectFilterableKeysFromJsx, extractFrontmatter } from './mdx-ast';\nimport { evaluatePredicate } from './option-filter';\nimport {\n filterableOptionsFromSchema,\n type GeneratorSchema,\n} from './schema-registry';\n\n// Re-export so existing callers of `generator-info` continue working.\nexport { buildNxCommand } from './guide-render';\n\n/**\n * Render summary information about a generator\n */\nexport const renderGeneratorInfo = (\n packageManager: string,\n info: NxGeneratorInfo,\n): string => {\n const schema = JSON.parse(fs.readFileSync(info.resolvedSchemaPath, 'utf-8'));\n\n return `${info.id}\n\nDescription: ${info.description}\n\nAvailable Parameters:\n${renderSchema(schema)}\n\nCommand:\n${renderGeneratorCommand(info.id, schema, packageManager)}\n`;\n};\n\nexport type FilterableOption = import('./schema-registry').FilterableOption;\n\n/**\n * Enum properties from the generator's JSON schema — the options a user\n * could pass on the CLI. Agents use this list to pick `options` values\n * when calling `generator-guide`.\n *\n * Multi-variant generators (e.g. `connection`) layer additional keys on\n * top via each guide page's `when:` frontmatter — merged in by\n * `collectFrontmatterFilterableOptions` / `renderFilterableOptionsAsync`.\n */\nexport const loadFilterableOptionsFromSchema = (\n info: NxGeneratorInfo,\n): FilterableOption[] => {\n try {\n const schema = JSON.parse(\n fs.readFileSync(info.resolvedSchemaPath, 'utf-8'),\n ) as GeneratorSchema;\n return filterableOptionsFromSchema(schema);\n } catch {\n return [];\n }\n};\n\n/**\n * Look at the `when:` frontmatter of every guide page belonging to a\n * generator and add any keys not already surfaced via the JSON schema.\n * This lets the `connection` generator advertise `sourceType` /\n * `targetType` / `protocol` without touching `generators.json`.\n */\nconst collectFrontmatterFilterableOptions = (\n fetched: FetchedGuide[],\n fromSchema: FilterableOption[],\n): FilterableOption[] => {\n const extras = new Map<string, Set<string>>();\n for (const guide of fetched) {\n const when = guide.frontmatter.when;\n if (!when) continue;\n for (const [key, rawValues] of Object.entries(when)) {\n const bucket = extras.get(key) ?? new Set<string>();\n for (const v of rawValues) bucket.add(v);\n extras.set(key, bucket);\n }\n }\n const out: FilterableOption[] = [];\n const seen = new Set(fromSchema.map((o) => o.key));\n for (const [key, values] of extras) {\n if (seen.has(key)) continue;\n out.push({ key, enum: [...values] });\n }\n return out;\n};\n\n/**\n * Decide whether the agent-supplied `options` describe a combination the\n * generator actually supports. Returns undefined when the combination is\n * fine (including when the agent hasn't narrowed enough to decide) and a\n * human-readable explanation otherwise.\n *\n * Supported combinations are inferred from the union of `when:` predicates\n * across a generator's guide pages. A generator with no `when:` predicates\n * on any of its pages (the common case — `ts#trpc-api`, `py#fast-api` …)\n * opts out of the check automatically.\n */\nconst describeUnsupportedCombinationFromFetched = (\n info: NxGeneratorInfo,\n fetched: FetchedGuide[],\n options: Record<string, string> | undefined,\n): string | undefined => {\n if (!options) return undefined;\n\n const predicates = fetched\n .map((g) => g.frontmatter.when)\n .filter((w): w is Record<string, string[]> => w !== undefined);\n if (predicates.length === 0) return undefined;\n\n // Consider only the option keys that actually participate in at least\n // one predicate — other options (e.g. schema enums) are orthogonal.\n const predicateKeys = new Set<string>();\n for (const p of predicates)\n for (const k of Object.keys(p)) predicateKeys.add(k);\n const suppliedPredicateKeys = [...predicateKeys].filter(\n (k) => options[k] !== undefined,\n );\n if (suppliedPredicateKeys.length === 0) return undefined;\n\n // If any predicate is still reachable given the keys the agent has\n // committed to so far, treat this as a partial (valid) selection and\n // skip the warning — the agent can keep narrowing.\n const stillReachable = predicates.some((pred) =>\n suppliedPredicateKeys.every((k) => {\n const values = pred[k];\n if (values === undefined) return true; // predicate doesn't care about this key\n return values.includes(options[k]);\n }),\n );\n if (stillReachable) return undefined;\n\n return renderUnsupportedMessage(info, options, predicates);\n};\n\nconst renderUnsupportedMessage = (\n info: NxGeneratorInfo,\n requested: Record<string, string>,\n predicates: Record<string, string[]>[],\n): string => {\n const requestedDesc = Object.entries(requested)\n .map(([k, v]) => `${k} = ${v}`)\n .join(', ');\n const supportedList = predicates\n .map((pred) => {\n const parts = Object.entries(pred).map(\n ([k, vs]) => `${k} = ${vs.join(' | ')}`,\n );\n return `- ${parts.join(', ')}`;\n })\n .join('\\n');\n return `## ${info.id}\n\n> [!WARNING] Unsupported combination: ${requestedDesc}. The \\`${info.id}\\` generator has no guide variant matching this combination — running it will likely fail.\n\nSupported combinations:\n${supportedList}\n\nPick a combination from the list above, or choose a different generator.`;\n};\n\n/**\n * Render the \"Filterable options\" block that list-generators emits for each\n * generator. Only keys the guide pages actually branch on are included —\n * enum properties the schema exposes but no guide filters on are omitted\n * so agents don't waste tokens setting options that won't affect the\n * returned content.\n *\n * Keys come from two sources:\n * - Schema enums, intersected with keys referenced by\n * `<OptionFilter when>` / `<TabItem _filter>` across the generator's\n * guide pages.\n * - Per-page `when:` frontmatter blocks (multi-variant generators like\n * `connection`).\n */\nexport const renderFilterableOptionsAsync = async (\n info: NxGeneratorInfo,\n): Promise<string> => {\n const fetched = await fetchGuideFrontmatters(info);\n\n const referenced = new Set<string>();\n for (const g of fetched) {\n for (const k of g.referencedKeys) referenced.add(k);\n }\n\n const schemaOptions = loadFilterableOptionsFromSchema(info).filter((o) =>\n referenced.has(o.key),\n );\n const frontmatterOptions = collectFrontmatterFilterableOptions(\n fetched,\n schemaOptions,\n );\n return formatFilterableOptions(info, [\n ...schemaOptions,\n ...frontmatterOptions,\n ]);\n};\n\nconst formatFilterableOptions = (\n _info: NxGeneratorInfo,\n filterable: FilterableOption[],\n): string => {\n if (filterable.length === 0) return '';\n const entries = filterable\n .map((opt) => {\n const def = opt.default ? ` (default: ${opt.default})` : '';\n return `- ${opt.key}: ${opt.enum.join(' | ')}${def}`;\n })\n .join('\\n');\n return `\\`generator-guide\\` options:\\n${entries}`;\n};\n\n/**\n * A guide page after its raw MDX has been fetched and the YAML frontmatter\n * parsed. The body excludes the frontmatter delimiter; the parsed\n * `frontmatter.when` predicate drives guide-level filtering.\n */\ninterface FetchedGuide {\n page: string;\n raw: string;\n body: string;\n frontmatter: {\n when?: Record<string, string[]>;\n title?: string;\n };\n /** Option keys referenced by `<OptionFilter when>` / `<TabItem _filter>` in the body. */\n referencedKeys: Set<string>;\n}\n\n/**\n * Result of `fetchGuidePagesForGenerator`. When the agent's options pick\n * a combination no variant page matches, `kind` is `'unsupported'` and\n * `content` holds an explanatory warning the tool should surface on its\n * own (without wrapping it in the usual `## <id>` summary). Otherwise\n * `content` is the rendered guide text.\n */\nexport type GuideFetchResult =\n | { kind: 'ok'; content: string }\n | { kind: 'unsupported'; content: string };\n\n/**\n * Retrieve the markdown guide pages for a generator.\n *\n * Every page listed in `guidePages` (or the kebab-cased generator id when\n * that field is absent) is fetched in parallel — local files first, GitHub\n * fallback — and its YAML frontmatter is parsed to pick up any `when:`\n * predicate. Pages without a `when:` are always included; pages with a\n * `when:` are included when either:\n * - `options` is absent (agent hasn't narrowed yet — keep every variant),\n * or\n * - the predicate matches `options` using the same semantics as\n * `<OptionFilter when={{…}}>` (AND across keys, OR within a key).\n *\n * If the agent has supplied enough options to identify a combination and\n * no variant page matches, the result is `{ kind: 'unsupported' }` and the\n * caller surfaces the warning directly.\n */\nexport const fetchGuidePagesForGenerator = async (\n info: NxGeneratorInfo,\n generators: NxGeneratorInfo[],\n packageManager?: string,\n snippetContentProvider?: SnippetContentProvider,\n options?: Record<string, string>,\n): Promise<GuideFetchResult> => {\n const fetched = await fetchGuideFrontmatters(info);\n\n const unsupported = describeUnsupportedCombinationFromFetched(\n info,\n fetched,\n options,\n );\n if (unsupported !== undefined) {\n return { kind: 'unsupported', content: unsupported };\n }\n\n const kept = fetched.filter((g) => {\n if (!g.frontmatter.when) return true;\n if (!options) return true;\n return evaluatePredicate(g.frontmatter.when, false, options);\n });\n\n const processed = await Promise.all(\n kept.map((g) =>\n postProcessGuide(\n g.body,\n generators,\n packageManager,\n snippetContentProvider,\n options,\n ),\n ),\n );\n return { kind: 'ok', content: processed.join('\\n\\n') };\n};\n\n/**\n * Fetch every guide page referenced by a generator, in parallel, and\n * return { page, raw, body, frontmatter } for each one. Used by both\n * `fetchGuidePagesForGenerator` (to filter + render) and\n * `renderFilterableOptionsAsync` (to build the filterable-options list\n * from the union of frontmatter `when:` keys).\n */\nexport const fetchGuideFrontmatters = async (\n info: NxGeneratorInfo,\n): Promise<FetchedGuide[]> => {\n const pages: string[] = [...(info.guidePages ?? [kebabCase(info.id)])];\n const results = await Promise.allSettled(\n pages.map(async (page) => ({ page, raw: await fetchGuideRaw(page) })),\n );\n const fulfilled: { page: string; raw: string }[] = [];\n for (const r of results) {\n if (r.status === 'fulfilled' && r.value.raw) fulfilled.push(r.value);\n }\n return Promise.all(\n fulfilled.map(async ({ page, raw }) => {\n const parsed = await parseGuide(raw);\n return { page, raw, ...parsed };\n }),\n );\n};\n\n/**\n * Read a guide's raw MDX from the local filesystem (bundled or monorepo).\n */\nconst fetchGuideRaw = async (page: string): Promise<string> => {\n const local = fetchLocalGuide(page);\n if (local !== undefined) return local;\n return '';\n};\n\n/**\n * Parse a guide's MDX once and return the body, the frontmatter, and the\n * set of option keys its `<OptionFilter>` / `<TabItem _filter>` blocks\n * actually reference. The yaml node's `position.end.offset` gives us the\n * body slice without re-stringifying the tree.\n */\nconst parseGuide = async (\n raw: string,\n): Promise<Omit<FetchedGuide, 'page' | 'raw'>> => {\n const tree = await parseMdx(raw);\n const { data, bodyOffset } = extractFrontmatter(tree);\n const body = raw.slice(bodyOffset).replace(/^\\r?\\n/, '');\n const frontmatter: { when?: Record<string, string[]>; title?: string } = {};\n if (typeof data.title === 'string') frontmatter.title = data.title;\n if (data.when && typeof data.when === 'object' && !Array.isArray(data.when)) {\n const when: Record<string, string[]> = {};\n for (const [key, value] of Object.entries(\n data.when as Record<string, unknown>,\n )) {\n when[key] = Array.isArray(value) ? value.map(String) : [String(value)];\n }\n frontmatter.when = when;\n }\n return {\n body,\n frontmatter,\n referencedKeys: collectFilterableKeysFromJsx(tree),\n };\n};\n\n/**\n * Base directories to probe for guide MDX files, relative to this module.\n * Each is checked in order:\n * 1. Bundled docs in the published @aws/nx-plugin-mcp package\n * 2. Source checkout when running from the monorepo (dev/test)\n * 3. Rolldown-bundled binary in dist/ (monorepo layout)\n */\nconst GUIDE_BASE_PROBES = [\n // Bundled docs inside published @aws/nx-plugin-mcp package (bin/ → ../docs)\n '../docs',\n // nx-plugin package compiled from source (src/mcp-server/…)\n '../../../docs/src/content/docs/en',\n // rolldown-bundled `@aws/nx-plugin-mcp` binary in dist (monorepo layout)\n '../../../../docs/src/content/docs/en',\n];\n\n/**\n * Content sub-directories that hold pages a generator may reference via\n * `guidePages`. Both the per-generator reference guides (`guides/`) and the\n * getting-started pages (`get_started/`) are fetchable, so a page can live in\n * whichever section reads best for humans while still being served by the MCP\n * tools. Bare `guidePages` names may also include a sub-path (e.g.\n * `connection/react-trpc`).\n */\nconst GUIDE_SECTIONS = ['guides', 'get_started'];\n\nconst fetchLocalGuide = (guide: string): string | undefined => {\n for (const base of GUIDE_BASE_PROBES) {\n for (const section of GUIDE_SECTIONS) {\n const candidate = path.resolve(\n import.meta.dirname,\n base,\n section,\n `${guide}.mdx`,\n );\n try {\n if (fs.existsSync(candidate)) {\n return fs.readFileSync(candidate, 'utf-8');\n }\n } catch {\n // Probe failure → keep looking.\n }\n }\n }\n return undefined;\n};\n\n/**\n * Fetch markdown guide pages from the local filesystem (bundled or monorepo).\n */\nexport const fetchGuidePages = async (\n guidePages: string[],\n generators: NxGeneratorInfo[],\n packageManager?: string,\n snippetContentProvider?: SnippetContentProvider,\n options?: Record<string, string>,\n): Promise<string> => {\n const guides = guidePages\n .map((guide) => fetchLocalGuide(guide))\n .filter((content): content is string => content !== undefined);\n const processed = await Promise.all(\n guides.map((content) =>\n postProcessGuide(\n content,\n generators,\n packageManager,\n snippetContentProvider,\n options,\n ),\n ),\n );\n return processed.join('\\n\\n');\n};\n\n/**\n * A function which retrieves snippet content given a snippet name.\n */\nexport type SnippetContentProvider = (\n snippetName: string,\n) => Promise<string> | string;\n\nconst SNIPPETS_RELATIVE_PROBES = [\n // Bundled docs inside published @aws/nx-plugin-mcp package (bin/ → ../docs/snippets)\n '../docs/snippets',\n '../../../docs/src/content/docs/en/snippets',\n '../../../../docs/src/content/docs/en/snippets',\n];\n\n/**\n * Fetch a snippet's content from the local filesystem (bundled or monorepo).\n */\nexport const fetchSnippet: SnippetContentProvider = async (\n snippetName: string,\n): Promise<string> => {\n for (const rel of SNIPPETS_RELATIVE_PROBES) {\n const candidate = path.resolve(\n import.meta.dirname,\n rel,\n `${snippetName}.mdx`,\n );\n try {\n if (fs.existsSync(candidate)) {\n return fs.readFileSync(candidate, 'utf-8');\n }\n } catch {\n // Probe failure — try next path.\n }\n }\n return '';\n};\n\n/**\n * Post-process a guide page. Thin wrapper around the unified/remark-mdx\n * pipeline in `guide-pipeline.ts` — the real work (snippet inlining,\n * OptionFilter/Infrastructure/TabItem filtering, command/schema rendering)\n * happens there. Kept under the same name so other packages\n * (e.g. the docs site's `markdown-content.astro`) can continue importing\n * `postProcessGuide` with the same signature.\n */\nexport const postProcessGuide = async (\n guide: string,\n generators: NxGeneratorInfo[],\n packageManager?: string,\n snippetContentProvider?: SnippetContentProvider,\n options?: Record<string, string>,\n): Promise<string> => {\n return postProcessGuideWithRemark(guide, {\n generators,\n packageManager,\n snippetContentProvider: snippetContentProvider ?? fetchSnippet,\n options,\n });\n};\n"],"names":["fs","path","kebabCase","parseMdx","postProcessGuideWithRemark","renderGeneratorCommand","renderSchema","collectFilterableKeysFromJsx","extractFrontmatter","evaluatePredicate","filterableOptionsFromSchema","buildNxCommand","renderGeneratorInfo","packageManager","info","schema","JSON","parse","readFileSync","resolvedSchemaPath","id","description","loadFilterableOptionsFromSchema","collectFrontmatterFilterableOptions","fetched","fromSchema","extras","Map","guide","when","frontmatter","key","rawValues","Object","entries","bucket","get","Set","v","add","set","out","seen","map","o","values","has","push","enum","describeUnsupportedCombinationFromFetched","options","undefined","predicates","g","filter","w","length","predicateKeys","p","k","keys","suppliedPredicateKeys","stillReachable","some","pred","every","includes","renderUnsupportedMessage","requested","requestedDesc","join","supportedList","parts","vs","renderFilterableOptionsAsync","fetchGuideFrontmatters","referenced","referencedKeys","schemaOptions","frontmatterOptions","formatFilterableOptions","_info","filterable","opt","def","default","fetchGuidePagesForGenerator","generators","snippetContentProvider","unsupported","kind","content","kept","processed","Promise","all","postProcessGuide","body","pages","guidePages","results","allSettled","page","raw","fetchGuideRaw","fulfilled","r","status","value","parsed","parseGuide","local","fetchLocalGuide","tree","data","bodyOffset","slice","replace","title","Array","isArray","String","GUIDE_BASE_PROBES","GUIDE_SECTIONS","base","section","candidate","resolve","dirname","existsSync","fetchGuidePages","guides","SNIPPETS_RELATIVE_PROBES","fetchSnippet","snippetName","rel"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */ import fs from "fs";
5
- import { buildCreateNxWorkspaceCommand, buildInstallCommand, buildPackageManagerExecCommand, buildPackageManagerShortCommand } from "../utils/commands.js";
5
+ import { buildCreateNxWorkspaceCommand, buildInstallCommand, buildNxInitCommand, buildPackageManagerExecCommand, buildPackageManagerShortCommand } from "../utils/commands.js";
6
6
  import { buildNxCommand, renderGeneratorCommand, renderSchema } from "./guide-render.js";
7
7
  import { hasBareAttr, isJsxElement, readEstreeAttr, readExpressionAttr, readStringAttr } from "./mdx-ast.js";
8
8
  import { describePredicate, evaluatePredicate, extractStringArrayExpression, parseWhenExpression } from "./option-filter.js";
@@ -30,12 +30,21 @@ const stringifyMdx = (tree, deps)=>String(deps.unified().use(deps.remarkFrontmat
30
30
  fences: true,
31
31
  listItemIndent: 'one'
32
32
  }).stringify(tree));
33
+ /**
34
+ * Remove nodes that are meaningless once the MDX is rendered to plain markdown
35
+ * for an agent: the YAML frontmatter block and the `import`/`export` (ESM)
36
+ * statements at the top of every docs page. They add noise and tokens without
37
+ * conveying guidance.
38
+ */ const stripFrontmatterAndEsm = (tree)=>{
39
+ tree.children = tree.children.filter((node)=>node.type !== 'yaml' && node.type !== 'mdxjsEsm');
40
+ };
33
41
  export const postProcessGuideWithRemark = async (guide, opts)=>{
34
42
  const deps = await loadRemarkDeps();
35
43
  const tree = parseMdxWithDeps(guide, deps);
36
44
  await inlineSnippets(tree, opts, deps);
37
45
  applyFilterTransforms(tree, opts.options);
38
46
  applyComponentTransforms(tree, opts, deps);
47
+ stripFrontmatterAndEsm(tree);
39
48
  return stringifyMdx(tree, deps);
40
49
  };
41
50
  const inlineSnippets = async (tree, opts, deps)=>{
@@ -309,6 +318,12 @@ const renderComponent = (node, opts, pm, deps)=>{
309
318
  codeBlock(buildCreateNxWorkspaceCommand(pm, workspace, iac))
310
319
  ];
311
320
  }
321
+ case 'NxInitCommand':
322
+ {
323
+ return [
324
+ codeBlock(buildNxInitCommand(pm))
325
+ ];
326
+ }
312
327
  case 'InstallCommand':
313
328
  {
314
329
  const pkg = readStringAttr(node, 'pkg') ?? readExpressionAttr(node, 'pkg');
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/mcp-server/guide-pipeline.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'fs';\n/**\n * Unified + remark-mdx pipeline for the MCP `generator-guide` tool.\n *\n * Passes (in order, each over the already-transformed tree):\n * 1. Snippet inlining — `<Snippet name>` → recursive post-process.\n * 2. Filter transforms — `<OptionFilter>`, `<Infrastructure>` slot\n * selection, `<Tabs><TabItem _filter>` pruning.\n * 3. Component transforms — `<NxCommands>` / `<RunGenerator>` /\n * `<GeneratorParameters>` / `<CreateNxWorkspaceCommand>` /\n * `<InstallCommand>` / `<PackageManagerShortCommand>` /\n * `<PackageManagerExecCommand>` render down to markdown.\n */\nimport type { Root, RootContent } from 'mdast';\nimport type { MdxJsxFlowElement } from 'mdast-util-mdx-jsx';\nimport {\n buildCreateNxWorkspaceCommand,\n buildInstallCommand,\n buildPackageManagerExecCommand,\n buildPackageManagerShortCommand,\n} from '../utils/commands';\nimport type { NxGeneratorInfo } from '../utils/generators';\nimport {\n buildNxCommand,\n renderGeneratorCommand,\n renderSchema,\n} from './guide-render';\nimport {\n hasBareAttr,\n isJsxElement,\n type JsxElement,\n type JsxParent,\n readEstreeAttr,\n readExpressionAttr,\n readStringAttr,\n} from './mdx-ast';\nimport {\n describePredicate,\n evaluatePredicate,\n extractStringArrayExpression,\n type Predicate,\n parseWhenExpression,\n} from './option-filter';\n\nexport interface PipelineOptions {\n generators: NxGeneratorInfo[];\n packageManager?: string;\n snippetContentProvider?: (name: string) => Promise<string> | string;\n options?: Record<string, string>;\n}\n\n// unified v11 is ESM-only and this package is CJS; dynamic import + rolldown's\n// inlineDynamicImports bundles everything into the published MCP binary.\ninterface RemarkDeps {\n unified: typeof import('unified').unified;\n remarkParse: typeof import('remark-parse').default;\n remarkMdx: typeof import('remark-mdx').default;\n remarkStringify: typeof import('remark-stringify').default;\n remarkFrontmatter: typeof import('remark-frontmatter').default;\n}\n\nlet depsPromise: Promise<RemarkDeps> | undefined;\nconst loadRemarkDeps = (): Promise<RemarkDeps> => {\n if (!depsPromise) {\n depsPromise = (async () => ({\n unified: (await import('unified')).unified,\n remarkParse: (await import('remark-parse')).default,\n remarkMdx: (await import('remark-mdx')).default,\n remarkStringify: (await import('remark-stringify')).default,\n remarkFrontmatter: (await import('remark-frontmatter')).default,\n }))();\n }\n return depsPromise;\n};\n\nconst parseMdxWithDeps = (source: string, deps: RemarkDeps): Root =>\n deps\n .unified()\n .use(deps.remarkParse)\n .use(deps.remarkFrontmatter)\n .use(deps.remarkMdx)\n .parse(source) as Root;\n\n/** Parse MDX (with frontmatter) into mdast. Exposed so callers like\n * `fetchGuideFrontmatters` don't need to re-load remark themselves. */\nexport const parseMdx = async (source: string): Promise<Root> => {\n const deps = await loadRemarkDeps();\n return parseMdxWithDeps(source, deps);\n};\n\nconst stringifyMdx = (tree: Root, deps: RemarkDeps): string =>\n String(\n deps\n .unified()\n .use(deps.remarkFrontmatter)\n .use(deps.remarkMdx)\n .use(deps.remarkStringify, {\n bullet: '-',\n fences: true,\n listItemIndent: 'one',\n })\n .stringify(tree),\n );\n\nexport const postProcessGuideWithRemark = async (\n guide: string,\n opts: PipelineOptions,\n): Promise<string> => {\n const deps = await loadRemarkDeps();\n const tree = parseMdxWithDeps(guide, deps);\n\n await inlineSnippets(tree, opts, deps);\n applyFilterTransforms(tree, opts.options);\n applyComponentTransforms(tree, opts, deps);\n\n return stringifyMdx(tree, deps);\n};\n\nconst inlineSnippets = async (\n tree: Root,\n opts: PipelineOptions,\n deps: RemarkDeps,\n): Promise<void> => {\n const provider = opts.snippetContentProvider;\n if (!provider) return;\n\n interface PendingSnippet {\n parent: JsxParent;\n index: number;\n name: string;\n node: JsxElement;\n }\n\n const pending: PendingSnippet[] = [];\n const walk = (parent: JsxParent): void => {\n const children = parent.children as RootContent[];\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!isJsxElement(child)) continue;\n if (child.name === 'Snippet') {\n const name = readStringAttr(child, 'name');\n if (name) pending.push({ parent, index: i, name, node: child });\n continue;\n }\n walk(child);\n }\n };\n walk(tree);\n if (pending.length === 0) return;\n\n const fetched = await Promise.all(\n pending.map(async (p) => {\n let raw = '';\n try {\n raw = await provider(p.name);\n } catch {\n raw = '';\n }\n if (!raw) return { ...p, replacement: undefined };\n const processed = await postProcessGuideWithRemark(raw.trim(), opts);\n return { ...p, replacement: processed };\n }),\n );\n\n // Splice in descending index order per parent so earlier indices stay valid.\n const byParent = new Map<JsxParent, (typeof fetched)[number][]>();\n for (const f of fetched) {\n const bucket = byParent.get(f.parent) ?? [];\n bucket.push(f);\n byParent.set(f.parent, bucket);\n }\n for (const [parent, items] of byParent) {\n items.sort((a, b) => b.index - a.index);\n for (const { index, name, replacement, node } of items) {\n if (replacement === undefined) continue;\n const snippetTree = parseMdxWithDeps(replacement, deps);\n const wrapper: MdxJsxFlowElement = {\n type: 'mdxJsxFlowElement',\n name: 'Snippet',\n attributes: [{ type: 'mdxJsxAttribute', name: 'name', value: name }],\n children: snippetTree.children as MdxJsxFlowElement['children'],\n };\n if ('position' in node && node.position) {\n (wrapper as { position?: unknown }).position = node.position;\n }\n (parent.children as RootContent[]).splice(\n index,\n 1,\n wrapper as RootContent,\n );\n }\n }\n};\n\nconst applyFilterTransforms = (\n tree: Root,\n options: Record<string, string> | undefined,\n): void => {\n const iac = options?.iac;\n\n const transform = (parent: JsxParent): void => {\n const children = parent.children as RootContent[];\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!isJsxElement(child)) continue;\n\n if (child.name === 'OptionFilter') {\n const when = parseWhenAttr(child);\n if (!when) continue; // malformed — leave alone\n // Recurse first so nested filters collapse before we replace this wrapper.\n transform(child);\n const not = hasBareAttr(child, 'not');\n if (options) {\n const replacement = evaluatePredicate(when, not, options)\n ? (child.children as RootContent[])\n : [];\n children.splice(i, 1, ...replacement);\n i += replacement.length - 1;\n } else {\n children.splice(i, 1, buildNoteQuote(child, when, not));\n }\n continue;\n }\n\n if (child.name === 'Infrastructure') {\n if (iac === 'cdk' || iac === 'terraform') {\n const body = selectInfrastructureSlot(child, iac);\n const pseudo: MdxJsxFlowElement = {\n type: 'mdxJsxFlowElement',\n name: 'tmp',\n attributes: [],\n children: body as MdxJsxFlowElement['children'],\n };\n transform(pseudo);\n children.splice(i, 1, ...(pseudo.children as RootContent[]));\n i--;\n continue;\n }\n // No iac → keep both slots so readers / agents see both variants.\n transform(child);\n continue;\n }\n\n if (child.name === 'Tabs' && child.type === 'mdxJsxFlowElement') {\n transform(child);\n const dropped = applyTabsFilter(child, options);\n if (dropped === 'empty') {\n children.splice(i, 1);\n i--;\n continue;\n }\n if (dropped === 'inline') {\n const survivor = (child.children as RootContent[]).find(\n (c): c is MdxJsxFlowElement =>\n isJsxElement(c) && c.name === 'TabItem',\n )!;\n const body = survivor.children as RootContent[];\n children.splice(i, 1, ...body);\n i += body.length - 1;\n continue;\n }\n continue;\n }\n\n transform(child);\n }\n };\n transform(tree);\n};\n\nconst selectInfrastructureSlot = (\n node: JsxElement,\n iac: 'cdk' | 'terraform',\n): RootContent[] => {\n const slotName = iac.toLowerCase();\n const frag = (node.children as RootContent[]).find(\n (c): c is MdxJsxFlowElement =>\n isJsxElement(c) &&\n c.name === 'Fragment' &&\n readStringAttr(c, 'slot') === slotName,\n );\n return (frag?.children as RootContent[]) ?? [];\n};\n\n/**\n * Prune TabItems whose `_filter` doesn't match `options`. Returns:\n * - `'empty'` if the <Tabs> now has no <TabItem>s — caller drops it.\n * - `'inline'` if exactly one filtered <TabItem> survived — caller\n * inlines the body so agents see just the picked variant.\n * - `'keep'` otherwise.\n */\nconst applyTabsFilter = (\n tabs: MdxJsxFlowElement,\n options: Record<string, string> | undefined,\n): 'empty' | 'inline' | 'keep' => {\n const children = tabs.children as RootContent[];\n const surviving: RootContent[] = [];\n let anyFiltered = false;\n for (const child of children) {\n if (!isJsxElement(child) || child.name !== 'TabItem') {\n surviving.push(child);\n continue;\n }\n const filterEstree = readEstreeAttr(child, '_filter');\n if (!filterEstree) {\n surviving.push(child);\n continue;\n }\n anyFiltered = true;\n let predicate: Predicate;\n try {\n predicate = parseWhenExpression(filterEstree as never);\n } catch {\n stripFilterAttr(child);\n surviving.push(child);\n continue;\n }\n if (!options || evaluatePredicate(predicate, false, options)) {\n stripFilterAttr(child);\n surviving.push(child);\n }\n }\n if (anyFiltered) {\n tabs.children = surviving as MdxJsxFlowElement['children'];\n }\n const tabItems = surviving.filter(\n (c) => isJsxElement(c) && c.name === 'TabItem',\n );\n if (tabItems.length === 0 && surviving.length === 0) return 'empty';\n if (anyFiltered && tabItems.length === 1) return 'inline';\n return 'keep';\n};\n\nconst stripFilterAttr = (el: JsxElement): void => {\n el.attributes = el.attributes.filter(\n (a) => !(a.type === 'mdxJsxAttribute' && a.name === '_filter'),\n );\n};\n\n/**\n * `> [!NOTE] Only when …` blockquote. The alert header goes through as an\n * `html` node so remark-stringify doesn't escape the `[`/`]` brackets —\n * downstream agents match on the literal GitHub alert syntax.\n */\nconst buildNoteQuote = (\n source: JsxElement,\n predicate: Predicate,\n not: boolean,\n): RootContent => {\n const marker = describePredicate(predicate, not);\n const description = readStringAttr(source, 'description');\n const headerLines = description\n ? [`[!NOTE] ${marker}`, description]\n : [`[!NOTE] ${marker}`];\n const headerNodes: RootContent[] = headerLines.map(\n (line) => ({ type: 'html', value: line }) as RootContent,\n );\n return {\n type: 'blockquote',\n children: [...headerNodes, ...(source.children as RootContent[])] as never,\n } as RootContent;\n};\n\nconst parseWhenAttr = (node: JsxElement): Predicate | undefined => {\n const estree = readEstreeAttr(node, 'when');\n if (!estree) return undefined;\n try {\n return parseWhenExpression(estree as never);\n } catch {\n return undefined;\n }\n};\n\nconst applyComponentTransforms = (\n tree: Root,\n opts: PipelineOptions,\n deps: RemarkDeps,\n): void => {\n const pm = opts.packageManager ?? 'pnpm';\n const transform = (parent: JsxParent): void => {\n const children = parent.children as RootContent[];\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!isJsxElement(child)) continue;\n const replacement = renderComponent(child, opts, pm, deps);\n if (replacement !== undefined) {\n children.splice(i, 1, ...replacement);\n i += replacement.length - 1;\n continue;\n }\n transform(child);\n }\n };\n transform(tree);\n};\n\nconst renderComponent = (\n node: JsxElement,\n opts: PipelineOptions,\n pm: string,\n deps: RemarkDeps,\n): RootContent[] | undefined => {\n switch (node.name) {\n case 'NxCommands': {\n const commands = readCommandsAttr(node);\n if (!commands) return undefined;\n return [\n codeBlock(\n commands\n .map((c) => buildNxCommand(c, opts.packageManager))\n .join('\\n'),\n ),\n ];\n }\n case 'RunGenerator': {\n const generatorId = readStringAttr(node, 'generator');\n if (!generatorId) return undefined;\n const schema = findSchema(opts.generators, generatorId);\n if (!schema) return undefined;\n return parseMarkdownFragment(\n renderGeneratorCommand(generatorId, schema, opts.packageManager),\n deps,\n );\n }\n case 'GeneratorParameters': {\n const generatorId = readStringAttr(node, 'generator');\n if (!generatorId) return undefined;\n const schema = findSchema(opts.generators, generatorId);\n if (!schema) return undefined;\n return parseMarkdownFragment(renderSchema(schema), deps);\n }\n case 'CreateNxWorkspaceCommand': {\n const workspace = readStringAttr(node, 'workspace');\n if (!workspace) return undefined;\n const iac = readStringAttr(node, 'iac') as\n | 'cdk'\n | 'terraform'\n | undefined;\n return [codeBlock(buildCreateNxWorkspaceCommand(pm, workspace, iac))];\n }\n case 'InstallCommand': {\n const pkg =\n readStringAttr(node, 'pkg') ?? readExpressionAttr(node, 'pkg');\n if (!pkg) return undefined;\n return [\n codeBlock(buildInstallCommand(pm, pkg, hasBareAttr(node, 'dev'))),\n ];\n }\n case 'PackageManagerShortCommand': {\n const commands = readCommandsAttr(node);\n if (!commands) return undefined;\n return [\n codeBlock(\n commands\n .map((c) => buildPackageManagerShortCommand(pm, c))\n .join('\\n'),\n ),\n ];\n }\n case 'PackageManagerExecCommand': {\n const commands = readCommandsAttr(node);\n if (!commands) return undefined;\n return [\n codeBlock(\n commands.map((c) => buildPackageManagerExecCommand(pm, c)).join('\\n'),\n ),\n ];\n }\n default:\n return undefined;\n }\n};\n\nconst codeBlock = (body: string): RootContent => ({\n type: 'code',\n lang: 'bash',\n value: body,\n});\n\nconst parseMarkdownFragment = (\n markdown: string,\n deps: RemarkDeps,\n): RootContent[] => {\n const fragTree = deps.unified().use(deps.remarkParse).parse(markdown) as Root;\n return fragTree.children as RootContent[];\n};\n\nconst findSchema = (\n generators: NxGeneratorInfo[],\n generatorId: string,\n):\n | { properties?: Record<string, unknown>; required?: string[] }\n | undefined => {\n const info = generators.find((g) => g.id === generatorId);\n if (!info) return undefined;\n try {\n return JSON.parse(fs.readFileSync(info.resolvedSchemaPath, 'utf-8'));\n } catch {\n return undefined;\n }\n};\n\n/** Parse the `commands={[…]}` attribute from the estree that remark-mdx\n * attaches to the JSX attribute value. */\nconst readCommandsAttr = (node: JsxElement): string[] | undefined => {\n const estree = readEstreeAttr(node, 'commands');\n if (!estree) return undefined;\n try {\n return extractStringArrayExpression(estree as never);\n } catch {\n return undefined;\n }\n};\n"],"names":["fs","buildCreateNxWorkspaceCommand","buildInstallCommand","buildPackageManagerExecCommand","buildPackageManagerShortCommand","buildNxCommand","renderGeneratorCommand","renderSchema","hasBareAttr","isJsxElement","readEstreeAttr","readExpressionAttr","readStringAttr","describePredicate","evaluatePredicate","extractStringArrayExpression","parseWhenExpression","depsPromise","loadRemarkDeps","unified","remarkParse","default","remarkMdx","remarkStringify","remarkFrontmatter","parseMdxWithDeps","source","deps","use","parse","parseMdx","stringifyMdx","tree","String","bullet","fences","listItemIndent","stringify","postProcessGuideWithRemark","guide","opts","inlineSnippets","applyFilterTransforms","options","applyComponentTransforms","provider","snippetContentProvider","pending","walk","parent","children","i","length","child","name","push","index","node","fetched","Promise","all","map","p","raw","replacement","undefined","processed","trim","byParent","Map","f","bucket","get","set","items","sort","a","b","snippetTree","wrapper","type","attributes","value","position","splice","iac","transform","when","parseWhenAttr","not","buildNoteQuote","body","selectInfrastructureSlot","pseudo","dropped","applyTabsFilter","survivor","find","c","slotName","toLowerCase","frag","tabs","surviving","anyFiltered","filterEstree","predicate","stripFilterAttr","tabItems","filter","el","marker","description","headerLines","headerNodes","line","estree","pm","packageManager","renderComponent","commands","readCommandsAttr","codeBlock","join","generatorId","schema","findSchema","generators","parseMarkdownFragment","workspace","pkg","lang","markdown","fragTree","info","g","id","JSON","readFileSync","resolvedSchemaPath"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/mcp-server/guide-pipeline.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'fs';\n/**\n * Unified + remark-mdx pipeline for the MCP `generator-guide` tool.\n *\n * Passes (in order, each over the already-transformed tree):\n * 1. Snippet inlining — `<Snippet name>` → recursive post-process.\n * 2. Filter transforms — `<OptionFilter>`, `<Infrastructure>` slot\n * selection, `<Tabs><TabItem _filter>` pruning.\n * 3. Component transforms — `<NxCommands>` / `<RunGenerator>` /\n * `<GeneratorParameters>` / `<CreateNxWorkspaceCommand>` /\n * `<InstallCommand>` / `<PackageManagerShortCommand>` /\n * `<PackageManagerExecCommand>` render down to markdown.\n */\nimport type { Root, RootContent } from 'mdast';\nimport type { MdxJsxFlowElement } from 'mdast-util-mdx-jsx';\nimport {\n buildCreateNxWorkspaceCommand,\n buildInstallCommand,\n buildNxInitCommand,\n buildPackageManagerExecCommand,\n buildPackageManagerShortCommand,\n} from '../utils/commands';\nimport type { NxGeneratorInfo } from '../utils/generators';\nimport {\n buildNxCommand,\n renderGeneratorCommand,\n renderSchema,\n} from './guide-render';\nimport {\n hasBareAttr,\n isJsxElement,\n type JsxElement,\n type JsxParent,\n readEstreeAttr,\n readExpressionAttr,\n readStringAttr,\n} from './mdx-ast';\nimport {\n describePredicate,\n evaluatePredicate,\n extractStringArrayExpression,\n type Predicate,\n parseWhenExpression,\n} from './option-filter';\n\nexport interface PipelineOptions {\n generators: NxGeneratorInfo[];\n packageManager?: string;\n snippetContentProvider?: (name: string) => Promise<string> | string;\n options?: Record<string, string>;\n}\n\n// unified v11 is ESM-only and this package is CJS; dynamic import + rolldown's\n// inlineDynamicImports bundles everything into the published MCP binary.\ninterface RemarkDeps {\n unified: typeof import('unified').unified;\n remarkParse: typeof import('remark-parse').default;\n remarkMdx: typeof import('remark-mdx').default;\n remarkStringify: typeof import('remark-stringify').default;\n remarkFrontmatter: typeof import('remark-frontmatter').default;\n}\n\nlet depsPromise: Promise<RemarkDeps> | undefined;\nconst loadRemarkDeps = (): Promise<RemarkDeps> => {\n if (!depsPromise) {\n depsPromise = (async () => ({\n unified: (await import('unified')).unified,\n remarkParse: (await import('remark-parse')).default,\n remarkMdx: (await import('remark-mdx')).default,\n remarkStringify: (await import('remark-stringify')).default,\n remarkFrontmatter: (await import('remark-frontmatter')).default,\n }))();\n }\n return depsPromise;\n};\n\nconst parseMdxWithDeps = (source: string, deps: RemarkDeps): Root =>\n deps\n .unified()\n .use(deps.remarkParse)\n .use(deps.remarkFrontmatter)\n .use(deps.remarkMdx)\n .parse(source) as Root;\n\n/** Parse MDX (with frontmatter) into mdast. Exposed so callers like\n * `fetchGuideFrontmatters` don't need to re-load remark themselves. */\nexport const parseMdx = async (source: string): Promise<Root> => {\n const deps = await loadRemarkDeps();\n return parseMdxWithDeps(source, deps);\n};\n\nconst stringifyMdx = (tree: Root, deps: RemarkDeps): string =>\n String(\n deps\n .unified()\n .use(deps.remarkFrontmatter)\n .use(deps.remarkMdx)\n .use(deps.remarkStringify, {\n bullet: '-',\n fences: true,\n listItemIndent: 'one',\n })\n .stringify(tree),\n );\n\n/**\n * Remove nodes that are meaningless once the MDX is rendered to plain markdown\n * for an agent: the YAML frontmatter block and the `import`/`export` (ESM)\n * statements at the top of every docs page. They add noise and tokens without\n * conveying guidance.\n */\nconst stripFrontmatterAndEsm = (tree: Root): void => {\n tree.children = tree.children.filter(\n (node) => node.type !== 'yaml' && node.type !== 'mdxjsEsm',\n );\n};\n\nexport const postProcessGuideWithRemark = async (\n guide: string,\n opts: PipelineOptions,\n): Promise<string> => {\n const deps = await loadRemarkDeps();\n const tree = parseMdxWithDeps(guide, deps);\n\n await inlineSnippets(tree, opts, deps);\n applyFilterTransforms(tree, opts.options);\n applyComponentTransforms(tree, opts, deps);\n stripFrontmatterAndEsm(tree);\n\n return stringifyMdx(tree, deps);\n};\n\nconst inlineSnippets = async (\n tree: Root,\n opts: PipelineOptions,\n deps: RemarkDeps,\n): Promise<void> => {\n const provider = opts.snippetContentProvider;\n if (!provider) return;\n\n interface PendingSnippet {\n parent: JsxParent;\n index: number;\n name: string;\n node: JsxElement;\n }\n\n const pending: PendingSnippet[] = [];\n const walk = (parent: JsxParent): void => {\n const children = parent.children as RootContent[];\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!isJsxElement(child)) continue;\n if (child.name === 'Snippet') {\n const name = readStringAttr(child, 'name');\n if (name) pending.push({ parent, index: i, name, node: child });\n continue;\n }\n walk(child);\n }\n };\n walk(tree);\n if (pending.length === 0) return;\n\n const fetched = await Promise.all(\n pending.map(async (p) => {\n let raw = '';\n try {\n raw = await provider(p.name);\n } catch {\n raw = '';\n }\n if (!raw) return { ...p, replacement: undefined };\n const processed = await postProcessGuideWithRemark(raw.trim(), opts);\n return { ...p, replacement: processed };\n }),\n );\n\n // Splice in descending index order per parent so earlier indices stay valid.\n const byParent = new Map<JsxParent, (typeof fetched)[number][]>();\n for (const f of fetched) {\n const bucket = byParent.get(f.parent) ?? [];\n bucket.push(f);\n byParent.set(f.parent, bucket);\n }\n for (const [parent, items] of byParent) {\n items.sort((a, b) => b.index - a.index);\n for (const { index, name, replacement, node } of items) {\n if (replacement === undefined) continue;\n const snippetTree = parseMdxWithDeps(replacement, deps);\n const wrapper: MdxJsxFlowElement = {\n type: 'mdxJsxFlowElement',\n name: 'Snippet',\n attributes: [{ type: 'mdxJsxAttribute', name: 'name', value: name }],\n children: snippetTree.children as MdxJsxFlowElement['children'],\n };\n if ('position' in node && node.position) {\n (wrapper as { position?: unknown }).position = node.position;\n }\n (parent.children as RootContent[]).splice(\n index,\n 1,\n wrapper as RootContent,\n );\n }\n }\n};\n\nconst applyFilterTransforms = (\n tree: Root,\n options: Record<string, string> | undefined,\n): void => {\n const iac = options?.iac;\n\n const transform = (parent: JsxParent): void => {\n const children = parent.children as RootContent[];\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!isJsxElement(child)) continue;\n\n if (child.name === 'OptionFilter') {\n const when = parseWhenAttr(child);\n if (!when) continue; // malformed — leave alone\n // Recurse first so nested filters collapse before we replace this wrapper.\n transform(child);\n const not = hasBareAttr(child, 'not');\n if (options) {\n const replacement = evaluatePredicate(when, not, options)\n ? (child.children as RootContent[])\n : [];\n children.splice(i, 1, ...replacement);\n i += replacement.length - 1;\n } else {\n children.splice(i, 1, buildNoteQuote(child, when, not));\n }\n continue;\n }\n\n if (child.name === 'Infrastructure') {\n if (iac === 'cdk' || iac === 'terraform') {\n const body = selectInfrastructureSlot(child, iac);\n const pseudo: MdxJsxFlowElement = {\n type: 'mdxJsxFlowElement',\n name: 'tmp',\n attributes: [],\n children: body as MdxJsxFlowElement['children'],\n };\n transform(pseudo);\n children.splice(i, 1, ...(pseudo.children as RootContent[]));\n i--;\n continue;\n }\n // No iac → keep both slots so readers / agents see both variants.\n transform(child);\n continue;\n }\n\n if (child.name === 'Tabs' && child.type === 'mdxJsxFlowElement') {\n transform(child);\n const dropped = applyTabsFilter(child, options);\n if (dropped === 'empty') {\n children.splice(i, 1);\n i--;\n continue;\n }\n if (dropped === 'inline') {\n const survivor = (child.children as RootContent[]).find(\n (c): c is MdxJsxFlowElement =>\n isJsxElement(c) && c.name === 'TabItem',\n )!;\n const body = survivor.children as RootContent[];\n children.splice(i, 1, ...body);\n i += body.length - 1;\n continue;\n }\n continue;\n }\n\n transform(child);\n }\n };\n transform(tree);\n};\n\nconst selectInfrastructureSlot = (\n node: JsxElement,\n iac: 'cdk' | 'terraform',\n): RootContent[] => {\n const slotName = iac.toLowerCase();\n const frag = (node.children as RootContent[]).find(\n (c): c is MdxJsxFlowElement =>\n isJsxElement(c) &&\n c.name === 'Fragment' &&\n readStringAttr(c, 'slot') === slotName,\n );\n return (frag?.children as RootContent[]) ?? [];\n};\n\n/**\n * Prune TabItems whose `_filter` doesn't match `options`. Returns:\n * - `'empty'` if the <Tabs> now has no <TabItem>s — caller drops it.\n * - `'inline'` if exactly one filtered <TabItem> survived — caller\n * inlines the body so agents see just the picked variant.\n * - `'keep'` otherwise.\n */\nconst applyTabsFilter = (\n tabs: MdxJsxFlowElement,\n options: Record<string, string> | undefined,\n): 'empty' | 'inline' | 'keep' => {\n const children = tabs.children as RootContent[];\n const surviving: RootContent[] = [];\n let anyFiltered = false;\n for (const child of children) {\n if (!isJsxElement(child) || child.name !== 'TabItem') {\n surviving.push(child);\n continue;\n }\n const filterEstree = readEstreeAttr(child, '_filter');\n if (!filterEstree) {\n surviving.push(child);\n continue;\n }\n anyFiltered = true;\n let predicate: Predicate;\n try {\n predicate = parseWhenExpression(filterEstree as never);\n } catch {\n stripFilterAttr(child);\n surviving.push(child);\n continue;\n }\n if (!options || evaluatePredicate(predicate, false, options)) {\n stripFilterAttr(child);\n surviving.push(child);\n }\n }\n if (anyFiltered) {\n tabs.children = surviving as MdxJsxFlowElement['children'];\n }\n const tabItems = surviving.filter(\n (c) => isJsxElement(c) && c.name === 'TabItem',\n );\n if (tabItems.length === 0 && surviving.length === 0) return 'empty';\n if (anyFiltered && tabItems.length === 1) return 'inline';\n return 'keep';\n};\n\nconst stripFilterAttr = (el: JsxElement): void => {\n el.attributes = el.attributes.filter(\n (a) => !(a.type === 'mdxJsxAttribute' && a.name === '_filter'),\n );\n};\n\n/**\n * `> [!NOTE] Only when …` blockquote. The alert header goes through as an\n * `html` node so remark-stringify doesn't escape the `[`/`]` brackets —\n * downstream agents match on the literal GitHub alert syntax.\n */\nconst buildNoteQuote = (\n source: JsxElement,\n predicate: Predicate,\n not: boolean,\n): RootContent => {\n const marker = describePredicate(predicate, not);\n const description = readStringAttr(source, 'description');\n const headerLines = description\n ? [`[!NOTE] ${marker}`, description]\n : [`[!NOTE] ${marker}`];\n const headerNodes: RootContent[] = headerLines.map(\n (line) => ({ type: 'html', value: line }) as RootContent,\n );\n return {\n type: 'blockquote',\n children: [...headerNodes, ...(source.children as RootContent[])] as never,\n } as RootContent;\n};\n\nconst parseWhenAttr = (node: JsxElement): Predicate | undefined => {\n const estree = readEstreeAttr(node, 'when');\n if (!estree) return undefined;\n try {\n return parseWhenExpression(estree as never);\n } catch {\n return undefined;\n }\n};\n\nconst applyComponentTransforms = (\n tree: Root,\n opts: PipelineOptions,\n deps: RemarkDeps,\n): void => {\n const pm = opts.packageManager ?? 'pnpm';\n const transform = (parent: JsxParent): void => {\n const children = parent.children as RootContent[];\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!isJsxElement(child)) continue;\n const replacement = renderComponent(child, opts, pm, deps);\n if (replacement !== undefined) {\n children.splice(i, 1, ...replacement);\n i += replacement.length - 1;\n continue;\n }\n transform(child);\n }\n };\n transform(tree);\n};\n\nconst renderComponent = (\n node: JsxElement,\n opts: PipelineOptions,\n pm: string,\n deps: RemarkDeps,\n): RootContent[] | undefined => {\n switch (node.name) {\n case 'NxCommands': {\n const commands = readCommandsAttr(node);\n if (!commands) return undefined;\n return [\n codeBlock(\n commands\n .map((c) => buildNxCommand(c, opts.packageManager))\n .join('\\n'),\n ),\n ];\n }\n case 'RunGenerator': {\n const generatorId = readStringAttr(node, 'generator');\n if (!generatorId) return undefined;\n const schema = findSchema(opts.generators, generatorId);\n if (!schema) return undefined;\n return parseMarkdownFragment(\n renderGeneratorCommand(generatorId, schema, opts.packageManager),\n deps,\n );\n }\n case 'GeneratorParameters': {\n const generatorId = readStringAttr(node, 'generator');\n if (!generatorId) return undefined;\n const schema = findSchema(opts.generators, generatorId);\n if (!schema) return undefined;\n return parseMarkdownFragment(renderSchema(schema), deps);\n }\n case 'CreateNxWorkspaceCommand': {\n const workspace = readStringAttr(node, 'workspace');\n if (!workspace) return undefined;\n const iac = readStringAttr(node, 'iac') as\n | 'cdk'\n | 'terraform'\n | undefined;\n return [codeBlock(buildCreateNxWorkspaceCommand(pm, workspace, iac))];\n }\n case 'NxInitCommand': {\n return [codeBlock(buildNxInitCommand(pm))];\n }\n case 'InstallCommand': {\n const pkg =\n readStringAttr(node, 'pkg') ?? readExpressionAttr(node, 'pkg');\n if (!pkg) return undefined;\n return [\n codeBlock(buildInstallCommand(pm, pkg, hasBareAttr(node, 'dev'))),\n ];\n }\n case 'PackageManagerShortCommand': {\n const commands = readCommandsAttr(node);\n if (!commands) return undefined;\n return [\n codeBlock(\n commands\n .map((c) => buildPackageManagerShortCommand(pm, c))\n .join('\\n'),\n ),\n ];\n }\n case 'PackageManagerExecCommand': {\n const commands = readCommandsAttr(node);\n if (!commands) return undefined;\n return [\n codeBlock(\n commands.map((c) => buildPackageManagerExecCommand(pm, c)).join('\\n'),\n ),\n ];\n }\n default:\n return undefined;\n }\n};\n\nconst codeBlock = (body: string): RootContent => ({\n type: 'code',\n lang: 'bash',\n value: body,\n});\n\nconst parseMarkdownFragment = (\n markdown: string,\n deps: RemarkDeps,\n): RootContent[] => {\n const fragTree = deps.unified().use(deps.remarkParse).parse(markdown) as Root;\n return fragTree.children as RootContent[];\n};\n\nconst findSchema = (\n generators: NxGeneratorInfo[],\n generatorId: string,\n):\n | { properties?: Record<string, unknown>; required?: string[] }\n | undefined => {\n const info = generators.find((g) => g.id === generatorId);\n if (!info) return undefined;\n try {\n return JSON.parse(fs.readFileSync(info.resolvedSchemaPath, 'utf-8'));\n } catch {\n return undefined;\n }\n};\n\n/** Parse the `commands={[…]}` attribute from the estree that remark-mdx\n * attaches to the JSX attribute value. */\nconst readCommandsAttr = (node: JsxElement): string[] | undefined => {\n const estree = readEstreeAttr(node, 'commands');\n if (!estree) return undefined;\n try {\n return extractStringArrayExpression(estree as never);\n } catch {\n return undefined;\n }\n};\n"],"names":["fs","buildCreateNxWorkspaceCommand","buildInstallCommand","buildNxInitCommand","buildPackageManagerExecCommand","buildPackageManagerShortCommand","buildNxCommand","renderGeneratorCommand","renderSchema","hasBareAttr","isJsxElement","readEstreeAttr","readExpressionAttr","readStringAttr","describePredicate","evaluatePredicate","extractStringArrayExpression","parseWhenExpression","depsPromise","loadRemarkDeps","unified","remarkParse","default","remarkMdx","remarkStringify","remarkFrontmatter","parseMdxWithDeps","source","deps","use","parse","parseMdx","stringifyMdx","tree","String","bullet","fences","listItemIndent","stringify","stripFrontmatterAndEsm","children","filter","node","type","postProcessGuideWithRemark","guide","opts","inlineSnippets","applyFilterTransforms","options","applyComponentTransforms","provider","snippetContentProvider","pending","walk","parent","i","length","child","name","push","index","fetched","Promise","all","map","p","raw","replacement","undefined","processed","trim","byParent","Map","f","bucket","get","set","items","sort","a","b","snippetTree","wrapper","attributes","value","position","splice","iac","transform","when","parseWhenAttr","not","buildNoteQuote","body","selectInfrastructureSlot","pseudo","dropped","applyTabsFilter","survivor","find","c","slotName","toLowerCase","frag","tabs","surviving","anyFiltered","filterEstree","predicate","stripFilterAttr","tabItems","el","marker","description","headerLines","headerNodes","line","estree","pm","packageManager","renderComponent","commands","readCommandsAttr","codeBlock","join","generatorId","schema","findSchema","generators","parseMarkdownFragment","workspace","pkg","lang","markdown","fragTree","info","g","id","JSON","readFileSync","resolvedSchemaPath"],"mappings":"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"}
@@ -6,6 +6,7 @@ import PackageJson from "../../package.json" with {
6
6
  type: 'json'
7
7
  };
8
8
  import { listGenerators } from "../utils/nx.js";
9
+ import { addToExistingProjectTool } from "./tools/add-to-existing-project.js";
9
10
  import { addCreateWorkspaceCommandTool } from "./tools/create-workspace-command.js";
10
11
  import { addGeneralGuidanceTool, TOOL_SELECTION_GUIDE } from "./tools/general-guidance.js";
11
12
  import { addGeneratorGuideTool } from "./tools/generator-guide.js";
@@ -32,6 +33,7 @@ ${TOOL_SELECTION_GUIDE}
32
33
  addCreateWorkspaceCommandTool(server);
33
34
  addListGeneratorsTool(server, generators);
34
35
  addGeneratorGuideTool(server, generators);
36
+ addToExistingProjectTool(server, generators);
35
37
  return server;
36
38
  };
37
39
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/mcp-server/server.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport PackageJson from '../../package.json' with { type: 'json' };\nimport { listGenerators } from '../utils/nx';\nimport { addCreateWorkspaceCommandTool } from './tools/create-workspace-command';\nimport {\n addGeneralGuidanceTool,\n TOOL_SELECTION_GUIDE,\n} from './tools/general-guidance';\nimport { addGeneratorGuideTool } from './tools/generator-guide';\nimport { addListGeneratorsTool } from './tools/list-generators';\n\n/**\n * Create the MCP Server\n */\nexport const createServer = () => {\n const generators = listGenerators();\n\n const server = new McpServer(\n {\n name: 'nx-plugin-for-aws',\n version: PackageJson.version,\n },\n {\n instructions: `# Nx Plugin for AWS MCP Server\n\nThis server provides resources and tools for quickly scaffolding AWS projects within an Nx workspace (monorepo), using the Nx Plugin for AWS (@aws/nx-plugin).\n\nThe Nx Plugin for AWS provides \"generators\" to add projects or functionality to your workspace. Use this to build the foundations of any project you are building\non AWS, if the generators apply to your use case.\n\n${TOOL_SELECTION_GUIDE}\n`,\n },\n );\n\n addGeneralGuidanceTool(server, generators);\n addCreateWorkspaceCommandTool(server);\n addListGeneratorsTool(server, generators);\n addGeneratorGuideTool(server, generators);\n\n return server;\n};\n"],"names":["McpServer","PackageJson","type","listGenerators","addCreateWorkspaceCommandTool","addGeneralGuidanceTool","TOOL_SELECTION_GUIDE","addGeneratorGuideTool","addListGeneratorsTool","createServer","generators","server","name","version","instructions"],"mappings":"AAAA;;;CAGC,GACD,SAASA,SAAS,QAAQ,0CAA0C;AACpE,OAAOC,iBAAiB,0BAA0B;IAAEC,MAAM;AAAO,EAAE;AACnE,SAASC,cAAc,QAAQ,iBAAc;AAC7C,SAASC,6BAA6B,QAAQ,sCAAmC;AACjF,SACEC,sBAAsB,EACtBC,oBAAoB,QACf,8BAA2B;AAClC,SAASC,qBAAqB,QAAQ,6BAA0B;AAChE,SAASC,qBAAqB,QAAQ,6BAA0B;AAEhE;;CAEC,GACD,OAAO,MAAMC,eAAe;IAC1B,MAAMC,aAAaP;IAEnB,MAAMQ,SAAS,IAAIX,UACjB;QACEY,MAAM;QACNC,SAASZ,YAAYY,OAAO;IAC9B,GACA;QACEC,cAAc,CAAC;;;;;;;AAOrB,EAAER,qBAAqB;AACvB,CAAC;IACG;IAGFD,uBAAuBM,QAAQD;IAC/BN,8BAA8BO;IAC9BH,sBAAsBG,QAAQD;IAC9BH,sBAAsBI,QAAQD;IAE9B,OAAOC;AACT,EAAE"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/mcp-server/server.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport PackageJson from '../../package.json' with { type: 'json' };\nimport { listGenerators } from '../utils/nx';\nimport { addToExistingProjectTool } from './tools/add-to-existing-project';\nimport { addCreateWorkspaceCommandTool } from './tools/create-workspace-command';\nimport {\n addGeneralGuidanceTool,\n TOOL_SELECTION_GUIDE,\n} from './tools/general-guidance';\nimport { addGeneratorGuideTool } from './tools/generator-guide';\nimport { addListGeneratorsTool } from './tools/list-generators';\n\n/**\n * Create the MCP Server\n */\nexport const createServer = () => {\n const generators = listGenerators();\n\n const server = new McpServer(\n {\n name: 'nx-plugin-for-aws',\n version: PackageJson.version,\n },\n {\n instructions: `# Nx Plugin for AWS MCP Server\n\nThis server provides resources and tools for quickly scaffolding AWS projects within an Nx workspace (monorepo), using the Nx Plugin for AWS (@aws/nx-plugin).\n\nThe Nx Plugin for AWS provides \"generators\" to add projects or functionality to your workspace. Use this to build the foundations of any project you are building\non AWS, if the generators apply to your use case.\n\n${TOOL_SELECTION_GUIDE}\n`,\n },\n );\n\n addGeneralGuidanceTool(server, generators);\n addCreateWorkspaceCommandTool(server);\n addListGeneratorsTool(server, generators);\n addGeneratorGuideTool(server, generators);\n addToExistingProjectTool(server, generators);\n\n return server;\n};\n"],"names":["McpServer","PackageJson","type","listGenerators","addToExistingProjectTool","addCreateWorkspaceCommandTool","addGeneralGuidanceTool","TOOL_SELECTION_GUIDE","addGeneratorGuideTool","addListGeneratorsTool","createServer","generators","server","name","version","instructions"],"mappings":"AAAA;;;CAGC,GACD,SAASA,SAAS,QAAQ,0CAA0C;AACpE,OAAOC,iBAAiB,0BAA0B;IAAEC,MAAM;AAAO,EAAE;AACnE,SAASC,cAAc,QAAQ,iBAAc;AAC7C,SAASC,wBAAwB,QAAQ,qCAAkC;AAC3E,SAASC,6BAA6B,QAAQ,sCAAmC;AACjF,SACEC,sBAAsB,EACtBC,oBAAoB,QACf,8BAA2B;AAClC,SAASC,qBAAqB,QAAQ,6BAA0B;AAChE,SAASC,qBAAqB,QAAQ,6BAA0B;AAEhE;;CAEC,GACD,OAAO,MAAMC,eAAe;IAC1B,MAAMC,aAAaR;IAEnB,MAAMS,SAAS,IAAIZ,UACjB;QACEa,MAAM;QACNC,SAASb,YAAYa,OAAO;IAC9B,GACA;QACEC,cAAc,CAAC;;;;;;;AAOrB,EAAER,qBAAqB;AACvB,CAAC;IACG;IAGFD,uBAAuBM,QAAQD;IAC/BN,8BAA8BO;IAC9BH,sBAAsBG,QAAQD;IAC9BH,sBAAsBI,QAAQD;IAC9BP,yBAAyBQ,QAAQD;IAEjC,OAAOC;AACT,EAAE"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import type { NxGeneratorInfo } from '../../utils/generators';
7
+ /**
8
+ * Add a tool which guides an agent through adding @aws/nx-plugin to an
9
+ * existing Nx or non-Nx workspace. Returns the `existing-project` docs page,
10
+ * which includes the full adoption steps and troubleshooting reference.
11
+ */
12
+ export declare const addToExistingProjectTool: (server: McpServer, generators: NxGeneratorInfo[]) => void;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { fetchGuidePages } from "../generator-info.js";
5
+ import { PackageManagerSchema } from "../schema.js";
6
+ /**
7
+ * The guide page (under `get_started/`) that backs this tool, so the tool and
8
+ * the published docs never drift.
9
+ */ const EXISTING_PROJECT_GUIDE = 'existing-project';
10
+ /**
11
+ * Add a tool which guides an agent through adding @aws/nx-plugin to an
12
+ * existing Nx or non-Nx workspace. Returns the `existing-project` docs page,
13
+ * which includes the full adoption steps and troubleshooting reference.
14
+ */ export const addToExistingProjectTool = (server, generators)=>{
15
+ server.registerTool('add-to-existing-project', {
16
+ title: 'Add to Existing Project',
17
+ description: 'Tool for adding the Nx Plugin for AWS to an existing Nx workspace or non-Nx monorepo. Use this when a user wants to adopt @aws/nx-plugin in a project that was not created with the plugin preset, or hits configuration errors when running generators in such a workspace.',
18
+ inputSchema: {
19
+ packageManager: PackageManagerSchema.optional()
20
+ }
21
+ }, async ({ packageManager })=>{
22
+ const guide = await fetchGuidePages([
23
+ EXISTING_PROJECT_GUIDE
24
+ ], generators, packageManager);
25
+ return {
26
+ content: [
27
+ {
28
+ type: 'text',
29
+ text: guide
30
+ }
31
+ ]
32
+ };
33
+ });
34
+ };
35
+
36
+ //# sourceMappingURL=add-to-existing-project.js.map