@ng-annotate/angular 0.3.6 → 0.3.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-annotate/angular",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "schematics": "./schematics/collection.json",
5
5
  "description": "Angular library for ng-annotate-mcp — browser overlay for annotating components and routing instructions to an AI agent",
6
6
  "keywords": [
@@ -1,8 +1,43 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.default = default_1;
4
37
  const schematics_1 = require("@angular-devkit/schematics");
5
38
  const tasks_1 = require("@angular-devkit/schematics/tasks");
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
6
41
  /** Insert `newImport` on the line after the last import statement (handles multi-line imports and blank lines between groups). */
7
42
  function insertAfterLastImport(content, newImport) {
8
43
  const lines = content.split('\n');
@@ -90,12 +125,43 @@ function addProviders() {
90
125
  context.logger.info(`✅ Added provideNgAnnotate() to ${appConfigPath}`);
91
126
  };
92
127
  }
128
+ /** Walk up from startDir until we find a .git folder; returns that directory or null. */
129
+ function findGitRoot(startDir) {
130
+ let dir = path.resolve(startDir);
131
+ while (true) {
132
+ if (fs.existsSync(path.join(dir, '.git')))
133
+ return dir;
134
+ const parent = path.dirname(dir);
135
+ if (parent === dir)
136
+ return null;
137
+ dir = parent;
138
+ }
139
+ }
140
+ /**
141
+ * Write a config file outside the schematic Tree (e.g. to a parent git root).
142
+ * Uses fs directly — intentionally bypasses Tree so it works for out-of-project paths.
143
+ */
144
+ function writeOutsideTree(absPath, content, context) {
145
+ const dir = path.dirname(absPath);
146
+ if (!fs.existsSync(dir))
147
+ fs.mkdirSync(dir, { recursive: true });
148
+ if (fs.existsSync(absPath)) {
149
+ context.logger.info(`${path.basename(absPath)} already exists at workspace root, skipping.`);
150
+ return;
151
+ }
152
+ fs.writeFileSync(absPath, content, 'utf-8');
153
+ context.logger.info(`✅ Created ${path.basename(absPath)} at workspace root (${dir})`);
154
+ }
93
155
  function addMcpConfig(options) {
94
156
  return (tree, context) => {
95
- const projectRoot = process.cwd().replace(/\\/g, '/');
96
- const env = { NG_ANNOTATE_PROJECT_ROOT: projectRoot };
157
+ const projectRoot = process.cwd();
158
+ const env = { NG_ANNOTATE_PROJECT_ROOT: projectRoot.replace(/\\/g, '/') };
97
159
  const isWindows = process.platform === 'win32';
98
160
  const { aiTool } = options;
161
+ // Detect monorepo: if git root is a parent of the Angular project, VS Code is likely
162
+ // opened there — write configs to both the project folder and the git root.
163
+ const gitRoot = findGitRoot(projectRoot);
164
+ const isSubproject = gitRoot !== null && path.resolve(gitRoot) !== path.resolve(projectRoot);
99
165
  if (aiTool === 'other') {
100
166
  const claudeConfig = JSON.stringify({
101
167
  mcpServers: {
@@ -125,41 +191,47 @@ function addMcpConfig(options) {
125
191
  }
126
192
  // .mcp.json — Claude Code (needs cmd /c on Windows to invoke npx.cmd)
127
193
  if (aiTool === 'claude-code' || aiTool === 'both') {
194
+ const mcpConfig = JSON.stringify({
195
+ mcpServers: {
196
+ 'ng-annotate': isWindows
197
+ ? { command: 'cmd', args: ['/c', 'npx', '-y', '@ng-annotate/mcp-server'], env }
198
+ : { command: 'npx', args: ['-y', '@ng-annotate/mcp-server'], env },
199
+ },
200
+ }, null, 2) + '\n';
128
201
  if (!tree.exists('.mcp.json')) {
129
- const mcpConfig = {
130
- mcpServers: {
131
- 'ng-annotate': isWindows
132
- ? { command: 'cmd', args: ['/c', 'npx', '-y', '@ng-annotate/mcp-server'], env }
133
- : { command: 'npx', args: ['-y', '@ng-annotate/mcp-server'], env },
134
- },
135
- };
136
- tree.create('.mcp.json', JSON.stringify(mcpConfig, null, 2) + '\n');
202
+ tree.create('.mcp.json', mcpConfig);
137
203
  context.logger.info('✅ Created .mcp.json');
138
204
  }
139
205
  else {
140
206
  context.logger.info('.mcp.json already exists, skipping.');
141
207
  }
208
+ if (isSubproject) {
209
+ writeOutsideTree(path.join(gitRoot, '.mcp.json'), mcpConfig, context);
210
+ }
142
211
  }
143
212
  // .vscode/mcp.json — VS Code Copilot
144
213
  if (aiTool === 'vscode' || aiTool === 'both') {
214
+ const vscodeMcpConfig = JSON.stringify({
215
+ servers: {
216
+ 'ng-annotate': {
217
+ type: 'stdio',
218
+ command: 'npx',
219
+ args: ['-y', '@ng-annotate/mcp-server'],
220
+ env,
221
+ },
222
+ },
223
+ }, null, 2) + '\n';
145
224
  const vscodeMcpPath = '.vscode/mcp.json';
146
225
  if (!tree.exists(vscodeMcpPath)) {
147
- const vscodeMcpConfig = {
148
- servers: {
149
- 'ng-annotate': {
150
- type: 'stdio',
151
- command: 'npx',
152
- args: ['-y', '@ng-annotate/mcp-server'],
153
- env,
154
- },
155
- },
156
- };
157
- tree.create(vscodeMcpPath, JSON.stringify(vscodeMcpConfig, null, 2) + '\n');
226
+ tree.create(vscodeMcpPath, vscodeMcpConfig);
158
227
  context.logger.info('✅ Created .vscode/mcp.json');
159
228
  }
160
229
  else {
161
230
  context.logger.info('.vscode/mcp.json already exists, skipping.');
162
231
  }
232
+ if (isSubproject) {
233
+ writeOutsideTree(path.join(gitRoot, '.vscode', 'mcp.json'), vscodeMcpConfig, context);
234
+ }
163
235
  }
164
236
  };
165
237
  }
@@ -1,5 +1,7 @@
1
1
  import { Rule, SchematicContext, Tree, chain, SchematicsException } from '@angular-devkit/schematics';
2
2
  import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
3
5
 
4
6
  /** Insert `newImport` on the line after the last import statement (handles multi-line imports and blank lines between groups). */
5
7
  function insertAfterLastImport(content: string, newImport: string): string {
@@ -116,13 +118,45 @@ function addProviders(): Rule {
116
118
  };
117
119
  }
118
120
 
121
+ /** Walk up from startDir until we find a .git folder; returns that directory or null. */
122
+ function findGitRoot(startDir: string): string | null {
123
+ let dir = path.resolve(startDir);
124
+ while (true) {
125
+ if (fs.existsSync(path.join(dir, '.git'))) return dir;
126
+ const parent = path.dirname(dir);
127
+ if (parent === dir) return null;
128
+ dir = parent;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Write a config file outside the schematic Tree (e.g. to a parent git root).
134
+ * Uses fs directly — intentionally bypasses Tree so it works for out-of-project paths.
135
+ */
136
+ function writeOutsideTree(absPath: string, content: string, context: SchematicContext): void {
137
+ const dir = path.dirname(absPath);
138
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
139
+ if (fs.existsSync(absPath)) {
140
+ context.logger.info(`${path.basename(absPath)} already exists at workspace root, skipping.`);
141
+ return;
142
+ }
143
+ fs.writeFileSync(absPath, content, 'utf-8');
144
+ context.logger.info(`✅ Created ${path.basename(absPath)} at workspace root (${dir})`);
145
+ }
146
+
119
147
  function addMcpConfig(options: Options): Rule {
120
148
  return (tree: Tree, context: SchematicContext) => {
121
- const projectRoot = process.cwd().replace(/\\/g, '/');
122
- const env = { NG_ANNOTATE_PROJECT_ROOT: projectRoot };
149
+ const projectRoot = process.cwd();
150
+ const env = { NG_ANNOTATE_PROJECT_ROOT: projectRoot.replace(/\\/g, '/') };
123
151
  const isWindows = process.platform === 'win32';
124
152
  const { aiTool } = options;
125
153
 
154
+ // Detect monorepo: if git root is a parent of the Angular project, VS Code is likely
155
+ // opened there — write configs to both the project folder and the git root.
156
+ const gitRoot = findGitRoot(projectRoot);
157
+ const isSubproject =
158
+ gitRoot !== null && path.resolve(gitRoot) !== path.resolve(projectRoot);
159
+
126
160
  if (aiTool === 'other') {
127
161
  const claudeConfig = JSON.stringify(
128
162
  {
@@ -163,40 +197,60 @@ function addMcpConfig(options: Options): Rule {
163
197
 
164
198
  // .mcp.json — Claude Code (needs cmd /c on Windows to invoke npx.cmd)
165
199
  if (aiTool === 'claude-code' || aiTool === 'both') {
166
- if (!tree.exists('.mcp.json')) {
167
- const mcpConfig = {
168
- mcpServers: {
169
- 'ng-annotate': isWindows
170
- ? { command: 'cmd', args: ['/c', 'npx', '-y', '@ng-annotate/mcp-server'], env }
171
- : { command: 'npx', args: ['-y', '@ng-annotate/mcp-server'], env },
200
+ const mcpConfig =
201
+ JSON.stringify(
202
+ {
203
+ mcpServers: {
204
+ 'ng-annotate': isWindows
205
+ ? { command: 'cmd', args: ['/c', 'npx', '-y', '@ng-annotate/mcp-server'], env }
206
+ : { command: 'npx', args: ['-y', '@ng-annotate/mcp-server'], env },
207
+ },
172
208
  },
173
- };
174
- tree.create('.mcp.json', JSON.stringify(mcpConfig, null, 2) + '\n');
209
+ null,
210
+ 2,
211
+ ) + '\n';
212
+
213
+ if (!tree.exists('.mcp.json')) {
214
+ tree.create('.mcp.json', mcpConfig);
175
215
  context.logger.info('✅ Created .mcp.json');
176
216
  } else {
177
217
  context.logger.info('.mcp.json already exists, skipping.');
178
218
  }
219
+
220
+ if (isSubproject) {
221
+ writeOutsideTree(path.join(gitRoot!, '.mcp.json'), mcpConfig, context);
222
+ }
179
223
  }
180
224
 
181
225
  // .vscode/mcp.json — VS Code Copilot
182
226
  if (aiTool === 'vscode' || aiTool === 'both') {
183
- const vscodeMcpPath = '.vscode/mcp.json';
184
- if (!tree.exists(vscodeMcpPath)) {
185
- const vscodeMcpConfig = {
186
- servers: {
187
- 'ng-annotate': {
188
- type: 'stdio',
189
- command: 'npx',
190
- args: ['-y', '@ng-annotate/mcp-server'],
191
- env,
227
+ const vscodeMcpConfig =
228
+ JSON.stringify(
229
+ {
230
+ servers: {
231
+ 'ng-annotate': {
232
+ type: 'stdio',
233
+ command: 'npx',
234
+ args: ['-y', '@ng-annotate/mcp-server'],
235
+ env,
236
+ },
192
237
  },
193
238
  },
194
- };
195
- tree.create(vscodeMcpPath, JSON.stringify(vscodeMcpConfig, null, 2) + '\n');
239
+ null,
240
+ 2,
241
+ ) + '\n';
242
+
243
+ const vscodeMcpPath = '.vscode/mcp.json';
244
+ if (!tree.exists(vscodeMcpPath)) {
245
+ tree.create(vscodeMcpPath, vscodeMcpConfig);
196
246
  context.logger.info('✅ Created .vscode/mcp.json');
197
247
  } else {
198
248
  context.logger.info('.vscode/mcp.json already exists, skipping.');
199
249
  }
250
+
251
+ if (isSubproject) {
252
+ writeOutsideTree(path.join(gitRoot!, '.vscode', 'mcp.json'), vscodeMcpConfig, context);
253
+ }
200
254
  }
201
255
  };
202
256
  }