@agiflowai/scaffold-mcp 1.0.0 → 1.0.2

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.
@@ -1,14 +1,13 @@
1
1
  import { ScaffoldConfigLoader } from "./ScaffoldConfigLoader-CI0T6zdG.js";
2
- import { ScaffoldService } from "./ScaffoldService-QgQKHMM-.js";
2
+ import { ScaffoldService } from "./ScaffoldService-DB7-Cyod.js";
3
3
  import { TemplateService } from "./TemplateService-CiZJA06s.js";
4
- import { VariableReplacementService } from "./VariableReplacementService-B3qARIC9.js";
4
+ import { VariableReplacementService } from "./VariableReplacementService-DRxd9ILB.js";
5
+ import { ProjectConfigResolver, log } from "@agiflowai/aicode-utils";
5
6
  import * as path$1 from "node:path";
6
7
  import path from "node:path";
7
- import { ProjectConfigResolver, log } from "@agiflowai/aicode-utils";
8
+ import { jsonSchemaToZod } from "@composio/json-schema-to-zod";
8
9
  import * as fs$1 from "fs-extra";
9
10
  import fs from "fs-extra";
10
- import { execa } from "execa";
11
- import { jsonSchemaToZod } from "@composio/json-schema-to-zod";
12
11
  import * as yaml$1 from "js-yaml";
13
12
  import yaml from "js-yaml";
14
13
  import { z } from "zod";
@@ -19,133 +18,6 @@ import express from "express";
19
18
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
20
19
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
21
20
 
22
- //#region src/utils/git.ts
23
- /**
24
- * Execute a git command safely using execa to prevent command injection
25
- */
26
- async function execGit(args, cwd) {
27
- try {
28
- await execa("git", args, { cwd });
29
- } catch (error) {
30
- const execaError = error;
31
- throw new Error(`Git command failed: ${execaError.stderr || execaError.message}`);
32
- }
33
- }
34
- /**
35
- * Find the workspace root by searching upwards for .git folder
36
- * Returns null if no .git folder is found (indicating a new project setup is needed)
37
- */
38
- async function findWorkspaceRoot(startPath = process.cwd()) {
39
- let currentPath = path.resolve(startPath);
40
- const rootPath = path.parse(currentPath).root;
41
- while (true) {
42
- const gitPath = path.join(currentPath, ".git");
43
- if (await fs$1.pathExists(gitPath)) return currentPath;
44
- if (currentPath === rootPath) return null;
45
- currentPath = path.dirname(currentPath);
46
- }
47
- }
48
- /**
49
- * Parse GitHub URL to detect if it's a subdirectory
50
- * Supports formats:
51
- * - https://github.com/user/repo
52
- * - https://github.com/user/repo/tree/branch/path/to/dir
53
- * - https://github.com/user/repo/tree/main/path/to/dir
54
- */
55
- function parseGitHubUrl(url) {
56
- const treeMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)$/);
57
- const blobMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)\/(.+)$/);
58
- const rootMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
59
- if (treeMatch || blobMatch) {
60
- const match = treeMatch || blobMatch;
61
- return {
62
- owner: match[1],
63
- repo: match[2],
64
- repoUrl: `https://github.com/${match[1]}/${match[2]}.git`,
65
- branch: match[3],
66
- subdirectory: match[4],
67
- isSubdirectory: true
68
- };
69
- }
70
- if (rootMatch) return {
71
- owner: rootMatch[1],
72
- repo: rootMatch[2],
73
- repoUrl: `https://github.com/${rootMatch[1]}/${rootMatch[2]}.git`,
74
- isSubdirectory: false
75
- };
76
- return {
77
- repoUrl: url,
78
- isSubdirectory: false
79
- };
80
- }
81
- /**
82
- * Clone a subdirectory from a git repository using sparse checkout
83
- */
84
- async function cloneSubdirectory(repoUrl, branch, subdirectory, targetFolder) {
85
- const tempFolder = `${targetFolder}.tmp`;
86
- try {
87
- await execGit(["init", tempFolder]);
88
- await execGit([
89
- "remote",
90
- "add",
91
- "origin",
92
- repoUrl
93
- ], tempFolder);
94
- await execGit([
95
- "config",
96
- "core.sparseCheckout",
97
- "true"
98
- ], tempFolder);
99
- const sparseCheckoutFile = path.join(tempFolder, ".git", "info", "sparse-checkout");
100
- await fs$1.writeFile(sparseCheckoutFile, `${subdirectory}\n`);
101
- await execGit([
102
- "pull",
103
- "--depth=1",
104
- "origin",
105
- branch
106
- ], tempFolder);
107
- const sourceDir = path.join(tempFolder, subdirectory);
108
- if (!await fs$1.pathExists(sourceDir)) throw new Error(`Subdirectory '${subdirectory}' not found in repository at branch '${branch}'`);
109
- if (await fs$1.pathExists(targetFolder)) throw new Error(`Target folder already exists: ${targetFolder}`);
110
- await fs$1.move(sourceDir, targetFolder);
111
- await fs$1.remove(tempFolder);
112
- } catch (error) {
113
- if (await fs$1.pathExists(tempFolder)) await fs$1.remove(tempFolder);
114
- throw error;
115
- }
116
- }
117
- /**
118
- * Clone entire repository
119
- */
120
- async function cloneRepository(repoUrl, targetFolder) {
121
- await execGit([
122
- "clone",
123
- repoUrl,
124
- targetFolder
125
- ]);
126
- const gitFolder = path.join(targetFolder, ".git");
127
- if (await fs$1.pathExists(gitFolder)) await fs$1.remove(gitFolder);
128
- }
129
- /**
130
- * Fetch directory listing from GitHub API
131
- */
132
- async function fetchGitHubDirectoryContents(owner, repo, path$2, branch = "main") {
133
- const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path$2}?ref=${branch}`;
134
- const response = await fetch(url, { headers: {
135
- Accept: "application/vnd.github.v3+json",
136
- "User-Agent": "scaffold-mcp"
137
- } });
138
- if (!response.ok) throw new Error(`Failed to fetch directory contents: ${response.statusText}`);
139
- const data = await response.json();
140
- if (!Array.isArray(data)) throw new Error("Expected directory but got file");
141
- return data.map((item) => ({
142
- name: item.name,
143
- type: item.type,
144
- path: item.path
145
- }));
146
- }
147
-
148
- //#endregion
149
21
  //#region src/services/FileSystemService.ts
150
22
  var FileSystemService = class {
151
23
  async pathExists(path$2) {
@@ -242,7 +114,28 @@ var BoilerplateService = class {
242
114
  * Executes a specific boilerplate with provided variables
243
115
  */
244
116
  async useBoilerplate(request) {
245
- const { boilerplateName, variables, monolith = false, targetFolderOverride } = request;
117
+ let { boilerplateName, variables, monolith, targetFolderOverride } = request;
118
+ if (monolith === void 0) try {
119
+ const config = await ProjectConfigResolver.resolveProjectConfig(process.cwd());
120
+ monolith = config.type === "monolith";
121
+ log.info(`Auto-detected project type: ${config.type}`);
122
+ } catch (_error) {
123
+ monolith = false;
124
+ log.info("No project configuration found, defaulting to monorepo mode");
125
+ }
126
+ if (monolith && !boilerplateName) try {
127
+ boilerplateName = (await ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
128
+ log.info(`Using boilerplate from toolkit.yaml: ${boilerplateName}`);
129
+ } catch (error) {
130
+ return {
131
+ success: false,
132
+ message: `Failed to read boilerplate name from toolkit.yaml: ${error instanceof Error ? error.message : String(error)}`
133
+ };
134
+ }
135
+ if (!boilerplateName) return {
136
+ success: false,
137
+ message: "Missing required parameter: boilerplateName"
138
+ };
246
139
  const boilerplateList = await this.listBoilerplates();
247
140
  const boilerplate = boilerplateList.boilerplates.find((b) => b.name === boilerplateName);
248
141
  if (!boilerplate) return {
@@ -261,9 +154,10 @@ var BoilerplateService = class {
261
154
  };
262
155
  const folderName = packageName.includes("/") ? packageName.split("/")[1] : packageName;
263
156
  const targetFolder = targetFolderOverride || (monolith ? "." : boilerplate.target_folder);
157
+ const projectNameForPath = monolith ? "" : folderName;
264
158
  try {
265
159
  const result = await this.scaffoldService.useBoilerplate({
266
- projectName: folderName,
160
+ projectName: projectNameForPath,
267
161
  packageName,
268
162
  targetFolder,
269
163
  templateFolder: boilerplate.template_path,
@@ -509,44 +403,28 @@ var BoilerplateGeneratorService = class {
509
403
  var GenerateBoilerplateFileTool = class GenerateBoilerplateFileTool {
510
404
  static TOOL_NAME = "generate-boilerplate-file";
511
405
  boilerplateGeneratorService;
512
- constructor(templatesPath) {
406
+ isMonolith;
407
+ constructor(templatesPath, isMonolith = false) {
513
408
  this.boilerplateGeneratorService = new BoilerplateGeneratorService(templatesPath);
409
+ this.isMonolith = isMonolith;
514
410
  }
515
411
  /**
516
412
  * Get the tool definition for MCP
517
413
  */
518
414
  getDefinition() {
519
- return {
520
- name: GenerateBoilerplateFileTool.TOOL_NAME,
521
- description: `Create or update template files for boilerplates or features in the specified template directory.
522
-
523
- This tool:
524
- - Creates template files with .liquid extension for variable substitution
525
- - Supports creating nested directory structures
526
- - Can create files from source files (copying and converting to templates)
527
- - Validates that the template directory exists
528
- - Works for both boilerplate includes and feature scaffold includes
529
-
530
- IMPORTANT - Always add header comments:
531
- - For code files (*.ts, *.tsx, *.js, *.jsx), ALWAYS include a header parameter with design patterns, coding standards, and things to avoid
532
- - Headers help AI understand and follow established patterns when working with generated code
533
- - Use the header parameter to document the architectural decisions and best practices
534
-
535
- Use this after generate-boilerplate or generate-feature-scaffold to create the actual template files referenced in the includes array.`,
536
- inputSchema: {
537
- type: "object",
538
- properties: {
539
- templateName: {
540
- type: "string",
541
- description: "Name of the template folder (must already exist)"
542
- },
543
- filePath: {
544
- type: "string",
545
- description: "Path of the file to create within the template (e.g., \"package.json\", \"src/app/page.tsx\")"
546
- },
547
- content: {
548
- type: "string",
549
- description: `Content of the template file using Liquid template syntax.
415
+ const properties = {};
416
+ if (!this.isMonolith) properties.templateName = {
417
+ type: "string",
418
+ description: "Name of the template folder (must already exist)"
419
+ };
420
+ Object.assign(properties, {
421
+ filePath: {
422
+ type: "string",
423
+ description: "Path of the file to create within the template (e.g., \"package.json\", \"src/app/page.tsx\")"
424
+ },
425
+ content: {
426
+ type: "string",
427
+ description: `Content of the template file using Liquid template syntax.
550
428
 
551
429
  LIQUID SYNTAX:
552
430
  - Variables: {{ variableName }} - Replaced with actual values
@@ -615,14 +493,14 @@ export function calculateTax(income: number) {
615
493
  const stateRate = 0.05;
616
494
  return income * (federalRate + stateRate);
617
495
  }`
618
- },
619
- sourceFile: {
620
- type: "string",
621
- description: "Optional: Path to a source file to copy and convert to a template"
622
- },
623
- header: {
624
- type: "string",
625
- description: `Optional: Header comment to add at the top of the file to provide AI hints about design patterns, coding standards, and best practices.
496
+ },
497
+ sourceFile: {
498
+ type: "string",
499
+ description: "Optional: Path to a source file to copy and convert to a template"
500
+ },
501
+ header: {
502
+ type: "string",
503
+ description: `Optional: Header comment to add at the top of the file to provide AI hints about design patterns, coding standards, and best practices.
626
504
 
627
505
  Example format for TypeScript/JavaScript files:
628
506
  /**
@@ -642,9 +520,31 @@ Example format for TypeScript/JavaScript files:
642
520
  */
643
521
 
644
522
  The header helps AI understand and follow established patterns when working with generated code.`
645
- }
646
- },
647
- required: ["templateName", "filePath"],
523
+ }
524
+ });
525
+ const required = ["filePath"];
526
+ if (!this.isMonolith) required.unshift("templateName");
527
+ return {
528
+ name: GenerateBoilerplateFileTool.TOOL_NAME,
529
+ description: `Create or update template files for boilerplates or features in the specified template directory.
530
+
531
+ This tool:
532
+ - Creates template files with .liquid extension for variable substitution
533
+ - Supports creating nested directory structures
534
+ - Can create files from source files (copying and converting to templates)
535
+ - Validates that the template directory exists
536
+ - Works for both boilerplate includes and feature scaffold includes
537
+
538
+ IMPORTANT - Always add header comments:
539
+ - For code files (*.ts, *.tsx, *.js, *.jsx), ALWAYS include a header parameter with design patterns, coding standards, and things to avoid
540
+ - Headers help AI understand and follow established patterns when working with generated code
541
+ - Use the header parameter to document the architectural decisions and best practices
542
+
543
+ Use this after generate-boilerplate or generate-feature-scaffold to create the actual template files referenced in the includes array.`,
544
+ inputSchema: {
545
+ type: "object",
546
+ properties,
547
+ required,
648
548
  additionalProperties: false
649
549
  }
650
550
  };
@@ -654,7 +554,29 @@ The header helps AI understand and follow established patterns when working with
654
554
  */
655
555
  async execute(args) {
656
556
  try {
657
- const result = await this.boilerplateGeneratorService.createTemplateFile(args);
557
+ let { templateName } = args;
558
+ if (this.isMonolith && !templateName) try {
559
+ templateName = (await ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
560
+ } catch (error) {
561
+ return {
562
+ content: [{
563
+ type: "text",
564
+ text: `Failed to read template name from configuration: ${error instanceof Error ? error.message : String(error)}`
565
+ }],
566
+ isError: true
567
+ };
568
+ }
569
+ if (!templateName) return {
570
+ content: [{
571
+ type: "text",
572
+ text: "Missing required parameter: templateName"
573
+ }],
574
+ isError: true
575
+ };
576
+ const result = await this.boilerplateGeneratorService.createTemplateFile({
577
+ ...args,
578
+ templateName
579
+ });
658
580
  if (!result.success) return {
659
581
  content: [{
660
582
  type: "text",
@@ -692,42 +614,32 @@ The header helps AI understand and follow established patterns when working with
692
614
  var GenerateBoilerplateTool = class GenerateBoilerplateTool {
693
615
  static TOOL_NAME = "generate-boilerplate";
694
616
  boilerplateGeneratorService;
695
- constructor(templatesPath) {
617
+ isMonolith;
618
+ constructor(templatesPath, isMonolith = false) {
696
619
  this.boilerplateGeneratorService = new BoilerplateGeneratorService(templatesPath);
620
+ this.isMonolith = isMonolith;
697
621
  }
698
622
  /**
699
623
  * Get the tool definition for MCP
700
624
  */
701
625
  getDefinition() {
702
- return {
703
- name: GenerateBoilerplateTool.TOOL_NAME,
704
- description: `Add a new boilerplate configuration to a template's scaffold.yaml file.
705
-
706
- This tool:
707
- - Creates or updates scaffold.yaml in the specified template directory
708
- - Adds a boilerplate entry with proper schema following the nextjs-15 pattern
709
- - Validates the boilerplate name doesn't already exist
710
- - Creates the template directory if it doesn't exist
711
-
712
- Use this to add custom boilerplate configurations for frameworks not yet supported or for your specific project needs.`,
713
- inputSchema: {
714
- type: "object",
715
- properties: {
716
- templateName: {
717
- type: "string",
718
- description: "Name of the template folder (kebab-case, e.g., \"my-framework\")"
719
- },
720
- boilerplateName: {
721
- type: "string",
722
- description: "Name of the boilerplate (kebab-case, e.g., \"scaffold-my-app\")"
723
- },
724
- targetFolder: {
725
- type: "string",
726
- description: "Target folder where projects will be created (e.g., \"apps\", \"packages\")"
727
- },
728
- description: {
729
- type: "string",
730
- description: `Detailed description of what this boilerplate creates and its key features.
626
+ const properties = {};
627
+ if (!this.isMonolith) properties.templateName = {
628
+ type: "string",
629
+ description: "Name of the template folder (kebab-case, e.g., \"my-framework\")"
630
+ };
631
+ Object.assign(properties, {
632
+ boilerplateName: {
633
+ type: "string",
634
+ description: "Name of the boilerplate (kebab-case, e.g., \"scaffold-my-app\")"
635
+ },
636
+ targetFolder: {
637
+ type: "string",
638
+ description: "Target folder where projects will be created (e.g., \"apps\", \"packages\")"
639
+ },
640
+ description: {
641
+ type: "string",
642
+ description: `Detailed description of what this boilerplate creates and its key features.
731
643
 
732
644
  STRUCTURE (3-5 sentences in multiple paragraphs):
733
645
  - Paragraph 1: Core technology stack and primary value proposition
@@ -738,10 +650,10 @@ Example: "A modern React SPA template powered by Vite for lightning-fast HMR, fe
738
650
  Perfect for building data-driven dashboards, admin panels, and interactive web applications requiring client-side routing and real-time data synchronization.
739
651
 
740
652
  Includes Agiflow Config Management System integration with systematic environment variable naming (VITE_{CATEGORY}_{SUBCATEGORY}_{PROPERTY}) and auto-generated configuration templates for cloud deployment."`
741
- },
742
- instruction: {
743
- type: "string",
744
- description: `Optional detailed instructions about the generated files, their purposes, and how to work with them.
653
+ },
654
+ instruction: {
655
+ type: "string",
656
+ description: `Optional detailed instructions about the generated files, their purposes, and how to work with them.
745
657
 
746
658
  STRUCTURE (Multi-section guide):
747
659
 
@@ -785,47 +697,47 @@ Design patterns to follow:
785
697
  - Type-safe Routes: Leverage [framework] type inference for params
786
698
  - State Management: Use [library] for server state, [library] for client state
787
699
  [... list key patterns with explanations ...]"`
700
+ },
701
+ variables: {
702
+ type: "array",
703
+ description: "Array of variable definitions for the boilerplate",
704
+ items: {
705
+ type: "object",
706
+ properties: {
707
+ name: {
708
+ type: "string",
709
+ description: "Variable name (camelCase)"
710
+ },
711
+ description: {
712
+ type: "string",
713
+ description: "Variable description"
714
+ },
715
+ type: {
716
+ type: "string",
717
+ enum: [
718
+ "string",
719
+ "number",
720
+ "boolean"
721
+ ],
722
+ description: "Variable type"
723
+ },
724
+ required: {
725
+ type: "boolean",
726
+ description: "Whether this variable is required"
727
+ },
728
+ default: { description: "Optional default value for the variable" }
788
729
  },
789
- variables: {
790
- type: "array",
791
- description: "Array of variable definitions for the boilerplate",
792
- items: {
793
- type: "object",
794
- properties: {
795
- name: {
796
- type: "string",
797
- description: "Variable name (camelCase)"
798
- },
799
- description: {
800
- type: "string",
801
- description: "Variable description"
802
- },
803
- type: {
804
- type: "string",
805
- enum: [
806
- "string",
807
- "number",
808
- "boolean"
809
- ],
810
- description: "Variable type"
811
- },
812
- required: {
813
- type: "boolean",
814
- description: "Whether this variable is required"
815
- },
816
- default: { description: "Optional default value for the variable" }
817
- },
818
- required: [
819
- "name",
820
- "description",
821
- "type",
822
- "required"
823
- ]
824
- }
825
- },
826
- includes: {
827
- type: "array",
828
- description: `Array of specific file paths to include in the boilerplate (highly recommended to list explicitly).
730
+ required: [
731
+ "name",
732
+ "description",
733
+ "type",
734
+ "required"
735
+ ]
736
+ }
737
+ },
738
+ includes: {
739
+ type: "array",
740
+ description: `Array of specific file paths to include in the boilerplate (highly recommended to list explicitly).
829
741
 
830
742
  Examples:
831
743
  - ["package.json", "tsconfig.json", "src/index.ts"] - Explicit file list (recommended)
@@ -839,16 +751,33 @@ Best practices:
839
751
  - Avoid wildcards unless you have a good reason
840
752
 
841
753
  See templates/nextjs-15/scaffold.yaml for a good example of explicit file listing.`,
842
- items: { type: "string" }
843
- }
844
- },
845
- required: [
846
- "templateName",
847
- "boilerplateName",
848
- "description",
849
- "targetFolder",
850
- "variables"
851
- ],
754
+ items: { type: "string" }
755
+ }
756
+ });
757
+ const required = [
758
+ "boilerplateName",
759
+ "description",
760
+ "variables"
761
+ ];
762
+ if (!this.isMonolith) {
763
+ required.unshift("templateName");
764
+ required.push("targetFolder");
765
+ }
766
+ return {
767
+ name: GenerateBoilerplateTool.TOOL_NAME,
768
+ description: `Add a new boilerplate configuration to a template's scaffold.yaml file.
769
+
770
+ This tool:
771
+ - Creates or updates scaffold.yaml in the specified template directory
772
+ - Adds a boilerplate entry with proper schema following the nextjs-15 pattern
773
+ - Validates the boilerplate name doesn't already exist
774
+ - Creates the template directory if it doesn't exist
775
+
776
+ Use this to add custom boilerplate configurations for frameworks not yet supported or for your specific project needs.`,
777
+ inputSchema: {
778
+ type: "object",
779
+ properties,
780
+ required,
852
781
  additionalProperties: false
853
782
  }
854
783
  };
@@ -858,7 +787,38 @@ See templates/nextjs-15/scaffold.yaml for a good example of explicit file listin
858
787
  */
859
788
  async execute(args) {
860
789
  try {
861
- const result = await this.boilerplateGeneratorService.generateBoilerplate(args);
790
+ let { templateName, targetFolder } = args;
791
+ if (this.isMonolith && !templateName) try {
792
+ templateName = (await ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
793
+ } catch (error) {
794
+ return {
795
+ content: [{
796
+ type: "text",
797
+ text: `Failed to read template name from configuration: ${error instanceof Error ? error.message : String(error)}`
798
+ }],
799
+ isError: true
800
+ };
801
+ }
802
+ if (this.isMonolith && !targetFolder) targetFolder = ".";
803
+ if (!templateName) return {
804
+ content: [{
805
+ type: "text",
806
+ text: "Missing required parameter: templateName"
807
+ }],
808
+ isError: true
809
+ };
810
+ if (!targetFolder) return {
811
+ content: [{
812
+ type: "text",
813
+ text: "Missing required parameter: targetFolder"
814
+ }],
815
+ isError: true
816
+ };
817
+ const result = await this.boilerplateGeneratorService.generateBoilerplate({
818
+ ...args,
819
+ templateName,
820
+ targetFolder
821
+ });
862
822
  if (!result.success) return {
863
823
  content: [{
864
824
  type: "text",
@@ -1026,38 +986,28 @@ var ScaffoldGeneratorService = class {
1026
986
  var GenerateFeatureScaffoldTool = class GenerateFeatureScaffoldTool {
1027
987
  static TOOL_NAME = "generate-feature-scaffold";
1028
988
  scaffoldGeneratorService;
1029
- constructor(templatesPath) {
989
+ isMonolith;
990
+ constructor(templatesPath, isMonolith = false) {
1030
991
  this.scaffoldGeneratorService = new ScaffoldGeneratorService(templatesPath);
992
+ this.isMonolith = isMonolith;
1031
993
  }
1032
994
  /**
1033
995
  * Get the tool definition for MCP
1034
996
  */
1035
997
  getDefinition() {
1036
- return {
1037
- name: GenerateFeatureScaffoldTool.TOOL_NAME,
1038
- description: `Add a new feature scaffold configuration to a template's scaffold.yaml file.
1039
-
1040
- This tool:
1041
- - Creates or updates scaffold.yaml in the specified template directory
1042
- - Adds a feature entry with proper schema following the nextjs-15 pattern
1043
- - Validates the feature name doesn't already exist
1044
- - Creates the template directory if it doesn't exist
1045
-
1046
- Use this to add custom feature scaffolds (pages, components, services, etc.) for frameworks not yet supported or for your specific project needs.`,
1047
- inputSchema: {
1048
- type: "object",
1049
- properties: {
1050
- templateName: {
1051
- type: "string",
1052
- description: "Name of the template folder (kebab-case, e.g., \"nextjs-15\")"
1053
- },
1054
- featureName: {
1055
- type: "string",
1056
- description: "Name of the feature (kebab-case, e.g., \"scaffold-nextjs-page\")"
1057
- },
1058
- description: {
1059
- type: "string",
1060
- description: `Detailed description of what this feature creates and its key capabilities.
998
+ const properties = {};
999
+ if (!this.isMonolith) properties.templateName = {
1000
+ type: "string",
1001
+ description: "Name of the template folder (kebab-case, e.g., \"nextjs-15\")"
1002
+ };
1003
+ Object.assign(properties, {
1004
+ featureName: {
1005
+ type: "string",
1006
+ description: "Name of the feature (kebab-case, e.g., \"scaffold-nextjs-page\")"
1007
+ },
1008
+ description: {
1009
+ type: "string",
1010
+ description: `Detailed description of what this feature creates and its key capabilities.
1061
1011
 
1062
1012
  STRUCTURE (2-3 sentences):
1063
1013
  - Sentence 1: What type of code it generates (component, page, service, etc.)
@@ -1065,10 +1015,10 @@ STRUCTURE (2-3 sentences):
1065
1015
  - Sentence 3: Primary use cases or when to use it
1066
1016
 
1067
1017
  Example: "Generate a new service class for TypeScript libraries following best practices. Creates a service class with interface, implementation, and unit tests. Perfect for creating reusable service modules with dependency injection patterns."`
1068
- },
1069
- instruction: {
1070
- type: "string",
1071
- description: `Optional detailed instructions about the generated files, their purposes, and how to work with them.
1018
+ },
1019
+ instruction: {
1020
+ type: "string",
1021
+ description: `Optional detailed instructions about the generated files, their purposes, and how to work with them.
1072
1022
 
1073
1023
  STRUCTURE (Concise multi-aspect guide):
1074
1024
 
@@ -1079,47 +1029,47 @@ STRUCTURE (Concise multi-aspect guide):
1079
1029
  5. **Testing approach**: How to test the feature
1080
1030
 
1081
1031
  Example: "Services follow a class-based pattern with optional interface separation. The service class implements business logic and can be dependency injected. Place services in src/services/ directory. For services with interfaces, define the interface in src/types/interfaces/ for better separation of concerns. Service names should be PascalCase and end with 'Service' suffix. Write comprehensive unit tests for all public methods."`
1032
+ },
1033
+ variables: {
1034
+ type: "array",
1035
+ description: "Array of variable definitions for the feature",
1036
+ items: {
1037
+ type: "object",
1038
+ properties: {
1039
+ name: {
1040
+ type: "string",
1041
+ description: "Variable name (camelCase)"
1042
+ },
1043
+ description: {
1044
+ type: "string",
1045
+ description: "Variable description"
1046
+ },
1047
+ type: {
1048
+ type: "string",
1049
+ enum: [
1050
+ "string",
1051
+ "number",
1052
+ "boolean"
1053
+ ],
1054
+ description: "Variable type"
1055
+ },
1056
+ required: {
1057
+ type: "boolean",
1058
+ description: "Whether this variable is required"
1059
+ },
1060
+ default: { description: "Optional default value for the variable" }
1082
1061
  },
1083
- variables: {
1084
- type: "array",
1085
- description: "Array of variable definitions for the feature",
1086
- items: {
1087
- type: "object",
1088
- properties: {
1089
- name: {
1090
- type: "string",
1091
- description: "Variable name (camelCase)"
1092
- },
1093
- description: {
1094
- type: "string",
1095
- description: "Variable description"
1096
- },
1097
- type: {
1098
- type: "string",
1099
- enum: [
1100
- "string",
1101
- "number",
1102
- "boolean"
1103
- ],
1104
- description: "Variable type"
1105
- },
1106
- required: {
1107
- type: "boolean",
1108
- description: "Whether this variable is required"
1109
- },
1110
- default: { description: "Optional default value for the variable" }
1111
- },
1112
- required: [
1113
- "name",
1114
- "description",
1115
- "type",
1116
- "required"
1117
- ]
1118
- }
1119
- },
1120
- includes: {
1121
- type: "array",
1122
- description: `Array of specific file paths to include in the feature (highly recommended to list explicitly).
1062
+ required: [
1063
+ "name",
1064
+ "description",
1065
+ "type",
1066
+ "required"
1067
+ ]
1068
+ }
1069
+ },
1070
+ includes: {
1071
+ type: "array",
1072
+ description: `Array of specific file paths to include in the feature (highly recommended to list explicitly).
1123
1073
 
1124
1074
  Supports advanced syntax:
1125
1075
  - Basic: "src/app/page/page.tsx" - Always included
@@ -1140,11 +1090,11 @@ Best practices:
1140
1090
  - Use path mapping with -> when source and target paths differ
1141
1091
  - Use {{ variableName }} in target paths for dynamic file placement
1142
1092
  - Avoid wildcards unless you have a good reason`,
1143
- items: { type: "string" }
1144
- },
1145
- patterns: {
1146
- type: "array",
1147
- description: `Optional array of glob patterns to match existing files that this feature works with.
1093
+ items: { type: "string" }
1094
+ },
1095
+ patterns: {
1096
+ type: "array",
1097
+ description: `Optional array of glob patterns to match existing files that this feature works with.
1148
1098
 
1149
1099
  Used to help identify where this feature can be applied in a project.
1150
1100
 
@@ -1157,15 +1107,30 @@ Best practices:
1157
1107
  - Use glob patterns that match the file types this feature works with
1158
1108
  - Keep patterns specific enough to be meaningful but broad enough to be useful
1159
1109
  - Consider both the feature's output and input files`,
1160
- items: { type: "string" }
1161
- }
1162
- },
1163
- required: [
1164
- "templateName",
1165
- "featureName",
1166
- "description",
1167
- "variables"
1168
- ],
1110
+ items: { type: "string" }
1111
+ }
1112
+ });
1113
+ const required = [
1114
+ "featureName",
1115
+ "description",
1116
+ "variables"
1117
+ ];
1118
+ if (!this.isMonolith) required.unshift("templateName");
1119
+ return {
1120
+ name: GenerateFeatureScaffoldTool.TOOL_NAME,
1121
+ description: `Add a new feature scaffold configuration to a template's scaffold.yaml file.
1122
+
1123
+ This tool:
1124
+ - Creates or updates scaffold.yaml in the specified template directory
1125
+ - Adds a feature entry with proper schema following the nextjs-15 pattern
1126
+ - Validates the feature name doesn't already exist
1127
+ - Creates the template directory if it doesn't exist
1128
+
1129
+ Use this to add custom feature scaffolds (pages, components, services, etc.) for frameworks not yet supported or for your specific project needs.`,
1130
+ inputSchema: {
1131
+ type: "object",
1132
+ properties,
1133
+ required,
1169
1134
  additionalProperties: false
1170
1135
  }
1171
1136
  };
@@ -1175,7 +1140,29 @@ Best practices:
1175
1140
  */
1176
1141
  async execute(args) {
1177
1142
  try {
1178
- const result = await this.scaffoldGeneratorService.generateFeatureScaffold(args);
1143
+ let { templateName } = args;
1144
+ if (this.isMonolith && !templateName) try {
1145
+ templateName = (await ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
1146
+ } catch (error) {
1147
+ return {
1148
+ content: [{
1149
+ type: "text",
1150
+ text: `Failed to read template name from configuration: ${error instanceof Error ? error.message : String(error)}`
1151
+ }],
1152
+ isError: true
1153
+ };
1154
+ }
1155
+ if (!templateName) return {
1156
+ content: [{
1157
+ type: "text",
1158
+ text: "Missing required parameter: templateName"
1159
+ }],
1160
+ isError: true
1161
+ };
1162
+ const result = await this.scaffoldGeneratorService.generateFeatureScaffold({
1163
+ ...args,
1164
+ templateName
1165
+ });
1179
1166
  if (!result.success) return {
1180
1167
  content: [{
1181
1168
  type: "text",
@@ -1210,29 +1197,30 @@ Best practices:
1210
1197
  }
1211
1198
  };
1212
1199
 
1200
+ //#endregion
1201
+ //#region src/instructions/tools/list-boilerplates/description.md?raw
1202
+ var description_default$2 = "{% if isMonolith %}\nNot available for monolith projects. Monolith uses a single template defined in `toolkit.yaml`.\n\nUse `list-scaffolding-methods` for available features instead.\n{% else %}\nLists all available project boilerplates for creating new applications, APIs, or packages in the monorepo.\n\nEach boilerplate includes:\n- Complete project template with starter files\n- Variable schema for customization\n- Target directory information (e.g., apps/, packages/)\n- Required and optional configuration options\n\nUse this FIRST when creating new projects to understand available templates and their requirements.\n{% endif %}\n";
1203
+
1213
1204
  //#endregion
1214
1205
  //#region src/tools/ListBoilerplatesTool.ts
1215
1206
  var ListBoilerplatesTool = class ListBoilerplatesTool {
1216
1207
  static TOOL_NAME = "list-boilerplates";
1217
1208
  boilerplateService;
1218
- constructor(templatesPath) {
1209
+ templateService;
1210
+ isMonolith;
1211
+ constructor(templatesPath, isMonolith = false) {
1219
1212
  this.boilerplateService = new BoilerplateService(templatesPath);
1213
+ this.templateService = new TemplateService();
1214
+ this.isMonolith = isMonolith;
1220
1215
  }
1221
1216
  /**
1222
1217
  * Get the tool definition for MCP
1223
1218
  */
1224
1219
  getDefinition() {
1220
+ const description = this.templateService.renderString(description_default$2, { isMonolith: this.isMonolith });
1225
1221
  return {
1226
1222
  name: ListBoilerplatesTool.TOOL_NAME,
1227
- description: `Lists all available project boilerplates for creating new applications, APIs, or packages in the monorepo.
1228
-
1229
- Each boilerplate includes:
1230
- - Complete project template with starter files
1231
- - Variable schema for customization
1232
- - Target directory information
1233
- - Required and optional configuration options
1234
-
1235
- Use this FIRST when creating new projects to understand available templates and their requirements.`,
1223
+ description: description.trim(),
1236
1224
  inputSchema: {
1237
1225
  type: "object",
1238
1226
  properties: {},
@@ -1262,6 +1250,10 @@ Use this FIRST when creating new projects to understand available templates and
1262
1250
  }
1263
1251
  };
1264
1252
 
1253
+ //#endregion
1254
+ //#region src/instructions/tools/list-scaffolding-methods/description.md?raw
1255
+ var description_default$1 = "Lists all available scaffolding methods (features) that can be added to an existing project{% if not isMonolith %} or for a specific template{% endif %}.\n\nThis tool:\n{% if isMonolith %}\n- Reads your project's sourceTemplate from toolkit.yaml at workspace root\n{% else %}\n- Reads the project's sourceTemplate from project.json (monorepo) or toolkit.yaml (monolith), OR\n- Directly uses the provided templateName to list available features\n{% endif %}\n- Returns available features for that template type\n- Provides variable schemas for each scaffolding method\n- Shows descriptions of what each method creates\n\nUse this FIRST when adding features to understand:\n- What scaffolding methods are available\n- What variables each method requires\n- What files/features will be generated\n\nExample methods might include:\n- Adding new React routes (for React apps)\n- Creating API endpoints (for backend projects)\n- Adding new components (for frontend projects)\n- Setting up database models (for API projects)\n";
1256
+
1265
1257
  //#endregion
1266
1258
  //#region src/services/ScaffoldingMethodsService.ts
1267
1259
  var ScaffoldingMethodsService = class {
@@ -1274,8 +1266,11 @@ var ScaffoldingMethodsService = class {
1274
1266
  async listScaffoldingMethods(projectPath) {
1275
1267
  const absoluteProjectPath = path.resolve(projectPath);
1276
1268
  const sourceTemplate = (await ProjectConfigResolver.resolveProjectConfig(absoluteProjectPath)).sourceTemplate;
1277
- const templatePath = await this.findTemplatePath(sourceTemplate);
1278
- if (!templatePath) throw new Error(`Template not found for sourceTemplate: ${sourceTemplate}`);
1269
+ return this.listScaffoldingMethodsByTemplate(sourceTemplate);
1270
+ }
1271
+ async listScaffoldingMethodsByTemplate(templateName) {
1272
+ const templatePath = await this.findTemplatePath(templateName);
1273
+ if (!templatePath) throw new Error(`Template not found for sourceTemplate: ${templateName}`);
1279
1274
  const fullTemplatePath = path.join(this.templatesRootPath, templatePath);
1280
1275
  const scaffoldYamlPath = path.join(fullTemplatePath, "scaffold.yaml");
1281
1276
  if (!await this.fileSystem.pathExists(scaffoldYamlPath)) throw new Error(`scaffold.yaml not found at ${scaffoldYamlPath}`);
@@ -1283,8 +1278,9 @@ var ScaffoldingMethodsService = class {
1283
1278
  const architectConfig = yaml.load(scaffoldContent);
1284
1279
  const methods = [];
1285
1280
  if (architectConfig.features && Array.isArray(architectConfig.features)) architectConfig.features.forEach((feature) => {
1286
- if (feature.name) methods.push({
1287
- name: feature.name,
1281
+ const featureName = feature.name || `scaffold-${templateName}`;
1282
+ methods.push({
1283
+ name: featureName,
1288
1284
  description: feature.description || "",
1289
1285
  instruction: feature.instruction || "",
1290
1286
  variables_schema: feature.variables_schema || {
@@ -1297,7 +1293,7 @@ var ScaffoldingMethodsService = class {
1297
1293
  });
1298
1294
  });
1299
1295
  return {
1300
- sourceTemplate,
1296
+ sourceTemplate: templateName,
1301
1297
  templatePath,
1302
1298
  methods
1303
1299
  };
@@ -1342,6 +1338,14 @@ var ScaffoldingMethodsService = class {
1342
1338
  return null;
1343
1339
  }
1344
1340
  /**
1341
+ * Resolves the project path, handling both monorepo and monolith cases
1342
+ * Uses ProjectConfigResolver to find the correct workspace/project root
1343
+ */
1344
+ async resolveProjectPath(projectPath) {
1345
+ const absolutePath = path.resolve(projectPath);
1346
+ return (await ProjectConfigResolver.resolveProjectConfig(absolutePath)).workspaceRoot || absolutePath;
1347
+ }
1348
+ /**
1345
1349
  * Dynamically discovers all template directories
1346
1350
  * Supports both flat structure (templates/nextjs-15) and nested structure (templates/apps/nextjs-15)
1347
1351
  **/
@@ -1379,21 +1383,21 @@ var ScaffoldingMethodsService = class {
1379
1383
  }
1380
1384
  async useScaffoldMethod(request) {
1381
1385
  const { projectPath, scaffold_feature_name, variables } = request;
1382
- const scaffoldingMethods = await this.listScaffoldingMethods(projectPath);
1386
+ const absoluteProjectPath = await this.resolveProjectPath(projectPath);
1387
+ const scaffoldingMethods = await this.listScaffoldingMethods(absoluteProjectPath);
1383
1388
  const method = scaffoldingMethods.methods.find((m) => m.name === scaffold_feature_name);
1384
1389
  if (!method) {
1385
1390
  const availableMethods = scaffoldingMethods.methods.map((m) => m.name).join(", ");
1386
1391
  throw new Error(`Scaffold method '${scaffold_feature_name}' not found. Available methods: ${availableMethods}`);
1387
1392
  }
1388
- const ScaffoldService$1 = (await import("./ScaffoldService-DVsusUh5.js")).ScaffoldService;
1393
+ const ScaffoldService$1 = (await import("./ScaffoldService-CJ3vNmAj.js")).ScaffoldService;
1389
1394
  const ScaffoldConfigLoader$1 = (await import("./ScaffoldConfigLoader-DhthV6xq.js")).ScaffoldConfigLoader;
1390
- const VariableReplacementService$1 = (await import("./VariableReplacementService-D8C-IsP-.js")).VariableReplacementService;
1395
+ const VariableReplacementService$1 = (await import("./VariableReplacementService-BAwTGv_R.js")).VariableReplacementService;
1391
1396
  const TemplateService$1 = (await import("./TemplateService-DropYdp8.js")).TemplateService;
1392
1397
  const templateService = new TemplateService$1();
1393
1398
  const scaffoldConfigLoader = new ScaffoldConfigLoader$1(this.fileSystem, templateService);
1394
1399
  const variableReplacer = new VariableReplacementService$1(this.fileSystem, templateService);
1395
1400
  const scaffoldService = new ScaffoldService$1(this.fileSystem, scaffoldConfigLoader, variableReplacer, this.templatesRootPath);
1396
- const absoluteProjectPath = path.resolve(projectPath);
1397
1401
  const projectName = path.basename(absoluteProjectPath);
1398
1402
  const result = await scaffoldService.useFeature({
1399
1403
  projectPath: absoluteProjectPath,
@@ -1426,41 +1430,36 @@ var ListScaffoldingMethodsTool = class ListScaffoldingMethodsTool {
1426
1430
  static TOOL_NAME = "list-scaffolding-methods";
1427
1431
  fileSystemService;
1428
1432
  scaffoldingMethodsService;
1429
- constructor(templatesPath) {
1433
+ templateService;
1434
+ isMonolith;
1435
+ constructor(templatesPath, isMonolith = false) {
1430
1436
  this.fileSystemService = new FileSystemService();
1431
1437
  this.scaffoldingMethodsService = new ScaffoldingMethodsService(this.fileSystemService, templatesPath);
1438
+ this.templateService = new TemplateService();
1439
+ this.isMonolith = isMonolith;
1432
1440
  }
1433
1441
  /**
1434
1442
  * Get the tool definition for MCP
1435
1443
  */
1436
1444
  getDefinition() {
1445
+ const description = this.templateService.renderString(description_default$1, { isMonolith: this.isMonolith });
1446
+ const properties = {};
1447
+ if (!this.isMonolith) {
1448
+ properties.projectPath = {
1449
+ type: "string",
1450
+ description: "Absolute path to the project directory (for monorepo: containing project.json; for monolith: workspace root with toolkit.yaml). Either projectPath or templateName is required."
1451
+ };
1452
+ properties.templateName = {
1453
+ type: "string",
1454
+ description: "Name of the template to list scaffolding methods for (e.g., \"nextjs-15\", \"typescript-mcp-package\"). Either projectPath or templateName is required."
1455
+ };
1456
+ }
1437
1457
  return {
1438
1458
  name: ListScaffoldingMethodsTool.TOOL_NAME,
1439
- description: `Lists all available scaffolding methods (features) that can be added to an existing project.
1440
-
1441
- This tool:
1442
- - Reads the project's sourceTemplate from project.json (monorepo) or toolkit.yaml (monolith)
1443
- - Returns available features for that template type
1444
- - Provides variable schemas for each scaffolding method
1445
- - Shows descriptions of what each method creates
1446
-
1447
- Use this FIRST when adding features to existing projects to understand:
1448
- - What scaffolding methods are available
1449
- - What variables each method requires
1450
- - What files/features will be generated
1451
-
1452
- Example methods might include:
1453
- - Adding new React routes (for React apps)
1454
- - Creating API endpoints (for backend projects)
1455
- - Adding new components (for frontend projects)
1456
- - Setting up database models (for API projects)`,
1459
+ description: description.trim(),
1457
1460
  inputSchema: {
1458
1461
  type: "object",
1459
- properties: { projectPath: {
1460
- type: "string",
1461
- description: "Absolute path to the project directory (for monorepo: containing project.json; for monolith: workspace root with toolkit.yaml)"
1462
- } },
1463
- required: ["projectPath"],
1462
+ properties,
1464
1463
  additionalProperties: false
1465
1464
  }
1466
1465
  };
@@ -1470,9 +1469,19 @@ Example methods might include:
1470
1469
  */
1471
1470
  async execute(args) {
1472
1471
  try {
1473
- const { projectPath } = args;
1474
- if (!projectPath) throw new Error("Missing required parameter: projectPath");
1475
- const result = await this.scaffoldingMethodsService.listScaffoldingMethods(projectPath);
1472
+ const { projectPath, templateName } = args;
1473
+ let result;
1474
+ if (this.isMonolith) try {
1475
+ const resolvedTemplateName = (await ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
1476
+ result = await this.scaffoldingMethodsService.listScaffoldingMethodsByTemplate(resolvedTemplateName);
1477
+ } catch (error) {
1478
+ throw new Error(`Failed to read template name from configuration: ${error instanceof Error ? error.message : String(error)}`);
1479
+ }
1480
+ else {
1481
+ if (!projectPath && !templateName) throw new Error("Either projectPath or templateName must be provided");
1482
+ if (projectPath) result = await this.scaffoldingMethodsService.listScaffoldingMethods(projectPath);
1483
+ else result = await this.scaffoldingMethodsService.listScaffoldingMethodsByTemplate(templateName);
1484
+ }
1476
1485
  return { content: [{
1477
1486
  type: "text",
1478
1487
  text: JSON.stringify(result, null, 2)
@@ -1489,57 +1498,48 @@ Example methods might include:
1489
1498
  }
1490
1499
  };
1491
1500
 
1501
+ //#endregion
1502
+ //#region src/instructions/tools/use-boilerplate/description.md?raw
1503
+ var description_default = "{% if isMonolith %}\nThis tool is not available for monolith projects.\n\nMonolith projects use a single template specified in `toolkit.yaml` (sourceTemplate field). The template cannot be changed through this tool - it's determined by the workspace configuration.\n\nUse `list-scaffolding-methods` and `use-scaffold-method` to add features to your monolith project instead.\n{% else %}\nCreates a new project from a boilerplate template with the specified variables.\n\n**For Monorepo Projects Only:**\nThis tool creates new sub-projects (apps, packages) in your monorepo. Each project can use a different template.\n\nThis tool will:\n- Generate all necessary files from the selected boilerplate template\n- Replace template variables with provided values\n- Create the project in targetFolder/projectName (e.g., apps/my-new-app)\n- Set up initial configuration files (package.json, tsconfig.json, etc.)\n- Create project.json with sourceTemplate reference\n\nIMPORTANT:\n- Always call `list-boilerplates` first to get the exact variable schema\n- Follow the schema exactly - required fields must be provided\n- Use kebab-case for project names (e.g., \"my-new-app\", not \"MyNewApp\")\n- The tool will validate all variables against the schema before proceeding\n- Each new project can use a different boilerplate template\n{% endif %}\n";
1504
+
1492
1505
  //#endregion
1493
1506
  //#region src/tools/UseBoilerplateTool.ts
1494
1507
  var UseBoilerplateTool = class UseBoilerplateTool {
1495
1508
  static TOOL_NAME = "use-boilerplate";
1496
1509
  boilerplateService;
1497
- constructor(templatesPath) {
1510
+ templateService;
1511
+ isMonolith;
1512
+ constructor(templatesPath, isMonolith = false) {
1498
1513
  this.boilerplateService = new BoilerplateService(templatesPath);
1514
+ this.templateService = new TemplateService();
1515
+ this.isMonolith = isMonolith;
1499
1516
  }
1500
1517
  /**
1501
1518
  * Get the tool definition for MCP
1502
1519
  */
1503
1520
  getDefinition() {
1521
+ const description = this.templateService.renderString(description_default, { isMonolith: this.isMonolith });
1522
+ const properties = { variables: {
1523
+ type: "object",
1524
+ description: "Variables object matching the boilerplate's variables_schema exactly"
1525
+ } };
1526
+ if (!this.isMonolith) {
1527
+ properties.boilerplateName = {
1528
+ type: "string",
1529
+ description: "Exact name of the boilerplate to use (from list-boilerplates response)"
1530
+ };
1531
+ properties.targetFolderOverride = {
1532
+ type: "string",
1533
+ description: "Optional override for target folder. If not provided, uses boilerplate targetFolder (monorepo) or workspace root (monolith)"
1534
+ };
1535
+ }
1504
1536
  return {
1505
1537
  name: UseBoilerplateTool.TOOL_NAME,
1506
- description: `Creates a new project from a boilerplate template with the specified variables.
1507
-
1508
- This tool will:
1509
- - Generate all necessary files from the template
1510
- - Replace template variables with provided values
1511
- - Create the project in the appropriate directory (monorepo or monolith)
1512
- - Set up initial configuration files (package.json, tsconfig.json, etc.)
1513
- - Create toolkit.yaml (monolith) or project.json (monorepo) with sourceTemplate
1514
-
1515
- IMPORTANT:
1516
- - Always call \`list-boilerplates\` first to get the exact variable schema
1517
- - Follow the schema exactly - required fields must be provided
1518
- - Use kebab-case for project names (e.g., "my-new-app", not "MyNewApp")
1519
- - The tool will validate all variables against the schema before proceeding
1520
- - For monolith projects, use monolith: true to create at workspace root
1521
- - For monorepo projects, files are created in targetFolder/projectName`,
1538
+ description: description.trim(),
1522
1539
  inputSchema: {
1523
1540
  type: "object",
1524
- properties: {
1525
- boilerplateName: {
1526
- type: "string",
1527
- description: "Exact name of the boilerplate to use (from list-boilerplates response)"
1528
- },
1529
- variables: {
1530
- type: "object",
1531
- description: "Variables object matching the boilerplate's variables_schema exactly"
1532
- },
1533
- monolith: {
1534
- type: "boolean",
1535
- description: "If true, creates project at workspace root with toolkit.yaml. If false or omitted, creates in targetFolder/projectName with project.json (monorepo mode)"
1536
- },
1537
- targetFolderOverride: {
1538
- type: "string",
1539
- description: "Optional override for target folder. If not provided, uses boilerplate targetFolder (monorepo) or workspace root (monolith)"
1540
- }
1541
- },
1542
- required: ["boilerplateName", "variables"],
1541
+ properties,
1542
+ required: this.isMonolith ? ["variables"] : ["boilerplateName", "variables"],
1543
1543
  additionalProperties: false
1544
1544
  }
1545
1545
  };
@@ -1549,14 +1549,12 @@ IMPORTANT:
1549
1549
  */
1550
1550
  async execute(args) {
1551
1551
  try {
1552
- const { boilerplateName, variables, monolith, targetFolderOverride } = args;
1553
- if (!boilerplateName) throw new Error("Missing required parameter: boilerplateName");
1554
- if (!variables) throw new Error("Missing required parameter: variables");
1552
+ const { boilerplateName, variables, targetFolderOverride } = args;
1555
1553
  const request = {
1556
1554
  boilerplateName,
1557
1555
  variables,
1558
- monolith,
1559
- targetFolderOverride
1556
+ targetFolderOverride,
1557
+ monolith: this.isMonolith
1560
1558
  };
1561
1559
  return { content: [{
1562
1560
  type: "text",
@@ -1589,14 +1587,30 @@ var UseScaffoldMethodTool = class UseScaffoldMethodTool {
1589
1587
  static TOOL_NAME = "use-scaffold-method";
1590
1588
  fileSystemService;
1591
1589
  scaffoldingMethodsService;
1592
- constructor(templatesPath) {
1590
+ isMonolith;
1591
+ constructor(templatesPath, isMonolith = false) {
1593
1592
  this.fileSystemService = new FileSystemService();
1594
1593
  this.scaffoldingMethodsService = new ScaffoldingMethodsService(this.fileSystemService, templatesPath);
1594
+ this.isMonolith = isMonolith;
1595
1595
  }
1596
1596
  /**
1597
1597
  * Get the tool definition for MCP
1598
1598
  */
1599
1599
  getDefinition() {
1600
+ const properties = {
1601
+ scaffold_feature_name: {
1602
+ type: "string",
1603
+ description: "Exact name of the scaffold method to use (from list-scaffolding-methods response)"
1604
+ },
1605
+ variables: {
1606
+ type: "object",
1607
+ description: "Variables object matching the scaffold method's variables_schema exactly"
1608
+ }
1609
+ };
1610
+ if (!this.isMonolith) properties.projectPath = {
1611
+ type: "string",
1612
+ description: "Absolute path to the project directory (for monorepo: containing project.json; for monolith: workspace root with toolkit.yaml)"
1613
+ };
1600
1614
  return {
1601
1615
  name: UseScaffoldMethodTool.TOOL_NAME,
1602
1616
  description: `Generates and adds a specific feature to an existing project using a scaffolding method.
@@ -1616,21 +1630,8 @@ IMPORTANT:
1616
1630
  `,
1617
1631
  inputSchema: {
1618
1632
  type: "object",
1619
- properties: {
1620
- projectPath: {
1621
- type: "string",
1622
- description: "Absolute path to the project directory (for monorepo: containing project.json; for monolith: workspace root with toolkit.yaml)"
1623
- },
1624
- scaffold_feature_name: {
1625
- type: "string",
1626
- description: "Exact name of the scaffold method to use (from list-scaffolding-methods response)"
1627
- },
1628
- variables: {
1629
- type: "object",
1630
- description: "Variables object matching the scaffold method's variables_schema exactly"
1631
- }
1632
- },
1633
- required: [
1633
+ properties,
1634
+ required: this.isMonolith ? ["scaffold_feature_name", "variables"] : [
1634
1635
  "projectPath",
1635
1636
  "scaffold_feature_name",
1636
1637
  "variables"
@@ -1645,13 +1646,11 @@ IMPORTANT:
1645
1646
  async execute(args) {
1646
1647
  try {
1647
1648
  const { projectPath, scaffold_feature_name, variables } = args;
1648
- if (!projectPath) throw new Error("Missing required parameter: projectPath");
1649
- if (!scaffold_feature_name) throw new Error("Missing required parameter: scaffold_feature_name");
1650
- if (!variables) throw new Error("Missing required parameter: variables");
1649
+ const resolvedProjectPath = this.isMonolith ? process.cwd() : projectPath;
1651
1650
  return { content: [{
1652
1651
  type: "text",
1653
1652
  text: `${(await this.scaffoldingMethodsService.useScaffoldMethod({
1654
- projectPath,
1653
+ projectPath: resolvedProjectPath,
1655
1654
  scaffold_feature_name,
1656
1655
  variables
1657
1656
  })).message}
@@ -2071,4 +2070,4 @@ var StdioTransportHandler = class {
2071
2070
  };
2072
2071
 
2073
2072
  //#endregion
2074
- export { BoilerplateGeneratorService, BoilerplateService, FileSystemService, GenerateBoilerplateFileTool, GenerateBoilerplateTool, GenerateFeatureScaffoldTool, HttpTransportHandler, ListBoilerplatesTool, ListScaffoldingMethodsTool, ScaffoldGeneratorService, ScaffoldingMethodsService, SseTransportHandler, StdioTransportHandler, UseBoilerplateTool, UseScaffoldMethodTool, WriteToFileTool, cloneRepository, cloneSubdirectory, fetchGitHubDirectoryContents, findWorkspaceRoot, parseGitHubUrl };
2073
+ export { BoilerplateGeneratorService, BoilerplateService, FileSystemService, GenerateBoilerplateFileTool, GenerateBoilerplateTool, GenerateFeatureScaffoldTool, HttpTransportHandler, ListBoilerplatesTool, ListScaffoldingMethodsTool, ScaffoldGeneratorService, ScaffoldingMethodsService, SseTransportHandler, StdioTransportHandler, UseBoilerplateTool, UseScaffoldMethodTool, WriteToFileTool };