@claudetools/tools 0.3.4 → 0.3.6
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/dist/cli.js +9 -1
- package/dist/helpers/config.d.ts +2 -1
- package/dist/helpers/config.js +14 -5
- package/dist/setup.d.ts +1 -0
- package/dist/setup.js +129 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { parseArgs } from 'node:util';
|
|
|
7
7
|
import { readFileSync } from 'node:fs';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { dirname, join } from 'node:path';
|
|
10
|
-
import { runSetup, runUninstall, runInit } from './setup.js';
|
|
10
|
+
import { runSetup, runUninstall, runInit, runCleanup } from './setup.js';
|
|
11
11
|
import { startServer } from './index.js';
|
|
12
12
|
import { startWatcher, stopWatcher, watcherStatus } from './watcher.js';
|
|
13
13
|
// Get version from package.json
|
|
@@ -49,6 +49,7 @@ Options:
|
|
|
49
49
|
|
|
50
50
|
Commands:
|
|
51
51
|
init Initialize current directory as a project
|
|
52
|
+
cleanup Remove legacy config and broken hooks
|
|
52
53
|
watch Start the file watcher daemon
|
|
53
54
|
watch --stop Stop the watcher daemon
|
|
54
55
|
watch --status Check watcher status
|
|
@@ -79,6 +80,13 @@ else if (positionals[0] === 'init') {
|
|
|
79
80
|
process.exit(1);
|
|
80
81
|
});
|
|
81
82
|
}
|
|
83
|
+
else if (positionals[0] === 'cleanup') {
|
|
84
|
+
// Handle cleanup command
|
|
85
|
+
runCleanup().catch((error) => {
|
|
86
|
+
console.error('Cleanup failed:', error);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
82
90
|
else if (positionals[0] === 'watch') {
|
|
83
91
|
// Handle watch command
|
|
84
92
|
const watchArgs = process.argv.slice(3); // Get args after 'watch'
|
package/dist/helpers/config.d.ts
CHANGED
|
@@ -14,7 +14,8 @@ export interface ProjectsCache {
|
|
|
14
14
|
last_sync: string;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Validates that a project ID is a
|
|
17
|
+
* Validates that a project ID is in a valid format
|
|
18
|
+
* Accepts both API-registered (proj_*) and local fallback (local_*) formats
|
|
18
19
|
*/
|
|
19
20
|
export declare function isValidProjectId(id: string): boolean;
|
|
20
21
|
/**
|
package/dist/helpers/config.js
CHANGED
|
@@ -13,10 +13,19 @@ export const PROJECTS_FILE = getProjectsPath();
|
|
|
13
13
|
// Cache for resolved project ID
|
|
14
14
|
let resolvedProjectId = null;
|
|
15
15
|
/**
|
|
16
|
-
* Validates that a project ID is a
|
|
16
|
+
* Validates that a project ID is in a valid format
|
|
17
|
+
* Accepts both API-registered (proj_*) and local fallback (local_*) formats
|
|
17
18
|
*/
|
|
18
19
|
export function isValidProjectId(id) {
|
|
19
|
-
|
|
20
|
+
// API-registered format: proj_ followed by 20 hex chars
|
|
21
|
+
if (/^proj_[a-f0-9]{20}$/.test(id)) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
// Local fallback format: local_ followed by sanitized project name
|
|
25
|
+
if (/^local_[a-z0-9_]+$/.test(id)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
20
29
|
}
|
|
21
30
|
/**
|
|
22
31
|
* Finds a project binding in the cache by directory path
|
|
@@ -78,7 +87,7 @@ export async function resolveProjectIdAsync() {
|
|
|
78
87
|
// Validate UUID format
|
|
79
88
|
if (!isValidProjectId(envProjectId)) {
|
|
80
89
|
throw new Error(`Invalid project ID format in CLAUDETOOLS_PROJECT_ID: ${envProjectId}. ` +
|
|
81
|
-
`Expected format: proj_xxxxxxxxxxxxxxxxxxxx
|
|
90
|
+
`Expected format: proj_xxxxxxxxxxxxxxxxxxxx or local_projectname`);
|
|
82
91
|
}
|
|
83
92
|
resolvedProjectId = envProjectId;
|
|
84
93
|
mcpLogger.debug('MEMORY', `Using project ID from env: ${resolvedProjectId}`);
|
|
@@ -135,7 +144,7 @@ export function getDefaultProjectId() {
|
|
|
135
144
|
if (config.defaultProjectId) {
|
|
136
145
|
if (!isValidProjectId(config.defaultProjectId)) {
|
|
137
146
|
throw new Error(`Invalid defaultProjectId in config: ${config.defaultProjectId}. ` +
|
|
138
|
-
`Expected format: proj_xxxxxxxxxxxxxxxxxxxx
|
|
147
|
+
`Expected format: proj_xxxxxxxxxxxxxxxxxxxx or local_projectname`);
|
|
139
148
|
}
|
|
140
149
|
_defaultProjectId = config.defaultProjectId;
|
|
141
150
|
return _defaultProjectId;
|
|
@@ -155,7 +164,7 @@ export async function getDefaultProjectIdAsync() {
|
|
|
155
164
|
if (config.defaultProjectId) {
|
|
156
165
|
if (!isValidProjectId(config.defaultProjectId)) {
|
|
157
166
|
throw new Error(`Invalid defaultProjectId in config: ${config.defaultProjectId}. ` +
|
|
158
|
-
`Expected format: proj_xxxxxxxxxxxxxxxxxxxx
|
|
167
|
+
`Expected format: proj_xxxxxxxxxxxxxxxxxxxx or local_projectname`);
|
|
159
168
|
}
|
|
160
169
|
_defaultProjectId = config.defaultProjectId;
|
|
161
170
|
return _defaultProjectId;
|
package/dist/setup.d.ts
CHANGED
package/dist/setup.js
CHANGED
|
@@ -18,11 +18,19 @@ import { GLOBAL_TEMPLATE, SECTION_START, SECTION_END, getProjectTemplate, } from
|
|
|
18
18
|
const CLAUDE_DIR = join(homedir(), '.claude');
|
|
19
19
|
const CLAUDETOOLS_DIR = join(homedir(), '.claudetools');
|
|
20
20
|
const MCP_CONFIG_PATH = join(CLAUDE_DIR, 'mcp.json');
|
|
21
|
+
const CLAUDE_DESKTOP_CONFIG_PATH = join(CLAUDE_DIR, 'claude_desktop_config.json');
|
|
21
22
|
const SETTINGS_PATH = join(CLAUDE_DIR, 'settings.json');
|
|
22
23
|
const HOOKS_DIR = join(CLAUDE_DIR, 'hooks');
|
|
23
24
|
const CLAUDE_MD_PATH = join(CLAUDE_DIR, 'CLAUDE.md');
|
|
24
25
|
const SYSTEM_FILE = join(CLAUDETOOLS_DIR, 'system.json');
|
|
25
26
|
const PROJECTS_FILE = join(CLAUDETOOLS_DIR, 'projects.json');
|
|
27
|
+
// Legacy env vars that should be removed from MCP configs
|
|
28
|
+
const LEGACY_ENV_VARS = [
|
|
29
|
+
'CLAUDETOOLS_PROJECT_ID',
|
|
30
|
+
'CLAUDETOOLS_USER_ID',
|
|
31
|
+
'AUTO_INJECT_CONTEXT',
|
|
32
|
+
'MEMORY_PROJECT_ID',
|
|
33
|
+
];
|
|
26
34
|
// -----------------------------------------------------------------------------
|
|
27
35
|
// Utility Functions
|
|
28
36
|
// -----------------------------------------------------------------------------
|
|
@@ -40,6 +48,61 @@ function error(msg) {
|
|
|
40
48
|
function info(msg) {
|
|
41
49
|
console.log(chalk.blue('ℹ ') + msg);
|
|
42
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Clean up legacy env vars from MCP server configs
|
|
53
|
+
* This removes deprecated vars like CLAUDETOOLS_PROJECT_ID that cause validation errors
|
|
54
|
+
*/
|
|
55
|
+
function cleanupLegacyMcpConfig(configPath) {
|
|
56
|
+
if (!existsSync(configPath)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
61
|
+
let modified = false;
|
|
62
|
+
if (config.mcpServers) {
|
|
63
|
+
for (const [serverName, serverConfig] of Object.entries(config.mcpServers)) {
|
|
64
|
+
if (serverConfig.env) {
|
|
65
|
+
for (const legacyVar of LEGACY_ENV_VARS) {
|
|
66
|
+
if (legacyVar in serverConfig.env) {
|
|
67
|
+
delete serverConfig.env[legacyVar];
|
|
68
|
+
modified = true;
|
|
69
|
+
info(`Removed legacy ${legacyVar} from ${serverName}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Remove empty env object
|
|
73
|
+
if (Object.keys(serverConfig.env).length === 0) {
|
|
74
|
+
delete serverConfig.env;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (modified) {
|
|
80
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
// Non-fatal - just skip cleanup
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Clean up all legacy MCP configs (both mcp.json and claude_desktop_config.json)
|
|
91
|
+
*/
|
|
92
|
+
function cleanupAllLegacyConfigs() {
|
|
93
|
+
let cleaned = false;
|
|
94
|
+
if (cleanupLegacyMcpConfig(MCP_CONFIG_PATH)) {
|
|
95
|
+
success('Cleaned up legacy config in mcp.json');
|
|
96
|
+
cleaned = true;
|
|
97
|
+
}
|
|
98
|
+
if (cleanupLegacyMcpConfig(CLAUDE_DESKTOP_CONFIG_PATH)) {
|
|
99
|
+
success('Cleaned up legacy config in claude_desktop_config.json');
|
|
100
|
+
cleaned = true;
|
|
101
|
+
}
|
|
102
|
+
if (!cleaned) {
|
|
103
|
+
info('No legacy config cleanup needed');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
43
106
|
// -----------------------------------------------------------------------------
|
|
44
107
|
// System Registration
|
|
45
108
|
// -----------------------------------------------------------------------------
|
|
@@ -999,15 +1062,18 @@ export async function runSetup() {
|
|
|
999
1062
|
header('Saving Configuration');
|
|
1000
1063
|
await saveConfig(extendedConfig);
|
|
1001
1064
|
success(`Configuration saved to ${getConfigPath()}`);
|
|
1002
|
-
// Step 6:
|
|
1065
|
+
// Step 6: Clean up legacy configs
|
|
1066
|
+
header('Legacy Config Cleanup');
|
|
1067
|
+
cleanupAllLegacyConfigs();
|
|
1068
|
+
// Step 7: Configure Claude Code MCP
|
|
1003
1069
|
await configureMcpSettings(services);
|
|
1004
|
-
// Step
|
|
1070
|
+
// Step 8: Install Hooks
|
|
1005
1071
|
await installHooks();
|
|
1006
|
-
// Step
|
|
1072
|
+
// Step 9: Configure Settings
|
|
1007
1073
|
await configureSettings();
|
|
1008
|
-
// Step
|
|
1074
|
+
// Step 10: Configure CLAUDE.md
|
|
1009
1075
|
await configureCLAUDEMD();
|
|
1010
|
-
// Step
|
|
1076
|
+
// Step 11: Verify
|
|
1011
1077
|
await verifySetup(extendedConfig);
|
|
1012
1078
|
// Done
|
|
1013
1079
|
header('Setup Complete');
|
|
@@ -1268,3 +1334,61 @@ export async function runInit() {
|
|
|
1268
1334
|
console.log(' ' + chalk.bold('Config:') + ` ${projectClaudeMd}\n`);
|
|
1269
1335
|
console.log(chalk.dim(' Memory tools are now configured for this project.\n'));
|
|
1270
1336
|
}
|
|
1337
|
+
// -----------------------------------------------------------------------------
|
|
1338
|
+
// Cleanup Command (standalone)
|
|
1339
|
+
// -----------------------------------------------------------------------------
|
|
1340
|
+
export async function runCleanup() {
|
|
1341
|
+
console.log('\n' + chalk.bold.cyan(' ClaudeTools Legacy Cleanup') + '\n');
|
|
1342
|
+
header('Cleaning Legacy Configurations');
|
|
1343
|
+
cleanupAllLegacyConfigs();
|
|
1344
|
+
// Also clean up any project-level legacy hooks
|
|
1345
|
+
const cwd = process.cwd();
|
|
1346
|
+
const projectSettingsPath = join(cwd, '.claude', 'settings.json');
|
|
1347
|
+
if (existsSync(projectSettingsPath)) {
|
|
1348
|
+
try {
|
|
1349
|
+
const settings = JSON.parse(readFileSync(projectSettingsPath, 'utf-8'));
|
|
1350
|
+
let modified = false;
|
|
1351
|
+
if (settings.hooks) {
|
|
1352
|
+
for (const hookType of Object.keys(settings.hooks)) {
|
|
1353
|
+
const hooks = settings.hooks[hookType];
|
|
1354
|
+
if (Array.isArray(hooks)) {
|
|
1355
|
+
const filtered = hooks.filter((h) => {
|
|
1356
|
+
// Remove hooks pointing to non-existent files or legacy memory-capture hooks
|
|
1357
|
+
if (h.hooks) {
|
|
1358
|
+
return !h.hooks.some(hk => {
|
|
1359
|
+
if (!hk.command)
|
|
1360
|
+
return false;
|
|
1361
|
+
// Remove if it's a legacy memory hook
|
|
1362
|
+
if (hk.command.includes('memory-capture') ||
|
|
1363
|
+
hk.command.includes('memory-context-injection') ||
|
|
1364
|
+
hk.command.includes('memory-session-save')) {
|
|
1365
|
+
return true;
|
|
1366
|
+
}
|
|
1367
|
+
// Remove if the file doesn't exist
|
|
1368
|
+
if (hk.command.startsWith('/') && !existsSync(hk.command.split(' ')[0])) {
|
|
1369
|
+
return true;
|
|
1370
|
+
}
|
|
1371
|
+
return false;
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
return true;
|
|
1375
|
+
});
|
|
1376
|
+
if (filtered.length !== hooks.length) {
|
|
1377
|
+
settings.hooks[hookType] = filtered;
|
|
1378
|
+
modified = true;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
if (modified) {
|
|
1384
|
+
writeFileSync(projectSettingsPath, JSON.stringify(settings, null, 2));
|
|
1385
|
+
success('Cleaned up project-level legacy hooks');
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
catch {
|
|
1389
|
+
// Non-fatal
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
console.log('\n' + chalk.green(' Cleanup complete!'));
|
|
1393
|
+
console.log(chalk.dim(' Restart Claude Code for changes to take effect.\n'));
|
|
1394
|
+
}
|