@angular/cli 21.1.0-next.0 → 21.1.0-next.1

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.
Files changed (55) hide show
  1. package/lib/code-examples.db +0 -0
  2. package/package.json +16 -16
  3. package/src/commands/mcp/host.d.ts +27 -0
  4. package/src/commands/mcp/host.js +8 -0
  5. package/src/commands/mcp/host.js.map +1 -1
  6. package/src/commands/mcp/mcp-server.d.ts +20 -9
  7. package/src/commands/mcp/mcp-server.js +4 -2
  8. package/src/commands/mcp/mcp-server.js.map +1 -1
  9. package/src/commands/mcp/resources/ai-tutor.md +199 -3
  10. package/src/commands/mcp/tools/ai-tutor.d.ts +5 -1
  11. package/src/commands/mcp/tools/best-practices.d.ts +3 -1
  12. package/src/commands/mcp/tools/build.d.ts +8 -19
  13. package/src/commands/mcp/tools/devserver/start-devserver.d.ts +2 -12
  14. package/src/commands/mcp/tools/devserver/stop-devserver.d.ts +3 -13
  15. package/src/commands/mcp/tools/devserver/wait-for-devserver-build.d.ts +10 -16
  16. package/src/commands/mcp/tools/doc-search.d.ts +1 -11
  17. package/src/commands/mcp/tools/examples/database-discovery.d.ts +34 -0
  18. package/src/commands/mcp/tools/examples/database-discovery.js +87 -0
  19. package/src/commands/mcp/tools/examples/database-discovery.js.map +1 -0
  20. package/src/commands/mcp/tools/examples/database.d.ts +35 -0
  21. package/src/commands/mcp/tools/examples/database.js +125 -0
  22. package/src/commands/mcp/tools/examples/database.js.map +1 -0
  23. package/src/commands/mcp/tools/examples/index.d.ts +26 -0
  24. package/src/commands/mcp/tools/examples/index.js +149 -0
  25. package/src/commands/mcp/tools/examples/index.js.map +1 -0
  26. package/src/commands/mcp/tools/examples/query-escaper.d.ts +20 -0
  27. package/src/commands/mcp/tools/examples/query-escaper.js +68 -0
  28. package/src/commands/mcp/tools/examples/query-escaper.js.map +1 -0
  29. package/src/commands/mcp/tools/examples/runtime-database.d.ts +10 -0
  30. package/src/commands/mcp/tools/examples/runtime-database.js +192 -0
  31. package/src/commands/mcp/tools/examples/runtime-database.js.map +1 -0
  32. package/src/commands/mcp/tools/examples/schemas.d.ts +29 -0
  33. package/src/commands/mcp/tools/examples/schemas.js +101 -0
  34. package/src/commands/mcp/tools/examples/schemas.js.map +1 -0
  35. package/src/commands/mcp/tools/examples/utils.d.ts +14 -0
  36. package/src/commands/mcp/tools/examples/utils.js +31 -0
  37. package/src/commands/mcp/tools/examples/utils.js.map +1 -0
  38. package/src/commands/mcp/tools/modernize.d.ts +8 -18
  39. package/src/commands/mcp/tools/onpush-zoneless-migration/zoneless-migration.d.ts +3 -1
  40. package/src/commands/mcp/tools/projects.d.ts +23 -64
  41. package/src/commands/mcp/tools/tool-registry.d.ts +4 -3
  42. package/src/commands/mcp/tools/tool-registry.js.map +1 -1
  43. package/src/package-managers/host.d.ts +6 -0
  44. package/src/package-managers/host.js +1 -0
  45. package/src/package-managers/host.js.map +1 -1
  46. package/src/package-managers/package-manager-descriptor.d.ts +6 -6
  47. package/src/package-managers/package-manager-descriptor.js +5 -5
  48. package/src/package-managers/package-manager-descriptor.js.map +1 -1
  49. package/src/package-managers/package-manager.d.ts +21 -3
  50. package/src/package-managers/package-manager.js +74 -5
  51. package/src/package-managers/package-manager.js.map +1 -1
  52. package/src/utilities/version.js +1 -1
  53. package/src/commands/mcp/tools/examples.d.ts +0 -58
  54. package/src/commands/mcp/tools/examples.js +0 -654
  55. package/src/commands/mcp/tools/examples.js.map +0 -1
@@ -14,24 +14,18 @@ export declare const WATCH_DELAY = 1000;
14
14
  declare const waitForDevserverBuildToolInputSchema: z.ZodObject<{
15
15
  project: z.ZodOptional<z.ZodString>;
16
16
  timeout: z.ZodDefault<z.ZodNumber>;
17
- }, "strip", z.ZodTypeAny, {
18
- timeout: number;
19
- project?: string | undefined;
20
- }, {
21
- project?: string | undefined;
22
- timeout?: number | undefined;
23
- }>;
17
+ }, z.core.$strip>;
24
18
  export type WaitForDevserverBuildToolInput = z.infer<typeof waitForDevserverBuildToolInputSchema>;
25
19
  declare const waitForDevserverBuildToolOutputSchema: z.ZodObject<{
26
- status: z.ZodEnum<["success", "failure", "unknown", "timeout", "no_devserver_found"]>;
27
- logs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
28
- }, "strip", z.ZodTypeAny, {
29
- status: "success" | "timeout" | "failure" | "unknown" | "no_devserver_found";
30
- logs?: string[] | undefined;
31
- }, {
32
- status: "success" | "timeout" | "failure" | "unknown" | "no_devserver_found";
33
- logs?: string[] | undefined;
34
- }>;
20
+ status: z.ZodEnum<{
21
+ success: "success";
22
+ timeout: "timeout";
23
+ failure: "failure";
24
+ unknown: "unknown";
25
+ no_devserver_found: "no_devserver_found";
26
+ }>;
27
+ logs: z.ZodOptional<z.ZodArray<z.ZodString>>;
28
+ }, z.core.$strip>;
35
29
  export type WaitForDevserverBuildToolOutput = z.infer<typeof waitForDevserverBuildToolOutputSchema>;
36
30
  export declare function waitForDevserverBuild(input: WaitForDevserverBuildToolInput, context: McpToolContext): Promise<{
37
31
  content: {
@@ -17,15 +17,5 @@ export declare const DOC_SEARCH_TOOL: import("./tool-registry").McpToolDeclarati
17
17
  breadcrumb: z.ZodString;
18
18
  url: z.ZodString;
19
19
  content: z.ZodOptional<z.ZodString>;
20
- }, "strip", z.ZodTypeAny, {
21
- title: string;
22
- breadcrumb: string;
23
- url: string;
24
- content?: string | undefined;
25
- }, {
26
- title: string;
27
- breadcrumb: string;
28
- url: string;
29
- content?: string | undefined;
30
- }>, "many">;
20
+ }, z.core.$strip>>;
31
21
  }>;
@@ -0,0 +1,34 @@
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 { McpToolContext } from '../tool-registry';
9
+ /**
10
+ * Attempts to find version-specific example databases from the user's installed
11
+ * versions of known Angular packages. It looks for a custom `angular` metadata property in each
12
+ * package's `package.json` to locate the database.
13
+ *
14
+ * @example A sample `package.json` `angular` field:
15
+ * ```json
16
+ * {
17
+ * "angular": {
18
+ * "examples": {
19
+ * "format": "sqlite",
20
+ * "path": "./resources/code-examples.db"
21
+ * }
22
+ * }
23
+ * }
24
+ * ```
25
+ *
26
+ * @param workspacePath The absolute path to the user's `angular.json` file.
27
+ * @param logger The MCP tool context logger for reporting warnings.
28
+ * @param host The host interface for file system and module resolution operations.
29
+ * @returns A promise that resolves to an array of objects, each containing a database path and source.
30
+ */
31
+ export declare function getVersionSpecificExampleDatabases(workspacePath: string, logger: McpToolContext['logger'], host: McpToolContext['host']): Promise<{
32
+ dbPath: string;
33
+ source: string;
34
+ }[]>;
@@ -0,0 +1,87 @@
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.getVersionSpecificExampleDatabases = getVersionSpecificExampleDatabases;
11
+ const node_path_1 = require("node:path");
12
+ /**
13
+ * A list of known Angular packages that may contain example databases.
14
+ * The tool will attempt to resolve and load example databases from these packages.
15
+ */
16
+ const KNOWN_EXAMPLE_PACKAGES = ['@angular/core', '@angular/aria', '@angular/forms'];
17
+ /**
18
+ * Attempts to find version-specific example databases from the user's installed
19
+ * versions of known Angular packages. It looks for a custom `angular` metadata property in each
20
+ * package's `package.json` to locate the database.
21
+ *
22
+ * @example A sample `package.json` `angular` field:
23
+ * ```json
24
+ * {
25
+ * "angular": {
26
+ * "examples": {
27
+ * "format": "sqlite",
28
+ * "path": "./resources/code-examples.db"
29
+ * }
30
+ * }
31
+ * }
32
+ * ```
33
+ *
34
+ * @param workspacePath The absolute path to the user's `angular.json` file.
35
+ * @param logger The MCP tool context logger for reporting warnings.
36
+ * @param host The host interface for file system and module resolution operations.
37
+ * @returns A promise that resolves to an array of objects, each containing a database path and source.
38
+ */
39
+ async function getVersionSpecificExampleDatabases(workspacePath, logger, host) {
40
+ const databases = [];
41
+ for (const packageName of KNOWN_EXAMPLE_PACKAGES) {
42
+ // 1. Resolve the path to package.json
43
+ let pkgJsonPath;
44
+ try {
45
+ pkgJsonPath = host.resolveModule(`${packageName}/package.json`, workspacePath);
46
+ }
47
+ catch (e) {
48
+ // This is not a warning because the user may not have all known packages installed.
49
+ continue;
50
+ }
51
+ // 2. Read and parse package.json, then find the database.
52
+ try {
53
+ const pkgJsonContent = await host.readFile(pkgJsonPath, 'utf-8');
54
+ const pkgJson = JSON.parse(pkgJsonContent);
55
+ const examplesInfo = pkgJson['angular']?.examples;
56
+ if (examplesInfo &&
57
+ examplesInfo.format === 'sqlite' &&
58
+ typeof examplesInfo.path === 'string') {
59
+ const packageDirectory = (0, node_path_1.dirname)(pkgJsonPath);
60
+ const dbPath = (0, node_path_1.resolve)(packageDirectory, examplesInfo.path);
61
+ // Ensure the resolved database path is within the package boundary.
62
+ const relativePath = (0, node_path_1.relative)(packageDirectory, dbPath);
63
+ if (relativePath.startsWith('..') || (0, node_path_1.isAbsolute)(relativePath)) {
64
+ logger.warn(`Detected a potential path traversal attempt in '${pkgJsonPath}'. ` +
65
+ `The path '${examplesInfo.path}' escapes the package boundary. ` +
66
+ 'This database will be skipped.');
67
+ continue;
68
+ }
69
+ // Check the file size to prevent reading a very large file.
70
+ const stats = await host.stat(dbPath);
71
+ if (stats.size > 10 * 1024 * 1024) {
72
+ // 10MB
73
+ logger.warn(`The example database at '${dbPath}' is larger than 10MB (${stats.size} bytes). ` +
74
+ 'This is unexpected and the file will not be used.');
75
+ continue;
76
+ }
77
+ const source = `package ${packageName}@${pkgJson.version}`;
78
+ databases.push({ dbPath, source });
79
+ }
80
+ }
81
+ catch (e) {
82
+ logger.warn(`Failed to read or parse version-specific examples metadata referenced in '${pkgJsonPath}': ${e instanceof Error ? e.message : e}.`);
83
+ }
84
+ }
85
+ return databases;
86
+ }
87
+ //# sourceMappingURL=database-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-discovery.js","sourceRoot":"","sources":["database-discovery.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAiCH,gFAkEC;AAjGD,yCAAmE;AAGnE;;;GAGG;AACH,MAAM,sBAAsB,GAAG,CAAC,eAAe,EAAE,eAAe,EAAE,gBAAgB,CAAC,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACI,KAAK,UAAU,kCAAkC,CACtD,aAAqB,EACrB,MAAgC,EAChC,IAA4B;IAE5B,MAAM,SAAS,GAAyC,EAAE,CAAC;IAE3D,KAAK,MAAM,WAAW,IAAI,sBAAsB,EAAE,CAAC;QACjD,sCAAsC;QACtC,IAAI,WAAmB,CAAC;QACxB,IAAI,CAAC;YACH,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,WAAW,eAAe,EAAE,aAAa,CAAC,CAAC;QACjF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,oFAAoF;YACpF,SAAS;QACX,CAAC;QAED,0DAA0D;QAC1D,IAAI,CAAC;YACH,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACjE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YAC3C,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC;YAElD,IACE,YAAY;gBACZ,YAAY,CAAC,MAAM,KAAK,QAAQ;gBAChC,OAAO,YAAY,CAAC,IAAI,KAAK,QAAQ,EACrC,CAAC;gBACD,MAAM,gBAAgB,GAAG,IAAA,mBAAO,EAAC,WAAW,CAAC,CAAC;gBAC9C,MAAM,MAAM,GAAG,IAAA,mBAAO,EAAC,gBAAgB,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;gBAE5D,oEAAoE;gBACpE,MAAM,YAAY,GAAG,IAAA,oBAAQ,EAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;gBACxD,IAAI,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAA,sBAAU,EAAC,YAAY,CAAC,EAAE,CAAC;oBAC9D,MAAM,CAAC,IAAI,CACT,mDAAmD,WAAW,KAAK;wBACjE,aAAa,YAAY,CAAC,IAAI,kCAAkC;wBAChE,gCAAgC,CACnC,CAAC;oBACF,SAAS;gBACX,CAAC;gBAED,4DAA4D;gBAC5D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACtC,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;oBAClC,OAAO;oBACP,MAAM,CAAC,IAAI,CACT,4BAA4B,MAAM,0BAA0B,KAAK,CAAC,IAAI,WAAW;wBAC/E,mDAAmD,CACtD,CAAC;oBACF,SAAS;gBACX,CAAC;gBAED,MAAM,MAAM,GAAG,WAAW,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBAC3D,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CACT,6EAA6E,WAAW,MACtF,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CACnC,GAAG,CACJ,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -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 { DatabaseSync } from 'node:sqlite';
9
+ import type { FindExampleInput } from './schemas';
10
+ /**
11
+ * Validates the schema version of the example database.
12
+ *
13
+ * @param db The database connection to validate.
14
+ * @param dbSource A string identifying the source of the database (e.g., 'bundled' or a version number).
15
+ * @throws An error if the schema version is missing or incompatible.
16
+ */
17
+ export declare function validateDatabaseSchema(db: DatabaseSync, dbSource: string): void;
18
+ export declare function queryDatabase(dbs: DatabaseSync[], input: FindExampleInput): {
19
+ content: {
20
+ type: "text";
21
+ text: string;
22
+ }[];
23
+ structuredContent: {
24
+ examples: {
25
+ title: string;
26
+ summary: string;
27
+ keywords: string[];
28
+ required_packages: string[];
29
+ related_concepts: string[];
30
+ related_tools: string[];
31
+ content: string;
32
+ snippet: string;
33
+ }[];
34
+ };
35
+ };
@@ -0,0 +1,125 @@
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.validateDatabaseSchema = validateDatabaseSchema;
11
+ exports.queryDatabase = queryDatabase;
12
+ const query_escaper_1 = require("./query-escaper");
13
+ const EXPECTED_SCHEMA_VERSION = 1;
14
+ /**
15
+ * Validates the schema version of the example database.
16
+ *
17
+ * @param db The database connection to validate.
18
+ * @param dbSource A string identifying the source of the database (e.g., 'bundled' or a version number).
19
+ * @throws An error if the schema version is missing or incompatible.
20
+ */
21
+ function validateDatabaseSchema(db, dbSource) {
22
+ const schemaVersionResult = db
23
+ .prepare('SELECT value FROM metadata WHERE key = ?')
24
+ .get('schema_version');
25
+ const actualSchemaVersion = schemaVersionResult ? Number(schemaVersionResult.value) : undefined;
26
+ if (actualSchemaVersion !== EXPECTED_SCHEMA_VERSION) {
27
+ db.close();
28
+ let errorMessage;
29
+ if (actualSchemaVersion === undefined) {
30
+ errorMessage = 'The example database is missing a schema version and cannot be used.';
31
+ }
32
+ else if (actualSchemaVersion > EXPECTED_SCHEMA_VERSION) {
33
+ errorMessage =
34
+ `This project's example database (version ${actualSchemaVersion})` +
35
+ ` is newer than what this version of the Angular CLI supports (version ${EXPECTED_SCHEMA_VERSION}).` +
36
+ ' Please update your `@angular/cli` package to a newer version.';
37
+ }
38
+ else {
39
+ errorMessage =
40
+ `This version of the Angular CLI (expects schema version ${EXPECTED_SCHEMA_VERSION})` +
41
+ ` requires a newer example database than the one found in this project (version ${actualSchemaVersion}).`;
42
+ }
43
+ throw new Error(`Incompatible example database schema from source '${dbSource}':\n${errorMessage}`);
44
+ }
45
+ }
46
+ function queryDatabase(dbs, input) {
47
+ const { query, keywords, required_packages, related_concepts, includeExperimental } = input;
48
+ // Build the query dynamically
49
+ const params = [];
50
+ let sql = `SELECT e.title, e.summary, e.keywords, e.required_packages, e.related_concepts, e.related_tools, e.content, ` +
51
+ // The `snippet` function generates a contextual snippet of the matched text.
52
+ // Column 6 is the `content` column. We highlight matches with asterisks and limit the snippet size.
53
+ "snippet(examples_fts, 6, '**', '**', '...', 15) AS snippet, " +
54
+ // The `bm25` function returns the relevance score of the match. The weights
55
+ // assigned to each column boost the ranking of documents where the search
56
+ // term appears in a more important field.
57
+ // Column order: title, summary, keywords, required_packages, related_concepts, related_tools, content
58
+ 'bm25(examples_fts, 10.0, 5.0, 5.0, 1.0, 2.0, 1.0, 1.0) AS rank ' +
59
+ 'FROM examples e JOIN examples_fts ON e.id = examples_fts.rowid';
60
+ const whereClauses = [];
61
+ // FTS query
62
+ if (query) {
63
+ whereClauses.push('examples_fts MATCH ?');
64
+ params.push((0, query_escaper_1.escapeSearchQuery)(query));
65
+ }
66
+ // JSON array filters
67
+ const addJsonFilter = (column, values) => {
68
+ if (values?.length) {
69
+ for (const value of values) {
70
+ whereClauses.push(`e.${column} LIKE ?`);
71
+ params.push(`%"${value}"%`);
72
+ }
73
+ }
74
+ };
75
+ addJsonFilter('keywords', keywords);
76
+ addJsonFilter('required_packages', required_packages);
77
+ addJsonFilter('related_concepts', related_concepts);
78
+ if (!includeExperimental) {
79
+ whereClauses.push('e.experimental = 0');
80
+ }
81
+ if (whereClauses.length > 0) {
82
+ sql += ` WHERE ${whereClauses.join(' AND ')}`;
83
+ }
84
+ // Query database and return results
85
+ const examples = [];
86
+ const textContent = [];
87
+ for (const db of dbs) {
88
+ const queryStatement = db.prepare(sql);
89
+ for (const exampleRecord of queryStatement.all(...params)) {
90
+ const record = exampleRecord;
91
+ const example = {
92
+ title: record['title'],
93
+ summary: record['summary'],
94
+ keywords: JSON.parse(record['keywords'] || '[]'),
95
+ required_packages: JSON.parse(record['required_packages'] || '[]'),
96
+ related_concepts: JSON.parse(record['related_concepts'] || '[]'),
97
+ related_tools: JSON.parse(record['related_tools'] || '[]'),
98
+ content: record['content'],
99
+ snippet: record['snippet'],
100
+ rank: record['rank'],
101
+ };
102
+ examples.push(example);
103
+ }
104
+ }
105
+ // Order the combined results by relevance.
106
+ // The `bm25` algorithm returns a smaller number for a more relevant match.
107
+ examples.sort((a, b) => a.rank - b.rank);
108
+ // The `rank` field is an internal implementation detail for sorting and should not be
109
+ // returned to the user. We create a new array of examples without the `rank`.
110
+ const finalExamples = examples.map(({ rank, ...rest }) => rest);
111
+ for (const example of finalExamples) {
112
+ // Also create a more structured text output
113
+ let text = `## Example: ${example.title}\n**Summary:** ${example.summary}`;
114
+ if (example.snippet) {
115
+ text += `\n**Snippet:** ${example.snippet}`;
116
+ }
117
+ text += `\n\n---\n\n${example.content}`;
118
+ textContent.push({ type: 'text', text });
119
+ }
120
+ return {
121
+ content: textContent,
122
+ structuredContent: { examples: finalExamples },
123
+ };
124
+ }
125
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
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
+ export declare const FIND_EXAMPLE_TOOL: import("../tool-registry").McpToolDeclaration<{
9
+ workspacePath: import("zod").ZodOptional<import("zod").ZodString>;
10
+ query: import("zod").ZodString;
11
+ keywords: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
12
+ required_packages: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
13
+ related_concepts: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
14
+ includeExperimental: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodBoolean>>;
15
+ }, {
16
+ examples: import("zod").ZodArray<import("zod").ZodObject<{
17
+ title: import("zod").ZodString;
18
+ summary: import("zod").ZodString;
19
+ keywords: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
20
+ required_packages: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
21
+ related_concepts: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
22
+ related_tools: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
23
+ content: import("zod").ZodString;
24
+ snippet: import("zod").ZodOptional<import("zod").ZodString>;
25
+ }, import("zod/v4/core").$strip>>;
26
+ }>;
@@ -0,0 +1,149 @@
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
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.FIND_EXAMPLE_TOOL = void 0;
44
+ const tool_registry_1 = require("../tool-registry");
45
+ const database_1 = require("./database");
46
+ const database_discovery_1 = require("./database-discovery");
47
+ const runtime_database_1 = require("./runtime-database");
48
+ const schemas_1 = require("./schemas");
49
+ const utils_1 = require("./utils");
50
+ exports.FIND_EXAMPLE_TOOL = (0, tool_registry_1.declareTool)({
51
+ name: 'find_examples',
52
+ title: 'Find Angular Code Examples',
53
+ description: `
54
+ <Purpose>
55
+ Augments your knowledge base with a curated database of official, best-practice code examples,
56
+ focusing on **modern, new, and recently updated** Angular features. This tool acts as a RAG
57
+ (Retrieval-Augmented Generation) source, providing ground-truth information on the latest Angular
58
+ APIs and patterns. You **MUST** use it to understand and apply current standards when working with
59
+ new or evolving features.
60
+ </Purpose>
61
+ <Use Cases>
62
+ * **Knowledge Augmentation:** Learning about new or updated Angular features (e.g., query: 'signal input' or 'deferrable views').
63
+ * **Modern Implementation:** Finding the correct modern syntax for features
64
+ (e.g., query: 'functional route guard' or 'http client with fetch').
65
+ * **Refactoring to Modern Patterns:** Upgrading older code by finding examples of new syntax
66
+ (e.g., query: 'built-in control flow' to replace "*ngIf").
67
+ * **Advanced Filtering:** Combining a full-text search with filters to narrow results.
68
+ (e.g., query: 'forms', required_packages: ['@angular/forms'], keywords: ['validation'])
69
+ </Use Cases>
70
+ <Operational Notes>
71
+ * **Project-Specific Use (Recommended):** For tasks inside a user's project, you **MUST** provide the
72
+ \`workspacePath\` argument to get examples that match the project's Angular version. Get this
73
+ path from \`list_projects\`.
74
+ * **General Use:** If no project context is available (e.g., for general questions or learning),
75
+ you can call the tool without the \`workspacePath\` argument. It will return the latest
76
+ generic examples.
77
+ * **Tool Selection:** This database primarily contains examples for new and recently updated Angular
78
+ features. For established, core features, the main documentation (via the
79
+ \`search_documentation\` tool) may be a better source of information.
80
+ * The examples in this database are the single source of truth for modern Angular coding patterns.
81
+ * The search query uses a powerful full-text search syntax (FTS5). Refer to the 'query'
82
+ parameter description for detailed syntax rules and examples.
83
+ * You can combine the main 'query' with optional filters like 'keywords', 'required_packages',
84
+ and 'related_concepts' to create highly specific searches.
85
+ </Operational Notes>`,
86
+ inputSchema: schemas_1.findExampleInputSchema.shape,
87
+ outputSchema: schemas_1.findExampleOutputSchema.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({ logger, exampleDatabasePath, host }) {
103
+ const runtimeDb = process.env['NG_MCP_EXAMPLES_DIR']
104
+ ? await (0, runtime_database_1.setupRuntimeExamples)(process.env['NG_MCP_EXAMPLES_DIR'], host)
105
+ : undefined;
106
+ (0, utils_1.suppressSqliteWarning)();
107
+ return async (input) => {
108
+ // If the dev-time override is present, use it and bypass all other logic.
109
+ if (runtimeDb) {
110
+ return (0, database_1.queryDatabase)([runtimeDb], input);
111
+ }
112
+ const resolvedDbs = [];
113
+ // First, try to get all available version-specific guides.
114
+ if (input.workspacePath) {
115
+ const versionSpecificDbs = await (0, database_discovery_1.getVersionSpecificExampleDatabases)(input.workspacePath, logger, host);
116
+ for (const db of versionSpecificDbs) {
117
+ resolvedDbs.push({ path: db.dbPath, source: db.source });
118
+ }
119
+ }
120
+ // If no version-specific guides were found for any reason, fall back to the bundled version.
121
+ if (resolvedDbs.length === 0 && exampleDatabasePath) {
122
+ resolvedDbs.push({ path: exampleDatabasePath, source: 'bundled' });
123
+ }
124
+ if (resolvedDbs.length === 0) {
125
+ // This should be prevented by the registration logic in mcp-server.ts
126
+ throw new Error('No example databases are available.');
127
+ }
128
+ const { DatabaseSync } = await Promise.resolve().then(() => __importStar(require('node:sqlite')));
129
+ const dbConnections = [];
130
+ for (const { path, source } of resolvedDbs) {
131
+ const db = new DatabaseSync(path, { readOnly: true });
132
+ try {
133
+ (0, database_1.validateDatabaseSchema)(db, source);
134
+ dbConnections.push(db);
135
+ }
136
+ catch (e) {
137
+ logger.warn(e.message);
138
+ // If a database is invalid, we should not query it, but we should not fail the whole tool.
139
+ // We will just skip this database and try to use the others.
140
+ continue;
141
+ }
142
+ }
143
+ if (dbConnections.length === 0) {
144
+ throw new Error('All available example databases were invalid. Cannot perform query.');
145
+ }
146
+ return (0, database_1.queryDatabase)(dbConnections, input);
147
+ };
148
+ }
149
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
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
+ /**
9
+ * Escapes a search query for FTS5 by tokenizing and quoting terms.
10
+ *
11
+ * This function processes a raw search string and prepares it for an FTS5 full-text search.
12
+ * It correctly handles quoted phrases, logical operators (AND, OR, NOT), parentheses,
13
+ * and prefix searches (ending with an asterisk), ensuring that individual search
14
+ * terms are properly quoted to be treated as literals by the search engine.
15
+ * This is primarily intended to avoid unintentional usage of FTS5 query syntax by consumers.
16
+ *
17
+ * @param query The raw search query string.
18
+ * @returns A sanitized query string suitable for FTS5.
19
+ */
20
+ export declare function escapeSearchQuery(query: string): string;
@@ -0,0 +1,68 @@
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.escapeSearchQuery = escapeSearchQuery;
11
+ /**
12
+ * Escapes a search query for FTS5 by tokenizing and quoting terms.
13
+ *
14
+ * This function processes a raw search string and prepares it for an FTS5 full-text search.
15
+ * It correctly handles quoted phrases, logical operators (AND, OR, NOT), parentheses,
16
+ * and prefix searches (ending with an asterisk), ensuring that individual search
17
+ * terms are properly quoted to be treated as literals by the search engine.
18
+ * This is primarily intended to avoid unintentional usage of FTS5 query syntax by consumers.
19
+ *
20
+ * @param query The raw search query string.
21
+ * @returns A sanitized query string suitable for FTS5.
22
+ */
23
+ function escapeSearchQuery(query) {
24
+ // This regex tokenizes the query string into parts:
25
+ // 1. Quoted phrases (e.g., "foo bar")
26
+ // 2. Parentheses ( and )
27
+ // 3. FTS5 operators (AND, OR, NOT, NEAR)
28
+ // 4. Words, which can include a trailing asterisk for prefix search (e.g., foo*)
29
+ const tokenizer = /"([^"]*)"|([()])|\b(AND|OR|NOT|NEAR)\b|([^\s()]+)/g;
30
+ let match;
31
+ const result = [];
32
+ let lastIndex = 0;
33
+ while ((match = tokenizer.exec(query)) !== null) {
34
+ // Add any whitespace or other characters between tokens
35
+ if (match.index > lastIndex) {
36
+ result.push(query.substring(lastIndex, match.index));
37
+ }
38
+ const [, quoted, parenthesis, operator, term] = match;
39
+ if (quoted !== undefined) {
40
+ // It's a quoted phrase, keep it as is.
41
+ result.push(`"${quoted}"`);
42
+ }
43
+ else if (parenthesis) {
44
+ // It's a parenthesis, keep it as is.
45
+ result.push(parenthesis);
46
+ }
47
+ else if (operator) {
48
+ // It's an operator, keep it as is.
49
+ result.push(operator);
50
+ }
51
+ else if (term) {
52
+ // It's a term that needs to be quoted.
53
+ if (term.endsWith('*')) {
54
+ result.push(`"${term.slice(0, -1)}"*`);
55
+ }
56
+ else {
57
+ result.push(`"${term}"`);
58
+ }
59
+ }
60
+ lastIndex = tokenizer.lastIndex;
61
+ }
62
+ // Add any remaining part of the string
63
+ if (lastIndex < query.length) {
64
+ result.push(query.substring(lastIndex));
65
+ }
66
+ return result.join('');
67
+ }
68
+ //# sourceMappingURL=query-escaper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-escaper.js","sourceRoot":"","sources":["query-escaper.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAcH,8CA6CC;AAzDD;;;;;;;;;;;GAWG;AACH,SAAgB,iBAAiB,CAAC,KAAa;IAC7C,oDAAoD;IACpD,sCAAsC;IACtC,yBAAyB;IACzB,yCAAyC;IACzC,iFAAiF;IACjF,MAAM,SAAS,GAAG,oDAAoD,CAAC;IACvE,IAAI,KAAK,CAAC;IACV,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAChD,wDAAwD;QACxD,IAAI,KAAK,CAAC,KAAK,GAAG,SAAS,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;QAEtD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,uCAAuC;YACvC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;QAC7B,CAAC;aAAM,IAAI,WAAW,EAAE,CAAC;YACvB,qCAAqC;YACrC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,QAAQ,EAAE,CAAC;YACpB,mCAAmC;YACnC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;aAAM,IAAI,IAAI,EAAE,CAAC;YAChB,uCAAuC;YACvC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC;IAClC,CAAC;IAED,uCAAuC;IACvC,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,10 @@
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 { DatabaseSync } from 'node:sqlite';
9
+ import type { McpToolContext } from '../tool-registry';
10
+ export declare function setupRuntimeExamples(examplesPath: string, host: McpToolContext['host']): Promise<DatabaseSync>;