@mhdd_24/angular-mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +145 -0
- package/dist/analyzers/architecture-auditor.d.ts +34 -0
- package/dist/analyzers/architecture-auditor.d.ts.map +1 -0
- package/dist/analyzers/architecture-auditor.js +332 -0
- package/dist/analyzers/architecture-auditor.js.map +1 -0
- package/dist/analyzers/route-analyzer.d.ts +14 -0
- package/dist/analyzers/route-analyzer.d.ts.map +1 -0
- package/dist/analyzers/route-analyzer.js +171 -0
- package/dist/analyzers/route-analyzer.js.map +1 -0
- package/dist/generators/crud-generator.d.ts +5 -0
- package/dist/generators/crud-generator.d.ts.map +1 -0
- package/dist/generators/crud-generator.js +67 -0
- package/dist/generators/crud-generator.js.map +1 -0
- package/dist/generators/crud-types.d.ts +31 -0
- package/dist/generators/crud-types.d.ts.map +1 -0
- package/dist/generators/crud-types.js +2 -0
- package/dist/generators/crud-types.js.map +1 -0
- package/dist/generators/kendo-crud-templates.d.ts +19 -0
- package/dist/generators/kendo-crud-templates.d.ts.map +1 -0
- package/dist/generators/kendo-crud-templates.js +309 -0
- package/dist/generators/kendo-crud-templates.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/angular-project.d.ts +14 -0
- package/dist/parsers/angular-project.d.ts.map +1 -0
- package/dist/parsers/angular-project.js +46 -0
- package/dist/parsers/angular-project.js.map +1 -0
- package/dist/parsers/component-parser.d.ts +12 -0
- package/dist/parsers/component-parser.d.ts.map +1 -0
- package/dist/parsers/component-parser.js +48 -0
- package/dist/parsers/component-parser.js.map +1 -0
- package/dist/server/create-server.d.ts +3 -0
- package/dist/server/create-server.d.ts.map +1 -0
- package/dist/server/create-server.js +11 -0
- package/dist/server/create-server.js.map +1 -0
- package/dist/tools/audit-architecture.d.ts +3 -0
- package/dist/tools/audit-architecture.d.ts.map +1 -0
- package/dist/tools/audit-architecture.js +74 -0
- package/dist/tools/audit-architecture.js.map +1 -0
- package/dist/tools/find-component.d.ts +3 -0
- package/dist/tools/find-component.d.ts.map +1 -0
- package/dist/tools/find-component.js +50 -0
- package/dist/tools/find-component.js.map +1 -0
- package/dist/tools/generate-crud.d.ts +3 -0
- package/dist/tools/generate-crud.d.ts.map +1 -0
- package/dist/tools/generate-crud.js +55 -0
- package/dist/tools/generate-crud.js.map +1 -0
- package/dist/tools/get-project-info.d.ts +3 -0
- package/dist/tools/get-project-info.d.ts.map +1 -0
- package/dist/tools/get-project-info.js +25 -0
- package/dist/tools/get-project-info.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +13 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list-routes.d.ts +3 -0
- package/dist/tools/list-routes.d.ts.map +1 -0
- package/dist/tools/list-routes.js +42 -0
- package/dist/tools/list-routes.js.map +1 -0
- package/package.json +55 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createAngularMcpServer } from "./server/create-server.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
async function main() {
|
|
5
|
+
const server = createAngularMcpServer();
|
|
6
|
+
const transport = new StdioServerTransport();
|
|
7
|
+
await server.connect(transport);
|
|
8
|
+
}
|
|
9
|
+
main().catch((error) => {
|
|
10
|
+
console.error("angular-mcp-server failed to start:", error);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,sBAAsB,EAAE,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;IAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface AngularProjectInfo {
|
|
2
|
+
workspaceRoot: string;
|
|
3
|
+
angularJsonPath: string | null;
|
|
4
|
+
projects: Record<string, {
|
|
5
|
+
projectType?: string;
|
|
6
|
+
root?: string;
|
|
7
|
+
sourceRoot?: string;
|
|
8
|
+
prefix?: string;
|
|
9
|
+
}>;
|
|
10
|
+
defaultProject: string | null;
|
|
11
|
+
}
|
|
12
|
+
export declare function resolveAngularProject(projectPath?: string): Promise<AngularProjectInfo>;
|
|
13
|
+
export declare function getDefaultSourceRoot(info: AngularProjectInfo): string | null;
|
|
14
|
+
//# sourceMappingURL=angular-project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"angular-project.d.ts","sourceRoot":"","sources":["../../src/parsers/angular-project.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,MAAM,CACd,MAAM,EACN;QACE,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CACF,CAAC;IACF,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,wBAAsB,qBAAqB,CACzC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAkC7B;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAmB5E"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
export async function resolveAngularProject(projectPath) {
|
|
4
|
+
const workspaceRoot = resolve(projectPath ?? process.cwd());
|
|
5
|
+
const angularJsonPath = join(workspaceRoot, "angular.json");
|
|
6
|
+
try {
|
|
7
|
+
const raw = await readFile(angularJsonPath, "utf8");
|
|
8
|
+
const config = JSON.parse(raw);
|
|
9
|
+
const projects = config.projects ?? {};
|
|
10
|
+
const defaultProject = config.defaultProject ??
|
|
11
|
+
Object.keys(projects).find((name) => projects[name]?.projectType === "application") ??
|
|
12
|
+
Object.entries(projects)[0]?.[0] ??
|
|
13
|
+
null;
|
|
14
|
+
return {
|
|
15
|
+
workspaceRoot,
|
|
16
|
+
angularJsonPath,
|
|
17
|
+
projects,
|
|
18
|
+
defaultProject,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return {
|
|
23
|
+
workspaceRoot,
|
|
24
|
+
angularJsonPath: null,
|
|
25
|
+
projects: {},
|
|
26
|
+
defaultProject: null,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function getDefaultSourceRoot(info) {
|
|
31
|
+
if (!info.defaultProject) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const project = info.projects[info.defaultProject];
|
|
35
|
+
if (!project) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
if (project.sourceRoot) {
|
|
39
|
+
return join(info.workspaceRoot, project.sourceRoot);
|
|
40
|
+
}
|
|
41
|
+
if (project.root) {
|
|
42
|
+
return join(info.workspaceRoot, project.root, "src");
|
|
43
|
+
}
|
|
44
|
+
return join(info.workspaceRoot, "src");
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=angular-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"angular-project.js","sourceRoot":"","sources":["../../src/parsers/angular-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiB1C,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,WAAoB;IAEpB,MAAM,aAAa,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5D,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAG5B,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;QACvC,MAAM,cAAc,GAClB,MAAM,CAAC,cAAc;YACrB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CACxB,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,KAAK,aAAa,CACxD;YACD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC;QAEP,OAAO;YACL,aAAa;YACb,eAAe;YACf,QAAQ;YACR,cAAc;SACf,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,aAAa;YACb,eAAe,EAAE,IAAI;YACrB,QAAQ,EAAE,EAAE;YACZ,cAAc,EAAE,IAAI;SACrB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAwB;IAC3D,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACnD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ComponentMatch {
|
|
2
|
+
filePath: string;
|
|
3
|
+
relativePath: string;
|
|
4
|
+
className: string | null;
|
|
5
|
+
selector: string | null;
|
|
6
|
+
standalone: boolean | null;
|
|
7
|
+
templateUrl: string | null;
|
|
8
|
+
styleUrl: string | null;
|
|
9
|
+
}
|
|
10
|
+
export declare function parseComponentFile(filePath: string, workspaceRoot: string): Promise<ComponentMatch | null>;
|
|
11
|
+
export declare function matchesComponentQuery(component: ComponentMatch, query: string): boolean;
|
|
12
|
+
//# sourceMappingURL=component-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-parser.d.ts","sourceRoot":"","sources":["../../src/parsers/component-parser.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAmBD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAmBhC;AAED,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,MAAM,GACZ,OAAO,CAaT"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { basename, relative } from "node:path";
|
|
3
|
+
const COMPONENT_DECORATOR = /@Component\s*\(\s*\{([\s\S]*?)\}\s*\)/;
|
|
4
|
+
const CLASS_NAME = /export\s+class\s+(\w+)/;
|
|
5
|
+
function readDecoratorProperty(block, property) {
|
|
6
|
+
const quoted = new RegExp(`${property}\\s*:\\s*['"\`]([^'"\`]+)['"\`]`);
|
|
7
|
+
const match = block.match(quoted);
|
|
8
|
+
return match?.[1] ?? null;
|
|
9
|
+
}
|
|
10
|
+
function readBooleanProperty(block, property) {
|
|
11
|
+
const match = block.match(new RegExp(`${property}\\s*:\\s*(true|false)`));
|
|
12
|
+
if (!match) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return match[1] === "true";
|
|
16
|
+
}
|
|
17
|
+
export async function parseComponentFile(filePath, workspaceRoot) {
|
|
18
|
+
const source = await readFile(filePath, "utf8");
|
|
19
|
+
const decoratorMatch = source.match(COMPONENT_DECORATOR);
|
|
20
|
+
if (!decoratorMatch) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const decoratorBlock = decoratorMatch[1];
|
|
24
|
+
const classMatch = source.match(CLASS_NAME);
|
|
25
|
+
return {
|
|
26
|
+
filePath,
|
|
27
|
+
relativePath: relative(workspaceRoot, filePath),
|
|
28
|
+
className: classMatch?.[1] ?? null,
|
|
29
|
+
selector: readDecoratorProperty(decoratorBlock, "selector"),
|
|
30
|
+
standalone: readBooleanProperty(decoratorBlock, "standalone"),
|
|
31
|
+
templateUrl: readDecoratorProperty(decoratorBlock, "templateUrl"),
|
|
32
|
+
styleUrl: readDecoratorProperty(decoratorBlock, "styleUrl"),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function matchesComponentQuery(component, query) {
|
|
36
|
+
const normalized = query.toLowerCase();
|
|
37
|
+
const haystack = [
|
|
38
|
+
component.className,
|
|
39
|
+
component.selector,
|
|
40
|
+
component.relativePath,
|
|
41
|
+
basename(component.filePath),
|
|
42
|
+
]
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.join(" ")
|
|
45
|
+
.toLowerCase();
|
|
46
|
+
return haystack.includes(normalized);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=component-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-parser.js","sourceRoot":"","sources":["../../src/parsers/component-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAY/C,MAAM,mBAAmB,GAAG,uCAAuC,CAAC;AACpE,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAE5C,SAAS,qBAAqB,CAAC,KAAa,EAAE,QAAgB;IAC5D,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,GAAG,QAAQ,iCAAiC,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAClC,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC5B,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa,EAAE,QAAgB;IAC1D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,GAAG,QAAQ,uBAAuB,CAAC,CAAC,CAAC;IAC1E,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAAgB,EAChB,aAAqB;IAErB,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACzD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAE5C,OAAO;QACL,QAAQ;QACR,YAAY,EAAE,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC;QAC/C,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI;QAClC,QAAQ,EAAE,qBAAqB,CAAC,cAAc,EAAE,UAAU,CAAC;QAC3D,UAAU,EAAE,mBAAmB,CAAC,cAAc,EAAE,YAAY,CAAC;QAC7D,WAAW,EAAE,qBAAqB,CAAC,cAAc,EAAE,aAAa,CAAC;QACjE,QAAQ,EAAE,qBAAqB,CAAC,cAAc,EAAE,UAAU,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,SAAyB,EACzB,KAAa;IAEb,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG;QACf,SAAS,CAAC,SAAS;QACnB,SAAS,CAAC,QAAQ;QAClB,SAAS,CAAC,YAAY;QACtB,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC;KAC7B;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC;SACT,WAAW,EAAE,CAAC;IAEjB,OAAO,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-server.d.ts","sourceRoot":"","sources":["../../src/server/create-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,wBAAgB,sBAAsB,IAAI,SAAS,CASlD"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { registerTools } from "../tools/index.js";
|
|
3
|
+
export function createAngularMcpServer() {
|
|
4
|
+
const server = new McpServer({
|
|
5
|
+
name: "angular-mcp-server",
|
|
6
|
+
version: "1.0.0",
|
|
7
|
+
});
|
|
8
|
+
registerTools(server);
|
|
9
|
+
return server;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=create-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-server.js","sourceRoot":"","sources":["../../src/server/create-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,UAAU,sBAAsB;IACpC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,aAAa,CAAC,MAAM,CAAC,CAAC;IAEtB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-architecture.d.ts","sourceRoot":"","sources":["../../src/tools/audit-architecture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAsBpE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuErE"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { glob } from "glob";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { auditWorkspace, } from "../analyzers/architecture-auditor.js";
|
|
6
|
+
import { getDefaultSourceRoot, resolveAngularProject } from "../parsers/angular-project.js";
|
|
7
|
+
const RULE_IDS = [
|
|
8
|
+
"layer-boundary",
|
|
9
|
+
"cross-feature-import",
|
|
10
|
+
"circular-dependency",
|
|
11
|
+
"deep-relative-import",
|
|
12
|
+
"lazy-loading",
|
|
13
|
+
"naming-convention",
|
|
14
|
+
"file-size",
|
|
15
|
+
];
|
|
16
|
+
export function registerAuditArchitectureTool(server) {
|
|
17
|
+
server.registerTool("audit_architecture", {
|
|
18
|
+
title: "Audit Angular Architecture",
|
|
19
|
+
description: "Run an enterprise architecture audit: layer boundaries, cross-feature imports, circular dependencies, deep relative imports, lazy-loading, naming conventions, and file size. Returns a health score and grade.",
|
|
20
|
+
inputSchema: {
|
|
21
|
+
projectPath: z
|
|
22
|
+
.string()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Path to the Angular workspace root. Defaults to the current working directory."),
|
|
25
|
+
rules: z
|
|
26
|
+
.array(z.enum(RULE_IDS))
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Subset of rules to run. Defaults to all rules."),
|
|
29
|
+
maxFileLines: z
|
|
30
|
+
.number()
|
|
31
|
+
.int()
|
|
32
|
+
.min(50)
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("Maximum lines before a file is flagged. Defaults to 400."),
|
|
35
|
+
maxRelativeDepth: z
|
|
36
|
+
.number()
|
|
37
|
+
.int()
|
|
38
|
+
.min(1)
|
|
39
|
+
.optional()
|
|
40
|
+
.describe("Maximum '../' depth before flagging deep relative imports. Defaults to 3."),
|
|
41
|
+
},
|
|
42
|
+
}, async ({ projectPath, rules, maxFileLines, maxRelativeDepth }) => {
|
|
43
|
+
const project = await resolveAngularProject(projectPath);
|
|
44
|
+
const sourceRoot = getDefaultSourceRoot(project) ?? project.workspaceRoot;
|
|
45
|
+
const pattern = join(sourceRoot, "**/*.{ts,tsx}");
|
|
46
|
+
const filePaths = await glob(pattern, {
|
|
47
|
+
nodir: true,
|
|
48
|
+
absolute: true,
|
|
49
|
+
ignore: ["**/node_modules/**", "**/dist/**", "**/*.spec.ts", "**/*.test.ts"],
|
|
50
|
+
});
|
|
51
|
+
const files = [];
|
|
52
|
+
for (const filePath of filePaths) {
|
|
53
|
+
files.push({ path: filePath, source: await readFile(filePath, "utf8") });
|
|
54
|
+
}
|
|
55
|
+
const report = auditWorkspace(files, project.workspaceRoot, {
|
|
56
|
+
rules: rules,
|
|
57
|
+
maxFileLines,
|
|
58
|
+
maxRelativeDepth,
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
content: [
|
|
62
|
+
{
|
|
63
|
+
type: "text",
|
|
64
|
+
text: JSON.stringify({
|
|
65
|
+
workspaceRoot: project.workspaceRoot,
|
|
66
|
+
sourceRoot,
|
|
67
|
+
...report,
|
|
68
|
+
}, null, 2),
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=audit-architecture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-architecture.js","sourceRoot":"","sources":["../../src/tools/audit-architecture.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,cAAc,GAGf,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAE5F,MAAM,QAAQ,GAAG;IACf,gBAAgB;IAChB,sBAAsB;IACtB,qBAAqB;IACrB,sBAAsB;IACtB,cAAc;IACd,mBAAmB;IACnB,WAAW;CACH,CAAC;AAEX,MAAM,UAAU,6BAA6B,CAAC,MAAiB;IAC7D,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,KAAK,EAAE,4BAA4B;QACnC,WAAW,EACT,iNAAiN;QACnN,WAAW,EAAE;YACX,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,gFAAgF,CACjF;YACH,KAAK,EAAE,CAAC;iBACL,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;iBACvB,QAAQ,EAAE;iBACV,QAAQ,CAAC,gDAAgD,CAAC;YAC7D,YAAY,EAAE,CAAC;iBACZ,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,GAAG,CAAC,EAAE,CAAC;iBACP,QAAQ,EAAE;iBACV,QAAQ,CAAC,0DAA0D,CAAC;YACvE,gBAAgB,EAAE,CAAC;iBAChB,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,EAAE;iBACV,QAAQ,CAAC,2EAA2E,CAAC;SACzF;KACF,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,EAAE,EAAE;QAC/D,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,WAAW,CAAC,CAAC;QACzD,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC;QAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE;YACpC,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,CAAC,oBAAoB,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,CAAC;SAC7E,CAAC,CAAC;QAEH,MAAM,KAAK,GAAiB,EAAE,CAAC;QAC/B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE;YAC1D,KAAK,EAAE,KAA6B;YACpC,YAAY;YACZ,gBAAgB;SACjB,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;wBACE,aAAa,EAAE,OAAO,CAAC,aAAa;wBACpC,UAAU;wBACV,GAAG,MAAM;qBACV,EACD,IAAI,EACJ,CAAC,CACF;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-component.d.ts","sourceRoot":"","sources":["../../src/tools/find-component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsDjE"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { glob } from "glob";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { getDefaultSourceRoot, resolveAngularProject } from "../parsers/angular-project.js";
|
|
5
|
+
import { matchesComponentQuery, parseComponentFile } from "../parsers/component-parser.js";
|
|
6
|
+
export function registerFindComponentTool(server) {
|
|
7
|
+
server.registerTool("find_component", {
|
|
8
|
+
title: "Find Angular Component",
|
|
9
|
+
description: "Search Angular components by selector, class name, or file path fragment within a workspace.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
query: z.string().describe("Selector, class name, or path fragment to search for."),
|
|
12
|
+
projectPath: z
|
|
13
|
+
.string()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("Path to the Angular workspace root. Defaults to the current working directory."),
|
|
16
|
+
limit: z.number().int().min(1).max(50).optional().describe("Maximum number of matches to return."),
|
|
17
|
+
},
|
|
18
|
+
}, async ({ query, projectPath, limit = 20 }) => {
|
|
19
|
+
const project = await resolveAngularProject(projectPath);
|
|
20
|
+
const sourceRoot = getDefaultSourceRoot(project) ?? project.workspaceRoot;
|
|
21
|
+
const pattern = join(sourceRoot, "**/*.component.ts");
|
|
22
|
+
const files = await glob(pattern, { nodir: true, absolute: true });
|
|
23
|
+
const matches = [];
|
|
24
|
+
for (const filePath of files) {
|
|
25
|
+
const component = await parseComponentFile(filePath, project.workspaceRoot);
|
|
26
|
+
if (!component || !matchesComponentQuery(component, query)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
matches.push(component);
|
|
30
|
+
if (matches.length >= limit) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: "text",
|
|
38
|
+
text: JSON.stringify({
|
|
39
|
+
query,
|
|
40
|
+
workspaceRoot: project.workspaceRoot,
|
|
41
|
+
sourceRoot,
|
|
42
|
+
matchCount: matches.length,
|
|
43
|
+
matches,
|
|
44
|
+
}, null, 2),
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=find-component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-component.js","sourceRoot":"","sources":["../../src/tools/find-component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAE3F,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EACT,8FAA8F;QAChG,WAAW,EAAE;YACX,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uDAAuD,CAAC;YACnF,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,gFAAgF,CAAC;YAC7F,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;SACnG;KACF,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,EAAE;QAC3C,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,WAAW,CAAC,CAAC;QACzD,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC;QAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnE,MAAM,OAAO,GAAG,EAAE,CAAC;QACnB,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;YAC5E,IAAI,CAAC,SAAS,IAAI,CAAC,qBAAqB,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC;gBAC3D,SAAS;YACX,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,IAAI,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;gBAC5B,MAAM;YACR,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;wBACE,KAAK;wBACL,aAAa,EAAE,OAAO,CAAC,aAAa;wBACpC,UAAU;wBACV,UAAU,EAAE,OAAO,CAAC,MAAM;wBAC1B,OAAO;qBACR,EACD,IAAI,EACJ,CAAC,CACF;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-crud.d.ts","sourceRoot":"","sources":["../../src/tools/generate-crud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiBpE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoDhE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatCrudGenerationResult, generateCrudScaffold, } from "../generators/crud-generator.js";
|
|
3
|
+
const fieldSchema = z.object({
|
|
4
|
+
name: z.string().describe("Field name, e.g. name or price."),
|
|
5
|
+
type: z
|
|
6
|
+
.enum(["string", "number", "boolean", "date"])
|
|
7
|
+
.describe("Field data type."),
|
|
8
|
+
label: z.string().optional().describe("Display label for grid and form."),
|
|
9
|
+
gridVisible: z.boolean().optional().describe("Show field in Kendo Grid."),
|
|
10
|
+
formVisible: z.boolean().optional().describe("Show field in detail form."),
|
|
11
|
+
});
|
|
12
|
+
export function registerGenerateCrudTool(server) {
|
|
13
|
+
server.registerTool("generate_crud", {
|
|
14
|
+
title: "Generate CRUD Scaffold",
|
|
15
|
+
description: "Generate an Angular 20 + Kendo UI CRUD scaffold with model, service, routes, grid list, and form detail.",
|
|
16
|
+
inputSchema: {
|
|
17
|
+
entityName: z.string().describe("Entity name in PascalCase, e.g. Product."),
|
|
18
|
+
routePath: z.string().describe("Route path segment, e.g. products."),
|
|
19
|
+
projectPath: z
|
|
20
|
+
.string()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Path to the Angular workspace root. Defaults to the current working directory."),
|
|
23
|
+
uiLibrary: z
|
|
24
|
+
.enum(["kendo", "material", "plain"])
|
|
25
|
+
.optional()
|
|
26
|
+
.describe('UI library to use. Defaults to "kendo".'),
|
|
27
|
+
fields: z
|
|
28
|
+
.array(fieldSchema)
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Entity fields for grid columns and form controls."),
|
|
31
|
+
writeFiles: z
|
|
32
|
+
.boolean()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("Write generated files to the workspace. Defaults to false and returns file contents only."),
|
|
35
|
+
},
|
|
36
|
+
}, async ({ entityName, routePath, projectPath, uiLibrary, fields, writeFiles }) => {
|
|
37
|
+
const result = await generateCrudScaffold({
|
|
38
|
+
entityName,
|
|
39
|
+
routePath,
|
|
40
|
+
projectPath,
|
|
41
|
+
uiLibrary,
|
|
42
|
+
fields,
|
|
43
|
+
writeFiles: writeFiles ?? false,
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: "text",
|
|
49
|
+
text: formatCrudGenerationResult(result),
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=generate-crud.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-crud.js","sourceRoot":"","sources":["../../src/tools/generate-crud.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,iCAAiC,CAAC;AAEzC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;IAC5D,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;SAC7C,QAAQ,CAAC,kBAAkB,CAAC;IAC/B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IACzE,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;IACzE,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;CAC3E,CAAC,CAAC;AAEH,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EACT,0GAA0G;QAC5G,WAAW,EAAE;YACX,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;YAC3E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;YACpE,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,gFAAgF,CACjF;YACH,SAAS,EAAE,CAAC;iBACT,IAAI,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;iBACpC,QAAQ,EAAE;iBACV,QAAQ,CAAC,yCAAyC,CAAC;YACtD,MAAM,EAAE,CAAC;iBACN,KAAK,CAAC,WAAW,CAAC;iBAClB,QAAQ,EAAE;iBACV,QAAQ,CAAC,mDAAmD,CAAC;YAChE,UAAU,EAAE,CAAC;iBACV,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,QAAQ,CACP,2FAA2F,CAC5F;SACJ;KACF,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE;QAC9E,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;YACxC,UAAU;YACV,SAAS;YACT,WAAW;YACX,SAAS;YACT,MAAM;YACN,UAAU,EAAE,UAAU,IAAI,KAAK;SAChC,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,0BAA0B,CAAC,MAAM,CAAC;iBACzC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-project-info.d.ts","sourceRoot":"","sources":["../../src/tools/get-project-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2BlE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { resolveAngularProject } from "../parsers/angular-project.js";
|
|
3
|
+
export function registerGetProjectInfoTool(server) {
|
|
4
|
+
server.registerTool("get_project_info", {
|
|
5
|
+
title: "Get Angular Project Info",
|
|
6
|
+
description: "Detect and summarize an Angular workspace from angular.json (project name, source root, projects).",
|
|
7
|
+
inputSchema: {
|
|
8
|
+
projectPath: z
|
|
9
|
+
.string()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe("Path to the Angular workspace root. Defaults to the current working directory."),
|
|
12
|
+
},
|
|
13
|
+
}, async ({ projectPath }) => {
|
|
14
|
+
const info = await resolveAngularProject(projectPath);
|
|
15
|
+
return {
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: JSON.stringify(info, null, 2),
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=get-project-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-project-info.js","sourceRoot":"","sources":["../../src/tools/get-project-info.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,MAAM,UAAU,0BAA0B,CAAC,MAAiB;IAC1D,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,oGAAoG;QACtG,WAAW,EAAE;YACX,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,gFAAgF,CAAC;SAC9F;KACF,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,MAAM,IAAI,GAAG,MAAM,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAEtD,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAMrD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { registerAuditArchitectureTool } from "./audit-architecture.js";
|
|
2
|
+
import { registerFindComponentTool } from "./find-component.js";
|
|
3
|
+
import { registerGenerateCrudTool } from "./generate-crud.js";
|
|
4
|
+
import { registerGetProjectInfoTool } from "./get-project-info.js";
|
|
5
|
+
import { registerListRoutesTool } from "./list-routes.js";
|
|
6
|
+
export function registerTools(server) {
|
|
7
|
+
registerGetProjectInfoTool(server);
|
|
8
|
+
registerFindComponentTool(server);
|
|
9
|
+
registerListRoutesTool(server);
|
|
10
|
+
registerAuditArchitectureTool(server);
|
|
11
|
+
registerGenerateCrudTool(server);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,UAAU,aAAa,CAAC,MAAiB;IAC7C,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-routes.d.ts","sourceRoot":"","sources":["../../src/tools/list-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkD9D"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { glob } from "glob";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { analyzeRoutesFile, flattenRoutes } from "../analyzers/route-analyzer.js";
|
|
5
|
+
import { getDefaultSourceRoot, resolveAngularProject } from "../parsers/angular-project.js";
|
|
6
|
+
export function registerListRoutesTool(server) {
|
|
7
|
+
server.registerTool("list_routes", {
|
|
8
|
+
title: "List Angular Routes",
|
|
9
|
+
description: "Parse Angular route files and return a flattened route tree.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
projectPath: z
|
|
12
|
+
.string()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("Path to the Angular workspace root. Defaults to the current working directory."),
|
|
15
|
+
},
|
|
16
|
+
}, async ({ projectPath }) => {
|
|
17
|
+
const project = await resolveAngularProject(projectPath);
|
|
18
|
+
const sourceRoot = getDefaultSourceRoot(project) ?? project.workspaceRoot;
|
|
19
|
+
const pattern = join(sourceRoot, "**/*.routes.ts");
|
|
20
|
+
const files = await glob(pattern, { nodir: true, absolute: true });
|
|
21
|
+
const routeFiles = await Promise.all(files.map((filePath) => analyzeRoutesFile(filePath, project.workspaceRoot)));
|
|
22
|
+
const flattened = routeFiles.flatMap((entry) => flattenRoutes(entry.routes).map((route) => ({
|
|
23
|
+
...route,
|
|
24
|
+
sourceFile: entry.file,
|
|
25
|
+
})));
|
|
26
|
+
return {
|
|
27
|
+
content: [
|
|
28
|
+
{
|
|
29
|
+
type: "text",
|
|
30
|
+
text: JSON.stringify({
|
|
31
|
+
workspaceRoot: project.workspaceRoot,
|
|
32
|
+
sourceRoot,
|
|
33
|
+
routeFileCount: routeFiles.length,
|
|
34
|
+
routeCount: flattened.length,
|
|
35
|
+
routes: flattened,
|
|
36
|
+
}, null, 2),
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=list-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-routes.js","sourceRoot":"","sources":["../../src/tools/list-routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAE5F,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,8DAA8D;QAC3E,WAAW,EAAE;YACX,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,gFAAgF,CAAC;SAC9F;KACF,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,WAAW,CAAC,CAAC;QACzD,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC;QAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnE,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAClC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,CAC5E,CAAC;QAEF,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAC7C,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC1C,GAAG,KAAK;YACR,UAAU,EAAE,KAAK,CAAC,IAAI;SACvB,CAAC,CAAC,CACJ,CAAC;QAEF,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;wBACE,aAAa,EAAE,OAAO,CAAC,aAAa;wBACpC,UAAU;wBACV,cAAc,EAAE,UAAU,CAAC,MAAM;wBACjC,UAAU,EAAE,SAAS,CAAC,MAAM;wBAC5B,MAAM,EAAE,SAAS;qBAClB,EACD,IAAI,EACJ,CAAC,CACF;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mhdd_24/angular-mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Model Context Protocol server with Angular-native tools for components, routes, architecture analysis, and CRUD generation",
|
|
5
|
+
"author": "Mhdd-24",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/Mhdd-24/angular-mcp-server.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/Mhdd-24/angular-mcp-server#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/Mhdd-24/angular-mcp-server/issues"
|
|
13
|
+
},
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "dist/index.js",
|
|
19
|
+
"bin": {
|
|
20
|
+
"angular-mcp-server": "dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"dev": "tsx watch src/index.ts",
|
|
28
|
+
"start": "node dist/index.js",
|
|
29
|
+
"test": "node --import tsx --test tests/**/*.test.ts",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"prepare": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"angular",
|
|
35
|
+
"mcp",
|
|
36
|
+
"model-context-protocol",
|
|
37
|
+
"cursor",
|
|
38
|
+
"ai",
|
|
39
|
+
"typescript"
|
|
40
|
+
],
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=20"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
47
|
+
"glob": "^11.0.2",
|
|
48
|
+
"zod": "^3.24.2"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^22.15.3",
|
|
52
|
+
"tsx": "^4.19.4",
|
|
53
|
+
"typescript": "^5.8.3"
|
|
54
|
+
}
|
|
55
|
+
}
|