@claudetools/tools 0.7.0 → 0.7.2
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 +62 -0
- package/dist/codedna/generators/base.d.ts +11 -2
- package/dist/codedna/generators/base.js +91 -8
- package/dist/codedna/generators/react-frontend.js +2 -1
- package/dist/codedna/parser.d.ts +6 -0
- package/dist/codedna/parser.js +7 -0
- package/dist/codedna/registry.d.ts +23 -17
- package/dist/codedna/registry.js +103 -263
- package/dist/codedna/template-engine.js +23 -0
- package/dist/codedna/types.d.ts +22 -0
- package/dist/handlers/codedna-handlers.d.ts +219 -6
- package/dist/handlers/codedna-handlers.js +379 -11
- package/dist/handlers/tool-handlers.js +56 -7
- package/dist/helpers/codebase-mapper.d.ts +66 -0
- package/dist/helpers/codebase-mapper.js +634 -0
- package/dist/helpers/config.d.ts +1 -1
- package/dist/helpers/config.js +39 -2
- package/dist/helpers/workers.js +60 -7
- package/dist/templates/orchestrator-prompt.js +15 -7
- package/dist/templates/worker-prompt.js +24 -31
- package/dist/tools.js +101 -2
- package/dist/watcher.js +97 -1
- package/package.json +3 -2
package/dist/helpers/config.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// =============================================================================
|
|
4
4
|
import { mcpLogger } from '../logger.js';
|
|
5
5
|
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
6
7
|
import { getConfig, getConfigDir, getProjectsPath, } from './config-manager.js';
|
|
7
8
|
import { getOrRegisterProject } from './project-registration.js';
|
|
8
9
|
// Configuration - now loaded from config manager
|
|
@@ -10,6 +11,28 @@ const config = getConfig();
|
|
|
10
11
|
export const API_BASE_URL = config.apiUrl;
|
|
11
12
|
export const CLAUDETOOLS_DIR = getConfigDir();
|
|
12
13
|
export const PROJECTS_FILE = getProjectsPath();
|
|
14
|
+
const SESSION_CONTEXT_FILE = path.join(CLAUDETOOLS_DIR, 'session-context.md');
|
|
15
|
+
/**
|
|
16
|
+
* Read project ID from session-context.md (written by session-start hook)
|
|
17
|
+
* This is the most reliable source since it's set by Claude Code's hook system
|
|
18
|
+
*/
|
|
19
|
+
function getProjectIdFromSessionContext() {
|
|
20
|
+
try {
|
|
21
|
+
if (!fs.existsSync(SESSION_CONTEXT_FILE)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const content = fs.readFileSync(SESSION_CONTEXT_FILE, 'utf-8');
|
|
25
|
+
// Parse: **Project ID:** proj_xxxxx
|
|
26
|
+
const match = content.match(/\*\*Project ID:\*\*\s*(proj_[a-f0-9]{20})/);
|
|
27
|
+
if (match) {
|
|
28
|
+
return match[1];
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
13
36
|
// Cache for resolved project ID
|
|
14
37
|
let resolvedProjectId = null;
|
|
15
38
|
/**
|
|
@@ -93,6 +116,14 @@ export async function resolveProjectIdAsync() {
|
|
|
93
116
|
mcpLogger.debug('MEMORY', `Using project ID from env: ${resolvedProjectId}`);
|
|
94
117
|
return resolvedProjectId;
|
|
95
118
|
}
|
|
119
|
+
// Check session-context.md (written by Claude Code's session-start hook)
|
|
120
|
+
// This is the most reliable source since MCP server's cwd isn't the project dir
|
|
121
|
+
const sessionProjectId = getProjectIdFromSessionContext();
|
|
122
|
+
if (sessionProjectId) {
|
|
123
|
+
resolvedProjectId = sessionProjectId;
|
|
124
|
+
mcpLogger.info('MEMORY', `Project resolved from session context: ${resolvedProjectId}`);
|
|
125
|
+
return resolvedProjectId;
|
|
126
|
+
}
|
|
96
127
|
const cwd = process.cwd();
|
|
97
128
|
// Check projects.json cache
|
|
98
129
|
const binding = findProjectBinding(cwd);
|
|
@@ -134,13 +165,19 @@ export async function resolveProjectIdAsync() {
|
|
|
134
165
|
let _defaultProjectId = null;
|
|
135
166
|
/**
|
|
136
167
|
* Gets the default project ID (synchronous version)
|
|
137
|
-
*
|
|
168
|
+
* Checks session-context.md first, then config, then falls back to cwd resolution
|
|
138
169
|
*/
|
|
139
170
|
export function getDefaultProjectId() {
|
|
140
171
|
if (_defaultProjectId) {
|
|
141
172
|
return _defaultProjectId;
|
|
142
173
|
}
|
|
143
|
-
//
|
|
174
|
+
// Check session-context.md first (most reliable for MCP server)
|
|
175
|
+
const sessionProjectId = getProjectIdFromSessionContext();
|
|
176
|
+
if (sessionProjectId) {
|
|
177
|
+
_defaultProjectId = sessionProjectId;
|
|
178
|
+
return _defaultProjectId;
|
|
179
|
+
}
|
|
180
|
+
// Try config second
|
|
144
181
|
if (config.defaultProjectId) {
|
|
145
182
|
if (!isValidProjectId(config.defaultProjectId)) {
|
|
146
183
|
// Legacy format - convert to local_ format instead of throwing
|
package/dist/helpers/workers.js
CHANGED
|
@@ -37,11 +37,17 @@ When complete, provide a concise summary of changes made.`,
|
|
|
37
37
|
- Response formatting
|
|
38
38
|
- Error handling for endpoints
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
PATTERN DETECTION (for existing projects):
|
|
41
|
+
1. Call codedna_detect_patterns(package_json) to find existing patterns
|
|
42
|
+
2. MATCH detected patterns - don't introduce conflicting libraries
|
|
43
|
+
3. Check for: zod vs yup validation, tanstack-query vs swr, etc.
|
|
44
|
+
|
|
45
|
+
CODEDNA PRIORITY: Before writing CRUD code manually:
|
|
46
|
+
1. Call codedna_list_generators() to discover available generators
|
|
47
|
+
2. Look for Entity DSL in task (e.g., "User(email:string:unique, password:string:hashed)")
|
|
48
|
+
3. Detect framework from project (check package.json, existing patterns)
|
|
49
|
+
4. Call codedna_generate_api(spec, framework="<detected>", options={...})
|
|
50
|
+
5. Only write manually for complex business logic that can't be generated
|
|
45
51
|
|
|
46
52
|
Focus only on API-related changes. Do not modify schema or extraction code.
|
|
47
53
|
When complete, provide a concise summary of endpoints created or modified.`,
|
|
@@ -99,6 +105,40 @@ TOOLS: Use codebase_context to see file dependencies.
|
|
|
99
105
|
|
|
100
106
|
Focus on integration without modifying core implementation logic.
|
|
101
107
|
When complete, provide a concise summary of integrations configured.`,
|
|
108
|
+
},
|
|
109
|
+
'frontend-expert': {
|
|
110
|
+
id: 'frontend-expert',
|
|
111
|
+
name: 'Frontend Expert',
|
|
112
|
+
description: 'Specialises in React, Vue, and frontend component development',
|
|
113
|
+
domains: ['**/components/**', '**/pages/**', '**/app/**', '**/*.tsx', '**/*.vue'],
|
|
114
|
+
capabilities: ['react', 'vue', 'components', 'forms', 'tables', 'styling'],
|
|
115
|
+
promptTemplate: `You are a frontend development expert. Your domain is limited to:
|
|
116
|
+
- React/Vue components and pages
|
|
117
|
+
- Form and table components
|
|
118
|
+
- UI component libraries
|
|
119
|
+
- Client-side state management
|
|
120
|
+
|
|
121
|
+
PATTERN DETECTION (CRITICAL for existing projects):
|
|
122
|
+
1. Call codedna_detect_patterns(package_json) to detect existing patterns
|
|
123
|
+
2. RESPECT detected patterns - consistency > "better":
|
|
124
|
+
- Compound components? Use compound pattern
|
|
125
|
+
- React Hook Form? Don't introduce Formik
|
|
126
|
+
- Zustand? Don't add Redux
|
|
127
|
+
- Tailwind? Match styling approach
|
|
128
|
+
3. Check codedna_list_patterns(category="anti-patterns") for code smells to avoid
|
|
129
|
+
|
|
130
|
+
CODEDNA PRIORITY: Before writing UI components manually:
|
|
131
|
+
1. Call codedna_list_generators() to discover available generators
|
|
132
|
+
2. Detect UI framework from project (check package.json for react, vue, etc.)
|
|
133
|
+
3. Check for UI library (package.json: @shadcn/ui, @mui/material, @chakra-ui, etc.)
|
|
134
|
+
4. Call codedna_generate_frontend or codedna_generate_component with detected settings
|
|
135
|
+
5. DO NOT assume any specific framework/library - discover via list_generators, detect from project
|
|
136
|
+
|
|
137
|
+
TOOLS: Use codebase_find to discover existing component patterns.
|
|
138
|
+
TOOLS: Use memory_search for past UI decisions.
|
|
139
|
+
|
|
140
|
+
Focus on components and pages. Do not modify API or schema code.
|
|
141
|
+
When complete, provide a concise summary of components created.`,
|
|
102
142
|
},
|
|
103
143
|
'general-expert': {
|
|
104
144
|
id: 'general-expert',
|
|
@@ -108,7 +148,13 @@ When complete, provide a concise summary of integrations configured.`,
|
|
|
108
148
|
capabilities: ['general-development', 'refactoring', 'documentation', 'testing'],
|
|
109
149
|
promptTemplate: `You are a general purpose development expert.
|
|
110
150
|
|
|
111
|
-
CODEDNA
|
|
151
|
+
CODEDNA - DISCOVER THEN DETECT:
|
|
152
|
+
1. Call codedna_list_generators() to see what's available
|
|
153
|
+
2. Detect project framework from package.json/pyproject.toml
|
|
154
|
+
3. Match detected framework to generator capabilities
|
|
155
|
+
4. If no match, ASK the user which framework to use
|
|
156
|
+
5. DO NOT assume any specific framework exists - always discover first
|
|
157
|
+
|
|
112
158
|
TOOLS: Use memory_search and codebase_find before implementing from scratch.
|
|
113
159
|
|
|
114
160
|
Handle this task with care:
|
|
@@ -267,7 +313,6 @@ export function matchTaskToWorker(task) {
|
|
|
267
313
|
'database': 'schema-expert',
|
|
268
314
|
'sql': 'schema-expert',
|
|
269
315
|
'migration': 'schema-expert',
|
|
270
|
-
'table': 'schema-expert',
|
|
271
316
|
'api': 'api-expert',
|
|
272
317
|
'route': 'api-expert',
|
|
273
318
|
'endpoint': 'api-expert',
|
|
@@ -282,6 +327,14 @@ export function matchTaskToWorker(task) {
|
|
|
282
327
|
'integration': 'integration-expert',
|
|
283
328
|
'config': 'integration-expert',
|
|
284
329
|
'wiring': 'integration-expert',
|
|
330
|
+
'component': 'frontend-expert',
|
|
331
|
+
'frontend': 'frontend-expert',
|
|
332
|
+
'react': 'frontend-expert',
|
|
333
|
+
'vue': 'frontend-expert',
|
|
334
|
+
'form': 'frontend-expert',
|
|
335
|
+
'table': 'frontend-expert',
|
|
336
|
+
'page': 'frontend-expert',
|
|
337
|
+
'ui': 'frontend-expert',
|
|
285
338
|
};
|
|
286
339
|
for (const [keyword, workerId] of Object.entries(keywordMap)) {
|
|
287
340
|
if (searchText.includes(keyword)) {
|
|
@@ -187,15 +187,23 @@ export function buildOrchestratorPrompt(params) {
|
|
|
187
187
|
- general-expert: Tasks that don't fit other domains`}
|
|
188
188
|
</available_workers>
|
|
189
189
|
|
|
190
|
-
<codedna_generators>
|
|
191
|
-
|
|
190
|
+
<codedna_generators priority="CRITICAL">
|
|
191
|
+
CodeDNA generates production code from Entity DSL - workers MUST check availability first.
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
BEFORE creating any task involving APIs, CRUD, or UI components:
|
|
194
|
+
1. Workers should call codedna_list_generators() to see available generators
|
|
195
|
+
2. If a generator exists, use it instead of writing code manually
|
|
196
196
|
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
AVAILABLE DOMAINS:
|
|
198
|
+
- api: Express, FastAPI, NestJS (full CRUD with auth, validation, tests)
|
|
199
|
+
- frontend: React/Next.js, Vue 3 (pages, forms, tables)
|
|
200
|
+
- component: Forms, tables, cards, modals (React, Vue, Svelte)
|
|
201
|
+
|
|
202
|
+
INCLUDE IN TASK DESCRIPTIONS:
|
|
203
|
+
When tasks involve entities, include the DSL spec so workers know to use CodeDNA:
|
|
204
|
+
"Create user registration. Entity: User(email:string:unique, password:string:hashed)"
|
|
205
|
+
|
|
206
|
+
Token savings: 95-99% vs manual coding
|
|
199
207
|
</codedna_generators>
|
|
200
208
|
|
|
201
209
|
${epicTitle ? `<epic_context>
|
|
@@ -71,16 +71,18 @@ function buildBehavioralSection(taskId) {
|
|
|
71
71
|
<behavior id="codedna_first" priority="MANDATORY">
|
|
72
72
|
BEFORE writing code manually, check if CodeDNA can generate it:
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
DISCOVERY WORKFLOW:
|
|
75
|
+
1. Call codedna_list_generators() to see available generators
|
|
76
|
+
2. Check if task includes Entity DSL format
|
|
77
|
+
Example: "User(email:string:unique, password:string:hashed)"
|
|
78
|
+
3. Detect framework from project (package.json, existing code)
|
|
79
|
+
4. Match detected framework to generator capabilities
|
|
80
|
+
5. Call appropriate generator with detected settings
|
|
81
|
+
|
|
82
|
+
BENEFITS:
|
|
76
83
|
→ Saves 95-99% tokens vs manual coding
|
|
77
84
|
→ Generates production-ready code with validation, auth, tests
|
|
78
85
|
|
|
79
|
-
FOR Entity definitions:
|
|
80
|
-
→ Check if task includes Entity DSL format
|
|
81
|
-
→ Example: "User(email:string:unique, password:string:hashed)"
|
|
82
|
-
→ Call codedna_generate_api with the spec
|
|
83
|
-
|
|
84
86
|
ONLY write code manually when:
|
|
85
87
|
- Logic is too complex for generation
|
|
86
88
|
- Modifying existing code (not creating new)
|
|
@@ -177,16 +179,12 @@ function buildDomainSection(worker) {
|
|
|
177
179
|
return `<!-- Layer 4: Domain Knowledge -->
|
|
178
180
|
<domain_knowledge>
|
|
179
181
|
<codedna_capabilities>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
2. codedna_validate_spec(spec)
|
|
188
|
-
- Validates Entity DSL syntax before generation
|
|
189
|
-
- Returns parsed structure or errors
|
|
182
|
+
CODEDNA DISCOVERY PATTERN:
|
|
183
|
+
1. Call codedna_list_generators() to see available generators
|
|
184
|
+
2. Each generator lists supported frameworks and options
|
|
185
|
+
3. Detect project framework from package.json/pyproject.toml
|
|
186
|
+
4. Match detected framework to generator capabilities
|
|
187
|
+
5. If no match, ASK the user which framework to use
|
|
190
188
|
|
|
191
189
|
ENTITY DSL FORMAT:
|
|
192
190
|
EntityName(field:type:constraint, field:type:constraint, ...)
|
|
@@ -197,20 +195,15 @@ function buildDomainSection(worker) {
|
|
|
197
195
|
- enum(val1|val2|val3) - enumeration
|
|
198
196
|
|
|
199
197
|
CONSTRAINTS:
|
|
200
|
-
- unique
|
|
201
|
-
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
framework: "express",
|
|
210
|
-
options: { auth: true, validation: true }
|
|
211
|
-
})
|
|
212
|
-
→ Generates 6 production files in ~5 seconds
|
|
213
|
-
→ Saves ~30,000 tokens vs manual implementation
|
|
198
|
+
- unique, required, min(n), max(n), hashed, default(value)
|
|
199
|
+
- UI hints: textarea, switch, radio (for form rendering)
|
|
200
|
+
|
|
201
|
+
WORKFLOW:
|
|
202
|
+
1. codedna_list_generators() → discover capabilities
|
|
203
|
+
2. codedna_validate_spec(spec) → validate DSL syntax
|
|
204
|
+
3. codedna_generate_*(spec, framework, options) → generate code
|
|
205
|
+
|
|
206
|
+
DO NOT assume frameworks exist - always discover via codedna_list_generators
|
|
214
207
|
</codedna_capabilities>
|
|
215
208
|
|
|
216
209
|
<worker_expertise>
|
package/dist/tools.js
CHANGED
|
@@ -952,6 +952,10 @@ export function registerToolDefinitions(server) {
|
|
|
952
952
|
},
|
|
953
953
|
},
|
|
954
954
|
},
|
|
955
|
+
package_json: {
|
|
956
|
+
type: 'object',
|
|
957
|
+
description: 'Optional: package.json content for pattern detection. If provided, generator will detect patterns (zod, yup, etc.) and use matching template variants.',
|
|
958
|
+
},
|
|
955
959
|
},
|
|
956
960
|
required: ['spec', 'framework'],
|
|
957
961
|
},
|
|
@@ -993,6 +997,10 @@ export function registerToolDefinitions(server) {
|
|
|
993
997
|
},
|
|
994
998
|
},
|
|
995
999
|
},
|
|
1000
|
+
package_json: {
|
|
1001
|
+
type: 'object',
|
|
1002
|
+
description: 'Optional: package.json content for pattern detection. Detects React Hook Form, Zod, TanStack Query, etc. and uses matching template variants.',
|
|
1003
|
+
},
|
|
996
1004
|
},
|
|
997
1005
|
required: ['spec', 'framework'],
|
|
998
1006
|
},
|
|
@@ -1031,16 +1039,26 @@ export function registerToolDefinitions(server) {
|
|
|
1031
1039
|
},
|
|
1032
1040
|
},
|
|
1033
1041
|
},
|
|
1042
|
+
package_json: {
|
|
1043
|
+
type: 'object',
|
|
1044
|
+
description: 'Optional: package.json content for pattern detection. Detects form libraries, validation tools, etc. and uses matching template variants.',
|
|
1045
|
+
},
|
|
1034
1046
|
},
|
|
1035
1047
|
required: ['spec', 'type', 'framework'],
|
|
1036
1048
|
},
|
|
1037
1049
|
},
|
|
1038
1050
|
{
|
|
1039
1051
|
name: 'codedna_list_generators',
|
|
1040
|
-
description: '
|
|
1052
|
+
description: 'CALL THIS BEFORE writing any API, CRUD, or UI component code. Lists available code generators that save 95-99% tokens vs manual coding. Returns generators grouped by domain (api/frontend/component) with their capabilities. If a generator exists for your task, use codedna_generate_* instead of writing code manually.',
|
|
1041
1053
|
inputSchema: {
|
|
1042
1054
|
type: 'object',
|
|
1043
|
-
properties: {
|
|
1055
|
+
properties: {
|
|
1056
|
+
domain: {
|
|
1057
|
+
type: 'string',
|
|
1058
|
+
enum: ['api', 'frontend', 'component'],
|
|
1059
|
+
description: 'Filter by domain: "api" for backend APIs, "frontend" for full frontend apps, "component" for individual UI components',
|
|
1060
|
+
},
|
|
1061
|
+
},
|
|
1044
1062
|
},
|
|
1045
1063
|
},
|
|
1046
1064
|
{
|
|
@@ -1057,6 +1075,87 @@ export function registerToolDefinitions(server) {
|
|
|
1057
1075
|
required: ['spec'],
|
|
1058
1076
|
},
|
|
1059
1077
|
},
|
|
1078
|
+
// =========================================================================
|
|
1079
|
+
// CodeDNA Pattern Library Tools
|
|
1080
|
+
// =========================================================================
|
|
1081
|
+
{
|
|
1082
|
+
name: 'codedna_list_patterns',
|
|
1083
|
+
description: 'List coding patterns from the library. Returns best practices (compound components, TanStack Query, Zod) and anti-patterns to avoid (prop drilling, useEffect fetch). Use to understand what patterns are available for a project.',
|
|
1084
|
+
inputSchema: {
|
|
1085
|
+
type: 'object',
|
|
1086
|
+
properties: {
|
|
1087
|
+
category: {
|
|
1088
|
+
type: 'string',
|
|
1089
|
+
enum: ['components', 'hooks', 'forms', 'state', 'validation', 'styling', 'anti-patterns'],
|
|
1090
|
+
description: 'Filter by category',
|
|
1091
|
+
},
|
|
1092
|
+
recommended_only: {
|
|
1093
|
+
type: 'boolean',
|
|
1094
|
+
description: 'Only return recommended best-practice patterns',
|
|
1095
|
+
},
|
|
1096
|
+
include_anti_patterns: {
|
|
1097
|
+
type: 'boolean',
|
|
1098
|
+
description: 'Include anti-patterns in results (default: true)',
|
|
1099
|
+
},
|
|
1100
|
+
},
|
|
1101
|
+
},
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
name: 'codedna_get_pattern',
|
|
1105
|
+
description: 'Get detailed documentation for a specific pattern including code examples, when to use/avoid, and migration guides. Use after codedna_list_patterns to get full details.',
|
|
1106
|
+
inputSchema: {
|
|
1107
|
+
type: 'object',
|
|
1108
|
+
properties: {
|
|
1109
|
+
pattern_id: {
|
|
1110
|
+
type: 'string',
|
|
1111
|
+
description: 'Pattern ID (e.g., "compound-components", "tanstack-query", "prop-drilling")',
|
|
1112
|
+
},
|
|
1113
|
+
},
|
|
1114
|
+
required: ['pattern_id'],
|
|
1115
|
+
},
|
|
1116
|
+
},
|
|
1117
|
+
{
|
|
1118
|
+
name: 'codedna_detect_patterns',
|
|
1119
|
+
description: 'Detect which patterns are used in an existing codebase. Analyzes package.json dependencies and code samples to identify patterns and anti-patterns. Use before making changes to understand project conventions.',
|
|
1120
|
+
inputSchema: {
|
|
1121
|
+
type: 'object',
|
|
1122
|
+
properties: {
|
|
1123
|
+
package_json: {
|
|
1124
|
+
type: 'object',
|
|
1125
|
+
description: 'The project package.json object (with dependencies/devDependencies)',
|
|
1126
|
+
},
|
|
1127
|
+
code_samples: {
|
|
1128
|
+
type: 'array',
|
|
1129
|
+
items: { type: 'string' },
|
|
1130
|
+
description: 'Code snippets to analyze for pattern signals',
|
|
1131
|
+
},
|
|
1132
|
+
},
|
|
1133
|
+
},
|
|
1134
|
+
},
|
|
1135
|
+
{
|
|
1136
|
+
name: 'codedna_init_project',
|
|
1137
|
+
description: 'Initialize a project with recommended patterns. For NEW projects, applies best-practice defaults. For EXISTING projects, use with auto_detect to match existing conventions.',
|
|
1138
|
+
inputSchema: {
|
|
1139
|
+
type: 'object',
|
|
1140
|
+
properties: {
|
|
1141
|
+
project_id: {
|
|
1142
|
+
type: 'string',
|
|
1143
|
+
description: 'Project ID from claudetools',
|
|
1144
|
+
},
|
|
1145
|
+
patterns: {
|
|
1146
|
+
type: 'array',
|
|
1147
|
+
items: { type: 'string' },
|
|
1148
|
+
description: 'Specific pattern IDs to apply (optional - uses recommended if not specified)',
|
|
1149
|
+
},
|
|
1150
|
+
project_type: {
|
|
1151
|
+
type: 'string',
|
|
1152
|
+
enum: ['new', 'existing'],
|
|
1153
|
+
description: '"new" for greenfield (uses recommended), "existing" for updating (detects patterns)',
|
|
1154
|
+
},
|
|
1155
|
+
},
|
|
1156
|
+
required: ['project_id'],
|
|
1157
|
+
},
|
|
1158
|
+
},
|
|
1060
1159
|
],
|
|
1061
1160
|
}));
|
|
1062
1161
|
}
|
package/dist/watcher.js
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
// Monitors project directories for changes and syncs with the API
|
|
5
5
|
import { homedir } from 'os';
|
|
6
6
|
import { join } from 'path';
|
|
7
|
-
import { existsSync, readFileSync, writeFileSync, unlinkSync, watch, readdirSync, statSync } from 'fs';
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync, watch, readdirSync, statSync, mkdirSync } from 'fs';
|
|
8
|
+
import { getProjectTemplate, SECTION_START } from './templates/claude-md.js';
|
|
9
|
+
import { generateCodebaseMap } from './helpers/codebase-mapper.js';
|
|
8
10
|
// -----------------------------------------------------------------------------
|
|
9
11
|
// Constants
|
|
10
12
|
// -----------------------------------------------------------------------------
|
|
@@ -136,6 +138,94 @@ function discoverProjects(directories) {
|
|
|
136
138
|
}
|
|
137
139
|
return projects;
|
|
138
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Ensures .claude/CLAUDE.md exists for a project
|
|
143
|
+
* Creates it if missing, using the project template
|
|
144
|
+
*/
|
|
145
|
+
function ensureProjectClaudeMd(projectPath, projectId, projectName) {
|
|
146
|
+
const claudeDir = join(projectPath, '.claude');
|
|
147
|
+
const claudeMdPath = join(claudeDir, 'CLAUDE.md');
|
|
148
|
+
// Skip if CLAUDE.md already exists with claudetools section
|
|
149
|
+
if (existsSync(claudeMdPath)) {
|
|
150
|
+
try {
|
|
151
|
+
const content = readFileSync(claudeMdPath, 'utf-8');
|
|
152
|
+
if (content.includes(SECTION_START)) {
|
|
153
|
+
return false; // Already has claudetools section
|
|
154
|
+
}
|
|
155
|
+
// Has CLAUDE.md but no claudetools section - append it
|
|
156
|
+
const template = getProjectTemplate(projectId, projectName);
|
|
157
|
+
writeFileSync(claudeMdPath, content.trimEnd() + '\n' + template);
|
|
158
|
+
log('info', `Added ClaudeTools section to existing CLAUDE.md: ${projectPath}`);
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Create .claude directory if needed
|
|
166
|
+
if (!existsSync(claudeDir)) {
|
|
167
|
+
try {
|
|
168
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
log('warn', `Could not create .claude directory for ${projectPath}: ${err}`);
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Create CLAUDE.md with template
|
|
176
|
+
try {
|
|
177
|
+
const template = getProjectTemplate(projectId, projectName);
|
|
178
|
+
writeFileSync(claudeMdPath, template);
|
|
179
|
+
log('info', `Created CLAUDE.md for project: ${projectPath}`);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
log('warn', `Could not create CLAUDE.md for ${projectPath}: ${err}`);
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Ensures all synced projects have CLAUDE.md files
|
|
189
|
+
*/
|
|
190
|
+
function ensureAllProjectsHaveClaudeMd(bindings) {
|
|
191
|
+
let created = 0;
|
|
192
|
+
for (const binding of bindings) {
|
|
193
|
+
if (binding.local_path && binding.project_id) {
|
|
194
|
+
if (ensureProjectClaudeMd(binding.local_path, binding.project_id, binding.project_name || 'Unknown')) {
|
|
195
|
+
created++;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (created > 0) {
|
|
200
|
+
log('info', `Created CLAUDE.md for ${created} projects`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Generate codebase maps for all synced projects
|
|
205
|
+
*/
|
|
206
|
+
async function generateMapsForProjects(bindings, apiKey) {
|
|
207
|
+
let generated = 0;
|
|
208
|
+
for (const binding of bindings) {
|
|
209
|
+
if (binding.local_path && binding.project_id) {
|
|
210
|
+
try {
|
|
211
|
+
log('info', `Generating codebase map for ${binding.project_name || binding.local_path}...`);
|
|
212
|
+
const result = await generateCodebaseMap(binding.local_path, binding.project_id, apiKey);
|
|
213
|
+
if (result.success) {
|
|
214
|
+
generated++;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
log('warn', `Map generation failed for ${binding.project_name}: ${result.error}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
log('warn', `Map generation error for ${binding.project_name}: ${err}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (generated > 0) {
|
|
226
|
+
log('info', `Generated codebase maps for ${generated} projects`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
139
229
|
// -----------------------------------------------------------------------------
|
|
140
230
|
// API Sync
|
|
141
231
|
// -----------------------------------------------------------------------------
|
|
@@ -166,6 +256,12 @@ async function syncProjectsWithAPI(config, system, projects) {
|
|
|
166
256
|
projectsData.bindings = data.bindings;
|
|
167
257
|
projectsData.last_sync = new Date().toISOString();
|
|
168
258
|
writeFileSync(PROJECTS_FILE, JSON.stringify(projectsData, null, 2));
|
|
259
|
+
// Auto-create CLAUDE.md for all synced projects
|
|
260
|
+
ensureAllProjectsHaveClaudeMd(data.bindings);
|
|
261
|
+
// Generate codebase maps for all projects (async, don't block)
|
|
262
|
+
generateMapsForProjects(data.bindings, config.apiKey).catch((err) => {
|
|
263
|
+
log('warn', `Map generation failed: ${err}`);
|
|
264
|
+
});
|
|
169
265
|
}
|
|
170
266
|
log('info', `Synced ${projects.length} projects with API`);
|
|
171
267
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudetools/tools",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Persistent AI memory, task management, and codebase intelligence for Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -59,7 +59,8 @@
|
|
|
59
59
|
"chalk": "^5.6.2",
|
|
60
60
|
"nunjucks": "^3.2.4",
|
|
61
61
|
"ora": "^9.0.0",
|
|
62
|
-
"prompts": "^2.4.2"
|
|
62
|
+
"prompts": "^2.4.2",
|
|
63
|
+
"typescript": "^5.3.0"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@types/node": "^20.10.0",
|