@frontmcp/nx 1.8.6 → 1.9.0

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 (129) hide show
  1. package/executors/build/build.impl.js +9 -19
  2. package/executors/build/build.impl.js.map +1 -1
  3. package/executors/build/schema.d.ts +2 -0
  4. package/executors/build/schema.js.map +1 -1
  5. package/executors/build/schema.json +22 -2
  6. package/executors/build-exec/build-exec.impl.js +5 -17
  7. package/executors/build-exec/build-exec.impl.js.map +1 -1
  8. package/executors/deploy/deploy.impl.js.map +1 -1
  9. package/executors/dev/dev.impl.js +11 -17
  10. package/executors/dev/dev.impl.js.map +1 -1
  11. package/executors/frontmcp-cli.d.ts +31 -0
  12. package/executors/frontmcp-cli.js +108 -0
  13. package/executors/frontmcp-cli.js.map +1 -0
  14. package/executors/inspector/inspector.impl.js +10 -18
  15. package/executors/inspector/inspector.impl.js.map +1 -1
  16. package/executors/serve/serve.impl.js +11 -17
  17. package/executors/serve/serve.impl.js.map +1 -1
  18. package/executors/test/test.impl.js +3 -15
  19. package/executors/test/test.impl.js.map +1 -1
  20. package/generators/adapter/files/__fileName__.adapter.ts__tmpl__ +9 -2
  21. package/generators/agent/agent.d.ts +1 -1
  22. package/generators/agent/agent.js +21 -7
  23. package/generators/agent/agent.js.map +1 -1
  24. package/generators/agent/files/__fileName__.agent.ts__tmpl__ +12 -6
  25. package/generators/app/app.d.ts +1 -1
  26. package/generators/app/app.js +3 -3
  27. package/generators/app/app.js.map +1 -1
  28. package/generators/app/files/jest.config.cjs__tmpl__ +37 -0
  29. package/generators/app/files/package.json__tmpl__ +5 -0
  30. package/generators/app/files/project.json__tmpl__ +12 -1
  31. package/generators/app/files/src/tools/hello.tool.spec.ts__tmpl__ +10 -0
  32. package/generators/app/files/tsconfig.json__tmpl__ +11 -9
  33. package/generators/app/files/tsconfig.lib.json__tmpl__ +1 -2
  34. package/generators/app/files/tsconfig.spec.json__tmpl__ +3 -4
  35. package/generators/app/lib/normalize-options.d.ts +10 -1
  36. package/generators/app/lib/normalize-options.js +7 -2
  37. package/generators/app/lib/normalize-options.js.map +1 -1
  38. package/generators/app/schema.d.ts +2 -0
  39. package/generators/app/schema.js.map +1 -1
  40. package/generators/app/schema.json +5 -0
  41. package/generators/auth-provider/files/__fileName__.auth-provider.ts__tmpl__ +0 -1
  42. package/generators/flow/files/__fileName__.flow.ts__tmpl__ +54 -16
  43. package/generators/init/init.d.ts +4 -0
  44. package/generators/init/init.js +40 -0
  45. package/generators/init/init.js.map +1 -0
  46. package/generators/init/schema.d.ts +4 -0
  47. package/generators/init/schema.js +3 -0
  48. package/generators/init/schema.js.map +1 -0
  49. package/generators/init/schema.json +21 -0
  50. package/generators/lib/files/adapter/src/__fileName__.adapter.spec.ts__tmpl__ +9 -0
  51. package/generators/lib/files/generic/src/__fileName__.spec.ts__tmpl__ +7 -0
  52. package/generators/lib/files/plugin/src/__fileName__.plugin.spec.ts__tmpl__ +11 -0
  53. package/generators/lib/files/tool-register/src/__fileName__.tools.spec.ts__tmpl__ +14 -0
  54. package/generators/lib/lib/normalize-options.d.ts +6 -1
  55. package/generators/lib/lib/normalize-options.js +5 -2
  56. package/generators/lib/lib/normalize-options.js.map +1 -1
  57. package/generators/lib/lib-project-files/jest.config.cjs__tmpl__ +39 -0
  58. package/generators/lib/lib-project-files/project.json__tmpl__ +32 -0
  59. package/generators/lib/lib-project-files/tsconfig.json__tmpl__ +22 -0
  60. package/generators/lib/lib-project-files/tsconfig.lib.json__tmpl__ +11 -0
  61. package/generators/lib/lib-project-files/tsconfig.spec.json__tmpl__ +8 -0
  62. package/generators/lib/lib.d.ts +1 -1
  63. package/generators/lib/lib.js +52 -20
  64. package/generators/lib/lib.js.map +1 -1
  65. package/generators/plugin/files/__fileName__.plugin.ts__tmpl__ +9 -5
  66. package/generators/provider/files/__fileName__.provider.ts__tmpl__ +5 -9
  67. package/generators/provider/provider.d.ts +1 -1
  68. package/generators/provider/provider.js +3 -3
  69. package/generators/provider/provider.js.map +1 -1
  70. package/generators/server/files/common/package.json__tmpl__ +5 -0
  71. package/generators/server/files/common/project.json__tmpl__ +18 -3
  72. package/generators/server/files/common/src/main.ts__tmpl__ +2 -2
  73. package/generators/server/files/common/tsconfig.json__tmpl__ +11 -8
  74. package/generators/server/files/common/tsconfig.lib.json__tmpl__ +0 -1
  75. package/generators/server/files/lambda/template.yaml__tmpl__ +4 -2
  76. package/generators/server/files/node/Dockerfile.dockerignore__tmpl__ +10 -0
  77. package/generators/server/files/node/Dockerfile__tmpl__ +6 -1
  78. package/generators/server/files/node/docker-compose.yml__tmpl__ +1 -1
  79. package/generators/server/files/vercel/vercel.json__tmpl__ +3 -12
  80. package/generators/server/lib/normalize-options.d.ts +16 -1
  81. package/generators/server/lib/normalize-options.js +22 -3
  82. package/generators/server/lib/normalize-options.js.map +1 -1
  83. package/generators/server/server.d.ts +1 -1
  84. package/generators/server/server.js +9 -2
  85. package/generators/server/server.js.map +1 -1
  86. package/generators/ui-component/files/__className__/__className__.tsx__tmpl__ +0 -1
  87. package/generators/ui-component/ui-component.d.ts +1 -1
  88. package/generators/ui-component/ui-component.js +4 -1
  89. package/generators/ui-component/ui-component.js.map +1 -1
  90. package/generators/ui-page/ui-page.d.ts +1 -1
  91. package/generators/ui-page/ui-page.js +4 -1
  92. package/generators/ui-page/ui-page.js.map +1 -1
  93. package/generators/ui-shared/add-ui-entry.js +2 -12
  94. package/generators/ui-shared/add-ui-entry.js.map +1 -1
  95. package/generators/ui-shared/ensure-ui-package.d.ts +17 -0
  96. package/generators/ui-shared/ensure-ui-package.js +123 -0
  97. package/generators/ui-shared/ensure-ui-package.js.map +1 -0
  98. package/generators/ui-shell/files/__fileName__/__fileName__.shell.spec.ts__tmpl__ +2 -1
  99. package/generators/ui-shell/ui-shell.d.ts +1 -1
  100. package/generators/ui-shell/ui-shell.js +4 -1
  101. package/generators/ui-shell/ui-shell.js.map +1 -1
  102. package/generators/workspace/files/__dot__gitignore__tmpl__ +1 -0
  103. package/generators/workspace/files/nx.json__tmpl__ +15 -11
  104. package/generators/workspace/files/package.json__tmpl__ +3 -3
  105. package/generators/workspace/workspace.d.ts +1 -1
  106. package/generators/workspace/workspace.js +3 -2
  107. package/generators/workspace/workspace.js.map +1 -1
  108. package/generators.json +5 -0
  109. package/index.d.ts +1 -0
  110. package/index.js +3 -1
  111. package/index.js.map +1 -1
  112. package/package.json +2 -2
  113. package/utils/add-dependencies.d.ts +4 -2
  114. package/utils/add-dependencies.js +2 -2
  115. package/utils/add-dependencies.js.map +1 -1
  116. package/utils/normalize-options.js.map +1 -1
  117. package/utils/package-manager.d.ts +11 -0
  118. package/utils/package-manager.js +33 -0
  119. package/utils/package-manager.js.map +1 -0
  120. package/utils/project-paths.d.ts +40 -0
  121. package/utils/project-paths.js +103 -0
  122. package/utils/project-paths.js.map +1 -0
  123. package/utils/versions.d.ts +10 -0
  124. package/utils/versions.js +45 -5
  125. package/utils/versions.js.map +1 -1
  126. package/generators/app/files/jest.config.ts__tmpl__ +0 -23
  127. package/generators/lib/files/adapter/src/__fileName__.adapter.ts__tmpl__ +0 -19
  128. package/generators/lib/files/plugin/src/__fileName__.plugin.ts__tmpl__ +0 -19
  129. package/generators/server/files/node/__dot__dockerignore__tmpl__ +0 -8
@@ -1 +1 @@
1
- {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../../src/generators/agent/agent.ts"],"names":[],"mappings":";;AAKA,wCAoBC;AAzBD,uCAA2F;AAC3F,+BAA4B;AAE5B,2EAA6E;AAEtE,KAAK,UAAU,cAAc,CAAC,IAAU,EAAE,MAA4B;IAC3E,MAAM,OAAO,GAAG,IAAA,gDAAyB,EAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC;IACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK;QAC3B,CAAC,CAAC,MAAM,CAAC,KAAK;aACT,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC;QACpB,CAAC,CAAC,EAAE,CAAC;IAEP,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE;QAC/D,GAAG,OAAO;QACV,KAAK;QACL,QAAQ;QACR,IAAI,EAAE,EAAE;KACT,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,kBAAe,cAAc,CAAC","sourcesContent":["import { type Tree, formatFiles, generateFiles, type GeneratorCallback } from '@nx/devkit';\nimport { join } from 'path';\nimport type { AgentGeneratorSchema } from './schema.js';\nimport { normalizePrimitiveOptions } from '../../utils/normalize-options.js';\n\nexport async function agentGenerator(tree: Tree, schema: AgentGeneratorSchema): Promise<GeneratorCallback | void> {\n const options = normalizePrimitiveOptions(tree, schema, 'agents');\n const model = schema.model ?? 'gpt-4';\n const toolRefs = schema.tools\n ? schema.tools\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean)\n : [];\n\n generateFiles(tree, join(__dirname, 'files'), options.directory, {\n ...options,\n model,\n toolRefs,\n tmpl: '',\n });\n\n if (!schema.skipFormat) {\n await formatFiles(tree);\n }\n}\n\nexport default agentGenerator;\n"]}
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../../src/generators/agent/agent.ts"],"names":[],"mappings":";;AAQA,wCAiCC;AAzCD,+BAAsC;AAEtC,uCAAkG;AAElG,mDAAkD;AAClD,2EAA6E;AAGtE,KAAK,UAAU,cAAc,CAAC,IAAU,EAAE,MAA4B;IAC3E,MAAM,OAAO,GAAG,IAAA,gDAAyB,EAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SAClC,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,IAAA,cAAK,EAAC,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAA,qBAAU,EAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACxE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;SACtF,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,UAAU,GAAG,IAAA,eAAQ,EAAC,OAAO,CAAC,SAAS,EAAE,IAAA,WAAI,EAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,QAAQ,OAAO,CAAC,CAAC;aACjF,KAAK,CAAC,IAAI,CAAC;aACX,IAAI,CAAC,GAAG,CAAC,CAAC;QACb,OAAO;YACL,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,EAAE;SACxE,CAAC;IACJ,CAAC,CAAC,CAAC;IACL,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAE7D,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE;QAC/D,GAAG,OAAO;QACV,KAAK;QACL,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ;QACjD,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,gBAAgB;QAC/D,QAAQ;QACR,IAAI,EAAE,EAAE;KACT,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,kBAAe,cAAc,CAAC","sourcesContent":["import { join, relative } from 'path';\n\nimport { formatFiles, generateFiles, names, type GeneratorCallback, type Tree } from '@nx/devkit';\n\nimport { toFileName } from '../../utils/names.js';\nimport { normalizePrimitiveOptions } from '../../utils/normalize-options.js';\nimport type { AgentGeneratorSchema } from './schema.js';\n\nexport async function agentGenerator(tree: Tree, schema: AgentGeneratorSchema): Promise<GeneratorCallback | void> {\n const options = normalizePrimitiveOptions(tree, schema, 'agents');\n const model = schema.model ?? 'gpt-4';\n const toolsDir = join(options.projectSourceRoot, 'tools');\n const toolRefs = (schema.tools ?? '')\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean)\n .map((t) => ({ className: names(t).className, fileName: toFileName(t) }))\n .filter((t, i, all) => all.findIndex((other) => other.className === t.className) === i)\n .map((t) => {\n const importPath = relative(options.directory, join(toolsDir, `${t.fileName}.tool`))\n .split('\\\\')\n .join('/');\n return {\n className: t.className,\n importPath: importPath.startsWith('.') ? importPath : `./${importPath}`,\n };\n });\n const isAnthropic = model.toLowerCase().startsWith('claude');\n\n generateFiles(tree, join(__dirname, 'files'), options.directory, {\n ...options,\n model,\n llmProvider: isAnthropic ? 'anthropic' : 'openai',\n apiKeyEnv: isAnthropic ? 'ANTHROPIC_API_KEY' : 'OPENAI_API_KEY',\n toolRefs,\n tmpl: '',\n });\n\n if (!schema.skipFormat) {\n await formatFiles(tree);\n }\n}\n\nexport default agentGenerator;\n"]}
@@ -1,17 +1,23 @@
1
- import { Agent, AgentContext } from '@frontmcp/sdk';
2
-
1
+ import { Agent, AgentContext, z } from '@frontmcp/sdk';
2
+ <% toolRefs.forEach(t => { %>import <%= t.className %>Tool from '<%= t.importPath %>';
3
+ <% }) %>
3
4
  @Agent({
4
5
  name: '<%= name %>',
5
6
  description: 'TODO: describe what this agent does',
6
7
  llm: {
8
+ provider: '<%= llmProvider %>',
7
9
  model: '<%= model %>',
10
+ apiKey: { env: '<%= apiKeyEnv %>' },
11
+ },
12
+ inputSchema: {
13
+ task: z.string().describe('TODO: describe the task the agent should perform'),
8
14
  },<% if (toolRefs.length > 0) { %>
9
- tools: [<%- toolRefs.map(t => `'${t}'`).join(', ') %>],<% } %>
15
+ tools: [<%- toolRefs.map(t => `${t.className}Tool`).join(', ') %>],<% } %>
10
16
  systemInstructions: 'TODO: define system instructions for this agent',
11
17
  })
12
18
  export default class <%= className %>Agent extends AgentContext {
13
- async execute(input: unknown): Promise<unknown> {
14
- // TODO: implement agent logic
15
- return {};
19
+ async execute(input: { task: string }) {
20
+ // The default implementation runs the LLM loop with the agent's tools.
21
+ return super.execute(input);
16
22
  }
17
23
  }
@@ -1,4 +1,4 @@
1
- import { type Tree, type GeneratorCallback } from '@nx/devkit';
1
+ import { type GeneratorCallback, type Tree } from '@nx/devkit';
2
2
  import type { AppGeneratorSchema } from './schema.js';
3
3
  export declare function appGenerator(tree: Tree, schema: AppGeneratorSchema): Promise<GeneratorCallback | void>;
4
4
  export default appGenerator;
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.appGenerator = appGenerator;
4
- const devkit_1 = require("@nx/devkit");
5
4
  const path_1 = require("path");
5
+ const devkit_1 = require("@nx/devkit");
6
6
  const index_js_1 = require("./lib/index.js");
7
7
  async function appGenerator(tree, schema) {
8
8
  return appGeneratorInternal(tree, schema);
9
9
  }
10
10
  async function appGeneratorInternal(tree, schema) {
11
- const options = (0, index_js_1.normalizeOptions)(schema);
12
- (0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files'), options.projectRoot, {
11
+ const options = (0, index_js_1.normalizeOptions)(tree, schema);
12
+ (0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files'), options.outputRoot, {
13
13
  ...options,
14
14
  tmpl: '',
15
15
  });
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../src/generators/app/app.ts"],"names":[],"mappings":";;AAKA,oCAEC;AAPD,uCAA2F;AAC3F,+BAA4B;AAE5B,6CAAkD;AAE3C,KAAK,UAAU,YAAY,CAAC,IAAU,EAAE,MAA0B;IACvE,OAAO,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,IAAU,EAAE,MAA0B;IACxE,MAAM,OAAO,GAAG,IAAA,2BAAgB,EAAC,MAAM,CAAC,CAAC;IAEzC,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,EAAE;QACjE,GAAG,OAAO;QACV,IAAI,EAAE,EAAE;KACT,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACxB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,kBAAe,YAAY,CAAC","sourcesContent":["import { type Tree, formatFiles, generateFiles, type GeneratorCallback } from '@nx/devkit';\nimport { join } from 'path';\nimport type { AppGeneratorSchema } from './schema.js';\nimport { normalizeOptions } from './lib/index.js';\n\nexport async function appGenerator(tree: Tree, schema: AppGeneratorSchema): Promise<GeneratorCallback | void> {\n return appGeneratorInternal(tree, schema);\n}\n\nasync function appGeneratorInternal(tree: Tree, schema: AppGeneratorSchema): Promise<GeneratorCallback | void> {\n const options = normalizeOptions(schema);\n\n generateFiles(tree, join(__dirname, 'files'), options.projectRoot, {\n ...options,\n tmpl: '',\n });\n\n if (!options.skipFormat) {\n await formatFiles(tree);\n }\n}\n\nexport default appGenerator;\n"]}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../src/generators/app/app.ts"],"names":[],"mappings":";;AAOA,oCAEC;AATD,+BAA4B;AAE5B,uCAA2F;AAE3F,6CAAkD;AAG3C,KAAK,UAAU,YAAY,CAAC,IAAU,EAAE,MAA0B;IACvE,OAAO,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,IAAU,EAAE,MAA0B;IACxE,MAAM,OAAO,GAAG,IAAA,2BAAgB,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAE/C,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE;QAChE,GAAG,OAAO;QACV,IAAI,EAAE,EAAE;KACT,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACxB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,kBAAe,YAAY,CAAC","sourcesContent":["import { join } from 'path';\n\nimport { formatFiles, generateFiles, type GeneratorCallback, type Tree } from '@nx/devkit';\n\nimport { normalizeOptions } from './lib/index.js';\nimport type { AppGeneratorSchema } from './schema.js';\n\nexport async function appGenerator(tree: Tree, schema: AppGeneratorSchema): Promise<GeneratorCallback | void> {\n return appGeneratorInternal(tree, schema);\n}\n\nasync function appGeneratorInternal(tree: Tree, schema: AppGeneratorSchema): Promise<GeneratorCallback | void> {\n const options = normalizeOptions(tree, schema);\n\n generateFiles(tree, join(__dirname, 'files'), options.outputRoot, {\n ...options,\n tmpl: '',\n });\n\n if (!options.skipFormat) {\n await formatFiles(tree);\n }\n}\n\nexport default appGenerator;\n"]}
@@ -0,0 +1,37 @@
1
+ const { join } = require('path');
2
+ const ts = require('typescript');
3
+
4
+ // Mirror the tsconfig.base.json path aliases so imports across projects (e.g. `@scope/lib`) resolve in tests.
5
+ const workspaceRoot = join(__dirname, '<%= offset %>');
6
+ const { config: baseConfig } = ts.readConfigFile(join(workspaceRoot, 'tsconfig.base.json'), ts.sys.readFile);
7
+ const aliases = (baseConfig && baseConfig.compilerOptions && baseConfig.compilerOptions.paths) || {};
8
+ const moduleNameMapper = Object.fromEntries(
9
+ Object.entries(aliases).map(([alias, [target]]) => [
10
+ '^' + alias.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace('*', '(.*)') + '$',
11
+ join(workspaceRoot, target).replace('*', '$1'),
12
+ ]),
13
+ );
14
+
15
+ module.exports = {
16
+ displayName: '<%= projectName %>',
17
+ testEnvironment: 'node',
18
+ transform: {
19
+ '^.+\\.[tj]s$': ['@swc/jest', {
20
+ jsc: {
21
+ target: 'es2022',
22
+ parser: { syntax: 'typescript', decorators: true, dynamicImport: true },
23
+ transform: { decoratorMetadata: true, legacyDecorator: true },
24
+ keepClassNames: true,
25
+ externalHelpers: true,
26
+ loose: true,
27
+ },
28
+ sourceMaps: true,
29
+ swcrc: false,
30
+ }],
31
+ },
32
+ setupFilesAfterEnv: ['@frontmcp/testing/setup'],
33
+ moduleFileExtensions: ['ts', 'js', 'html'],
34
+ moduleNameMapper,
35
+ // Transpile ESM-only deps; the `.pnpm` skip keeps this correct under pnpm (issue #519).
36
+ transformIgnorePatterns: ['node_modules[/\\\\](?!\\.pnpm[/\\\\])(?!(jose)[/\\\\])'],
37
+ };
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "<%= projectName %>",
3
+ "version": "0.0.1",
4
+ "private": true
5
+ }
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "<%= projectName %>",
3
- "$schema": "../../node_modules/nx/schemas/project-schema.json",
3
+ "$schema": "<%= offset %>node_modules/nx/schemas/project-schema.json",
4
4
  "sourceRoot": "<%= projectRoot %>/src",
5
5
  "projectType": "application",
6
6
  "tags": [<%- parsedTags.map(t => `"${t}"`).join(', ') %>],
7
7
  "targets": {
8
8
  "build": {
9
9
  "executor": "@frontmcp/nx:build",
10
+ "cache": true,
10
11
  "outputs": ["{projectRoot}/dist"],
11
12
  "options": {
12
13
  "entry": "{projectRoot}/src/main.ts",
@@ -27,8 +28,18 @@
27
28
  },
28
29
  "test": {
29
30
  "executor": "@frontmcp/nx:test",
31
+ "cache": true,
30
32
  "options": {}
31
33
  },
34
+ "typecheck": {
35
+ "executor": "nx:run-commands",
36
+ "cache": true,
37
+ "options": {
38
+ "commands": ["tsc --noEmit -p tsconfig.lib.json", "tsc --noEmit -p tsconfig.spec.json"],
39
+ "parallel": false,
40
+ "cwd": "{projectRoot}"
41
+ }
42
+ },
32
43
  "inspector": {
33
44
  "executor": "@frontmcp/nx:inspector",
34
45
  "options": {}
@@ -0,0 +1,10 @@
1
+ import HelloTool from './hello.tool';
2
+
3
+ describe('HelloTool', () => {
4
+ it('greets the caller by name', async () => {
5
+ // execute() holds the tool's logic; build the tool without the request context the server injects.
6
+ const tool: HelloTool = Object.create(HelloTool.prototype);
7
+
8
+ await expect(tool.execute({ name: 'Ada' })).resolves.toEqual({ message: 'Hello, Ada!' });
9
+ });
10
+ });
@@ -1,17 +1,19 @@
1
1
  {
2
- "extends": "../../tsconfig.base.json",
2
+ "extends": "<%= offset %>tsconfig.base.json",
3
3
  "compilerOptions": {
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
4
+ "module": "commonjs",
5
+ "moduleResolution": "<%= moduleResolution %>",<% if (resetCustomConditions) { %>
6
+ "customConditions": null,<% } %>
7
+ "rootDir": "<%= offset %>",
8
+ "composite": false,
9
+ "declarationMap": false,
10
+ "emitDeclarationOnly": false,
6
11
  "forceConsistentCasingInFileNames": true,
7
12
  "strict": true,
8
13
  "emitDecoratorMetadata": true,
9
14
  "experimentalDecorators": true
10
15
  },
11
- "files": [],
12
- "include": [],
13
- "references": [
14
- { "path": "./tsconfig.lib.json" },
15
- { "path": "./tsconfig.spec.json" }
16
- ]
16
+ "include": ["src/**/*.ts"],
17
+ "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"],
18
+ "nx": { "addTypecheckTarget": false }
17
19
  }
@@ -2,10 +2,9 @@
2
2
  "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
4
  "outDir": "./dist",
5
- "rootDir": "./src",
6
5
  "declaration": true,
7
6
  "types": ["node"]
8
7
  },
9
8
  "include": ["src/**/*.ts"],
10
- "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
9
+ "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"]
11
10
  }
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
- "outDir": "../../dist/out-tsc",
5
- "module": "commonjs",
6
- "moduleResolution": "NodeNext",
4
+ "outDir": "<%= offset %>dist/out-tsc",
7
5
  "types": ["jest", "node"]
8
6
  },
9
- "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
7
+ "include": ["src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"],
8
+ "exclude": []
10
9
  }
@@ -1,12 +1,21 @@
1
+ import { type Tree } from '@nx/devkit';
1
2
  import type { AppGeneratorSchema } from '../schema.js';
3
+ import { type ProjectModuleResolution } from '../../../utils/project-paths.js';
2
4
  export interface NormalizedAppOptions {
3
5
  name: string;
4
6
  projectName: string;
7
+ /** Project root relative to the Nx workspace root. */
5
8
  projectRoot: string;
9
+ /** Where the files are written, relative to the tree root. */
10
+ outputRoot: string;
11
+ /** Path from the project back to the workspace root, e.g. `../../`. */
12
+ offset: string;
13
+ moduleResolution: ProjectModuleResolution;
14
+ resetCustomConditions: boolean;
6
15
  className: string;
7
16
  fileName: string;
8
17
  propertyName: string;
9
18
  parsedTags: string[];
10
19
  skipFormat: boolean;
11
20
  }
12
- export declare function normalizeOptions(schema: AppGeneratorSchema): NormalizedAppOptions;
21
+ export declare function normalizeOptions(tree: Tree, schema: AppGeneratorSchema): NormalizedAppOptions;
@@ -2,14 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.normalizeOptions = normalizeOptions;
4
4
  const devkit_1 = require("@nx/devkit");
5
- function normalizeOptions(schema) {
5
+ const project_paths_js_1 = require("../../../utils/project-paths.js");
6
+ function normalizeOptions(tree, schema) {
6
7
  const { className, fileName, propertyName } = (0, devkit_1.names)(schema.name);
7
- const projectRoot = schema.directory ?? (0, devkit_1.joinPathFragments)('apps', fileName);
8
+ const outputRoot = schema.directory ?? (0, devkit_1.joinPathFragments)(schema.workspaceRoot ?? '', 'apps', fileName);
9
+ const { projectRoot, offset } = (0, project_paths_js_1.resolveProjectPaths)(outputRoot, schema.workspaceRoot);
8
10
  const parsedTags = schema.tags ? schema.tags.split(',').map((t) => t.trim()) : ['scope:apps'];
9
11
  return {
10
12
  name: schema.name,
11
13
  projectName: fileName,
12
14
  projectRoot,
15
+ outputRoot,
16
+ offset,
17
+ ...(0, project_paths_js_1.getProjectTsOptions)(tree, schema.workspaceRoot),
13
18
  className,
14
19
  fileName,
15
20
  propertyName,
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-options.js","sourceRoot":"","sources":["../../../../../src/generators/app/lib/normalize-options.ts"],"names":[],"mappings":";;AAcA,4CAeC;AA7BD,uCAAsD;AActD,SAAgB,gBAAgB,CAAC,MAA0B;IACzD,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAA,cAAK,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,IAAI,IAAA,0BAAiB,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5E,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAE9F,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,QAAQ;QACrB,WAAW;QACX,SAAS;QACT,QAAQ;QACR,YAAY;QACZ,UAAU;QACV,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,KAAK;KACvC,CAAC;AACJ,CAAC","sourcesContent":["import { names, joinPathFragments } from '@nx/devkit';\nimport type { AppGeneratorSchema } from '../schema.js';\n\nexport interface NormalizedAppOptions {\n name: string;\n projectName: string;\n projectRoot: string;\n className: string;\n fileName: string;\n propertyName: string;\n parsedTags: string[];\n skipFormat: boolean;\n}\n\nexport function normalizeOptions(schema: AppGeneratorSchema): NormalizedAppOptions {\n const { className, fileName, propertyName } = names(schema.name);\n const projectRoot = schema.directory ?? joinPathFragments('apps', fileName);\n const parsedTags = schema.tags ? schema.tags.split(',').map((t) => t.trim()) : ['scope:apps'];\n\n return {\n name: schema.name,\n projectName: fileName,\n projectRoot,\n className,\n fileName,\n propertyName,\n parsedTags,\n skipFormat: schema.skipFormat ?? false,\n };\n}\n"]}
1
+ {"version":3,"file":"normalize-options.js","sourceRoot":"","sources":["../../../../../src/generators/app/lib/normalize-options.ts"],"names":[],"mappings":";;AAsBA,4CAmBC;AAzCD,uCAAiE;AAEjE,sEAAyH;AAoBzH,SAAgB,gBAAgB,CAAC,IAAU,EAAE,MAA0B;IACrE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAA,cAAK,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,IAAI,IAAA,0BAAiB,EAAC,MAAM,CAAC,aAAa,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvG,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,IAAA,sCAAmB,EAAC,UAAU,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;IACtF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAE9F,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,QAAQ;QACrB,WAAW;QACX,UAAU;QACV,MAAM;QACN,GAAG,IAAA,sCAAmB,EAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC;QAClD,SAAS;QACT,QAAQ;QACR,YAAY;QACZ,UAAU;QACV,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,KAAK;KACvC,CAAC;AACJ,CAAC","sourcesContent":["import { type Tree, names, joinPathFragments } from '@nx/devkit';\nimport type { AppGeneratorSchema } from '../schema.js';\nimport { getProjectTsOptions, resolveProjectPaths, type ProjectModuleResolution } from '../../../utils/project-paths.js';\n\nexport interface NormalizedAppOptions {\n name: string;\n projectName: string;\n /** Project root relative to the Nx workspace root. */\n projectRoot: string;\n /** Where the files are written, relative to the tree root. */\n outputRoot: string;\n /** Path from the project back to the workspace root, e.g. `../../`. */\n offset: string;\n moduleResolution: ProjectModuleResolution;\n resetCustomConditions: boolean;\n className: string;\n fileName: string;\n propertyName: string;\n parsedTags: string[];\n skipFormat: boolean;\n}\n\nexport function normalizeOptions(tree: Tree, schema: AppGeneratorSchema): NormalizedAppOptions {\n const { className, fileName, propertyName } = names(schema.name);\n const outputRoot = schema.directory ?? joinPathFragments(schema.workspaceRoot ?? '', 'apps', fileName);\n const { projectRoot, offset } = resolveProjectPaths(outputRoot, schema.workspaceRoot);\n const parsedTags = schema.tags ? schema.tags.split(',').map((t) => t.trim()) : ['scope:apps'];\n\n return {\n name: schema.name,\n projectName: fileName,\n projectRoot,\n outputRoot,\n offset,\n ...getProjectTsOptions(tree, schema.workspaceRoot),\n className,\n fileName,\n propertyName,\n parsedTags,\n skipFormat: schema.skipFormat ?? false,\n };\n}\n"]}
@@ -1,6 +1,8 @@
1
1
  export interface AppGeneratorSchema {
2
2
  name: string;
3
3
  directory?: string;
4
+ /** Set when the tree root is above the Nx workspace (the `workspace` generator scaffolds into `<name>/`). */
5
+ workspaceRoot?: string;
4
6
  tags?: string;
5
7
  skipFormat?: boolean;
6
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/generators/app/schema.ts"],"names":[],"mappings":"","sourcesContent":["export interface AppGeneratorSchema {\n name: string;\n directory?: string;\n tags?: string;\n skipFormat?: boolean;\n}\n"]}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/generators/app/schema.ts"],"names":[],"mappings":"","sourcesContent":["export interface AppGeneratorSchema {\n name: string;\n directory?: string;\n /** Set when the tree root is above the Nx workspace (the `workspace` generator scaffolds into `<name>/`). */\n workspaceRoot?: string;\n tags?: string;\n skipFormat?: boolean;\n}\n"]}
@@ -17,6 +17,11 @@
17
17
  "description": "The directory of the application (default: apps/<name>)",
18
18
  "x-priority": "important"
19
19
  },
20
+ "workspaceRoot": {
21
+ "type": "string",
22
+ "description": "Folder of the Nx workspace when it is not the tree root",
23
+ "x-priority": "internal"
24
+ },
20
25
  "tags": {
21
26
  "type": "string",
22
27
  "description": "Comma-separated tags for the project",
@@ -2,7 +2,6 @@ import { AuthProvider } from '@frontmcp/sdk';
2
2
 
3
3
  @AuthProvider({
4
4
  name: '<%= name %>',
5
- type: '<%= authType %>',
6
5
  })
7
6
  export class <%= className %>AuthProvider {
8
7
  async headers(): Promise<Record<string, string>> {
@@ -1,31 +1,69 @@
1
- import { Flow, FlowBase } from '@frontmcp/sdk';
1
+ import { Flow, FlowBase, FlowHooksOf, z, type FlowPlan, type FlowRunOptions } from '@frontmcp/sdk';
2
+
3
+ const name = '<%= name %>' as const;
4
+
5
+ const inputSchema = z.object({
6
+ // TODO: describe the flow input
7
+ value: z.string().default(''),
8
+ });
9
+
10
+ const outputSchema = z.object({
11
+ // TODO: describe the flow output
12
+ result: z.string(),
13
+ });
14
+
15
+ const stateSchema = z.object({
16
+ result: z.string().default(''),
17
+ });
18
+
19
+ const plan = {
20
+ pre: ['pre'],
21
+ execute: ['execute'],
22
+ post: ['post'],
23
+ finalize: ['finalize'],
24
+ } as const satisfies FlowPlan<string>;
25
+
26
+ declare global {
27
+ interface ExtendFlows {
28
+ [name]: FlowRunOptions<
29
+ <%= className %>Flow,
30
+ typeof plan,
31
+ typeof inputSchema,
32
+ typeof outputSchema,
33
+ typeof stateSchema
34
+ >;
35
+ }
36
+ }
37
+
38
+ const { Stage } = FlowHooksOf<typeof name>(name);
2
39
 
3
40
  @Flow({
4
- name: '<%= name %>',
41
+ name,
5
42
  description: 'TODO: describe what this flow does',
6
- plan: {
7
- steps: ['pre', 'execute', 'post', 'finalize'],
8
- },
43
+ plan,
44
+ inputSchema,
45
+ outputSchema,
46
+ access: 'public',
9
47
  })
10
- export default class <%= className %>Flow extends FlowBase {
11
- async pre(): Promise<void> {
48
+ export default class <%= className %>Flow extends FlowBase<typeof name> {
49
+ @Stage('pre')
50
+ async pre() {
12
51
  // TODO: pre-processing logic
13
52
  }
14
53
 
15
- async execute(): Promise<void> {
54
+ @Stage('execute')
55
+ async execute() {
16
56
  // TODO: main execution logic
57
+ this.state.set('result', this.rawInput.value ?? '');
17
58
  }
18
59
 
19
- async post(): Promise<void> {
60
+ @Stage('post')
61
+ async post() {
20
62
  // TODO: post-processing logic
21
63
  }
22
64
 
23
- async finalize(): Promise<void> {
24
- // TODO: finalization logic
25
- }
26
-
27
- async error(err: Error): Promise<void> {
28
- // TODO: error handling logic
29
- throw err;
65
+ @Stage('finalize')
66
+ async finalize() {
67
+ this.respond({ result: this.state.result ?? '' });
30
68
  }
31
69
  }
@@ -0,0 +1,4 @@
1
+ import { type GeneratorCallback, type Tree } from '@nx/devkit';
2
+ import type { InitGeneratorSchema } from './schema.js';
3
+ export declare function initGenerator(tree: Tree, schema?: InitGeneratorSchema): Promise<GeneratorCallback>;
4
+ export default initGenerator;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initGenerator = initGenerator;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const add_dependencies_js_1 = require("../../utils/add-dependencies.js");
6
+ const versions_js_1 = require("../../utils/versions.js");
7
+ const CACHEABLE_EXECUTORS = ['@frontmcp/nx:build', '@frontmcp/nx:build-exec', '@frontmcp/nx:test'];
8
+ /**
9
+ * Executors are only cached when the target (or a `targetDefaults` entry for
10
+ * the executor) says so — Nx does not read that from the plugin itself.
11
+ */
12
+ function makeExecutorsCacheable(tree) {
13
+ const nxJson = (0, devkit_1.readNxJson)(tree);
14
+ if (!nxJson)
15
+ return;
16
+ const targetDefaults = nxJson.targetDefaults ?? {};
17
+ const inputs = nxJson.namedInputs?.['production'] ? ['production', '^production'] : undefined;
18
+ for (const executor of CACHEABLE_EXECUTORS) {
19
+ const existing = targetDefaults[executor];
20
+ targetDefaults[executor] = {
21
+ cache: true,
22
+ ...(executor !== '@frontmcp/nx:test' && { dependsOn: ['^build'] }),
23
+ ...(inputs && { inputs }),
24
+ ...existing,
25
+ };
26
+ }
27
+ (0, devkit_1.updateNxJson)(tree, { ...nxJson, targetDefaults });
28
+ }
29
+ async function initGenerator(tree, schema = {}) {
30
+ makeExecutorsCacheable(tree);
31
+ const installTask = schema.skipPackageJson
32
+ ? () => undefined
33
+ : (0, add_dependencies_js_1.addFrontmcpDependencies)(tree, { ...(0, versions_js_1.getFrontmcpDependencies)(), tslib: '^2.3.0' }, { ...(0, versions_js_1.getFrontmcpDevDependencies)(), ...(0, versions_js_1.getJestDevDependencies)() }, { keepExistingVersions: true });
34
+ if (!schema.skipFormat) {
35
+ await (0, devkit_1.formatFiles)(tree);
36
+ }
37
+ return installTask;
38
+ }
39
+ exports.default = initGenerator;
40
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../../src/generators/init/init.ts"],"names":[],"mappings":";;AAgCA,sCAiBC;AAjDD,uCAAsG;AAEtG,yEAA0E;AAC1E,yDAAsH;AAGtH,MAAM,mBAAmB,GAAG,CAAC,oBAAoB,EAAE,yBAAyB,EAAE,mBAAmB,CAAU,CAAC;AAE5G;;;GAGG;AACH,SAAS,sBAAsB,CAAC,IAAU;IACxC,MAAM,MAAM,GAAG,IAAA,mBAAU,EAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM;QAAE,OAAO;IAEpB,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC;IACnD,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE9F,KAAK,MAAM,QAAQ,IAAI,mBAAmB,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC1C,cAAc,CAAC,QAAQ,CAAC,GAAG;YACzB,KAAK,EAAE,IAAI;YACX,GAAG,CAAC,QAAQ,KAAK,mBAAmB,IAAI,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClE,GAAG,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC;YACzB,GAAG,QAAQ;SACZ,CAAC;IACJ,CAAC;IAED,IAAA,qBAAY,EAAC,IAAI,EAAE,EAAE,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;AACpD,CAAC;AAEM,KAAK,UAAU,aAAa,CAAC,IAAU,EAAE,SAA8B,EAAE;IAC9E,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAE7B,MAAM,WAAW,GAAG,MAAM,CAAC,eAAe;QACxC,CAAC,CAAC,GAAG,EAAE,CAAC,SAAS;QACjB,CAAC,CAAC,IAAA,6CAAuB,EACrB,IAAI,EACJ,EAAE,GAAG,IAAA,qCAAuB,GAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EACjD,EAAE,GAAG,IAAA,wCAA0B,GAAE,EAAE,GAAG,IAAA,oCAAsB,GAAE,EAAE,EAChE,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAC/B,CAAC;IAEN,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,kBAAe,aAAa,CAAC","sourcesContent":["import { formatFiles, readNxJson, updateNxJson, type GeneratorCallback, type Tree } from '@nx/devkit';\n\nimport { addFrontmcpDependencies } from '../../utils/add-dependencies.js';\nimport { getFrontmcpDependencies, getFrontmcpDevDependencies, getJestDevDependencies } from '../../utils/versions.js';\nimport type { InitGeneratorSchema } from './schema.js';\n\nconst CACHEABLE_EXECUTORS = ['@frontmcp/nx:build', '@frontmcp/nx:build-exec', '@frontmcp/nx:test'] as const;\n\n/**\n * Executors are only cached when the target (or a `targetDefaults` entry for\n * the executor) says so — Nx does not read that from the plugin itself.\n */\nfunction makeExecutorsCacheable(tree: Tree): void {\n const nxJson = readNxJson(tree);\n if (!nxJson) return;\n\n const targetDefaults = nxJson.targetDefaults ?? {};\n const inputs = nxJson.namedInputs?.['production'] ? ['production', '^production'] : undefined;\n\n for (const executor of CACHEABLE_EXECUTORS) {\n const existing = targetDefaults[executor];\n targetDefaults[executor] = {\n cache: true,\n ...(executor !== '@frontmcp/nx:test' && { dependsOn: ['^build'] }),\n ...(inputs && { inputs }),\n ...existing,\n };\n }\n\n updateNxJson(tree, { ...nxJson, targetDefaults });\n}\n\nexport async function initGenerator(tree: Tree, schema: InitGeneratorSchema = {}): Promise<GeneratorCallback> {\n makeExecutorsCacheable(tree);\n\n const installTask = schema.skipPackageJson\n ? () => undefined\n : addFrontmcpDependencies(\n tree,\n { ...getFrontmcpDependencies(), tslib: '^2.3.0' },\n { ...getFrontmcpDevDependencies(), ...getJestDevDependencies() },\n { keepExistingVersions: true },\n );\n\n if (!schema.skipFormat) {\n await formatFiles(tree);\n }\n\n return installTask;\n}\n\nexport default initGenerator;\n"]}
@@ -0,0 +1,4 @@
1
+ export interface InitGeneratorSchema {
2
+ skipPackageJson?: boolean;
3
+ skipFormat?: boolean;
4
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/generators/init/schema.ts"],"names":[],"mappings":"","sourcesContent":["export interface InitGeneratorSchema {\n skipPackageJson?: boolean;\n skipFormat?: boolean;\n}\n"]}
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "FrontMcpInit",
4
+ "title": "FrontMCP Init Generator",
5
+ "description": "Prepare an existing Nx workspace for FrontMCP: install the FrontMCP packages and make the executors cacheable",
6
+ "type": "object",
7
+ "properties": {
8
+ "skipPackageJson": {
9
+ "type": "boolean",
10
+ "description": "Do not add FrontMCP dependencies to package.json",
11
+ "default": false
12
+ },
13
+ "skipFormat": {
14
+ "type": "boolean",
15
+ "description": "Skip formatting files",
16
+ "default": false,
17
+ "x-priority": "internal"
18
+ }
19
+ },
20
+ "required": []
21
+ }
@@ -0,0 +1,9 @@
1
+ import { <%= className %>Adapter } from './<%= fileName %>.adapter';
2
+
3
+ describe('<%= className %>Adapter', () => {
4
+ it('returns no tools, resources or prompts yet', async () => {
5
+ const adapter = new <%= className %>Adapter({ name: '<%= fileName %>' });
6
+
7
+ await expect(adapter.fetch()).resolves.toEqual({ tools: [], resources: [], prompts: [] });
8
+ });
9
+ });
@@ -0,0 +1,7 @@
1
+ import { <%= className %> } from './<%= fileName %>';
2
+
3
+ describe('<%= className %>', () => {
4
+ it('greets by name', () => {
5
+ expect(new <%= className %>().greet('Ada')).toBe('Hello from <%= className %>, Ada!');
6
+ });
7
+ });
@@ -0,0 +1,11 @@
1
+ import { <%= className %>Plugin } from './<%= fileName %>.plugin';
2
+
3
+ describe('<%= className %>Plugin', () => {
4
+ it('keeps the options it is created with', () => {
5
+ expect(new <%= className %>Plugin({}).options).toEqual({});
6
+ });
7
+
8
+ it('contributes no providers yet', () => {
9
+ expect(<%= className %>Plugin.dynamicProviders({})).toEqual([]);
10
+ });
11
+ });
@@ -0,0 +1,14 @@
1
+ import { ExampleTool, <%= className %>Tools } from './<%= fileName %>.tools';
2
+
3
+ describe('<%= className %>Tools', () => {
4
+ it('registers the example tool', () => {
5
+ expect(<%= className %>Tools).toContain(ExampleTool);
6
+ });
7
+
8
+ it('echoes the value', async () => {
9
+ // execute() holds the tool's logic; build the tool without the request context the server injects.
10
+ const tool: ExampleTool = Object.create(ExampleTool.prototype);
11
+
12
+ await expect(tool.execute({ value: 'ping' })).resolves.toEqual({ result: 'ping' });
13
+ });
14
+ });
@@ -1,8 +1,13 @@
1
+ import { type Tree } from '@nx/devkit';
1
2
  import type { LibGeneratorSchema } from '../schema.js';
3
+ import { type ProjectModuleResolution } from '../../../utils/project-paths.js';
2
4
  export interface NormalizedLibOptions {
3
5
  name: string;
4
6
  projectName: string;
5
7
  projectRoot: string;
8
+ offset: string;
9
+ moduleResolution: ProjectModuleResolution;
10
+ resetCustomConditions: boolean;
6
11
  className: string;
7
12
  fileName: string;
8
13
  propertyName: string;
@@ -12,4 +17,4 @@ export interface NormalizedLibOptions {
12
17
  parsedTags: string[];
13
18
  skipFormat: boolean;
14
19
  }
15
- export declare function normalizeOptions(schema: LibGeneratorSchema): NormalizedLibOptions;
20
+ export declare function normalizeOptions(tree: Tree, schema: LibGeneratorSchema): NormalizedLibOptions;
@@ -2,9 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.normalizeOptions = normalizeOptions;
4
4
  const devkit_1 = require("@nx/devkit");
5
- function normalizeOptions(schema) {
5
+ const project_paths_js_1 = require("../../../utils/project-paths.js");
6
+ function normalizeOptions(tree, schema) {
6
7
  const { className, fileName, propertyName } = (0, devkit_1.names)(schema.name);
7
- const projectRoot = schema.directory ?? (0, devkit_1.joinPathFragments)('libs', fileName);
8
+ const { projectRoot, offset } = (0, project_paths_js_1.resolveProjectPaths)(schema.directory ?? (0, devkit_1.joinPathFragments)('libs', fileName));
8
9
  const libType = schema.libType ?? 'generic';
9
10
  const publishable = schema.publishable ?? false;
10
11
  const importPath = schema.importPath ?? `@frontmcp/${fileName}`;
@@ -18,6 +19,8 @@ function normalizeOptions(schema) {
18
19
  name: schema.name,
19
20
  projectName: fileName,
20
21
  projectRoot,
22
+ offset,
23
+ ...(0, project_paths_js_1.getProjectTsOptions)(tree),
21
24
  className,
22
25
  fileName,
23
26
  propertyName,
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-options.js","sourceRoot":"","sources":["../../../../../src/generators/lib/lib/normalize-options.ts"],"names":[],"mappings":";;AAiBA,4CA2BC;AA5CD,uCAAsD;AAiBtD,SAAgB,gBAAgB,CAAC,MAA0B;IACzD,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAA,cAAK,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,IAAI,IAAA,0BAAiB,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5E,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,SAAS,CAAC;IAC5C,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,KAAK,CAAC;IAChD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,aAAa,QAAQ,EAAE,CAAC;IAChE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI;QAC5B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAEnB,IAAI,WAAW,EAAE,CAAC;QAChB,UAAU,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACvC,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,QAAQ;QACrB,WAAW;QACX,SAAS;QACT,QAAQ;QACR,YAAY;QACZ,OAAO;QACP,WAAW;QACX,UAAU;QACV,UAAU;QACV,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,KAAK;KACvC,CAAC;AACJ,CAAC","sourcesContent":["import { names, joinPathFragments } from '@nx/devkit';\nimport type { LibGeneratorSchema } from '../schema.js';\n\nexport interface NormalizedLibOptions {\n name: string;\n projectName: string;\n projectRoot: string;\n className: string;\n fileName: string;\n propertyName: string;\n libType: 'generic' | 'plugin' | 'adapter' | 'tool-register';\n publishable: boolean;\n importPath: string;\n parsedTags: string[];\n skipFormat: boolean;\n}\n\nexport function normalizeOptions(schema: LibGeneratorSchema): NormalizedLibOptions {\n const { className, fileName, propertyName } = names(schema.name);\n const projectRoot = schema.directory ?? joinPathFragments('libs', fileName);\n const libType = schema.libType ?? 'generic';\n const publishable = schema.publishable ?? false;\n const importPath = schema.importPath ?? `@frontmcp/${fileName}`;\n const parsedTags = schema.tags\n ? schema.tags.split(',').map((t) => t.trim())\n : ['scope:libs'];\n\n if (publishable) {\n parsedTags.push('scope:publishable');\n }\n\n return {\n name: schema.name,\n projectName: fileName,\n projectRoot,\n className,\n fileName,\n propertyName,\n libType,\n publishable,\n importPath,\n parsedTags,\n skipFormat: schema.skipFormat ?? false,\n };\n}\n"]}
1
+ {"version":3,"file":"normalize-options.js","sourceRoot":"","sources":["../../../../../src/generators/lib/lib/normalize-options.ts"],"names":[],"mappings":";;AAqBA,4CA6BC;AAlDD,uCAAiE;AAEjE,sEAAyH;AAmBzH,SAAgB,gBAAgB,CAAC,IAAU,EAAE,MAA0B;IACrE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAA,cAAK,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,IAAA,sCAAmB,EAAC,MAAM,CAAC,SAAS,IAAI,IAAA,0BAAiB,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC7G,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,SAAS,CAAC;IAC5C,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,KAAK,CAAC;IAChD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,aAAa,QAAQ,EAAE,CAAC;IAChE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI;QAC5B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAEnB,IAAI,WAAW,EAAE,CAAC;QAChB,UAAU,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACvC,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,QAAQ;QACrB,WAAW;QACX,MAAM;QACN,GAAG,IAAA,sCAAmB,EAAC,IAAI,CAAC;QAC5B,SAAS;QACT,QAAQ;QACR,YAAY;QACZ,OAAO;QACP,WAAW;QACX,UAAU;QACV,UAAU;QACV,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,KAAK;KACvC,CAAC;AACJ,CAAC","sourcesContent":["import { type Tree, names, joinPathFragments } from '@nx/devkit';\nimport type { LibGeneratorSchema } from '../schema.js';\nimport { getProjectTsOptions, resolveProjectPaths, type ProjectModuleResolution } from '../../../utils/project-paths.js';\n\nexport interface NormalizedLibOptions {\n name: string;\n projectName: string;\n projectRoot: string;\n offset: string;\n moduleResolution: ProjectModuleResolution;\n resetCustomConditions: boolean;\n className: string;\n fileName: string;\n propertyName: string;\n libType: 'generic' | 'plugin' | 'adapter' | 'tool-register';\n publishable: boolean;\n importPath: string;\n parsedTags: string[];\n skipFormat: boolean;\n}\n\nexport function normalizeOptions(tree: Tree, schema: LibGeneratorSchema): NormalizedLibOptions {\n const { className, fileName, propertyName } = names(schema.name);\n const { projectRoot, offset } = resolveProjectPaths(schema.directory ?? joinPathFragments('libs', fileName));\n const libType = schema.libType ?? 'generic';\n const publishable = schema.publishable ?? false;\n const importPath = schema.importPath ?? `@frontmcp/${fileName}`;\n const parsedTags = schema.tags\n ? schema.tags.split(',').map((t) => t.trim())\n : ['scope:libs'];\n\n if (publishable) {\n parsedTags.push('scope:publishable');\n }\n\n return {\n name: schema.name,\n projectName: fileName,\n projectRoot,\n offset,\n ...getProjectTsOptions(tree),\n className,\n fileName,\n propertyName,\n libType,\n publishable,\n importPath,\n parsedTags,\n skipFormat: schema.skipFormat ?? false,\n };\n}\n"]}