@angular/cli 20.2.0-next.2 → 20.2.0-rc.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/lib/code-examples.db +0 -0
- package/lib/config/schema.json +18 -2
- package/lib/config/workspace-schema.d.ts +14 -0
- package/lib/config/workspace-schema.js +11 -1
- package/package.json +17 -17
- package/src/commands/mcp/cli.d.ts +5 -1
- package/src/commands/mcp/cli.js +25 -4
- package/src/commands/mcp/mcp-server.d.ts +13 -1
- package/src/commands/mcp/mcp-server.js +51 -27
- package/src/commands/mcp/{instructions → resources}/best-practices.md +0 -5
- package/src/commands/mcp/resources/instructions.d.ts +9 -0
- package/src/commands/mcp/resources/instructions.js +28 -0
- package/src/commands/mcp/tools/best-practices.d.ts +1 -2
- package/src/commands/mcp/tools/best-practices.js +30 -24
- package/src/commands/mcp/tools/doc-search.d.ts +5 -9
- package/src/commands/mcp/tools/doc-search.js +34 -37
- package/src/commands/mcp/tools/examples.d.ts +4 -11
- package/src/commands/mcp/tools/examples.js +68 -34
- package/src/commands/mcp/tools/modernize.d.ts +31 -0
- package/src/commands/mcp/tools/modernize.js +135 -0
- package/src/commands/mcp/tools/projects.d.ts +22 -5
- package/src/commands/mcp/tools/projects.js +37 -35
- package/src/commands/mcp/tools/tool-registry.d.ts +35 -0
- package/src/commands/mcp/tools/tool-registry.js +33 -0
- package/src/commands/version/cli.d.ts +24 -2
- package/src/commands/version/cli.js +74 -115
- package/src/commands/version/version-info.d.ts +33 -0
- package/src/commands/version/version-info.js +122 -0
- package/src/utilities/config.js +3 -0
- package/src/utilities/environment-options.d.ts +13 -0
- package/src/utilities/environment-options.js +43 -14
- package/src/utilities/eol.d.ts +12 -0
- package/src/utilities/eol.js +12 -0
- package/src/utilities/error.d.ts +8 -0
- package/src/utilities/error.js +24 -4
- package/src/utilities/json-file.d.ts +15 -2
- package/src/utilities/json-file.js +100 -27
- package/src/utilities/tty.d.ts +8 -0
- package/src/utilities/tty.js +10 -10
- package/src/utilities/version.js +1 -1
- package/src/utilities/load-esm.d.ts +0 -20
- package/src/utilities/load-esm.js +0 -30
|
@@ -39,34 +39,18 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
return result;
|
|
40
40
|
};
|
|
41
41
|
})();
|
|
42
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
43
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
44
|
+
};
|
|
42
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
-
exports.
|
|
46
|
+
exports.FIND_EXAMPLE_TOOL = void 0;
|
|
44
47
|
exports.escapeSearchQuery = escapeSearchQuery;
|
|
48
|
+
const promises_1 = require("node:fs/promises");
|
|
49
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
45
50
|
const zod_1 = require("zod");
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
* This tool allows users to search for best-practice Angular code examples
|
|
50
|
-
* from a local SQLite database.
|
|
51
|
-
*
|
|
52
|
-
* @param server The MCP server instance.
|
|
53
|
-
* @param exampleDatabasePath The path to the SQLite database file containing the examples.
|
|
54
|
-
*/
|
|
55
|
-
function registerFindExampleTool(server, exampleDatabasePath) {
|
|
56
|
-
let db;
|
|
57
|
-
let queryStatement;
|
|
58
|
-
server.registerTool('find_examples', {
|
|
59
|
-
title: 'Find Angular Code Examples',
|
|
60
|
-
description: 'Before writing or modifying any Angular code including templates, ' +
|
|
61
|
-
'**ALWAYS** use this tool to find current best-practice examples. ' +
|
|
62
|
-
'This is critical for ensuring code quality and adherence to modern Angular standards. ' +
|
|
63
|
-
'This tool searches a curated database of approved Angular code examples and returns the most relevant results for your query. ' +
|
|
64
|
-
'Example Use Cases: ' +
|
|
65
|
-
"1) Creating new components, directives, or services (e.g., query: 'standalone component' or 'signal input'). " +
|
|
66
|
-
"2) Implementing core features (e.g., query: 'lazy load route', 'httpinterceptor', or 'route guard'). " +
|
|
67
|
-
"3) Refactoring existing code to use modern patterns (e.g., query: 'ngfor trackby' or 'form validation').",
|
|
68
|
-
inputSchema: {
|
|
69
|
-
query: zod_1.z.string().describe(`Performs a full-text search using FTS5 syntax. The query should target relevant Angular concepts.
|
|
51
|
+
const tool_registry_1 = require("./tool-registry");
|
|
52
|
+
const findExampleInputSchema = zod_1.z.object({
|
|
53
|
+
query: zod_1.z.string().describe(`Performs a full-text search using FTS5 syntax. The query should target relevant Angular concepts.
|
|
70
54
|
|
|
71
55
|
Key Syntax Features (see https://www.sqlite.org/fts5.html for full documentation):
|
|
72
56
|
- AND (default): Space-separated terms are combined with AND.
|
|
@@ -88,16 +72,50 @@ Examples of queries:
|
|
|
88
72
|
- Find signal inputs: 'signal input'
|
|
89
73
|
- Find lazy loading a route: 'lazy load route'
|
|
90
74
|
- Find forms with validation: 'form AND (validation OR validator)'`),
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
75
|
+
});
|
|
76
|
+
exports.FIND_EXAMPLE_TOOL = (0, tool_registry_1.declareTool)({
|
|
77
|
+
name: 'find_examples',
|
|
78
|
+
title: 'Find Angular Code Examples',
|
|
79
|
+
description: 'Before writing or modifying any Angular code including templates, ' +
|
|
80
|
+
'**ALWAYS** use this tool to find current best-practice examples. ' +
|
|
81
|
+
'This is critical for ensuring code quality and adherence to modern Angular standards. ' +
|
|
82
|
+
'This tool searches a curated database of approved Angular code examples and returns the most relevant results for your query. ' +
|
|
83
|
+
'Example Use Cases: ' +
|
|
84
|
+
"1) Creating new components, directives, or services (e.g., query: 'standalone component' or 'signal input'). " +
|
|
85
|
+
"2) Implementing core features (e.g., query: 'lazy load route', 'httpinterceptor', or 'route guard'). " +
|
|
86
|
+
"3) Refactoring existing code to use modern patterns (e.g., query: 'ngfor trackby' or 'form validation').",
|
|
87
|
+
inputSchema: findExampleInputSchema.shape,
|
|
88
|
+
isReadOnly: true,
|
|
89
|
+
isLocalOnly: true,
|
|
90
|
+
shouldRegister: ({ logger }) => {
|
|
91
|
+
// sqlite database support requires Node.js 22.16+
|
|
92
|
+
const [nodeMajor, nodeMinor] = process.versions.node.split('.', 2).map(Number);
|
|
93
|
+
if (nodeMajor < 22 || (nodeMajor === 22 && nodeMinor < 16)) {
|
|
94
|
+
logger.warn(`MCP tool 'find_examples' requires Node.js 22.16 (or higher). ` +
|
|
95
|
+
' Registration of this tool has been skipped.');
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
},
|
|
100
|
+
factory: createFindExampleHandler,
|
|
101
|
+
});
|
|
102
|
+
async function createFindExampleHandler({ exampleDatabasePath }) {
|
|
103
|
+
let db;
|
|
104
|
+
let queryStatement;
|
|
105
|
+
if (process.env['NG_MCP_EXAMPLES_DIR']) {
|
|
106
|
+
db = await setupRuntimeExamples(process.env['NG_MCP_EXAMPLES_DIR']);
|
|
107
|
+
}
|
|
108
|
+
suppressSqliteWarning();
|
|
109
|
+
return async ({ query }) => {
|
|
110
|
+
if (!db) {
|
|
111
|
+
if (!exampleDatabasePath) {
|
|
112
|
+
// This should be prevented by the registration logic in mcp-server.ts
|
|
113
|
+
throw new Error('Example database path is not available.');
|
|
114
|
+
}
|
|
99
115
|
const { DatabaseSync } = await Promise.resolve().then(() => __importStar(require('node:sqlite')));
|
|
100
116
|
db = new DatabaseSync(exampleDatabasePath, { readOnly: true });
|
|
117
|
+
}
|
|
118
|
+
if (!queryStatement) {
|
|
101
119
|
queryStatement = db.prepare('SELECT * from examples WHERE examples MATCH ? ORDER BY rank;');
|
|
102
120
|
}
|
|
103
121
|
const sanitizedQuery = escapeSearchQuery(query);
|
|
@@ -109,7 +127,7 @@ Examples of queries:
|
|
|
109
127
|
return {
|
|
110
128
|
content,
|
|
111
129
|
};
|
|
112
|
-
}
|
|
130
|
+
};
|
|
113
131
|
}
|
|
114
132
|
/**
|
|
115
133
|
* Escapes a search query for FTS5 by tokenizing and quoting terms.
|
|
@@ -188,3 +206,19 @@ function suppressSqliteWarning() {
|
|
|
188
206
|
return originalProcessEmit.apply(process, arguments);
|
|
189
207
|
};
|
|
190
208
|
}
|
|
209
|
+
async function setupRuntimeExamples(examplesPath) {
|
|
210
|
+
const { DatabaseSync } = await Promise.resolve().then(() => __importStar(require('node:sqlite')));
|
|
211
|
+
const db = new DatabaseSync(':memory:');
|
|
212
|
+
db.exec(`CREATE VIRTUAL TABLE examples USING fts5(content, tokenize = 'porter ascii');`);
|
|
213
|
+
const insertStatement = db.prepare('INSERT INTO examples(content) VALUES(?);');
|
|
214
|
+
db.exec('BEGIN TRANSACTION');
|
|
215
|
+
for await (const entry of (0, promises_1.glob)('*.md', { cwd: examplesPath, withFileTypes: true })) {
|
|
216
|
+
if (!entry.isFile()) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const example = await (0, promises_1.readFile)(node_path_1.default.join(entry.parentPath, entry.name), 'utf-8');
|
|
220
|
+
insertStatement.run(example);
|
|
221
|
+
}
|
|
222
|
+
db.exec('END TRANSACTION');
|
|
223
|
+
return db;
|
|
224
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright Google LLC All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
+
* found in the LICENSE file at https://angular.dev/license
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
declare const modernizeInputSchema: z.ZodObject<{
|
|
10
|
+
transformations: z.ZodOptional<z.ZodArray<z.ZodEnum<[string, ...string[]]>, "many">>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
transformations?: string[] | undefined;
|
|
13
|
+
}, {
|
|
14
|
+
transformations?: string[] | undefined;
|
|
15
|
+
}>;
|
|
16
|
+
export type ModernizeInput = z.infer<typeof modernizeInputSchema>;
|
|
17
|
+
export declare function runModernization(input: ModernizeInput): Promise<{
|
|
18
|
+
content: {
|
|
19
|
+
type: "text";
|
|
20
|
+
text: string;
|
|
21
|
+
}[];
|
|
22
|
+
structuredContent: {
|
|
23
|
+
instructions: string[];
|
|
24
|
+
};
|
|
25
|
+
}>;
|
|
26
|
+
export declare const MODERNIZE_TOOL: import("./tool-registry").McpToolDeclaration<{
|
|
27
|
+
transformations: z.ZodOptional<z.ZodArray<z.ZodEnum<[string, ...string[]]>, "many">>;
|
|
28
|
+
}, {
|
|
29
|
+
instructions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
30
|
+
}>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright Google LLC All Rights Reserved.
|
|
5
|
+
*
|
|
6
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7
|
+
* found in the LICENSE file at https://angular.dev/license
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.MODERNIZE_TOOL = void 0;
|
|
11
|
+
exports.runModernization = runModernization;
|
|
12
|
+
const zod_1 = require("zod");
|
|
13
|
+
const tool_registry_1 = require("./tool-registry");
|
|
14
|
+
const TRANSFORMATIONS = [
|
|
15
|
+
{
|
|
16
|
+
name: 'control-flow-migration',
|
|
17
|
+
description: 'Migrates from `*ngIf`, `*ngFor`, and `*ngSwitch` to the new `@if`, `@for`, and `@switch` block syntax in templates.',
|
|
18
|
+
documentationUrl: 'https://angular.dev/reference/migrations/control-flow',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'self-closing-tags-migration',
|
|
22
|
+
description: 'Converts tags for elements with no content to be self-closing (e.g., `<app-foo></app-foo>` becomes `<app-foo />`).',
|
|
23
|
+
documentationUrl: 'https://angular.dev/reference/migrations/self-closing-tags',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'test-bed-get',
|
|
27
|
+
description: 'Updates `TestBed.get` to the preferred and type-safe `TestBed.inject` in TypeScript test files.',
|
|
28
|
+
documentationUrl: 'https://angular.dev/guide/testing/dependency-injection',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'inject',
|
|
32
|
+
description: 'Converts usages of constructor-based injection to the inject() function.',
|
|
33
|
+
documentationUrl: 'https://angular.dev/reference/migrations/inject-function',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'output-migration',
|
|
37
|
+
description: 'Converts `@Output` declarations to the new functional `output()` syntax.',
|
|
38
|
+
documentationUrl: 'https://angular.dev/reference/migrations/outputs',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'signal-input-migration',
|
|
42
|
+
description: 'Migrates `@Input` declarations to the new signal-based `input()` syntax.',
|
|
43
|
+
documentationUrl: 'https://angular.dev/reference/migrations/signal-inputs',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'signal-queries-migration',
|
|
47
|
+
description: 'Migrates `@ViewChild` and `@ContentChild` queries to their signal-based `viewChild` and `contentChild` versions.',
|
|
48
|
+
documentationUrl: 'https://angular.dev/reference/migrations/signal-queries',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'standalone',
|
|
52
|
+
description: 'Converts the application to use standalone components, directives, and pipes. This is a ' +
|
|
53
|
+
'three-step process. After each step, you should verify that your application builds and ' +
|
|
54
|
+
'runs correctly.',
|
|
55
|
+
instructions: 'This migration requires running a cli schematic multiple times. Run the commands in the ' +
|
|
56
|
+
'order listed below, verifying that your code builds and runs between each step:\n\n' +
|
|
57
|
+
'1. Run `ng g @angular/core:standalone` and select "Convert all components, directives and pipes to standalone"\n' +
|
|
58
|
+
'2. Run `ng g @angular/core:standalone` and select "Remove unnecessary NgModule classes"\n' +
|
|
59
|
+
'3. Run `ng g @angular/core:standalone` and select "Bootstrap the project using standalone APIs"',
|
|
60
|
+
documentationUrl: 'https://angular.dev/reference/migrations/standalone',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'zoneless',
|
|
64
|
+
description: 'Migrates the application to be zoneless.',
|
|
65
|
+
documentationUrl: 'https://angular.dev/guide/zoneless',
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
const modernizeInputSchema = zod_1.z.object({
|
|
69
|
+
// Casting to [string, ...string[]] since the enum definition requires a nonempty array.
|
|
70
|
+
transformations: zod_1.z
|
|
71
|
+
.array(zod_1.z.enum(TRANSFORMATIONS.map((t) => t.name)))
|
|
72
|
+
.optional(),
|
|
73
|
+
});
|
|
74
|
+
function generateInstructions(transformationNames) {
|
|
75
|
+
if (transformationNames.length === 0) {
|
|
76
|
+
return [
|
|
77
|
+
'See https://angular.dev/best-practices for Angular best practices. ' +
|
|
78
|
+
'You can call this tool if you have specific transformation you want to run.',
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
const instructions = [];
|
|
82
|
+
const transformationsToRun = TRANSFORMATIONS.filter((t) => transformationNames?.includes(t.name));
|
|
83
|
+
for (const transformation of transformationsToRun) {
|
|
84
|
+
let transformationInstructions = '';
|
|
85
|
+
if (transformation.instructions) {
|
|
86
|
+
transformationInstructions = transformation.instructions;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// If no instructions are included, default to running a cli schematic with the transformation name.
|
|
90
|
+
const command = `ng generate @angular/core:${transformation.name}`;
|
|
91
|
+
transformationInstructions = `To run the ${transformation.name} migration, execute the following command: \`${command}\`.`;
|
|
92
|
+
}
|
|
93
|
+
if (transformation.documentationUrl) {
|
|
94
|
+
transformationInstructions += `\nFor more information, see ${transformation.documentationUrl}.`;
|
|
95
|
+
}
|
|
96
|
+
instructions.push(transformationInstructions);
|
|
97
|
+
}
|
|
98
|
+
return instructions;
|
|
99
|
+
}
|
|
100
|
+
async function runModernization(input) {
|
|
101
|
+
const structuredContent = { instructions: generateInstructions(input.transformations ?? []) };
|
|
102
|
+
return {
|
|
103
|
+
content: [{ type: 'text', text: JSON.stringify(structuredContent) }],
|
|
104
|
+
structuredContent,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
exports.MODERNIZE_TOOL = (0, tool_registry_1.declareTool)({
|
|
108
|
+
name: 'modernize',
|
|
109
|
+
title: 'Modernize Angular Code',
|
|
110
|
+
description: '<Purpose>\n' +
|
|
111
|
+
'This tool modernizes Angular code by applying the latest best practices and syntax improvements, ' +
|
|
112
|
+
'ensuring it is idiomatic, readable, and maintainable.\n\n' +
|
|
113
|
+
'</Purpose>\n' +
|
|
114
|
+
'<Use Cases>\n' +
|
|
115
|
+
'* After generating new code: Run this tool immediately after creating new Angular components, directives, ' +
|
|
116
|
+
'or services to ensure they adhere to modern standards.\n' +
|
|
117
|
+
'* On existing code: Apply to existing TypeScript files (.ts) and Angular templates (.html) to update ' +
|
|
118
|
+
'them with the latest features, such as the new built-in control flow syntax.\n\n' +
|
|
119
|
+
'* When the user asks for a specific transformation: When the transformation list is populated, ' +
|
|
120
|
+
'these specific ones will be ran on the inputs.\n' +
|
|
121
|
+
'</Use Cases>\n' +
|
|
122
|
+
'<Transformations>\n' +
|
|
123
|
+
TRANSFORMATIONS.map((t) => `* ${t.name}: ${t.description}`).join('\n') +
|
|
124
|
+
'\n</Transformations>\n',
|
|
125
|
+
inputSchema: modernizeInputSchema.shape,
|
|
126
|
+
outputSchema: {
|
|
127
|
+
instructions: zod_1.z
|
|
128
|
+
.array(zod_1.z.string())
|
|
129
|
+
.optional()
|
|
130
|
+
.describe('A list of instructions on how to run the migrations.'),
|
|
131
|
+
},
|
|
132
|
+
isLocalOnly: true,
|
|
133
|
+
isReadOnly: true,
|
|
134
|
+
factory: () => (input) => runModernization(input),
|
|
135
|
+
});
|
|
@@ -5,8 +5,25 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
import z from 'zod';
|
|
9
|
+
export declare const LIST_PROJECTS_TOOL: import("./tool-registry").McpToolDeclaration<z.ZodRawShape, {
|
|
10
|
+
projects: z.ZodArray<z.ZodObject<{
|
|
11
|
+
name: z.ZodString;
|
|
12
|
+
type: z.ZodOptional<z.ZodEnum<["application", "library"]>>;
|
|
13
|
+
root: z.ZodString;
|
|
14
|
+
sourceRoot: z.ZodString;
|
|
15
|
+
selectorPrefix: z.ZodOptional<z.ZodString>;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
name: string;
|
|
18
|
+
root: string;
|
|
19
|
+
sourceRoot: string;
|
|
20
|
+
type?: "application" | "library" | undefined;
|
|
21
|
+
selectorPrefix?: string | undefined;
|
|
22
|
+
}, {
|
|
23
|
+
name: string;
|
|
24
|
+
root: string;
|
|
25
|
+
sourceRoot: string;
|
|
26
|
+
type?: "application" | "library" | undefined;
|
|
27
|
+
selectorPrefix?: string | undefined;
|
|
28
|
+
}>, "many">;
|
|
29
|
+
}>;
|
|
@@ -10,42 +10,44 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
10
10
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
11
|
};
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.
|
|
13
|
+
exports.LIST_PROJECTS_TOOL = void 0;
|
|
14
14
|
const node_path_1 = __importDefault(require("node:path"));
|
|
15
15
|
const zod_1 = __importDefault(require("zod"));
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
type
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
16
|
+
const tool_registry_1 = require("./tool-registry");
|
|
17
|
+
exports.LIST_PROJECTS_TOOL = (0, tool_registry_1.declareTool)({
|
|
18
|
+
name: 'list_projects',
|
|
19
|
+
title: 'List Angular Projects',
|
|
20
|
+
description: 'Lists the names of all applications and libraries defined within an Angular workspace. ' +
|
|
21
|
+
'It reads the `angular.json` configuration file to identify the projects. ',
|
|
22
|
+
outputSchema: {
|
|
23
|
+
projects: zod_1.default.array(zod_1.default.object({
|
|
24
|
+
name: zod_1.default
|
|
25
|
+
.string()
|
|
26
|
+
.describe('The name of the project, as defined in the `angular.json` file.'),
|
|
27
|
+
type: zod_1.default
|
|
28
|
+
.enum(['application', 'library'])
|
|
29
|
+
.optional()
|
|
30
|
+
.describe(`The type of the project, either 'application' or 'library'.`),
|
|
31
|
+
root: zod_1.default
|
|
32
|
+
.string()
|
|
33
|
+
.describe('The root directory of the project, relative to the workspace root.'),
|
|
34
|
+
sourceRoot: zod_1.default
|
|
35
|
+
.string()
|
|
36
|
+
.describe(`The root directory of the project's source files, relative to the workspace root.`),
|
|
37
|
+
selectorPrefix: zod_1.default
|
|
38
|
+
.string()
|
|
39
|
+
.optional()
|
|
40
|
+
.describe('The prefix to use for component selectors.' +
|
|
41
|
+
` For example, a prefix of 'app' would result in selectors like '<app-my-component>'.`),
|
|
42
|
+
})),
|
|
43
|
+
},
|
|
44
|
+
isReadOnly: true,
|
|
45
|
+
isLocalOnly: true,
|
|
46
|
+
shouldRegister: (context) => !!context.workspace,
|
|
47
|
+
factory: createListProjectsHandler,
|
|
48
|
+
});
|
|
49
|
+
function createListProjectsHandler({ workspace }) {
|
|
50
|
+
return async () => {
|
|
49
51
|
if (!workspace) {
|
|
50
52
|
return {
|
|
51
53
|
content: [
|
|
@@ -81,5 +83,5 @@ function registerListProjectsTool(server, context) {
|
|
|
81
83
|
],
|
|
82
84
|
structuredContent: { projects },
|
|
83
85
|
};
|
|
84
|
-
}
|
|
86
|
+
};
|
|
85
87
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright Google LLC All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
+
* found in the LICENSE file at https://angular.dev/license
|
|
7
|
+
*/
|
|
8
|
+
import type { McpServer, ToolCallback } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
|
+
import { ZodRawShape } from 'zod';
|
|
10
|
+
import type { AngularWorkspace } from '../../../utilities/config';
|
|
11
|
+
type ToolConfig = Parameters<McpServer['registerTool']>[1];
|
|
12
|
+
export interface McpToolContext {
|
|
13
|
+
workspace?: AngularWorkspace;
|
|
14
|
+
logger: {
|
|
15
|
+
warn(text: string): void;
|
|
16
|
+
};
|
|
17
|
+
exampleDatabasePath?: string;
|
|
18
|
+
}
|
|
19
|
+
export type McpToolFactory<TInput extends ZodRawShape> = (context: McpToolContext) => ToolCallback<TInput> | Promise<ToolCallback<TInput>>;
|
|
20
|
+
export interface McpToolDeclaration<TInput extends ZodRawShape, TOutput extends ZodRawShape> {
|
|
21
|
+
name: string;
|
|
22
|
+
title?: string;
|
|
23
|
+
description: string;
|
|
24
|
+
annotations?: ToolConfig['annotations'];
|
|
25
|
+
inputSchema?: TInput;
|
|
26
|
+
outputSchema?: TOutput;
|
|
27
|
+
factory: McpToolFactory<TInput>;
|
|
28
|
+
shouldRegister?: (context: McpToolContext) => boolean | Promise<boolean>;
|
|
29
|
+
isReadOnly?: boolean;
|
|
30
|
+
isLocalOnly?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export type AnyMcpToolDeclaration = McpToolDeclaration<any, any>;
|
|
33
|
+
export declare function declareTool<TInput extends ZodRawShape, TOutput extends ZodRawShape>(declaration: McpToolDeclaration<TInput, TOutput>): McpToolDeclaration<TInput, TOutput>;
|
|
34
|
+
export declare function registerTools(server: McpServer, context: McpToolContext, declarations: AnyMcpToolDeclaration[]): Promise<void>;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright Google LLC All Rights Reserved.
|
|
5
|
+
*
|
|
6
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7
|
+
* found in the LICENSE file at https://angular.dev/license
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.declareTool = declareTool;
|
|
11
|
+
exports.registerTools = registerTools;
|
|
12
|
+
function declareTool(declaration) {
|
|
13
|
+
return declaration;
|
|
14
|
+
}
|
|
15
|
+
async function registerTools(server, context, declarations) {
|
|
16
|
+
for (const declaration of declarations) {
|
|
17
|
+
if (declaration.shouldRegister && !(await declaration.shouldRegister(context))) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const { name, factory, shouldRegister, isReadOnly, isLocalOnly, ...config } = declaration;
|
|
21
|
+
const handler = await factory(context);
|
|
22
|
+
// Add declarative characteristics to annotations
|
|
23
|
+
config.annotations ??= {};
|
|
24
|
+
if (isReadOnly !== undefined) {
|
|
25
|
+
config.annotations.readOnlyHint = isReadOnly;
|
|
26
|
+
}
|
|
27
|
+
if (isLocalOnly !== undefined) {
|
|
28
|
+
// openWorldHint: false means local only
|
|
29
|
+
config.annotations.openWorldHint = !isLocalOnly;
|
|
30
|
+
}
|
|
31
|
+
server.registerTool(name, config, handler);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -5,14 +5,36 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
|
-
import { Argv } from 'yargs';
|
|
8
|
+
import type { Argv } from 'yargs';
|
|
9
9
|
import { CommandModule, CommandModuleImplementation } from '../../command-builder/command-module';
|
|
10
|
+
/**
|
|
11
|
+
* The command-line module for the `ng version` command.
|
|
12
|
+
*/
|
|
10
13
|
export default class VersionCommandModule extends CommandModule implements CommandModuleImplementation {
|
|
11
14
|
command: string;
|
|
12
15
|
aliases: string[] | undefined;
|
|
13
16
|
describe: string;
|
|
14
17
|
longDescriptionPath?: string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Builds the command-line options for the `ng version` command.
|
|
20
|
+
* @param localYargs The `yargs` instance to configure.
|
|
21
|
+
* @returns The configured `yargs` instance.
|
|
22
|
+
*/
|
|
15
23
|
builder(localYargs: Argv): Argv;
|
|
24
|
+
/**
|
|
25
|
+
* The main execution logic for the `ng version` command.
|
|
26
|
+
*/
|
|
16
27
|
run(): Promise<void>;
|
|
17
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Formats the Angular packages section of the version output.
|
|
30
|
+
* @param versionInfo An object containing the version information.
|
|
31
|
+
* @returns A string containing the formatted Angular packages information.
|
|
32
|
+
*/
|
|
33
|
+
private formatAngularPackages;
|
|
34
|
+
/**
|
|
35
|
+
* Formats the package table section of the version output.
|
|
36
|
+
* @param versions A map of package names to their versions.
|
|
37
|
+
* @returns A string containing the formatted package table.
|
|
38
|
+
*/
|
|
39
|
+
private formatPackageTable;
|
|
18
40
|
}
|