aidex-mcp 1.5.1 → 1.6.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/CHANGELOG.md +15 -0
- package/build/commands/setup.d.ts +2 -1
- package/build/commands/setup.js +253 -69
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to AiDex will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.6.0] - 2026-02-01
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Auto CLAUDE.md instructions**: `aidex setup` now installs AI instructions in `~/.claude/CLAUDE.md`
|
|
9
|
+
- Tells Claude to auto-run `aidex_init` when no `.aidex/` exists
|
|
10
|
+
- Provides tool usage guide (prefer AiDex over Grep/Glob)
|
|
11
|
+
- `aidex unsetup` cleanly removes the instructions block
|
|
12
|
+
- **Idempotent setup**: Re-running `aidex setup` updates existing config without errors
|
|
13
|
+
|
|
14
|
+
## [1.5.2] - 2026-02-01
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- **`aidex setup` for Claude Code**: Uses `claude mcp add --scope user` instead of editing settings.json directly
|
|
18
|
+
- Claude Desktop, Cursor, Windsurf still use JSON config editing
|
|
19
|
+
|
|
5
20
|
## [1.5.1] - 2026-01-31
|
|
6
21
|
|
|
7
22
|
### Fixed
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AiDex Setup - Auto-register as MCP server in AI clients
|
|
3
3
|
*
|
|
4
|
-
* Supports: Claude Code, Claude Desktop, Cursor, Windsurf
|
|
4
|
+
* Supports: Claude Code (via CLI), Claude Desktop, Cursor, Windsurf
|
|
5
|
+
* Also installs CLAUDE.md instructions for Claude Code/Desktop.
|
|
5
6
|
*/
|
|
6
7
|
export declare function setupMcpClients(): void;
|
|
7
8
|
export declare function unsetupMcpClients(): void;
|
package/build/commands/setup.js
CHANGED
|
@@ -1,35 +1,89 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AiDex Setup - Auto-register as MCP server in AI clients
|
|
3
3
|
*
|
|
4
|
-
* Supports: Claude Code, Claude Desktop, Cursor, Windsurf
|
|
4
|
+
* Supports: Claude Code (via CLI), Claude Desktop, Cursor, Windsurf
|
|
5
|
+
* Also installs CLAUDE.md instructions for Claude Code/Desktop.
|
|
5
6
|
*/
|
|
6
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
7
|
-
import { join } from 'path';
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
8
|
+
import { join, dirname } from 'path';
|
|
8
9
|
import { homedir, platform } from 'os';
|
|
10
|
+
import { execSync } from 'child_process';
|
|
9
11
|
// ============================================================
|
|
10
|
-
// MCP Server Entry
|
|
12
|
+
// MCP Server Entry (for JSON-based clients)
|
|
11
13
|
// ============================================================
|
|
12
14
|
const AIDEX_MCP_ENTRY = {
|
|
13
15
|
command: 'aidex',
|
|
14
16
|
args: []
|
|
15
17
|
};
|
|
16
18
|
// ============================================================
|
|
19
|
+
// CLAUDE.md Instructions Block
|
|
20
|
+
// ============================================================
|
|
21
|
+
const CLAUDE_MD_START = '<!-- AIDEX-START -->';
|
|
22
|
+
const CLAUDE_MD_END = '<!-- AIDEX-END -->';
|
|
23
|
+
const CLAUDE_MD_BLOCK = `${CLAUDE_MD_START}
|
|
24
|
+
## AiDex - Persistent Code Index (MCP Server)
|
|
25
|
+
|
|
26
|
+
AiDex provides fast, precise code search through a pre-built index. **Always prefer AiDex over Grep/Glob for code searches.**
|
|
27
|
+
|
|
28
|
+
### Auto-Init Rule
|
|
29
|
+
|
|
30
|
+
**At the start of every session, check if \`.aidex/\` exists in the project directory.**
|
|
31
|
+
- If \`.aidex/\` does NOT exist → **automatically run \`aidex_init\`** to create the index. Do not ask, just do it.
|
|
32
|
+
- If \`.aidex/\` exists → use AiDex tools for all code searches.
|
|
33
|
+
|
|
34
|
+
### When to Use AiDex (instead of Grep/Glob)
|
|
35
|
+
|
|
36
|
+
| Task | Do NOT use | Use instead |
|
|
37
|
+
|------|-----------|-------------|
|
|
38
|
+
| Find a function/class/variable | \`Grep pattern="name"\` | \`aidex_query term="name"\` |
|
|
39
|
+
| See all methods in a file | \`Read entire_file.cs\` | \`aidex_signature file="..."\` |
|
|
40
|
+
| Explore multiple files | Multiple Read calls | \`aidex_signatures pattern="src/**"\` |
|
|
41
|
+
| Project overview | Many Glob/Read calls | \`aidex_summary\` + \`aidex_tree\` |
|
|
42
|
+
| What changed recently? | \`git log\` + Read | \`aidex_query term="X" modified_since="2h"\` |
|
|
43
|
+
|
|
44
|
+
### Available Tools
|
|
45
|
+
|
|
46
|
+
| Tool | Purpose |
|
|
47
|
+
|------|---------|
|
|
48
|
+
| \`aidex_init\` | Index a project (creates \`.aidex/\`) |
|
|
49
|
+
| \`aidex_query\` | Search by term (exact/contains/starts_with) |
|
|
50
|
+
| \`aidex_signature\` | Get one file's classes + methods |
|
|
51
|
+
| \`aidex_signatures\` | Get signatures for multiple files (glob) |
|
|
52
|
+
| \`aidex_update\` | Re-index a single changed file |
|
|
53
|
+
| \`aidex_summary\` | Project overview with entry points |
|
|
54
|
+
| \`aidex_tree\` | File tree with statistics |
|
|
55
|
+
| \`aidex_files\` | List project files by type |
|
|
56
|
+
| \`aidex_session\` | Start session, detect external changes |
|
|
57
|
+
| \`aidex_note\` | Read/write session notes |
|
|
58
|
+
| \`aidex_viewer\` | Open interactive project tree in browser |
|
|
59
|
+
|
|
60
|
+
### Why AiDex over Grep?
|
|
61
|
+
|
|
62
|
+
- **~50 tokens** per search vs 2000+ with Grep
|
|
63
|
+
- **Identifiers only** - no noise from comments/strings
|
|
64
|
+
- **Persistent** - index survives between sessions
|
|
65
|
+
- **Structure-aware** - knows methods, classes, types
|
|
66
|
+
${CLAUDE_MD_END}`;
|
|
67
|
+
// ============================================================
|
|
17
68
|
// Client Detection
|
|
18
69
|
// ============================================================
|
|
19
70
|
function getClients() {
|
|
20
71
|
const home = homedir();
|
|
21
72
|
const plat = platform();
|
|
22
73
|
const clients = [];
|
|
23
|
-
// Claude Code
|
|
74
|
+
// Claude Code - uses its own CLI for MCP management
|
|
24
75
|
clients.push({
|
|
76
|
+
type: 'cli',
|
|
25
77
|
name: 'Claude Code',
|
|
26
|
-
|
|
27
|
-
|
|
78
|
+
detectCmd: 'claude --version',
|
|
79
|
+
addCmd: ['claude', 'mcp', 'add', '--scope', 'user', 'aidex', '--', 'aidex'],
|
|
80
|
+
removeCmd: ['claude', 'mcp', 'remove', '--scope', 'user', 'aidex']
|
|
28
81
|
});
|
|
29
|
-
// Claude Desktop
|
|
82
|
+
// Claude Desktop - JSON config
|
|
30
83
|
if (plat === 'win32') {
|
|
31
84
|
const appData = process.env.APPDATA || join(home, 'AppData', 'Roaming');
|
|
32
85
|
clients.push({
|
|
86
|
+
type: 'json',
|
|
33
87
|
name: 'Claude Desktop',
|
|
34
88
|
configPath: join(appData, 'Claude', 'claude_desktop_config.json'),
|
|
35
89
|
detectDir: join(appData, 'Claude')
|
|
@@ -37,6 +91,7 @@ function getClients() {
|
|
|
37
91
|
}
|
|
38
92
|
else if (plat === 'darwin') {
|
|
39
93
|
clients.push({
|
|
94
|
+
type: 'json',
|
|
40
95
|
name: 'Claude Desktop',
|
|
41
96
|
configPath: join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
|
|
42
97
|
detectDir: join(home, 'Library', 'Application Support', 'Claude')
|
|
@@ -44,19 +99,22 @@ function getClients() {
|
|
|
44
99
|
}
|
|
45
100
|
else {
|
|
46
101
|
clients.push({
|
|
102
|
+
type: 'json',
|
|
47
103
|
name: 'Claude Desktop',
|
|
48
104
|
configPath: join(home, '.config', 'Claude', 'claude_desktop_config.json'),
|
|
49
105
|
detectDir: join(home, '.config', 'Claude')
|
|
50
106
|
});
|
|
51
107
|
}
|
|
52
|
-
// Cursor
|
|
108
|
+
// Cursor - JSON config
|
|
53
109
|
clients.push({
|
|
110
|
+
type: 'json',
|
|
54
111
|
name: 'Cursor',
|
|
55
112
|
configPath: join(home, '.cursor', 'mcp.json'),
|
|
56
113
|
detectDir: join(home, '.cursor')
|
|
57
114
|
});
|
|
58
|
-
// Windsurf
|
|
115
|
+
// Windsurf - JSON config
|
|
59
116
|
clients.push({
|
|
117
|
+
type: 'json',
|
|
60
118
|
name: 'Windsurf',
|
|
61
119
|
configPath: join(home, '.codeium', 'windsurf', 'mcp_config.json'),
|
|
62
120
|
detectDir: join(home, '.codeium', 'windsurf')
|
|
@@ -64,7 +122,29 @@ function getClients() {
|
|
|
64
122
|
return clients;
|
|
65
123
|
}
|
|
66
124
|
// ============================================================
|
|
67
|
-
//
|
|
125
|
+
// CLI helpers
|
|
126
|
+
// ============================================================
|
|
127
|
+
function isCmdAvailable(cmd) {
|
|
128
|
+
try {
|
|
129
|
+
execSync(cmd, { stdio: 'pipe', timeout: 5000 });
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function runCmd(args) {
|
|
137
|
+
try {
|
|
138
|
+
const output = execSync(args.join(' '), { stdio: 'pipe', timeout: 10000 }).toString().trim();
|
|
139
|
+
return { success: true, output };
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
143
|
+
return { success: false, error: msg };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// ============================================================
|
|
147
|
+
// JSON Config Read/Write
|
|
68
148
|
// ============================================================
|
|
69
149
|
function readJsonConfig(filePath) {
|
|
70
150
|
try {
|
|
@@ -92,83 +172,187 @@ function writeJsonConfig(filePath, data) {
|
|
|
92
172
|
}
|
|
93
173
|
}
|
|
94
174
|
// ============================================================
|
|
95
|
-
//
|
|
175
|
+
// CLAUDE.md Management
|
|
176
|
+
// ============================================================
|
|
177
|
+
function getClaudeMdPath() {
|
|
178
|
+
return join(homedir(), '.claude', 'CLAUDE.md');
|
|
179
|
+
}
|
|
180
|
+
function installClaudeMd() {
|
|
181
|
+
const mdPath = getClaudeMdPath();
|
|
182
|
+
const dir = dirname(mdPath);
|
|
183
|
+
// Ensure directory exists
|
|
184
|
+
if (!existsSync(dir)) {
|
|
185
|
+
mkdirSync(dir, { recursive: true });
|
|
186
|
+
}
|
|
187
|
+
let content = '';
|
|
188
|
+
if (existsSync(mdPath)) {
|
|
189
|
+
content = readFileSync(mdPath, 'utf8');
|
|
190
|
+
// Already has AiDex block? Replace it
|
|
191
|
+
if (content.includes(CLAUDE_MD_START)) {
|
|
192
|
+
const regex = new RegExp(`${CLAUDE_MD_START}[\\s\\S]*?${CLAUDE_MD_END}`, 'g');
|
|
193
|
+
content = content.replace(regex, CLAUDE_MD_BLOCK);
|
|
194
|
+
writeFileSync(mdPath, content, 'utf8');
|
|
195
|
+
return { success: true, action: 'updated' };
|
|
196
|
+
}
|
|
197
|
+
// Append to existing file
|
|
198
|
+
content = content.trimEnd() + '\n\n' + CLAUDE_MD_BLOCK + '\n';
|
|
199
|
+
writeFileSync(mdPath, content, 'utf8');
|
|
200
|
+
return { success: true, action: 'appended' };
|
|
201
|
+
}
|
|
202
|
+
// Create new file
|
|
203
|
+
writeFileSync(mdPath, CLAUDE_MD_BLOCK + '\n', 'utf8');
|
|
204
|
+
return { success: true, action: 'created' };
|
|
205
|
+
}
|
|
206
|
+
function uninstallClaudeMd() {
|
|
207
|
+
const mdPath = getClaudeMdPath();
|
|
208
|
+
if (!existsSync(mdPath)) {
|
|
209
|
+
return { success: true, removed: false };
|
|
210
|
+
}
|
|
211
|
+
let content = readFileSync(mdPath, 'utf8');
|
|
212
|
+
if (!content.includes(CLAUDE_MD_START)) {
|
|
213
|
+
return { success: true, removed: false };
|
|
214
|
+
}
|
|
215
|
+
const regex = new RegExp(`\\n?\\n?${CLAUDE_MD_START}[\\s\\S]*?${CLAUDE_MD_END}\\n?`, 'g');
|
|
216
|
+
content = content.replace(regex, '').trim();
|
|
217
|
+
if (content.length === 0) {
|
|
218
|
+
// File would be empty, but don't delete it - might have been user-created
|
|
219
|
+
writeFileSync(mdPath, '', 'utf8');
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
writeFileSync(mdPath, content + '\n', 'utf8');
|
|
223
|
+
}
|
|
224
|
+
return { success: true, removed: true };
|
|
225
|
+
}
|
|
226
|
+
// ============================================================
|
|
227
|
+
// Setup
|
|
96
228
|
// ============================================================
|
|
229
|
+
function setupCliClient(client) {
|
|
230
|
+
if (!isCmdAvailable(client.detectCmd)) {
|
|
231
|
+
return { status: ` - ${client.name} (not installed)`, registered: false };
|
|
232
|
+
}
|
|
233
|
+
const result = runCmd(client.addCmd);
|
|
234
|
+
if (result.success) {
|
|
235
|
+
return { status: ` ✓ ${client.name}`, registered: true };
|
|
236
|
+
}
|
|
237
|
+
// "already exists" is not an error
|
|
238
|
+
if (result.error && result.error.includes('already exists')) {
|
|
239
|
+
return { status: ` ✓ ${client.name} (already registered)`, registered: true };
|
|
240
|
+
}
|
|
241
|
+
return { status: ` ✗ ${client.name} (${result.error})`, registered: false };
|
|
242
|
+
}
|
|
243
|
+
function setupJsonClient(client) {
|
|
244
|
+
if (!existsSync(client.detectDir)) {
|
|
245
|
+
return { status: ` - ${client.name} (not installed)`, registered: false };
|
|
246
|
+
}
|
|
247
|
+
let data;
|
|
248
|
+
if (existsSync(client.configPath)) {
|
|
249
|
+
const config = readJsonConfig(client.configPath);
|
|
250
|
+
if (!config.success || !config.data) {
|
|
251
|
+
return { status: ` ✗ ${client.name} (${config.error})`, registered: false };
|
|
252
|
+
}
|
|
253
|
+
data = config.data;
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
data = {};
|
|
257
|
+
}
|
|
258
|
+
if (!data.mcpServers || typeof data.mcpServers !== 'object') {
|
|
259
|
+
data.mcpServers = {};
|
|
260
|
+
}
|
|
261
|
+
data.mcpServers.aidex = { ...AIDEX_MCP_ENTRY };
|
|
262
|
+
const writeResult = writeJsonConfig(client.configPath, data);
|
|
263
|
+
if (!writeResult.success) {
|
|
264
|
+
return { status: ` ✗ ${client.name} (${writeResult.error})`, registered: false };
|
|
265
|
+
}
|
|
266
|
+
return { status: ` ✓ ${client.name} (${client.configPath})`, registered: true };
|
|
267
|
+
}
|
|
97
268
|
export function setupMcpClients() {
|
|
98
269
|
const clients = getClients();
|
|
99
|
-
const results = [];
|
|
100
270
|
let registered = 0;
|
|
101
271
|
console.log('\nAiDex MCP Server Registration');
|
|
102
272
|
console.log('==============================\n');
|
|
273
|
+
// Register with AI clients
|
|
274
|
+
console.log(' MCP Servers:');
|
|
103
275
|
for (const client of clients) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
data = config.data;
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
data = {};
|
|
123
|
-
}
|
|
124
|
-
if (!data.mcpServers || typeof data.mcpServers !== 'object') {
|
|
125
|
-
data.mcpServers = {};
|
|
126
|
-
}
|
|
127
|
-
data.mcpServers.aidex = { ...AIDEX_MCP_ENTRY };
|
|
128
|
-
const writeResult = writeJsonConfig(client.configPath, data);
|
|
129
|
-
if (!writeResult.success) {
|
|
130
|
-
results.push({ client: client.name, status: 'error', configPath: client.configPath, message: writeResult.error });
|
|
131
|
-
console.log(` ✗ ${client.name} (${writeResult.error})`);
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
registered++;
|
|
135
|
-
results.push({ client: client.name, status: 'registered', configPath: client.configPath });
|
|
136
|
-
console.log(` ✓ ${client.name} (${client.configPath})`);
|
|
276
|
+
const result = client.type === 'cli'
|
|
277
|
+
? setupCliClient(client)
|
|
278
|
+
: setupJsonClient(client);
|
|
279
|
+
console.log(result.status);
|
|
280
|
+
if (result.registered)
|
|
281
|
+
registered++;
|
|
282
|
+
}
|
|
283
|
+
// Install CLAUDE.md instructions
|
|
284
|
+
console.log('\n AI Instructions:');
|
|
285
|
+
const mdResult = installClaudeMd();
|
|
286
|
+
const mdPath = getClaudeMdPath();
|
|
287
|
+
if (mdResult.success) {
|
|
288
|
+
console.log(` ✓ CLAUDE.md (${mdResult.action}: ${mdPath})`);
|
|
137
289
|
}
|
|
138
290
|
console.log(`\nRegistered AiDex with ${registered} client(s).\n`);
|
|
139
291
|
if (registered > 0) {
|
|
140
292
|
console.log('Restart your AI client(s) to activate AiDex.\n');
|
|
141
293
|
}
|
|
142
294
|
}
|
|
295
|
+
// ============================================================
|
|
296
|
+
// Unsetup
|
|
297
|
+
// ============================================================
|
|
298
|
+
function unsetupCliClient(client) {
|
|
299
|
+
if (!isCmdAvailable(client.detectCmd)) {
|
|
300
|
+
return { status: ` - ${client.name} (not installed)`, removed: false };
|
|
301
|
+
}
|
|
302
|
+
const result = runCmd(client.removeCmd);
|
|
303
|
+
if (result.success) {
|
|
304
|
+
return { status: ` ✓ Removed from ${client.name}`, removed: true };
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
return { status: ` - ${client.name} (not registered)`, removed: false };
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function unsetupJsonClient(client) {
|
|
311
|
+
if (!existsSync(client.detectDir)) {
|
|
312
|
+
return { status: ` - ${client.name} (not installed)`, removed: false };
|
|
313
|
+
}
|
|
314
|
+
if (!existsSync(client.configPath)) {
|
|
315
|
+
return { status: ` - ${client.name} (not registered)`, removed: false };
|
|
316
|
+
}
|
|
317
|
+
const config = readJsonConfig(client.configPath);
|
|
318
|
+
if (!config.success || !config.data) {
|
|
319
|
+
return { status: ` ✗ ${client.name} (${config.error})`, removed: false };
|
|
320
|
+
}
|
|
321
|
+
const data = config.data;
|
|
322
|
+
const servers = data.mcpServers;
|
|
323
|
+
if (!servers || !servers.aidex) {
|
|
324
|
+
return { status: ` - ${client.name} (not registered)`, removed: false };
|
|
325
|
+
}
|
|
326
|
+
delete servers.aidex;
|
|
327
|
+
const writeResult = writeJsonConfig(client.configPath, data);
|
|
328
|
+
if (!writeResult.success) {
|
|
329
|
+
return { status: ` ✗ ${client.name} (${writeResult.error})`, removed: false };
|
|
330
|
+
}
|
|
331
|
+
return { status: ` ✓ Removed from ${client.name}`, removed: true };
|
|
332
|
+
}
|
|
143
333
|
export function unsetupMcpClients() {
|
|
144
334
|
const clients = getClients();
|
|
145
335
|
let removed = 0;
|
|
146
336
|
console.log('\nAiDex MCP Server Unregistration');
|
|
147
337
|
console.log('================================\n');
|
|
338
|
+
// Unregister from AI clients
|
|
339
|
+
console.log(' MCP Servers:');
|
|
148
340
|
for (const client of clients) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
delete servers.aidex;
|
|
165
|
-
const writeResult = writeJsonConfig(client.configPath, data);
|
|
166
|
-
if (!writeResult.success) {
|
|
167
|
-
console.log(` ✗ ${client.name} (${writeResult.error})`);
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
removed++;
|
|
171
|
-
console.log(` ✓ Removed from ${client.name}`);
|
|
341
|
+
const result = client.type === 'cli'
|
|
342
|
+
? unsetupCliClient(client)
|
|
343
|
+
: unsetupJsonClient(client);
|
|
344
|
+
console.log(result.status);
|
|
345
|
+
if (result.removed)
|
|
346
|
+
removed++;
|
|
347
|
+
}
|
|
348
|
+
// Remove CLAUDE.md instructions
|
|
349
|
+
console.log('\n AI Instructions:');
|
|
350
|
+
const mdResult = uninstallClaudeMd();
|
|
351
|
+
if (mdResult.removed) {
|
|
352
|
+
console.log(` ✓ Removed AiDex block from CLAUDE.md`);
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
console.log(` - CLAUDE.md (no AiDex block found)`);
|
|
172
356
|
}
|
|
173
357
|
console.log(`\nUnregistered AiDex from ${removed} client(s).\n`);
|
|
174
358
|
}
|