codeninja 2.0.0 → 3.2.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.
Files changed (46) hide show
  1. package/README.md +122 -251
  2. package/agent/global-agent.md +8 -0
  3. package/cli.js +248 -223
  4. package/commands/debug.workflow.md +94 -0
  5. package/commands/explain.workflow.md +59 -0
  6. package/commands/optimize.workflow.md +124 -0
  7. package/commands/review.workflow.md +85 -0
  8. package/ide/antigravity/.agents/personas/database-architect.md +249 -0
  9. package/ide/antigravity/.agents/personas/global-orchestrator.md +144 -0
  10. package/ide/antigravity/.agents/personas/nodejs-backend.md +250 -0
  11. package/ide/antigravity/.agents/personas/reactjs-frontend.md +179 -0
  12. package/ide/antigravity/.agents/skills/api-builder/SKILL.md +179 -0
  13. package/ide/antigravity/.agents/skills/code-intelligence/SKILL.md +184 -0
  14. package/ide/antigravity/.agents/skills/database/SKILL.md +165 -0
  15. package/ide/antigravity/.agents/skills/mcp-and-context/SKILL.md +111 -0
  16. package/ide/antigravity/.agents/skills/reactjs/SKILL.md +211 -0
  17. package/ide/antigravity/.agents/workflows/codeninja-api.md +111 -0
  18. package/ide/antigravity/.agents/workflows/codeninja-audit.md +81 -0
  19. package/ide/antigravity/.agents/workflows/codeninja-db-create.md +124 -0
  20. package/ide/antigravity/.agents/workflows/codeninja-db-drop.md +87 -0
  21. package/ide/antigravity/.agents/workflows/codeninja-db-index.md +70 -0
  22. package/ide/antigravity/.agents/workflows/codeninja-db-modify.md +106 -0
  23. package/ide/antigravity/.agents/workflows/codeninja-db-seed.md +76 -0
  24. package/ide/antigravity/.agents/workflows/codeninja-db-sync.md +70 -0
  25. package/ide/antigravity/.agents/workflows/codeninja-debug.md +82 -0
  26. package/ide/antigravity/.agents/workflows/codeninja-design.md +54 -0
  27. package/ide/antigravity/.agents/workflows/codeninja-explain.md +40 -0
  28. package/ide/antigravity/.agents/workflows/codeninja-init.md +336 -0
  29. package/ide/antigravity/.agents/workflows/codeninja-integrate-api.md +336 -0
  30. package/ide/antigravity/.agents/workflows/codeninja-modularize.md +216 -0
  31. package/ide/antigravity/.agents/workflows/codeninja-optimize.md +84 -0
  32. package/ide/antigravity/.agents/workflows/codeninja-refactor.md +68 -0
  33. package/ide/antigravity/.agents/workflows/codeninja-review.md +70 -0
  34. package/ide/antigravity/.agents/workflows/codeninja-sync.md +183 -0
  35. package/ide/antigravity/.agents/workflows/codeninja-test.md +61 -0
  36. package/ide/antigravity/.agents/workflows/codeninja-validate-page.md +250 -0
  37. package/ide/cursor/.cursor/mcp.json +8 -0
  38. package/ide/cursor/.cursor/rules/01-global-orchestrator.mdc +63 -0
  39. package/ide/cursor/.cursor/rules/02-mcp-and-context.mdc +38 -0
  40. package/ide/cursor/.cursor/rules/03-api-builder.mdc +124 -0
  41. package/ide/cursor/.cursor/rules/04-database.mdc +90 -0
  42. package/ide/cursor/.cursor/rules/05-reactjs.mdc +147 -0
  43. package/ide/cursor/.cursor/rules/06-code-intelligence.mdc +112 -0
  44. package/ide/vscode/.github/copilot-instructions.md +399 -0
  45. package/ide/vscode/.vscode/mcp.json +9 -0
  46. package/package.json +24 -23
package/cli.js CHANGED
@@ -3,320 +3,330 @@
3
3
  /**
4
4
  * codeninja CLI
5
5
  * Installs the codeninja agent system into any project.
6
+ * Detects the active IDE and writes the appropriate structure.
6
7
  *
7
8
  * Usage:
8
- * codeninja init Install into current directory
9
- * codeninja help Show available commands
10
- * codeninja version Show installed version
9
+ * codeninja init Auto-detect IDE and install
10
+ * codeninja init --ide=<ide> Force a specific IDE
11
+ * codeninja help Show available commands
12
+ * codeninja version Show installed version
13
+ *
14
+ * Supported IDEs:
15
+ * antigravity Google Antigravity IDE (.agents/ structure + slash commands)
16
+ * cursor Cursor IDE (.cursor/rules/ + .cursor/mcp.json)
17
+ * vscode VS Code / GitHub Copilot (.github/ + .vscode/mcp.json)
18
+ * all Install files for all three IDEs
11
19
  */
12
20
 
13
- const fs = require('fs');
21
+ const fs = require('fs');
14
22
  const path = require('path');
15
- const os = require('os');
23
+ const os = require('os');
16
24
  const { execSync } = require('child_process');
17
25
 
18
- const command = process.argv[2];
26
+ const args = process.argv.slice(2);
27
+ const command = args[0];
28
+ const ideFlag = (args.find(a => a.startsWith('--ide=')) || '').replace('--ide=', '');
29
+
19
30
  const projectRoot = process.cwd();
20
- const destDir = path.join(projectRoot, '.codeninja');
21
- const srcDir = path.dirname(__filename);
31
+ const destDir = path.join(projectRoot, '.codeninja');
32
+ const srcDir = path.dirname(__filename);
22
33
 
23
34
  // ─── Command Router ───────────────────────────────────────────────────────────
24
35
 
25
- if (!command || command === 'help') {
26
- printHelp();
27
- process.exit(0);
28
- }
29
-
36
+ if (!command || command === 'help') { printHelp(); process.exit(0); }
30
37
  if (command === 'version') {
31
38
  const pkg = JSON.parse(fs.readFileSync(path.join(srcDir, 'package.json'), 'utf8'));
32
39
  console.log('codeninja v' + pkg.version);
33
40
  process.exit(0);
34
41
  }
35
-
36
- if (command === 'init') {
37
- runInit();
38
- process.exit(0);
39
- }
42
+ if (command === 'init') { runInit(); process.exit(0); }
40
43
 
41
44
  console.error('Unknown command: ' + command + '\n');
42
45
  printHelp();
43
46
  process.exit(1);
44
47
 
48
+ // ─── IDE Detection ────────────────────────────────────────────────────────────
49
+
50
+ /**
51
+ * Detects which IDE is likely active by checking for known config files and env vars.
52
+ * @returns {'antigravity'|'cursor'|'vscode'|'unknown'}
53
+ */
54
+ function detectIDE() {
55
+ // Antigravity: ~/.gemini/antigravity/ directory exists
56
+ if (process.env.ANTIGRAVITY_IDE ||
57
+ fs.existsSync(path.join(os.homedir(), '.gemini', 'antigravity'))) {
58
+ return 'antigravity';
59
+ }
60
+ // Cursor: ~/.cursor/ directory or Cursor-specific env vars
61
+ if (process.env.CURSOR_TRACE || process.env.CURSOR_SESSION_ID ||
62
+ fs.existsSync(path.join(os.homedir(), '.cursor'))) {
63
+ return 'cursor';
64
+ }
65
+ // VS Code: VSCODE_PID, terminal integration, or ~/.vscode/ exists
66
+ if (process.env.VSCODE_PID || process.env.TERM_PROGRAM === 'vscode' ||
67
+ fs.existsSync(path.join(os.homedir(), '.vscode'))) {
68
+ return 'vscode';
69
+ }
70
+ return 'unknown';
71
+ }
72
+
45
73
  // ─── Init ─────────────────────────────────────────────────────────────────────
46
74
 
47
75
  function runInit() {
48
- console.log('\ncodeninja installing into ' + projectRoot + '\n');
76
+ let targetIDE = ideFlag || detectIDE();
77
+ const installAll = targetIDE === 'all';
78
+
79
+ if (!ideFlag && targetIDE === 'unknown') {
80
+ console.log('\ncodeninja could not auto-detect your IDE.');
81
+ console.log('Installing for all supported IDEs instead.');
82
+ console.log('(Use --ide=antigravity | --ide=cursor | --ide=vscode to be specific)\n');
83
+ targetIDE = 'all';
84
+ }
85
+
86
+ const detectedLabel = ideFlag ? 'forced via --ide' : 'auto-detected';
87
+ console.log('\ncodeninja — installing into ' + projectRoot);
88
+ console.log('IDE: ' + (installAll ? 'all (antigravity + cursor + vscode)' : targetIDE)
89
+ + ' (' + detectedLabel + ')\n');
49
90
 
50
91
  if (fs.existsSync(destDir)) {
51
- console.log('codeninja is already installed in this project.');
52
- console.log('If you want to reinstall, delete the .codeninja folder first.\n');
92
+ console.log('codeninja is already installed. Delete .codeninja/ first to reinstall.\n');
53
93
  return;
54
94
  }
55
95
 
56
- // Absolute path to mcp-server.js — used for Antigravity and Claude Desktop
57
- // because they do not support relative or workspace-variable paths.
58
96
  const mcpServerAbsPath = path.join(destDir, 'mcp-server.js');
59
-
60
- // Ensure .codeninja root exists
61
97
  fs.mkdirSync(destDir, { recursive: true });
62
98
 
63
- // ── Step 1: Copy agent system files into .codeninja/ ────────────────────
64
- console.log('[ 1/7 ] Copying agent files...');
65
- copyDir(path.join(srcDir, 'agent'), path.join(destDir, 'agent'));
99
+ // ── 1: Core agent files ────────────────────────────────────────────────
100
+ console.log('[ 1/6 ] Copying core agent files...');
101
+ copyDir(path.join(srcDir, 'agent'), path.join(destDir, 'agent'));
66
102
  copyDir(path.join(srcDir, 'commands'), path.join(destDir, 'commands'));
67
- copyDir(path.join(srcDir, 'tasks'), path.join(destDir, 'tasks'));
68
-
69
- fs.copyFileSync(
70
- path.join(srcDir, 'mcp-server.js'),
71
- path.join(destDir, 'mcp-server.js')
72
- );
73
-
74
- const innerPkg = {
75
- name: 'codeninja-mcp',
76
- private: true,
77
- dependencies: { '@modelcontextprotocol/sdk': '^1.0.0' }
78
- };
103
+ copyDir(path.join(srcDir, 'tasks'), path.join(destDir, 'tasks'));
104
+ fs.copyFileSync(path.join(srcDir, 'mcp-server.js'), path.join(destDir, 'mcp-server.js'));
79
105
  fs.writeFileSync(
80
106
  path.join(destDir, 'package.json'),
81
- JSON.stringify(innerPkg, null, 2),
107
+ JSON.stringify({ name: 'codeninja-mcp', private: true,
108
+ dependencies: { '@modelcontextprotocol/sdk': '^1.0.0' } }, null, 2),
82
109
  'utf8'
83
110
  );
84
111
 
85
- // ── Step 2: Create context directory ──────────────────────────────────────
86
- console.log('[ 2/7 ] Creating context directory...');
112
+ // ── 2: Context directory ───────────────────────────────────────────────
113
+ console.log('[ 2/6 ] Creating context directory...');
87
114
  fs.mkdirSync(path.join(destDir, 'context'), { recursive: true });
88
115
 
89
- // ── Step 3: Install MCP SDK inside .codeninja/ ──────────────────────────
90
- console.log('[ 3/7 ] Installing MCP SDK...');
116
+ // ── 3: Install MCP SDK ─────────────────────────────────────────────────
117
+ console.log('[ 3/6 ] Installing MCP SDK...');
91
118
  try {
92
119
  execSync('npm install', { cwd: destDir, stdio: 'inherit' });
93
120
  } catch (e) {
94
- console.error('\nERROR: npm install failed inside .codeninja/');
95
- console.error('Make sure npm is installed and you have internet access.');
96
- console.error(e.message);
121
+ console.error('\nERROR: npm install failed inside .codeninja/\n' + e.message);
97
122
  process.exit(1);
98
123
  }
99
124
 
100
- // ── Step 4: Write VS Code config ──────────────────────────────────────────
101
- // VS Code global MCP config lives at ~/.vscode/mcp.json (user-level).
102
- // We use absolute path since global config has no workspaceFolder context.
103
- // We deep-merge never overwrite other entries.
104
- console.log('[ 4/7 ] Writing VS Code global config (~/.vscode/mcp.json)...');
105
- const vscodePath = path.join(os.homedir(), '.vscode', 'mcp.json');
106
- writeGlobalMcpConfig(vscodePath, 'servers', {
107
- type: 'stdio',
108
- command: 'node',
109
- args: [mcpServerAbsPath]
110
- }, 'VS Code');
111
-
112
- // ── Step 5: Write Cursor config ───────────────────────────────────────────
113
- // Cursor global MCP config lives at ~/.cursor/mcp.json (user-level).
114
- // We use absolute path since global config has no workspace context.
115
- // We deep-merge — never overwrite other entries.
116
- console.log('[ 5/7 ] Writing Cursor global config (~/.cursor/mcp.json)...');
117
- const cursorPath = path.join(os.homedir(), '.cursor', 'mcp.json');
118
- writeGlobalMcpConfig(cursorPath, 'mcpServers', {
119
- command: 'node',
120
- args: [mcpServerAbsPath]
121
- }, 'Cursor');
122
-
123
- // ── Step 6: Write Antigravity config ──────────────────────────────────────
124
- // Antigravity (Google's IDE) stores MCP config globally at:
125
- // ~/.gemini/antigravity/mcp_config.json (Mac/Linux)
126
- // %USERPROFILE%\.gemini\antigravity\mcp_config.json (Windows)
127
- //
128
- // IMPORTANT: Antigravity does NOT support ${workspaceFolder} or relative paths.
129
- // The absolute path to mcp-server.js must be written here.
130
- //
131
- // Unlike VS Code and Cursor, this is a GLOBAL file shared across all projects.
132
- // We deep-merge our entry into it — never overwrite the whole file.
133
- console.log('[ 6/7 ] Writing Antigravity config (~/.gemini/antigravity/mcp_config.json)...');
134
- const antigravityConfigPath = path.join(
135
- os.homedir(), '.gemini', 'antigravity', 'mcp_config.json'
136
- );
137
- writeAntigravityConfig(antigravityConfigPath, mcpServerAbsPath);
138
-
139
- // ── Step 7: Update .gitignore if it already exists ────────────────────────
140
- // We never create a .gitignore — that is the project's responsibility.
141
- // The agent's generate-gitignore task already includes .codeninja/node_modules/
142
- // in the .gitignore it writes during @initialize-project.
143
- // This step handles the case where codeninja init runs on a project that
144
- // already has a .gitignore but has NOT yet run @initialize-project.
145
- console.log('[ 7/7 ] Checking .gitignore...');
125
+ // ── 4: IDE-specific project files ─────────────────────────────────────
126
+ console.log('\n[ 4/6 ] Writing IDE-specific files...');
127
+ const ides = installAll ? ['antigravity', 'cursor', 'vscode'] : [targetIDE];
128
+ for (const ide of ides) {
129
+ console.log('\n ── ' + ide.toUpperCase() + ' ──');
130
+ if (ide === 'antigravity') installAntigravityFiles();
131
+ else if (ide === 'cursor') installCursorFiles();
132
+ else if (ide === 'vscode') installVSCodeFiles();
133
+ else console.log(' Unknown IDE: ' + ide + ' — skipped');
134
+ }
135
+
136
+ // ── 5: Global MCP configs ──────────────────────────────────────────────
137
+ console.log('\n[ 5/6 ] Writing global MCP configs...');
138
+ if (installAll || targetIDE === 'vscode') {
139
+ writeGlobalMcpConfig(
140
+ path.join(os.homedir(), '.vscode', 'mcp.json'),
141
+ 'servers', { type: 'stdio', command: 'node', args: [mcpServerAbsPath] }, 'VS Code'
142
+ );
143
+ }
144
+ if (installAll || targetIDE === 'cursor') {
145
+ writeGlobalMcpConfig(
146
+ path.join(os.homedir(), '.cursor', 'mcp.json'),
147
+ 'mcpServers', { command: 'node', args: [mcpServerAbsPath] }, 'Cursor'
148
+ );
149
+ }
150
+ if (installAll || targetIDE === 'antigravity') {
151
+ writeAntigravityConfig(
152
+ path.join(os.homedir(), '.gemini', 'antigravity', 'mcp_config.json'),
153
+ mcpServerAbsPath
154
+ );
155
+ }
156
+
157
+ // ── 6: .gitignore ──────────────────────────────────────────────────────
158
+ console.log('\n[ 6/6 ] Checking .gitignore...');
146
159
  const gitignorePath = path.join(projectRoot, '.gitignore');
147
- const entry = '\n# codeninja — MCP server dependencies (do not commit)\n.codeninja/node_modules/\n';
160
+ const giEntry = '\n# codeninja — MCP server dependencies (do not commit)\n.codeninja/node_modules/\n';
148
161
  if (fs.existsSync(gitignorePath)) {
149
162
  const content = fs.readFileSync(gitignorePath, 'utf8');
150
163
  if (!content.includes('.codeninja/node_modules')) {
151
- fs.appendFileSync(gitignorePath, entry, 'utf8');
164
+ fs.appendFileSync(gitignorePath, giEntry, 'utf8');
152
165
  console.log(' .gitignore updated ✓');
153
166
  } else {
154
- console.log(' .gitignore already has entry — skipped');
167
+ console.log(' .gitignore already up to date — skipped');
155
168
  }
156
169
  } else {
157
- console.log(' .gitignore not found — skipped');
158
- console.log(' (The @initialize-project command will add this automatically)');
170
+ console.log(' No .gitignore found — skipped');
171
+ console.log(' (/codeninja:init will add this automatically)');
172
+ }
173
+
174
+ printInstallSummary(mcpServerAbsPath, ides);
175
+ }
176
+
177
+ // ─── IDE file installers ──────────────────────────────────────────────────────
178
+
179
+ function installAntigravityFiles() {
180
+ const src = path.join(srcDir, 'ide', 'antigravity', '.agents');
181
+ const dest = path.join(projectRoot, '.agents');
182
+ if (!fs.existsSync(src)) { console.log(' [SKIP] ide/antigravity source not found'); return; }
183
+ copyDir(src, dest);
184
+ const personaCount = countFiles(path.join(dest, 'personas'));
185
+ const skillCount = countDirs(path.join(dest, 'skills'));
186
+ const wfCount = countFiles(path.join(dest, 'workflows'));
187
+ console.log(' .agents/personas/ (' + personaCount + ' personas) ✓');
188
+ console.log(' global-orchestrator · nodejs-backend · database-architect · reactjs-frontend');
189
+ console.log(' .agents/skills/ (' + skillCount + ' skill domains) ✓');
190
+ console.log(' mcp-and-context · api-builder · database · reactjs · code-intelligence');
191
+ console.log(' .agents/workflows/ (' + wfCount + ' slash commands) ✓');
192
+ }
193
+
194
+ function installCursorFiles() {
195
+ const src = path.join(srcDir, 'ide', 'cursor', '.cursor');
196
+ const dest = path.join(projectRoot, '.cursor');
197
+ if (!fs.existsSync(src)) { console.log(' [SKIP] ide/cursor source not found'); return; }
198
+ copyDir(src, dest);
199
+ const ruleCount = countFiles(path.join(dest, 'rules'));
200
+ console.log(' .cursor/rules/ (' + ruleCount + ' scoped rule files) ✓');
201
+ console.log(' 01-global-orchestrator · 02-mcp-and-context · 03-api-builder');
202
+ console.log(' 04-database · 05-reactjs · 06-code-intelligence');
203
+ console.log(' .cursor/mcp.json ✓');
204
+ }
205
+
206
+ function installVSCodeFiles() {
207
+ const ideSrc = path.join(srcDir, 'ide', 'vscode');
208
+
209
+ const githubSrc = path.join(ideSrc, '.github');
210
+ const githubDest = path.join(projectRoot, '.github');
211
+ if (fs.existsSync(githubSrc)) {
212
+ copyDir(githubSrc, githubDest);
213
+ console.log(' .github/copilot-instructions.md ✓');
159
214
  }
160
215
 
161
- // ── Done ──────────────────────────────────────────────────────────────────
162
- printInstallSummary(mcpServerAbsPath);
216
+ const vscodeSrc = path.join(ideSrc, '.vscode');
217
+ const vscodeDest = path.join(projectRoot, '.vscode');
218
+ if (fs.existsSync(vscodeSrc)) {
219
+ fs.mkdirSync(vscodeDest, { recursive: true });
220
+ const mcpDest = path.join(vscodeDest, 'mcp.json');
221
+ if (!fs.existsSync(mcpDest)) {
222
+ fs.copyFileSync(path.join(vscodeSrc, 'mcp.json'), mcpDest);
223
+ console.log(' .vscode/mcp.json ✓');
224
+ } else {
225
+ console.log(' .vscode/mcp.json already exists — skipped');
226
+ }
227
+ }
163
228
  }
164
229
 
165
- // ─── Global MCP Config Writer (VS Code & Cursor) ──────────────────────────────
230
+ // ─── Config Writers ───────────────────────────────────────────────────────────
166
231
 
167
232
  function writeGlobalMcpConfig(configPath, serversKey, entry, ideName) {
168
233
  try {
169
234
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
170
-
171
235
  let existing = {};
172
-
173
236
  if (fs.existsSync(configPath)) {
174
- try {
175
- existing = JSON.parse(fs.readFileSync(configPath, 'utf8'));
176
- } catch {
177
- console.log(' Warning: existing ' + path.basename(configPath) + ' could not be parsed — will overwrite.');
178
- }
237
+ try { existing = JSON.parse(fs.readFileSync(configPath, 'utf8')); }
238
+ catch { console.log(' Warning: ' + path.basename(configPath) + ' could not be parsed — overwriting.'); }
179
239
  }
180
-
181
240
  if (!existing[serversKey]) existing[serversKey] = {};
182
-
183
- const current = existing[serversKey].codeninja;
184
- if (current && JSON.stringify(current.args) === JSON.stringify(entry.args)) {
185
- console.log(' ' + ideName + ' global config already has codeninja entry — skipped');
241
+ const cur = existing[serversKey].codeninja;
242
+ if (cur && JSON.stringify(cur.args) === JSON.stringify(entry.args)) {
243
+ console.log(' ' + ideName + ' global config already current skipped');
186
244
  return;
187
245
  }
188
-
189
246
  existing[serversKey].codeninja = entry;
190
247
  fs.writeFileSync(configPath, JSON.stringify(existing, null, 2), 'utf8');
191
- console.log(' ' + configPath + ' written ✓');
248
+ console.log(' ' + configPath + ' ✓');
192
249
  } catch (e) {
193
- console.log(' ' + ideName + ' global config skipped — could not write: ' + e.message);
250
+ console.log(' ' + ideName + ' global config skipped: ' + e.message);
194
251
  }
195
252
  }
196
253
 
197
- // ─── Antigravity Config Writer ────────────────────────────────────────────────
198
-
199
254
  function writeAntigravityConfig(configPath, mcpServerAbsPath) {
200
- const newEntry = {
201
- command: 'node',
202
- args: [mcpServerAbsPath]
203
- };
204
-
205
255
  try {
206
256
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
207
-
208
257
  let existing = { mcpServers: {} };
209
-
210
- // If the file already exists, read and parse it safely.
211
- // We deep-merge — never overwrite other entries the developer has added.
212
258
  if (fs.existsSync(configPath)) {
213
- try {
214
- const raw = fs.readFileSync(configPath, 'utf8');
215
- const parsed = JSON.parse(raw);
216
- existing = parsed;
217
- } catch {
218
- // File is corrupt or empty — start fresh but preserve the file
219
- console.log(' Warning: existing mcp_config.json could not be parsed — will overwrite.');
220
- }
259
+ try { existing = JSON.parse(fs.readFileSync(configPath, 'utf8')); }
260
+ catch { console.log(' Warning: mcp_config.json parse failed — overwriting.'); }
221
261
  }
222
-
223
262
  if (!existing.mcpServers) existing.mcpServers = {};
224
-
225
- // Check if our entry is already there with the same path — skip if so
226
- const current = existing.mcpServers.codeninja;
227
- if (current && current.args && current.args[0] === mcpServerAbsPath) {
228
- console.log(' Antigravity config already has codeninja entry — skipped');
263
+ const cur = existing.mcpServers.codeninja;
264
+ if (cur && cur.args && cur.args[0] === mcpServerAbsPath) {
265
+ console.log(' Antigravity config already current skipped');
229
266
  return;
230
267
  }
231
-
232
- // Write our entry (adds or updates only the codeninja key)
233
- existing.mcpServers.codeninja = newEntry;
234
-
268
+ existing.mcpServers.codeninja = { command: 'node', args: [mcpServerAbsPath] };
235
269
  fs.writeFileSync(configPath, JSON.stringify(existing, null, 2), 'utf8');
236
- console.log(' ~/.gemini/antigravity/mcp_config.json written ✓');
237
-
270
+ console.log(' ~/.gemini/antigravity/mcp_config.json ✓');
238
271
  } catch (e) {
239
- // Antigravity may not be installed — this is non-fatal
240
- console.log(' Antigravity config skipped could not write: ' + e.message);
241
- console.log(' (This is fine if you are not using Antigravity IDE)');
272
+ console.log(' Antigravity config skipped: ' + e.message);
273
+ console.log(' (OK if Antigravity is not installed)');
242
274
  }
243
275
  }
244
276
 
245
277
  // ─── Summary ──────────────────────────────────────────────────────────────────
246
278
 
247
- function printInstallSummary(mcpServerAbsPath) {
279
+ function printInstallSummary(mcpServerAbsPath, ides) {
248
280
  const platform = process.platform;
249
-
250
- // Claude Desktop config path varies by OS
251
- let claudeConfigPath;
252
- if (platform === 'win32') {
253
- claudeConfigPath = path.join(process.env.APPDATA || '%APPDATA%', 'Claude', 'claude_desktop_config.json');
254
- } else if (platform === 'darwin') {
255
- claudeConfigPath = path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
256
- } else {
257
- claudeConfigPath = path.join(os.homedir(), '.config', 'claude', 'claude_desktop_config.json');
258
- }
281
+ const claudeConfigPath = platform === 'win32'
282
+ ? path.join(process.env.APPDATA || '%APPDATA%', 'Claude', 'claude_desktop_config.json')
283
+ : platform === 'darwin'
284
+ ? path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json')
285
+ : path.join(os.homedir(), '.config', 'claude', 'claude_desktop_config.json');
286
+
287
+ let ideNotes = '';
288
+ if (ides.includes('antigravity')) ideNotes += `
289
+ Antigravity ... MCP Servers → Manage MCP Servers → Refresh
290
+ Structure installed:
291
+ .agents/personas/ 4 personas (global-orchestrator, nodejs-backend, database-architect, reactjs-frontend)
292
+ .agents/skills/ 5 skill domains (mcp-and-context, api-builder, database, reactjs, code-intelligence)
293
+ .agents/workflows/ 20 slash commands
294
+ Slash commands: /codeninja:init /codeninja:api /codeninja:design /codeninja:audit
295
+ /codeninja:test /codeninja:refactor /codeninja:sync
296
+ /codeninja:explain /codeninja:review /codeninja:debug /codeninja:optimize
297
+ /codeninja:db:create /codeninja:db:modify /codeninja:db:index
298
+ /codeninja:db:drop /codeninja:db:seed /codeninja:db:sync
299
+ @modularize @validate-page @integrate-api
300
+ `;
301
+ if (ides.includes('cursor')) ideNotes += `
302
+ Cursor → reopen project → use /codeninja:* in AI Chat
303
+ Rules installed: 6 scoped .mdc files (auto-loaded per file type)
304
+ 01-global-orchestrator 02-mcp-and-context 03-api-builder
305
+ 04-database 05-reactjs 06-code-intelligence
306
+ `;
307
+ if (ides.includes('vscode')) ideNotes += `
308
+ VS Code → reopen project → use @workspace /codeninja:* in Copilot Chat
309
+ `;
259
310
 
260
311
  console.log(`
261
312
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
262
313
  codeninja installed successfully
263
314
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
264
-
265
- ✓ .codeninja/ agent files installed
266
- ✓ ~/.vscode/mcp.json VS Code configured (global)
267
- ✓ ~/.cursor/mcp.json Cursor configured (global)
268
- ✓ ~/.gemini/antigravity/ Antigravity configured (global)
269
-
315
+ ${ideNotes}
270
316
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
271
- CLAUDE DESKTOP (manual step — one time only)
317
+ CLAUDE DESKTOP (manual — one time only)
272
318
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
273
319
 
274
- Open this file:
275
- ${claudeConfigPath}
276
-
277
- Add this inside the "mcpServers" object:
320
+ File: ${claudeConfigPath}
278
321
 
322
+ Add inside "mcpServers":
279
323
  "codeninja": {
280
324
  "command": "node",
281
325
  "args": ["${mcpServerAbsPath}"]
282
326
  }
283
327
 
284
- Save and restart Claude Desktop.
285
-
286
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
287
- IDE NOTES
288
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
289
-
290
- VS Code — reopen this project to activate the MCP server
291
- Cursor — reopen this project to activate the MCP server
292
- Antigravity — go to ... → MCP Servers → Manage MCP Servers
293
- and click Refresh to pick up the new entry
294
-
295
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
296
- AVAILABLE COMMANDS (type in your AI chat)
297
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
298
-
299
- @initialize-project Bootstrap a new service or database
300
- @create-api Add a new API module to a service
301
- @design Plan a feature before coding
302
- @audit Security and quality review
303
- @test Generate Jest test files
304
- @refactor Rename with full context tracking
305
- @sync Rebuild context from repo
306
-
307
- Database commands:
308
- @db:create-table Design and generate a new table
309
- @db:modify-table Add / rename / drop a column
310
- @db:add-index Add a new index
311
- @db:drop-table Generate a DROP migration
312
- @db:seed Add seed data
313
- @db:sync Rebuild DB schema in context
314
-
315
328
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
316
-
317
- Next step: open this project in your IDE,
318
- then type @initialize-project to get started.
319
-
329
+ Next: open project in your IDE → /codeninja:init
320
330
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
321
331
  `);
322
332
  }
@@ -326,27 +336,42 @@ function printHelp() {
326
336
  codeninja — AI agent scaffolding system
327
337
 
328
338
  Usage:
329
- codeninja init Install into the current project directory
330
- codeninja version Show the installed version
331
- codeninja help Show this help message
332
-
333
- After running init, open your project in VS Code, Cursor, or Antigravity.
334
- The MCP server connects automatically.
339
+ codeninja init Install (auto-detects IDE)
340
+ codeninja init --ide=<ide> Force a specific IDE
341
+ codeninja version Show version
342
+ codeninja help Show this help
343
+
344
+ IDE values for --ide:
345
+ antigravity → .agents/ structure (slash commands)
346
+ cursor → .cursor/rules/ + mcp.json
347
+ vscode → .github/copilot-instructions.md + .vscode/mcp.json
348
+ all → all three IDEs
349
+
350
+ Examples:
351
+ codeninja init
352
+ codeninja init --ide=antigravity
353
+ codeninja init --ide=all
335
354
  `);
336
355
  }
337
356
 
338
- // ─── Helpers ─────────────────────────────────────────────────────────────────
357
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
339
358
 
340
359
  function copyDir(src, dest) {
341
360
  if (!fs.existsSync(src)) return;
342
361
  fs.mkdirSync(dest, { recursive: true });
343
362
  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
344
- const srcPath = path.join(src, entry.name);
345
- const destPath = path.join(dest, entry.name);
346
- if (entry.isDirectory()) {
347
- copyDir(srcPath, destPath);
348
- } else {
349
- fs.copyFileSync(srcPath, destPath);
350
- }
363
+ const s = path.join(src, entry.name);
364
+ const d = path.join(dest, entry.name);
365
+ entry.isDirectory() ? copyDir(s, d) : fs.copyFileSync(s, d);
351
366
  }
352
- }
367
+ }
368
+
369
+ function countFiles(dir) {
370
+ if (!fs.existsSync(dir)) return 0;
371
+ return fs.readdirSync(dir).filter(f => fs.statSync(path.join(dir, f)).isFile()).length;
372
+ }
373
+
374
+ function countDirs(dir) {
375
+ if (!fs.existsSync(dir)) return 0;
376
+ return fs.readdirSync(dir).filter(f => fs.statSync(path.join(dir, f)).isDirectory()).length;
377
+ }