@claudetools/tools 0.1.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.
@@ -0,0 +1,50 @@
1
+ export interface MemoryContext {
2
+ relevant_facts: {
3
+ fact: string;
4
+ source_name?: string;
5
+ target_name?: string;
6
+ relation_type: string;
7
+ created_at: string;
8
+ }[];
9
+ relevant_entities: {
10
+ name: string;
11
+ labels: string[];
12
+ summary?: string;
13
+ }[];
14
+ metadata: {
15
+ query: string;
16
+ retrieval_time_ms: number;
17
+ total_facts: number;
18
+ };
19
+ }
20
+ export declare function apiRequest<T>(endpoint: string, method?: 'GET' | 'POST', body?: unknown): Promise<T>;
21
+ export declare function addMemory(projectId: string, sessionId: string, messages: {
22
+ role: string;
23
+ content: string;
24
+ }[], extractFacts?: boolean): Promise<{
25
+ success: boolean;
26
+ episode_ids: string[];
27
+ }>;
28
+ export declare function searchMemory(projectId: string, query: string, limit?: number): Promise<MemoryContext>;
29
+ export declare function storeFact(projectId: string, entity1: string, relationship: string, entity2: string, context: string): Promise<{
30
+ success: boolean;
31
+ fact_id: string;
32
+ }>;
33
+ export declare function getContext(projectId: string, query?: string): Promise<MemoryContext>;
34
+ export declare function getSummary(projectId: string): Promise<string>;
35
+ export declare function getEntities(projectId: string): Promise<{
36
+ name: string;
37
+ labels: string[];
38
+ entity_id: string;
39
+ }[]>;
40
+ export declare function injectContext(projectId: string, query: string, userId?: string): Promise<{
41
+ augmentedSystemPrompt: string;
42
+ metadata: {
43
+ memoryNeeded: boolean;
44
+ retrievalTimeMs: number;
45
+ factsScored: number;
46
+ factsIncluded: number;
47
+ avgRelevanceScore: number;
48
+ reason?: string;
49
+ };
50
+ }>;
@@ -0,0 +1,60 @@
1
+ // =============================================================================
2
+ // API Client and Memory Operations
3
+ // =============================================================================
4
+ import { API_BASE_URL, DEFAULT_USER_ID } from './config.js';
5
+ export async function apiRequest(endpoint, method = 'GET', body) {
6
+ const url = `${API_BASE_URL}${endpoint}`;
7
+ const options = {
8
+ method,
9
+ headers: {
10
+ 'Content-Type': 'application/json',
11
+ },
12
+ };
13
+ if (body) {
14
+ options.body = JSON.stringify(body);
15
+ }
16
+ const response = await fetch(url, options);
17
+ if (!response.ok) {
18
+ throw new Error(`API error: ${response.status} ${response.statusText}`);
19
+ }
20
+ return response.json();
21
+ }
22
+ export async function addMemory(projectId, sessionId, messages, extractFacts = true) {
23
+ return apiRequest(`/api/v1/memory/${projectId}/add`, 'POST', {
24
+ session_id: sessionId,
25
+ messages,
26
+ extract_facts: extractFacts,
27
+ });
28
+ }
29
+ export async function searchMemory(projectId, query, limit = 10) {
30
+ return apiRequest(`/api/v1/memory/${projectId}/search`, 'POST', {
31
+ query,
32
+ limit,
33
+ });
34
+ }
35
+ export async function storeFact(projectId, entity1, relationship, entity2, context) {
36
+ return apiRequest(`/api/v1/memory/${projectId}/fact`, 'POST', {
37
+ entity1,
38
+ relationship,
39
+ entity2,
40
+ context,
41
+ });
42
+ }
43
+ export async function getContext(projectId, query) {
44
+ const params = query ? `?query=${encodeURIComponent(query)}` : '';
45
+ return apiRequest(`/api/v1/memory/${projectId}/context${params}`);
46
+ }
47
+ export async function getSummary(projectId) {
48
+ const response = await fetch(`${API_BASE_URL}/api/v1/memory/${projectId}/summary`);
49
+ return response.text();
50
+ }
51
+ export async function getEntities(projectId) {
52
+ return apiRequest(`/api/v1/memory/${projectId}/entities`);
53
+ }
54
+ export async function injectContext(projectId, query, userId) {
55
+ const response = await apiRequest(`/api/v1/memory/${projectId}/inject`, 'POST', {
56
+ query,
57
+ userId: userId || DEFAULT_USER_ID,
58
+ });
59
+ return response.data;
60
+ }
@@ -0,0 +1,68 @@
1
+ export interface ClaudeToolsConfig {
2
+ apiUrl: string;
3
+ apiKey?: string;
4
+ autoRegister: boolean;
5
+ defaultProjectId?: string;
6
+ defaultUserId?: string;
7
+ autoInjectContext: boolean;
8
+ contextRelevanceThreshold: number;
9
+ maxContextFacts: number;
10
+ verbosity: 'quiet' | 'normal' | 'verbose' | 'debug';
11
+ logToFile: boolean;
12
+ logFilePath?: string;
13
+ watchedDirectories: string[];
14
+ cacheTimeout: number;
15
+ maxRetries: number;
16
+ requestTimeout: number;
17
+ }
18
+ export declare const DEFAULT_CONFIG: ClaudeToolsConfig;
19
+ export declare function getConfigDir(): string;
20
+ export declare function getConfigPath(): string;
21
+ export declare function getProjectsPath(): string;
22
+ /**
23
+ * Ensures the ~/.claudetools directory exists
24
+ */
25
+ export declare function ensureConfigDir(): Promise<void>;
26
+ /**
27
+ * Synchronous version for initialization
28
+ */
29
+ export declare function ensureConfigDirSync(): void;
30
+ /**
31
+ * Loads configuration from ~/.claudetools/config.json
32
+ * Creates default configuration if file doesn't exist
33
+ */
34
+ export declare function loadConfigFromFile(): Promise<Partial<ClaudeToolsConfig>>;
35
+ /**
36
+ * Synchronous version for startup initialization
37
+ */
38
+ export declare function loadConfigFromFileSync(): Partial<ClaudeToolsConfig>;
39
+ /**
40
+ * Saves configuration to ~/.claudetools/config.json
41
+ */
42
+ export declare function saveConfig(config: ClaudeToolsConfig): Promise<void>;
43
+ /**
44
+ * Synchronous version for startup initialization
45
+ */
46
+ export declare function saveConfigSync(config: ClaudeToolsConfig): void;
47
+ /**
48
+ * Returns the complete configuration with environment overrides
49
+ * Priority: Environment Variables > Config File > Defaults
50
+ */
51
+ export declare function getConfig(): ClaudeToolsConfig;
52
+ /**
53
+ * Resets the cached configuration (useful for testing or runtime updates)
54
+ */
55
+ export declare function resetConfigCache(): void;
56
+ /**
57
+ * Updates a specific configuration value and saves to file
58
+ */
59
+ export declare function updateConfig(updates: Partial<ClaudeToolsConfig>): Promise<ClaudeToolsConfig>;
60
+ /**
61
+ * Resets configuration to defaults
62
+ */
63
+ export declare function resetConfig(): Promise<ClaudeToolsConfig>;
64
+ /**
65
+ * Initialize configuration on module load
66
+ * This ensures config file exists and is loaded early
67
+ */
68
+ export declare function initializeConfig(): ClaudeToolsConfig;
@@ -0,0 +1,306 @@
1
+ // =============================================================================
2
+ // ClaudeTools Configuration Manager
3
+ // =============================================================================
4
+ // Unified configuration system with file-based config and environment overrides
5
+ // Creates ~/.claudetools/config.json with sensible defaults on first run
6
+ // =============================================================================
7
+ import { mcpLogger } from '../logger.js';
8
+ import * as fs from 'fs/promises';
9
+ import * as fsSync from 'fs';
10
+ import * as path from 'path';
11
+ import * as os from 'os';
12
+ // -----------------------------------------------------------------------------
13
+ // Default Configuration
14
+ // -----------------------------------------------------------------------------
15
+ export const DEFAULT_CONFIG = {
16
+ // API Configuration
17
+ apiUrl: 'https://api.claudetools.dev',
18
+ apiKey: undefined,
19
+ // Project Management
20
+ autoRegister: true,
21
+ defaultProjectId: undefined,
22
+ defaultUserId: 'default',
23
+ // Context Injection
24
+ autoInjectContext: false, // Disabled by default for backward compatibility
25
+ contextRelevanceThreshold: 0.5,
26
+ maxContextFacts: 10,
27
+ // Logging & Verbosity
28
+ verbosity: 'normal',
29
+ logToFile: false,
30
+ logFilePath: undefined,
31
+ // Watched Directories
32
+ watchedDirectories: [],
33
+ // Performance
34
+ cacheTimeout: 300, // 5 minutes
35
+ maxRetries: 3,
36
+ requestTimeout: 30, // 30 seconds
37
+ };
38
+ // -----------------------------------------------------------------------------
39
+ // Environment Variable Mapping
40
+ // -----------------------------------------------------------------------------
41
+ const ENV_VAR_MAP = {
42
+ CLAUDETOOLS_API_URL: 'apiUrl',
43
+ CLAUDETOOLS_API_KEY: 'apiKey',
44
+ CLAUDETOOLS_AUTO_REGISTER: 'autoRegister',
45
+ CLAUDETOOLS_PROJECT_ID: 'defaultProjectId',
46
+ CLAUDETOOLS_USER_ID: 'defaultUserId',
47
+ AUTO_INJECT_CONTEXT: 'autoInjectContext',
48
+ CLAUDETOOLS_VERBOSITY: 'verbosity',
49
+ CLAUDETOOLS_LOG_TO_FILE: 'logToFile',
50
+ CLAUDETOOLS_LOG_FILE_PATH: 'logFilePath',
51
+ CLAUDETOOLS_CACHE_TIMEOUT: 'cacheTimeout',
52
+ CLAUDETOOLS_MAX_RETRIES: 'maxRetries',
53
+ CLAUDETOOLS_REQUEST_TIMEOUT: 'requestTimeout',
54
+ };
55
+ // -----------------------------------------------------------------------------
56
+ // Path Helpers
57
+ // -----------------------------------------------------------------------------
58
+ export function getConfigDir() {
59
+ return path.join(os.homedir(), '.claudetools');
60
+ }
61
+ export function getConfigPath() {
62
+ return path.join(getConfigDir(), 'config.json');
63
+ }
64
+ export function getProjectsPath() {
65
+ return path.join(getConfigDir(), 'projects.json');
66
+ }
67
+ // -----------------------------------------------------------------------------
68
+ // Directory Management
69
+ // -----------------------------------------------------------------------------
70
+ /**
71
+ * Ensures the ~/.claudetools directory exists
72
+ */
73
+ export async function ensureConfigDir() {
74
+ const configDir = getConfigDir();
75
+ try {
76
+ await fs.access(configDir);
77
+ }
78
+ catch {
79
+ mcpLogger.debug('CONFIG', `Creating config directory: ${configDir}`);
80
+ await fs.mkdir(configDir, { recursive: true });
81
+ }
82
+ }
83
+ /**
84
+ * Synchronous version for initialization
85
+ */
86
+ export function ensureConfigDirSync() {
87
+ const configDir = getConfigDir();
88
+ if (!fsSync.existsSync(configDir)) {
89
+ mcpLogger.debug('CONFIG', `Creating config directory: ${configDir}`);
90
+ fsSync.mkdirSync(configDir, { recursive: true });
91
+ }
92
+ }
93
+ // -----------------------------------------------------------------------------
94
+ // Configuration File Operations
95
+ // -----------------------------------------------------------------------------
96
+ /**
97
+ * Loads configuration from ~/.claudetools/config.json
98
+ * Creates default configuration if file doesn't exist
99
+ */
100
+ export async function loadConfigFromFile() {
101
+ const configPath = getConfigPath();
102
+ try {
103
+ await ensureConfigDir();
104
+ // Check if config file exists
105
+ try {
106
+ await fs.access(configPath);
107
+ }
108
+ catch {
109
+ // Config doesn't exist, create with defaults
110
+ mcpLogger.debug('CONFIG', `Creating default config at: ${configPath}`);
111
+ await saveConfig(DEFAULT_CONFIG);
112
+ return DEFAULT_CONFIG;
113
+ }
114
+ // Read and parse config file
115
+ const content = await fs.readFile(configPath, 'utf-8');
116
+ try {
117
+ const config = JSON.parse(content);
118
+ mcpLogger.debug('CONFIG', `Loaded config from: ${configPath}`);
119
+ return config;
120
+ }
121
+ catch (parseError) {
122
+ mcpLogger.error('CONFIG', `Failed to parse config file: ${parseError}`);
123
+ mcpLogger.info('CONFIG', 'Using default configuration');
124
+ return DEFAULT_CONFIG;
125
+ }
126
+ }
127
+ catch (error) {
128
+ mcpLogger.error('CONFIG', `Error loading config: ${error}`);
129
+ return {};
130
+ }
131
+ }
132
+ /**
133
+ * Synchronous version for startup initialization
134
+ */
135
+ export function loadConfigFromFileSync() {
136
+ const configPath = getConfigPath();
137
+ try {
138
+ ensureConfigDirSync();
139
+ // Check if config file exists
140
+ if (!fsSync.existsSync(configPath)) {
141
+ // Config doesn't exist, create with defaults
142
+ mcpLogger.debug('CONFIG', `Creating default config at: ${configPath}`);
143
+ saveConfigSync(DEFAULT_CONFIG);
144
+ return DEFAULT_CONFIG;
145
+ }
146
+ // Read and parse config file
147
+ const content = fsSync.readFileSync(configPath, 'utf-8');
148
+ try {
149
+ const config = JSON.parse(content);
150
+ mcpLogger.debug('CONFIG', `Loaded config from: ${configPath}`);
151
+ return config;
152
+ }
153
+ catch (parseError) {
154
+ mcpLogger.error('CONFIG', `Failed to parse config file: ${parseError}`);
155
+ mcpLogger.info('CONFIG', 'Using default configuration');
156
+ return DEFAULT_CONFIG;
157
+ }
158
+ }
159
+ catch (error) {
160
+ mcpLogger.error('CONFIG', `Error loading config: ${error}`);
161
+ return {};
162
+ }
163
+ }
164
+ /**
165
+ * Saves configuration to ~/.claudetools/config.json
166
+ */
167
+ export async function saveConfig(config) {
168
+ const configPath = getConfigPath();
169
+ try {
170
+ await ensureConfigDir();
171
+ const content = JSON.stringify(config, null, 2);
172
+ await fs.writeFile(configPath, content, 'utf-8');
173
+ mcpLogger.debug('CONFIG', `Saved config to: ${configPath}`);
174
+ }
175
+ catch (error) {
176
+ mcpLogger.error('CONFIG', `Failed to save config: ${error}`);
177
+ throw error;
178
+ }
179
+ }
180
+ /**
181
+ * Synchronous version for startup initialization
182
+ */
183
+ export function saveConfigSync(config) {
184
+ const configPath = getConfigPath();
185
+ try {
186
+ ensureConfigDirSync();
187
+ const content = JSON.stringify(config, null, 2);
188
+ fsSync.writeFileSync(configPath, content, 'utf-8');
189
+ mcpLogger.debug('CONFIG', `Saved config to: ${configPath}`);
190
+ }
191
+ catch (error) {
192
+ mcpLogger.error('CONFIG', `Failed to save config: ${error}`);
193
+ throw error;
194
+ }
195
+ }
196
+ // -----------------------------------------------------------------------------
197
+ // Environment Variable Overrides
198
+ // -----------------------------------------------------------------------------
199
+ /**
200
+ * Reads configuration overrides from environment variables
201
+ */
202
+ function getEnvOverrides() {
203
+ const overrides = {};
204
+ for (const [envVar, configKey] of Object.entries(ENV_VAR_MAP)) {
205
+ const value = process.env[envVar];
206
+ if (value !== undefined && value !== '') {
207
+ // Type conversion based on default config type
208
+ const defaultValue = DEFAULT_CONFIG[configKey];
209
+ if (typeof defaultValue === 'boolean') {
210
+ overrides[configKey] = value.toLowerCase() === 'true';
211
+ }
212
+ else if (typeof defaultValue === 'number') {
213
+ const numValue = parseInt(value, 10);
214
+ if (!isNaN(numValue)) {
215
+ overrides[configKey] = numValue;
216
+ }
217
+ }
218
+ else if (Array.isArray(defaultValue)) {
219
+ // Parse comma-separated values
220
+ overrides[configKey] = value.split(',').map(s => s.trim());
221
+ }
222
+ else {
223
+ overrides[configKey] = value;
224
+ }
225
+ mcpLogger.debug('CONFIG', `Environment override: ${configKey} = ${value}`);
226
+ }
227
+ }
228
+ return overrides;
229
+ }
230
+ // -----------------------------------------------------------------------------
231
+ // Merged Configuration
232
+ // -----------------------------------------------------------------------------
233
+ let cachedConfig = null;
234
+ /**
235
+ * Returns the complete configuration with environment overrides
236
+ * Priority: Environment Variables > Config File > Defaults
237
+ */
238
+ export function getConfig() {
239
+ // Return cached config if available
240
+ if (cachedConfig) {
241
+ return cachedConfig;
242
+ }
243
+ // Load config from file
244
+ const fileConfig = loadConfigFromFileSync();
245
+ // Get environment overrides
246
+ const envOverrides = getEnvOverrides();
247
+ // Merge: defaults < file < environment
248
+ cachedConfig = {
249
+ ...DEFAULT_CONFIG,
250
+ ...fileConfig,
251
+ ...envOverrides,
252
+ };
253
+ // Log final configuration in verbose mode
254
+ if (cachedConfig.verbosity === 'verbose' || cachedConfig.verbosity === 'debug') {
255
+ mcpLogger.debug('CONFIG', 'Final configuration:');
256
+ mcpLogger.debug('CONFIG', JSON.stringify(cachedConfig, null, 2));
257
+ }
258
+ return cachedConfig;
259
+ }
260
+ /**
261
+ * Resets the cached configuration (useful for testing or runtime updates)
262
+ */
263
+ export function resetConfigCache() {
264
+ cachedConfig = null;
265
+ mcpLogger.debug('CONFIG', 'Configuration cache reset');
266
+ }
267
+ /**
268
+ * Updates a specific configuration value and saves to file
269
+ */
270
+ export async function updateConfig(updates) {
271
+ const currentConfig = getConfig();
272
+ const newConfig = { ...currentConfig, ...updates };
273
+ await saveConfig(newConfig);
274
+ resetConfigCache();
275
+ mcpLogger.info('CONFIG', 'Configuration updated');
276
+ return newConfig;
277
+ }
278
+ /**
279
+ * Resets configuration to defaults
280
+ */
281
+ export async function resetConfig() {
282
+ await saveConfig(DEFAULT_CONFIG);
283
+ resetConfigCache();
284
+ mcpLogger.info('CONFIG', 'Configuration reset to defaults');
285
+ return DEFAULT_CONFIG;
286
+ }
287
+ // -----------------------------------------------------------------------------
288
+ // Initialization
289
+ // -----------------------------------------------------------------------------
290
+ /**
291
+ * Initialize configuration on module load
292
+ * This ensures config file exists and is loaded early
293
+ */
294
+ export function initializeConfig() {
295
+ ensureConfigDirSync();
296
+ return getConfig();
297
+ }
298
+ // Auto-initialize on import
299
+ const initialConfig = initializeConfig();
300
+ // Log configuration status on startup
301
+ if (initialConfig.verbosity !== 'quiet') {
302
+ mcpLogger.info('CONFIG', `ClaudeTools configuration loaded from: ${getConfigPath()}`);
303
+ mcpLogger.info('CONFIG', `API URL: ${initialConfig.apiUrl}`);
304
+ mcpLogger.info('CONFIG', `Verbosity: ${initialConfig.verbosity}`);
305
+ mcpLogger.info('CONFIG', `Auto-inject context: ${initialConfig.autoInjectContext}`);
306
+ }
@@ -0,0 +1,55 @@
1
+ export declare const API_BASE_URL: string;
2
+ export declare const CLAUDETOOLS_DIR: string;
3
+ export declare const PROJECTS_FILE: string;
4
+ export interface ProjectBinding {
5
+ project_id: string;
6
+ project_name: string;
7
+ org_id: string;
8
+ local_path: string;
9
+ git_remote?: string;
10
+ cached_at: string;
11
+ }
12
+ export interface ProjectsCache {
13
+ bindings: ProjectBinding[];
14
+ last_sync: string;
15
+ }
16
+ /**
17
+ * Validates that a project ID is a proper UUID format
18
+ */
19
+ export declare function isValidProjectId(id: string): boolean;
20
+ /**
21
+ * Finds a project binding in the cache by directory path
22
+ */
23
+ export declare function findProjectBinding(dirPath: string): ProjectBinding | null;
24
+ /**
25
+ * Look up project ID from local cache based on current working directory
26
+ * Synchronous version - throws if not already resolved
27
+ */
28
+ export declare function resolveProjectId(): string;
29
+ /**
30
+ * Async version that auto-registers if needed
31
+ * Should be called during server startup
32
+ */
33
+ export declare function resolveProjectIdAsync(): Promise<string>;
34
+ /**
35
+ * Gets the default project ID (synchronous version)
36
+ * Throws if not already resolved - call resolveProjectIdAsync() first
37
+ */
38
+ export declare function getDefaultProjectId(): string;
39
+ /**
40
+ * Async version for server startup
41
+ */
42
+ export declare function getDefaultProjectIdAsync(): Promise<string>;
43
+ export declare const DEFAULT_USER_ID: string;
44
+ export declare const AUTO_INJECT_CONTEXT: boolean;
45
+ export declare let lastContextUsed: {
46
+ augmentedSystemPrompt: string;
47
+ metadata: {
48
+ memoryNeeded: boolean;
49
+ retrievalTimeMs: number;
50
+ factsScored: number;
51
+ factsIncluded: number;
52
+ avgRelevanceScore: number;
53
+ };
54
+ } | null;
55
+ export declare function setLastContextUsed(context: typeof lastContextUsed): void;