11import { mkdir } from "node:fs/promises" ;
22import { z } from "zod" ;
33import { GENERATIONS_DIR } from "@/config" ;
4- import type { ToolContext , ToolDefinition , ToolResponse } from "@/tools/types" ;
54import {
6- buildWidgetOptions ,
75 DEFAULT_WIDGET_OPTIONS ,
8- GENERATOR_PROMPTS ,
9- runWidgetGenerator ,
10- SCAFFOLD_PROGRESS
11- } from "@/tools/utils/generator" ;
6+ widgetOptionsSchema ,
7+ type ToolContext ,
8+ type ToolDefinition ,
9+ type ToolResponse
10+ } from "@/tools/types" ;
11+ import { buildWidgetOptions , GENERATOR_PROMPTS , runWidgetGenerator , SCAFFOLD_PROGRESS } from "@/tools/utils/generator" ;
1212import { ProgressTracker } from "@/tools/utils/progress-tracker" ;
1313import { createErrorResponse , createToolResponse } from "@/tools/utils/response" ;
1414
15- const createWidgetSchema = z . object ( {
16- name : z
15+ /**
16+ * Schema for create-widget tool input.
17+ * Extends the base widgetOptionsSchema with tool-specific options like outputPath.
18+ */
19+ const createWidgetSchema = widgetOptionsSchema . extend ( {
20+ outputPath : z
1721 . string ( )
18- . min ( 1 )
19- . max ( 100 )
20- . describe ( "[REQUIRED] The name of the widget in PascalCase (e.g., 'MyAwesomeWidget', 'DataChart')" ) ,
21- description : z . string ( ) . min ( 1 ) . max ( 200 ) . describe ( "[REQUIRED] A brief description of what the widget does" ) ,
22- version : z
23- . string ( )
24- . regex ( / ^ \d + \. \d + \. \d + $ / , "Version must be in semver format: x.y.z" )
25- . optional ( )
26- . describe ( `[OPTIONAL] Initial version in semver format. Default: "${ DEFAULT_WIDGET_OPTIONS . version } "` ) ,
27- author : z
28- . string ( )
29- . min ( 1 )
30- . max ( 100 )
31- . optional ( )
32- . describe ( `[OPTIONAL] Author name. Default: "${ DEFAULT_WIDGET_OPTIONS . author } "` ) ,
33- license : z
34- . string ( )
35- . min ( 1 )
36- . max ( 50 )
37- . optional ( )
38- . describe ( `[OPTIONAL] License type. Default: "${ DEFAULT_WIDGET_OPTIONS . license } "` ) ,
39- organization : z
40- . string ( )
41- . min ( 1 )
42- . max ( 100 )
43- . optional ( )
44- . describe (
45- `[OPTIONAL] Organization name for the widget namespace. Default: "${ DEFAULT_WIDGET_OPTIONS . organization } "`
46- ) ,
47- template : z
48- . enum ( [ "full" , "empty" ] )
49- . optional ( )
50- . describe (
51- `[OPTIONAL] Widget template: "full" includes sample code and examples, "empty" is minimal/blank. Default: "${ DEFAULT_WIDGET_OPTIONS . template } "`
52- ) ,
53- programmingLanguage : z
54- . enum ( [ "typescript" , "javascript" ] )
55- . optional ( )
56- . describe (
57- `[OPTIONAL] Programming language for the widget source code. Default: "${ DEFAULT_WIDGET_OPTIONS . programmingLanguage } "`
58- ) ,
59- unitTests : z
60- . boolean ( )
61- . optional ( )
62- . describe ( `[OPTIONAL] Include unit test setup with Jest. Default: ${ DEFAULT_WIDGET_OPTIONS . unitTests } ` ) ,
63- e2eTests : z
64- . boolean ( )
6522 . optional ( )
6623 . describe (
67- ` [OPTIONAL] Include end-to-end test setup with Playwright. Default: ${ DEFAULT_WIDGET_OPTIONS . e2eTests } `
24+ " [OPTIONAL] Directory where widget will be created. Defaults to ./generations/ within the MCP server package."
6825 )
6926} ) ;
7027
@@ -87,9 +44,22 @@ OPTIONAL (with defaults):
8744 • programmingLanguage: "typescript" or "javascript" (default: "${ DEFAULT_WIDGET_OPTIONS . programmingLanguage } ")
8845 • unitTests: Include Jest test setup (default: ${ DEFAULT_WIDGET_OPTIONS . unitTests } )
8946 • e2eTests: Include Playwright E2E tests (default: ${ DEFAULT_WIDGET_OPTIONS . e2eTests } )
47+ • outputPath: Directory where widget will be created (default: ./generations/)
9048
9149Ask the user if they want to customize any options before proceeding.` ;
9250
51+ /**
52+ * Returns scaffolding-related tools for widget creation and management.
53+ *
54+ * Currently contains only the create-widget tool, but structured as an array
55+ * for extensibility. This modular pattern allows easy addition of related tools
56+ * such as:
57+ * - Widget property editing
58+ * - XML configuration management
59+ * - Build and deployment automation
60+ *
61+ * @see AGENTS.md Roadmap Context section for planned additions
62+ */
9363export function getScaffoldingTools ( ) : Array < ToolDefinition < CreateWidgetInput > > {
9464 return [
9565 {
@@ -104,6 +74,7 @@ export function getScaffoldingTools(): Array<ToolDefinition<CreateWidgetInput>>
10474
10575async function handleCreateWidget ( args : CreateWidgetInput , context : ToolContext ) : Promise < ToolResponse > {
10676 const options = buildWidgetOptions ( args ) ;
77+ const outputDir = args . outputPath ?? GENERATIONS_DIR ;
10778 const tracker = new ProgressTracker ( {
10879 context,
10980 logger : "scaffolding" ,
@@ -116,14 +87,15 @@ async function handleCreateWidget(args: CreateWidgetInput, context: ToolContext)
11687 await tracker . info ( `Starting widget scaffolding for "${ options . name } "...` , {
11788 widgetName : options . name ,
11889 template : options . template ,
119- organization : options . organization
90+ organization : options . organization ,
91+ outputDir
12092 } ) ;
12193
122- // Ensure generations directory exists
123- await mkdir ( GENERATIONS_DIR , { recursive : true } ) ;
94+ // Ensure output directory exists
95+ await mkdir ( outputDir , { recursive : true } ) ;
12496
125- const widgetFolder = await runWidgetGenerator ( options , tracker ) ;
126- const widgetPath = `${ GENERATIONS_DIR } /${ widgetFolder } ` ;
97+ const widgetFolder = await runWidgetGenerator ( options , tracker , outputDir ) ;
98+ const widgetPath = `${ outputDir } /${ widgetFolder } ` ;
12799
128100 console . error ( `[create-widget] Widget created successfully at ${ widgetPath } ` ) ;
129101 await tracker . progress ( SCAFFOLD_PROGRESS . COMPLETE , "Widget created successfully!" ) ;
0 commit comments