@locofy/mcp 1.1.5 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Server}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema,ListToolsRequestSchema}from"@modelcontextprotocol/sdk/types.js";import{pullComponentsToolName,pullComponentsToolDescription,PullComponentsToolSchema,runPullComponentsTool}from"./tools/pullComponents.js";import{pullFilesToolName,pullFilesToolDescription,PullFilesToolSchema,runPullFilesTool}from"./tools/pullFiles.js";import"./api.js";const server=new Server({name:"locofy-mcp",version:"2.0.1"},{capabilities:{tools:{}}});async function main(){const transport=new StdioServerTransport;await server.connect(transport),process.env.DEBUG_MODE}server.setRequestHandler(ListToolsRequestSchema,(async()=>({tools:[{name:pullComponentsToolName,description:pullComponentsToolDescription,inputSchema:{type:"object",properties:{componentNames:{type:"array",items:{type:"string"},description:'The list of component or screen names to be retrieved. Do not send a single string for this parameter. The values must be provided as a valid JSON array, with each string value enclosed in double quotes (e.g., ["Homepage", "DetailPage"]).'},workspacePath:{type:"string",description:"The full path to the workspace."}},required:["componentNames","workspacePath"]}},{name:pullFilesToolName,description:pullFilesToolDescription,inputSchema:{type:"object",properties:{fileNames:{type:"array",items:{type:"string"},description:'The list of specific file names to be retrieved, without resolving their component dependencies. Do not send a single string for this parameter. The values must be provided as a valid JSON array, with each string value enclosed in double quotes (e.g., ["Homepage.tsx", "DetailPage.tsx"]).'},workspacePath:{type:"string",description:"The full path to the workspace."}},required:["fileNames","workspacePath"]}}]}))),server.setRequestHandler(CallToolRequestSchema,(async request=>{const{name:name,arguments:args}=request.params;switch(name){case pullComponentsToolName:{const validated=PullComponentsToolSchema.parse(args);return await runPullComponentsTool(validated)}case pullFilesToolName:{const validated=PullFilesToolSchema.parse(args);return await runPullFilesTool(validated)}default:throw new Error(`Unknown tool: ${name}`)}})),main().catch((error=>{process.exit(1)}));
|
|
2
|
+
import{Server}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema,ListToolsRequestSchema}from"@modelcontextprotocol/sdk/types.js";import{pullComponentsToolName,pullComponentsToolDescription,PullComponentsToolSchema,runPullComponentsTool}from"./tools/pullComponents.js";import{pullFilesToolName,pullFilesToolDescription,PullFilesToolSchema,runPullFilesTool}from"./tools/pullFiles.js";import{getConfigSchemaToolName,getConfigSchemaToolDescription,getConfigSchemaToolSchema,runGetConfigSchemaTool}from"./tools/getComponentConfigSchema.js";import"./api.js";const server=new Server({name:"locofy-mcp",version:"2.0.1"},{capabilities:{tools:{}}});async function main(){const transport=new StdioServerTransport;await server.connect(transport),process.env.DEBUG_MODE}server.setRequestHandler(ListToolsRequestSchema,(async()=>({tools:[{name:pullComponentsToolName,description:pullComponentsToolDescription,inputSchema:{type:"object",properties:{componentNames:{type:"array",items:{type:"string"},description:'The list of component or screen names to be retrieved. Do not send a single string for this parameter. The values must be provided as a valid JSON array, with each string value enclosed in double quotes (e.g., ["Homepage", "DetailPage"]).'},workspacePath:{type:"string",description:"The full path to the workspace."}},required:["componentNames","workspacePath"]}},{name:pullFilesToolName,description:pullFilesToolDescription,inputSchema:{type:"object",properties:{fileNames:{type:"array",items:{type:"string"},description:'The list of specific file names to be retrieved, without resolving their component dependencies. Do not send a single string for this parameter. The values must be provided as a valid JSON array, with each string value enclosed in double quotes (e.g., ["Homepage.tsx", "DetailPage.tsx"]).'},workspacePath:{type:"string",description:"The full path to the workspace."}},required:["fileNames","workspacePath"]}},{name:getConfigSchemaToolName,description:getConfigSchemaToolDescription,inputSchema:{type:"object",properties:{withExamples:{type:"boolean",description:"Include example configs in the response for guidance (default true)."}}}}]}))),server.setRequestHandler(CallToolRequestSchema,(async request=>{const{name:name,arguments:args}=request.params;switch(name){case pullComponentsToolName:{const validated=PullComponentsToolSchema.parse(args);return await runPullComponentsTool(validated)}case pullFilesToolName:{const validated=PullFilesToolSchema.parse(args);return await runPullFilesTool(validated)}case getConfigSchemaToolName:{const validated=getConfigSchemaToolSchema.parse(args??{});return await runGetConfigSchemaTool(validated)}default:throw new Error(`Unknown tool: ${name}`)}})),main().catch((error=>{process.exit(1)}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{z}from"zod";export const getConfigSchemaToolName="getComponentConfigSchema";export const getConfigSchemaToolDescription='WORKFLOW: When user mentions one or more component files, call this tool ONCE to get the LocofyConfig schema for props. Then for EACH component file: 1) Read and analyze the component file to extract props/types, 2) For Angular components: MANDATORY comprehensive directive detection using ALL methods (imports, constructor injection, inheritance, providers, template analysis if available), 3) For re-exported components (export {default} from "library"), check package.json for library version and research the original component props from version-specific documentation or examine node_modules files, 4) Generate a component config object following the returned schema (name + props + directives for Angular), 5) Write or merge this entry into locofy.config.json at the project root in the format: { "components": [ { "path": "./relative/path/to/file", "name": "ComponentName", "props": [...], "directives": [...] } ] }. IMPORTANT: Never leave props empty for re-exported components. For Angular: Never skip directive detection even from single file analysis. Do NOT modify source files.';export const getConfigSchemaToolSchema=z.object({withExamples:z.boolean().describe("Include example configs in the response for guidance (default true).").optional()});export async function runGetConfigSchemaTool(args){const payload={name:"LocofyConfigSchema",version:"1.0.0",schema_kind:"json_schema_draft_07",schema:{$schema:"http://json-schema.org/draft-07/schema#",title:"LocofyConfigFile",type:"object",additionalProperties:!1,properties:{components:{type:"array",description:"List of component entries for Locofy configuration.",items:{$ref:"#/$defs/Component"}}},required:["components"],$defs:{Component:{type:"object",additionalProperties:!1,properties:{path:{type:"string",description:"Relative path to the component source file (e.g., ./src/components/Button.tsx, ./src/components/button.component.ts, ./src/directives/loading.directive.ts)."},name:{type:"string",description:"Component name as exported from the source file."},props:{type:"array",description:"List of prop definitions.",items:{$ref:"#/$defs/Prop"}},directives:{type:"array",description:"Angular-specific: List of CUSTOM PROJECT directive dependencies for this component. Only include directives defined within the project (relative paths). Exclude Angular built-in, Material, and third-party library directives.",items:{$ref:"#/$defs/Directive"}},module:{type:"string",description:"Angular-specific: Path to the module file if component is defined in a module (e.g., ./src/components/header.locofy.module.ts)."}},required:["path"],anyOf:[{required:["name","props"]},{required:["directives"]},{required:["module"]}]},DefaultPreviewValue:{anyOf:[{type:"string"},{type:"number"},{type:"boolean"},{type:"object",additionalProperties:!0},{type:"array"}],description:"Allowed for defaultValue and previewValue. Component instance values are not supported. If you cannot extract a value, leave it empty."},Prop:{type:"object",additionalProperties:!1,properties:{name:{type:"string",description:"Prop name."},type:{type:"string",enum:["string","number","boolean","enum","node","function","object","array"],description:"Supported prop types."},required:{type:"boolean",default:!1,description:"Whether the prop is required."},attr:{type:"string",description:"HTML attribute to bind (e.g., 'src', 'href')."},defaultValue:{$ref:"#/$defs/DefaultPreviewValue"},previewValue:{$ref:"#/$defs/DefaultPreviewValue"},enum:{type:"array",items:{anyOf:[{type:"string"},{type:"number"},{type:"boolean"}]},minItems:1,description:"Allowed values when type is 'enum'."},valueMapping:{type:"object",description:"Maps prop values to design system states/variants for UI preview purposes.",additionalProperties:{type:"array",items:{type:"string"},description:"Array of state names that correspond to this prop value."}}},required:["name","type"],allOf:[{if:{properties:{type:{const:"enum"}},required:["type"]},then:{required:["enum"]}},{if:{properties:{type:{const:"node"}},required:["type"]},then:{not:{required:["defaultValue"]}}},{if:{properties:{type:{const:"function"}},required:["type"]},then:{not:{required:["defaultValue"]}}}]},Directive:{type:"object",additionalProperties:!1,properties:{path:{type:"string",description:"Relative path to the CUSTOM PROJECT directive source file (e.g., ./src/directives/loading.directive.ts). Must start with ./ or ../ (no @angular/* or node_modules paths)."},selector:{type:"string",description:'Custom project directive selector (e.g., "ds-loading", "app-tooltip"). Exclude Angular built-in selectors (mat-*, fx-, ng*).'}},required:["path","selector"]}}},quick_reference:{types:["string","number","boolean","enum","node","function","object","array"],notes:{name:'Component name extraction rules: 1) For direct exports (export default ComponentName), use "ComponentName". 2) For re-exports (export {default} from "library"), derive the name from the file name (e.g., MUIButton.tsx → "MUIButton"). 3) For named exports (export {Button}), use the exported name "Button". 4) For Angular components, extract from @Component decorator or class name. Never use "default" as the component name.',required:"Set to true for PropTypes.*.isRequired props, defaults to false. Check ALL PropTypes definitions carefully. For Angular: check constructor parameters and @Input() decorators.",attr:"Maps prop to a concrete HTML attribute.",defaultValue:"Supports string | number | boolean | object | array. Not allowed for node and function types. For Angular: look in constructor default parameters, property initializers, and ngOnInit method.",previewValue:"Same as defaultValue; for Mapping UI only.",valueMapping:"Maps prop values to design system states/variants. Sources: 1) .figma.ts files in component directory (primary), 2) SCSS state files (*.states.scss), 3) Component logic analysis (@HostBinding, conditional CSS classes). Check component directory first for design system files.",directives:"Angular-specific: Array of CUSTOM PROJECT directive dependencies with path and selector. ONLY include directives defined within the project (relative paths starting with ./). EXCLUDE: 1) Angular built-in directives (@angular/*), 2) Third-party library directives (node_modules), 3) Base class directives from inheritance, 4) Angular Material/Flex Layout directives. For single file analysis: Check import statements for *Directive imports with relative paths, examine constructor parameters with @Self/@Optional decorators, check @Component providers array for project-specific directive dependencies.",module:"Angular-specific: Path to module file if component is defined in a module."},usage_patterns:['Write entries to locofy.config.json under a top-level "components" array.','React/Vue entry: { "path": "./src/components/Button.tsx", "name": "Button", "props": [...] }','Angular component: { "path": "./src/button/button.component.ts", "name": "ButtonComponent", "props": [...], "directives": [...] }','Angular directive: { "path": "./src/loading.directive.ts", "module": "./src/form-field.module.ts" }'],workflow_steps:['1. User mentions one or more component files (e.g., "add configs to Avatar.tsx, Button.tsx, Modal.tsx")',"2. Call getComponentConfigSchema tool ONCE to get this schema","3. FOR EACH component file mentioned by user:"," a. Read and analyze the component file AND its directory to extract ALL prop types, interfaces, and design metadata:"," - FIRST: List files in component directory to identify design system files (.figma.ts, *.states.scss)"," - React/Vue: Examine PropTypes definitions (including .isRequired props)"," - React/Vue: Check TypeScript interfaces/types for component props"," - React/Vue: Look at function parameters and destructuring patterns"," - Angular: Extract @Input() decorated properties from component class"," - Angular: Check constructor parameters with public/private modifiers"," - Angular: Look for property initializers and ngOnInit assignments for default values"," - Angular: Identify component dependencies via @Component.selector and imports"," - VALUE MAPPING DETECTION (for design system components):"," 1. PRIMARY: Check component directory for .figma.ts files (e.g., button.figma.ts)"," 2. SECONDARY: Look for SCSS state files (*.states.scss) in component or parent directories"," 3. FALLBACK: Analyze component logic for conditional states (@HostBinding, CSS classes)",' 4. Map prop values to state names (e.g., disabled: true → ["Disabled"], disabled: false → ["Enabled", "Enabled :hover"])'," - Angular CUSTOM PROJECT DIRECTIVE DETECTION (critical for single file analysis):",' * Import Analysis: Look for imports ending with "Directive" from RELATIVE PATHS ONLY (e.g., import { DsLoadingDirective } from "../ds-loading/loading.directive")'," * EXCLUDE imports from @angular/*, node_modules, or absolute package paths (e.g., @angular/flex-layout, @angular/material)"," * Constructor Dependencies: Check constructor parameters with @Self, @Optional decorators for project directives only"," * Provider Configuration: Examine @Component providers array for project-specific directive dependencies"," * Template Analysis: If templateUrl exists, read the .html file to find CUSTOM directive usage (exclude mat-*, fx*, standard HTML attributes)"," * Property References: Search class properties and methods for project directive references only"," - Include ALL props found, even internal/styling props (e.g., classes, style)"," - Do NOT filter out any props - include everything defined in PropTypes, interfaces, or @Input decorators"," b. Determine the correct component name using these rules:",' - React/Vue: For "export default ComponentName" → use "ComponentName"',' - React/Vue: For "export {default} from \'@mui/material/Button\'" in file "MUIButton.tsx" → use "MUIButton" (from filename)',' - React/Vue: For "export {Button} from \'./Button\'" → use "Button"',' - Angular: Extract class name from "export class ButtonComponent" → use "ButtonComponent"',' - Angular: If @Component.selector exists, can derive from selector (e.g., "ds-button" → "DsButtonComponent")',' - NEVER use "default" as the component name',' c. For re-exported components (export {default/ComponentName} from "library"), analyze the original component props:'," - First, check package.json or package-lock.json to identify the exact library version installed"," - If it's a well-known library (e.g., @mui/material, @chakra-ui, antd), use your knowledge of the component props for that specific version"," - Consider examining the library files in node_modules/[library-name] to understand component interfaces and prop types"," - If searching web documentation, ensure you're looking at docs that match the installed library version"," - Include all relevant props with proper types, enums, default values, and descriptions"," - For Higher-Order Components (HOCs) like withStyles, include both original component props AND HOC-injected props"," - Do NOT leave props empty for re-exported components"," d. For Angular components, identify additional metadata (COMPREHENSIVE DIRECTIVE DETECTION):"," - MANDATORY: Analyze CUSTOM PROJECT directive dependencies using ALL detection methods:",' 1. Import statements: Find "*Directive" imports from RELATIVE PATHS ONLY (e.g., import { DsLoadingDirective } from "../ds-loading/loading.directive")'," 2. EXCLUDE Angular built-in (@angular/*) and third-party library imports (@angular/material, @angular/flex-layout, node_modules)"," 3. Constructor injection: Check parameters with @Self/@Optional decorators for project directives only"," 4. Component providers: Examine @Component({ providers: [...] }) for project-specific directive dependencies"," 5. Template file: If templateUrl exists, read the HTML file and search for CUSTOM directive selectors (exclude mat-*, fx*, ng-*)"," 6. Property/method usage: Search for project directive references in component properties and methods"," 7. ViewChild/ContentChildren: Check decorators that reference project directive types only"," - EXCLUDE directives from class inheritance (extends relationships) as these are base class dependencies"," - EXCLUDE Angular built-in directives (ngIf, ngFor, mat-*, fx*, etc.) and third-party library directives"," - For EACH detected directive: derive path from import statement and selector from directive definition"," - Look for module file if component is declared in a specific module"," - Extract directive selector from @Directive decorator if file is a directive"," e. Build a component entry: { path, name, props, [directives], [module] }"," - Include directives array if Angular component has directive dependencies"," - Include module path if component is defined in a specific module"," - For directive-only entries, include module but may omit name/props"," - Add valueMapping to props when design system states are detected from .figma.ts or SCSS files",' f. Create or update locofy.config.json at project root with a top-level { "components": [...] }'," g. Merge by (path + name): if an entry exists, update its props; otherwise append a new entry. Never remove existing entries not related to the current file.","4. Confirm completion and summarize the components written to locofy.config.json"]}};return!1!==args.withExamples&&(payload.examples=[{label:"single_component_config_entry",description:"For files with one main component, add or merge this entry into locofy.config.json:",code_to_write:'{\n "components": [\n {\n "path": "./src/components/Avatar.tsx",\n "name": "Avatar",\n "props": [\n { "name": "src", "type": "string", "required": true, "attr": "src", "previewValue": "https://placehold.co/80x80" },\n { "name": "alt", "type": "string", "attr": "alt", "defaultValue": "Avatar" },\n { "name": "size", "type": "number", "defaultValue": 40, "previewValue": 96 },\n { "name": "shape", "type": "enum", "enum": ["circle", "square"], "defaultValue": "circle" },\n { "name": "bordered", "type": "boolean", "defaultValue": false, "previewValue": true },\n { "name": "link", "type": "string", "attr": "href", "defaultValue": "" },\n { "name": "onClick", "type": "function" }\n ]\n }\n ]\n}',config:{name:"Avatar",props:[{name:"src",type:"string",required:!0,attr:"src",defaultValue:"",previewValue:"https://placehold.co/80x80"},{name:"alt",type:"string",attr:"alt",defaultValue:"Avatar"},{name:"size",type:"number",defaultValue:40,previewValue:96},{name:"shape",type:"enum",enum:["circle","square"],defaultValue:"circle"},{name:"bordered",type:"boolean",defaultValue:!1,previewValue:!0},{name:"link",type:"string",attr:"href",defaultValue:""},{name:"onClick",type:"function"}]}},{label:"multi_component_config_entries",description:"For files exporting multiple components, add an entry per exported component:",code_to_write:'{\n "components": [\n {\n "path": "./src/components/ButtonAndIcon.tsx",\n "name": "Button",\n "props": [\n { "name": "label", "type": "string", "required": true },\n { "name": "variant", "type": "enum", "enum": ["primary", "secondary"], "defaultValue": "primary" }\n ]\n },\n {\n "path": "./src/components/ButtonAndIcon.tsx",\n "name": "Icon",\n "props": [\n { "name": "name", "type": "string", "required": true },\n { "name": "size", "type": "number", "defaultValue": 16 }\n ]\n }\n ]\n}',fragments:{Button:{props:[{name:"label",type:"string",required:!0},{name:"variant",type:"enum",enum:["primary","secondary"],defaultValue:"primary"}]},Icon:{props:[{name:"name",type:"string",required:!0},{name:"size",type:"number",defaultValue:16}]}}},{label:"batch_processing_example",description:"When user mentions multiple files, process each one and merge into locofy.config.json:",user_request:"Add configs to Avatar.tsx, Button.tsx, and Modal.tsx",workflow:["1. Call getComponentConfigSchema once","2. Read Avatar.tsx → generate { path, name, props } → merge into locofy.config.json","3. Read Button.tsx → generate { path, name, props } → merge into locofy.config.json","4. Read Modal.tsx → generate { path, name, props } → merge into locofy.config.json",'5. Confirm: "Updated locofy.config.json for Avatar, Button, and Modal"']},{label:"reexported_component_example",description:"For re-exported components using export {default}, derive name from filename AND analyze original component props:",file_content:'export { default } from "@mui/material/Button";',file_path:"./src/components/MUIButton.tsx",correct_config:{path:"./src/components/MUIButton.tsx",name:"MUIButton",props:[{name:"children",type:"node"},{name:"variant",type:"enum",enum:["text","contained","outlined"],defaultValue:"text"},{name:"color",type:"enum",enum:["inherit","primary","secondary","success","error","info","warning"],defaultValue:"primary"},{name:"size",type:"enum",enum:["small","medium","large"],defaultValue:"medium"},{name:"disabled",type:"boolean",defaultValue:!1},{name:"fullWidth",type:"boolean",defaultValue:!1},{name:"href",type:"string",attr:"href"}]},note:'Component name "MUIButton" is derived from filename. Props are analyzed from the original @mui/material/Button component (check package.json for version), NOT left empty.',workflow_example:['1. Read MUIButton.tsx → see export { default } from "@mui/material/Button"','2. Check package.json → find "@mui/material": "^5.14.0"',"3. Use MUI v5 Button props knowledge OR examine node_modules/@mui/material/Button/",'4. Generate config with component name "MUIButton" and complete props list']},{label:"hoc_component_with_all_props",description:"For HOC components, include ALL props from PropTypes, including required ones:",file_content:"Display.propTypes = { children: PropTypes.node, bold: PropTypes.bool, className: PropTypes.string, size: PropTypes.number, classes: PropTypes.object.isRequired, color: PropTypes.string };",correct_config:{path:"./src/atoms/Display/Display.js",name:"Display",props:[{name:"children",type:"node"},{name:"className",type:"string"},{name:"size",type:"number",defaultValue:1},{name:"bold",type:"boolean",defaultValue:!1},{name:"color",type:"string"},{name:"classes",type:"object",required:!0}]},note:'ALL props from PropTypes are included, including the required "classes" prop from withStyles HOC. Do not filter out any props.'},{label:"angular_component_with_directives",description:"For Angular components with directive dependencies and valueMapping:",file_content:'@Component({ selector: "ds-button", template: "..." }) export class ButtonComponent { @Input() disabled: boolean = false; @Input() variant: "primary" | "outline" = "primary"; }',correct_config:{path:"./src/button/button.component.ts",name:"ButtonComponent",directives:[{path:"./src/directives/loading.directive.ts",selector:"ds-loading"}],props:[{name:"disabled",type:"boolean",defaultValue:!1,previewValue:!0,valueMapping:{true:["Disabled"],false:["Enabled","Enabled :hover","Enabled :active","Loading"]}},{name:"variant",type:"enum",enum:["primary","outline"],defaultValue:"primary",previewValue:"primary"}]},note:"Angular components: Extract @Input() properties, default values from property initializers, and include directive dependencies."},{label:"angular_directive_module_only",description:"For Angular directive files that are part of a module:",file_content:'@Directive({ selector: "[dsInput]" }) export class InputDirective { }',correct_config:{path:"./src/input/input.directive.ts",module:"./src/form-field/form-field.module.ts"},note:"Directive-only entries may omit name and props but should include the module path where they are declared."},{label:"angular_constructor_defaults",description:"For Angular components with constructor parameter defaults:",file_content:'@Component({ selector: "ds-badge" }) export class BadgeComponent { constructor(public label: string = "badge", private tone: string = "neutral") { } @Input() counter: number; ngOnInit() { this.counter = this.counter || 0; } }',correct_config:{path:"./src/badge/badge.component.ts",name:"BadgeComponent",props:[{name:"label",type:"string",defaultValue:"badge",previewValue:"badge"},{name:"tone",type:"string",defaultValue:"neutral",previewValue:"neutral"},{name:"counter",type:"number",defaultValue:0,previewValue:0}]},note:"Angular defaultValue detection: Check constructor parameter defaults, property initializers, and ngOnInit assignments."},{label:"angular_single_file_directive_detection",description:"Comprehensive directive detection from single component file analysis:",file_content:"import { DsBadgeDirective } from './../ds-badge/badge.directive';\nimport { DsLoadingDirective } from './../ds-utilities/ds-loading/ds-loading.directive';\nimport { DsA11yDirective } from '../ds-a11y/directives/ds-a11y.directive';\n\n@Component({\n selector: 'ds-button, [ds-button]',\n templateUrl: './button.component.html',\n providers: [\n {\n provide: DsComponentDirective,\n useExisting: forwardRef(() => DsButtonComponent),\n },\n ],\n})\nexport class DsButtonComponent extends DsA11yDirective {\n constructor(\n @Self() @Optional() public loadingConfig?: DsLoadingDirective,\n @Self() @Optional() public badgeDirective?: DsBadgeDirective\n ) {}\n}",directive_detection_analysis:{method_1_imports:["DsBadgeDirective from ./../ds-badge/badge.directive","DsLoadingDirective from ./../ds-utilities/ds-loading/ds-loading.directive","DsA11yDirective from ../ds-a11y/directives/ds-a11y.directive"],method_2_constructor:["loadingConfig?: DsLoadingDirective (with @Self @Optional)","badgeDirective?: DsBadgeDirective (with @Self @Optional)"],method_3_inheritance_excluded:["extends DsA11yDirective (EXCLUDED - base class dependency)"],method_4_providers:["DsComponentDirective (from providers array)"]},correct_config:{path:"./src/button/button.component.ts",name:"DsButtonComponent",directives:[{path:"./../ds-badge/badge.directive.ts",selector:"ds-badge"},{path:"./../ds-utilities/ds-loading/ds-loading.directive.ts",selector:"ds-loading"},{path:"../ds-utilities/ds-component.directive.ts",selector:"ds-component"}],props:[{name:"id",type:"string"},{name:"type",type:"enum",enum:["button","reset","submit","menu"],defaultValue:"button"},{name:"tabIndex",type:"number"},{name:"icon",type:"string"},{name:"applyIconTone",type:"boolean",defaultValue:!0},{name:"disabled",type:"boolean",defaultValue:!1}]},note:"SINGLE FILE ANALYSIS: Component-specific directives detected from imports, constructor injection, and providers. Base class directives from inheritance (DsA11yDirective) are excluded as they are not component-specific dependencies.",workflow_example:["1. Read button.component.ts file","2. Scan imports: Find DsBadgeDirective, DsLoadingDirective (INCLUDE - relative paths), DsA11yDirective (EXCLUDE - inheritance)","3. Filter imports: EXCLUDE any @angular/*, @material/*, node_modules imports","4. Check constructor: Find @Self() @Optional() loadingConfig?: DsLoadingDirective, badgeDirective?: DsBadgeDirective (INCLUDE - project directives)","5. Check class inheritance: Find extends DsA11yDirective (EXCLUDE - base class dependency)","6. Check providers: Find DsComponentDirective in providers array (INCLUDE if relative path)","7. Apply filtering rules: Only include directives with relative paths (./,../)","8. Result: 3 project-specific directives detected (DsBadgeDirective, DsLoadingDirective, DsComponentDirective)","9. EXCLUDED: Angular built-in directives, Material directives, inherited base classes"]},{label:"valuemapping_from_figma_files",description:"Extract valueMapping from .figma.ts files and SCSS state definitions:",component_directory_files:["button.component.ts","button.component.html","button.component.scss","button.figma.ts","button.states.scss"],figma_file_content:"// button.figma.ts\nexport const buttonStates = {\n disabled: {\n true: ['Disabled'],\n false: ['Enabled', 'Enabled :hover', 'Enabled :active', 'Loading']\n },\n variant: {\n primary: ['Primary'],\n outline: ['Outline'],\n ghost: ['Ghost', 'Ghost :hover'],\n destructive: ['Destructive', 'Destructive :hover']\n },\n size: {\n sm: ['Small'],\n md: ['Medium'],\n lg: ['Large']\n }\n};",scss_state_content:"// button.states.scss\n.ds-button {\n &--disabled { /* Disabled state */ }\n &:hover:not(.ds-button--disabled) { /* Enabled :hover */ }\n &:active:not(.ds-button--disabled) { /* Enabled :active */ }\n &--loading { /* Loading state */ }\n}",component_logic_analysis:{hostbinding_loading:'@HostBinding("class.ds-button--loading") get isLoading() { return this.loadingConfig?.isLoading; }',disabled_getter:"get disabled(): boolean { return this._disabled; }",variant_setter:'set variant(value: ButtonVariant) { this.hostCSSClass = `${this.getHostCssClass("component")}--${value}`; }'},correct_valuemapping_extraction:{disabled:{true:["Disabled"],false:["Enabled","Enabled :hover","Enabled :active","Loading"]},variant:{primary:["Primary"],outline:["Outline"],ghost:["Ghost","Ghost :hover"],destructive:["Destructive","Destructive :hover"]},size:{sm:["Small"],md:["Medium"],lg:["Large"]}},detection_workflow:["1. List component directory files → Find button.figma.ts and button.states.scss","2. Read button.figma.ts → Extract buttonStates object with state mappings","3. Read button.states.scss → Identify CSS state classes (.ds-button--disabled, :hover, :active, --loading)","4. Analyze component logic → Find @HostBinding for loading state, disabled getter/setter","5. Cross-reference prop values with state definitions",'6. Build valueMapping: disabled.true→["Disabled"], disabled.false→["Enabled","Enabled :hover","Enabled :active","Loading"]'],note:"PRIORITY ORDER: 1) .figma.ts files (most comprehensive), 2) SCSS state files (CSS classes), 3) Component logic (@HostBinding, conditional classes). Always check component directory first for design system files."},{label:"directive_filtering_include_vs_exclude",description:"Comprehensive guide for filtering project directives vs excluding Angular/third-party directives:",component_imports:"// INCLUDE: Project-specific directives (relative paths)\nimport { DsLoadingDirective } from '../ds-utilities/ds-loading/ds-loading.directive';\nimport { DsBadgeDirective } from '../ds-badge/badge.directive';\nimport { DsTooltipDirective } from './tooltip/tooltip.directive';\nimport { CustomFormDirective } from '../../directives/form.directive';\n\n// EXCLUDE: Angular built-in and third-party library directives\nimport { MatTooltip } from '@angular/material/tooltip';\nimport { FlexLayoutModule } from '@angular/flex-layout';\nimport { NgIf, NgFor } from '@angular/common';",template_analysis:'\x3c!-- INCLUDE: Custom project directive selectors --\x3e\n<div ds-loading="true"></div>\n<span ds-badge="5"></span>\n<input ds-tooltip="Help text"></input>\n<form custom-form></form>\n\n\x3c!-- EXCLUDE: Angular built-in and third-party directives --\x3e\n<div fxLayout="row" fxLayoutGap="16px"></div>\n<button mat-icon-button matTooltip="Click me"></button>\n<div *ngIf="condition" *ngFor="let item of items"></div>',constructor_injection:"// INCLUDE: Project directive injection\nconstructor(\n @Self() @Optional() public loadingConfig?: DsLoadingDirective,\n @Self() @Optional() public badgeDirective?: DsBadgeDirective,\n @Self() @Optional() public tooltipDirective?: DsTooltipDirective\n) {}\n\n// EXCLUDE: Angular/Material directive injection\nconstructor(\n @Self() @Optional() public matTooltip?: MatTooltip,\n @Self() @Optional() public flexLayout?: FlexLayoutDirective\n) {}",correct_directives_array:[{path:"../ds-utilities/ds-loading/ds-loading.directive.ts",selector:"ds-loading"},{path:"../ds-badge/badge.directive.ts",selector:"ds-badge"},{path:"./tooltip/tooltip.directive.ts",selector:"ds-tooltip"},{path:"../../directives/form.directive.ts",selector:"custom-form"}],excluded_directives:["Angular built-in: *ngIf, *ngFor, ngModel, ngClass, ngStyle","Angular Material: mat-*, matTooltip, matRipple, matButton","Angular Flex Layout: fxLayout, fxFlex, fxLayoutGap, fxLayoutAlign","Third-party libraries: Any directive from node_modules or @package/*","Base class inheritance: extends SomeDirective (not component-specific)"],detection_rules:{include_criteria:["Import path starts with ./ or ../ (relative paths)",'Directive class name ends with "Directive"',"Constructor injection with @Self/@Optional decorators","Defined within the project codebase","Custom selector prefix (e.g., ds-, app-, custom-)"],exclude_criteria:["Import path starts with @angular/, @material/, or package name","Angular built-in directives (ng*, mat-*, fx*)","Third-party library directives from node_modules","Base class directives from inheritance (extends)","Standard HTML attributes and events"]},note:"ONLY include directives that are custom-built for the project. Exclude ALL Angular built-in, Material, Flex Layout, and third-party library directives. Focus on project-specific business logic and design system directives."}]),{content:[{type:"text",text:JSON.stringify(payload,null,2)}]}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@locofy/mcp",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "Locofy MCP Server with Cursor",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"figma",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "rm -rf build && tsc && node -e \"const fs=require('fs');const f='build/index.js';fs.writeFileSync(f,'#!/usr/bin/env node\\n'+fs.readFileSync(f));fs.chmodSync(f,'755')\" && find build -name '*.js' -exec npx terser {} --compress drop_console=true --output {} \\;",
|
|
22
22
|
"link": "npm run build && npm link",
|
|
23
|
+
"unlink": "npm unlink -g @locofy/mcp",
|
|
23
24
|
"start": "node build/index.js",
|
|
24
25
|
"lint": "eslint . --ext .ts --fix --ignore-pattern \"**/__tests__/**\" --ignore-pattern \"**/*.test.ts\"",
|
|
25
26
|
"test": "NODE_ENV=test jest --coverage --coverageReporters=text-summary --detectOpenHandles --forceExit"
|