@claudetools/tools 0.2.2 → 0.3.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/dist/cli.js +9 -1
- package/dist/setup.d.ts +1 -0
- package/dist/setup.js +309 -8
- package/dist/templates/claude-md.d.ts +24 -0
- package/dist/templates/claude-md.js +157 -0
- 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 } from './setup.js';
|
|
10
|
+
import { runSetup, runUninstall, runInit } 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
|
|
@@ -47,6 +47,7 @@ Options:
|
|
|
47
47
|
-h, --help Show this help
|
|
48
48
|
|
|
49
49
|
Commands:
|
|
50
|
+
init Initialize current directory as a project
|
|
50
51
|
watch Start the file watcher daemon
|
|
51
52
|
watch --stop Stop the watcher daemon
|
|
52
53
|
watch --status Check watcher status
|
|
@@ -70,6 +71,13 @@ else if (values.uninstall) {
|
|
|
70
71
|
process.exit(1);
|
|
71
72
|
});
|
|
72
73
|
}
|
|
74
|
+
else if (positionals[0] === 'init') {
|
|
75
|
+
// Handle init command
|
|
76
|
+
runInit().catch((error) => {
|
|
77
|
+
console.error('Init failed:', error);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
73
81
|
else if (positionals[0] === 'watch') {
|
|
74
82
|
// Handle watch command
|
|
75
83
|
const watchArgs = process.argv.slice(3); // Get args after 'watch'
|
package/dist/setup.d.ts
CHANGED
package/dist/setup.js
CHANGED
|
@@ -10,6 +10,7 @@ import { join, basename } from 'path';
|
|
|
10
10
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'fs';
|
|
11
11
|
import { randomUUID } from 'crypto';
|
|
12
12
|
import { loadConfigFromFile, saveConfig, ensureConfigDir, getConfigPath, DEFAULT_CONFIG, } from './helpers/config-manager.js';
|
|
13
|
+
import { GLOBAL_TEMPLATE, SECTION_START, SECTION_END, getProjectTemplate, } from './templates/claude-md.js';
|
|
13
14
|
// -----------------------------------------------------------------------------
|
|
14
15
|
// Constants
|
|
15
16
|
// -----------------------------------------------------------------------------
|
|
@@ -18,6 +19,7 @@ const CLAUDETOOLS_DIR = join(homedir(), '.claudetools');
|
|
|
18
19
|
const MCP_CONFIG_PATH = join(CLAUDE_DIR, 'mcp.json');
|
|
19
20
|
const SETTINGS_PATH = join(CLAUDE_DIR, 'settings.json');
|
|
20
21
|
const HOOKS_DIR = join(CLAUDE_DIR, 'hooks');
|
|
22
|
+
const CLAUDE_MD_PATH = join(CLAUDE_DIR, 'CLAUDE.md');
|
|
21
23
|
const SYSTEM_FILE = join(CLAUDETOOLS_DIR, 'system.json');
|
|
22
24
|
const PROJECTS_FILE = join(CLAUDETOOLS_DIR, 'projects.json');
|
|
23
25
|
// -----------------------------------------------------------------------------
|
|
@@ -455,26 +457,111 @@ async function installHooks() {
|
|
|
455
457
|
// Session start hook - ensures watcher is running
|
|
456
458
|
const sessionStartHook = `#!/bin/bash
|
|
457
459
|
# ClaudeTools Session Start Hook
|
|
458
|
-
# Ensures the code watcher is running
|
|
460
|
+
# 1. Ensures the code watcher is running
|
|
461
|
+
# 2. Fetches and injects project context for the session
|
|
459
462
|
|
|
460
463
|
# Skip if disabled
|
|
461
464
|
if [ "$CLAUDE_DISABLE_HOOKS" = "1" ]; then exit 0; fi
|
|
462
465
|
|
|
463
|
-
|
|
466
|
+
CONFIG_FILE="$HOME/.claudetools/config.json"
|
|
467
|
+
CONTEXT_FILE="$HOME/.claudetools/session-context.md"
|
|
468
|
+
PROJECTS_FILE="$HOME/.claudetools/projects.json"
|
|
464
469
|
WATCHER_PID_FILE="/tmp/claudetools-watcher.pid"
|
|
470
|
+
|
|
471
|
+
# --- Watcher Management ---
|
|
472
|
+
|
|
473
|
+
# Check if watcher is already running
|
|
465
474
|
if [ -f "$WATCHER_PID_FILE" ]; then
|
|
466
475
|
PID=$(cat "$WATCHER_PID_FILE")
|
|
467
|
-
if kill -0 "$PID" 2>/dev/null; then
|
|
468
|
-
#
|
|
469
|
-
|
|
476
|
+
if ! kill -0 "$PID" 2>/dev/null; then
|
|
477
|
+
# PID file exists but process is dead, clean up
|
|
478
|
+
rm -f "$WATCHER_PID_FILE"
|
|
470
479
|
fi
|
|
471
480
|
fi
|
|
472
481
|
|
|
473
|
-
# Start watcher in background if
|
|
474
|
-
if command -v claudetools &> /dev/null; then
|
|
482
|
+
# Start watcher in background if not running
|
|
483
|
+
if [ ! -f "$WATCHER_PID_FILE" ] && command -v claudetools &> /dev/null; then
|
|
475
484
|
nohup claudetools watch > /tmp/claudetools-watcher.log 2>&1 &
|
|
476
485
|
echo $! > "$WATCHER_PID_FILE"
|
|
477
486
|
fi
|
|
487
|
+
|
|
488
|
+
# --- Context Injection ---
|
|
489
|
+
|
|
490
|
+
# Read config
|
|
491
|
+
if [ ! -f "$CONFIG_FILE" ]; then exit 0; fi
|
|
492
|
+
|
|
493
|
+
API_URL=$(jq -r '.apiUrl // "https://api.claudetools.dev"' "$CONFIG_FILE" 2>/dev/null)
|
|
494
|
+
API_KEY=$(jq -r '.apiKey // empty' "$CONFIG_FILE" 2>/dev/null)
|
|
495
|
+
|
|
496
|
+
if [ -z "$API_KEY" ]; then exit 0; fi
|
|
497
|
+
|
|
498
|
+
# Get current project from working directory
|
|
499
|
+
CWD=$(pwd)
|
|
500
|
+
PROJECT_ID=""
|
|
501
|
+
PROJECT_NAME=""
|
|
502
|
+
|
|
503
|
+
if [ -f "$PROJECTS_FILE" ]; then
|
|
504
|
+
# Find project by path prefix match
|
|
505
|
+
PROJECT_DATA=$(jq -r --arg cwd "$CWD" '
|
|
506
|
+
.bindings[]? | select(.local_path != null) |
|
|
507
|
+
select($cwd | startswith(.local_path)) |
|
|
508
|
+
{project_id, project_name}' "$PROJECTS_FILE" 2>/dev/null | head -1)
|
|
509
|
+
|
|
510
|
+
if [ -n "$PROJECT_DATA" ]; then
|
|
511
|
+
PROJECT_ID=$(echo "$PROJECT_DATA" | jq -r '.project_id // empty')
|
|
512
|
+
PROJECT_NAME=$(echo "$PROJECT_DATA" | jq -r '.project_name // empty')
|
|
513
|
+
fi
|
|
514
|
+
fi
|
|
515
|
+
|
|
516
|
+
# If no project found, use directory name
|
|
517
|
+
if [ -z "$PROJECT_NAME" ]; then
|
|
518
|
+
PROJECT_NAME=$(basename "$CWD")
|
|
519
|
+
fi
|
|
520
|
+
|
|
521
|
+
# Fetch context from API (with 2s timeout)
|
|
522
|
+
if [ -n "$PROJECT_ID" ]; then
|
|
523
|
+
CONTEXT=$(curl -s --max-time 2 -X POST "$API_URL/api/v1/context/session" \\
|
|
524
|
+
-H "Authorization: Bearer $API_KEY" \\
|
|
525
|
+
-H "Content-Type: application/json" \\
|
|
526
|
+
-d "{\\"project_id\\": \\"$PROJECT_ID\\"}" 2>/dev/null)
|
|
527
|
+
|
|
528
|
+
if [ -n "$CONTEXT" ] && [ "$CONTEXT" != "null" ]; then
|
|
529
|
+
# Extract facts and patterns from response
|
|
530
|
+
FACTS=$(echo "$CONTEXT" | jq -r '.facts // []' 2>/dev/null)
|
|
531
|
+
PATTERNS=$(echo "$CONTEXT" | jq -r '.patterns // []' 2>/dev/null)
|
|
532
|
+
|
|
533
|
+
# Generate session context file
|
|
534
|
+
cat > "$CONTEXT_FILE" << CTXEOF
|
|
535
|
+
# Session Context: $PROJECT_NAME
|
|
536
|
+
|
|
537
|
+
**Project ID:** $PROJECT_ID
|
|
538
|
+
**Generated:** $(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
539
|
+
|
|
540
|
+
## Relevant Facts
|
|
541
|
+
|
|
542
|
+
$(echo "$FACTS" | jq -r '.[] | "- \\(.entity1) \\(.relationship) \\(.entity2): \\(.context)"' 2>/dev/null || echo "- No facts stored yet")
|
|
543
|
+
|
|
544
|
+
## Detected Patterns
|
|
545
|
+
|
|
546
|
+
$(echo "$PATTERNS" | jq -r '.[] | "- **\\(.name)**: \\(.description)"' 2>/dev/null || echo "- No patterns detected yet")
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
*This file is regenerated each session. Do not edit manually.*
|
|
550
|
+
CTXEOF
|
|
551
|
+
fi
|
|
552
|
+
else
|
|
553
|
+
# No project registered, create minimal context file
|
|
554
|
+
cat > "$CONTEXT_FILE" << CTXEOF
|
|
555
|
+
# Session Context: $PROJECT_NAME
|
|
556
|
+
|
|
557
|
+
**Status:** Project not registered with ClaudeTools
|
|
558
|
+
|
|
559
|
+
Run \\\`claudetools init\\\` in this directory to register the project and enable memory features.
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
*This file is regenerated each session.*
|
|
563
|
+
CTXEOF
|
|
564
|
+
fi
|
|
478
565
|
`;
|
|
479
566
|
const sessionStartPath = join(HOOKS_DIR, 'session-start.sh');
|
|
480
567
|
if (existsSync(sessionStartPath)) {
|
|
@@ -662,6 +749,83 @@ async function configureSettings() {
|
|
|
662
749
|
success(`Saved settings to ${SETTINGS_PATH}`);
|
|
663
750
|
}
|
|
664
751
|
// -----------------------------------------------------------------------------
|
|
752
|
+
// CLAUDE.md Configuration
|
|
753
|
+
// -----------------------------------------------------------------------------
|
|
754
|
+
async function configureCLAUDEMD() {
|
|
755
|
+
header('CLAUDE.md Configuration');
|
|
756
|
+
ensureClaudeDir();
|
|
757
|
+
// Check if CLAUDE.md exists
|
|
758
|
+
let existingContent = '';
|
|
759
|
+
if (existsSync(CLAUDE_MD_PATH)) {
|
|
760
|
+
existingContent = readFileSync(CLAUDE_MD_PATH, 'utf-8');
|
|
761
|
+
// Check if claudetools section already exists
|
|
762
|
+
if (existingContent.includes(SECTION_START)) {
|
|
763
|
+
info('ClaudeTools section already exists in CLAUDE.md');
|
|
764
|
+
const { update } = await prompts({
|
|
765
|
+
type: 'confirm',
|
|
766
|
+
name: 'update',
|
|
767
|
+
message: 'Update existing ClaudeTools section?',
|
|
768
|
+
initial: true,
|
|
769
|
+
});
|
|
770
|
+
if (update) {
|
|
771
|
+
// Remove existing section
|
|
772
|
+
const startIdx = existingContent.indexOf(SECTION_START);
|
|
773
|
+
const endIdx = existingContent.indexOf(SECTION_END);
|
|
774
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
775
|
+
existingContent =
|
|
776
|
+
existingContent.slice(0, startIdx).trimEnd() +
|
|
777
|
+
'\n' +
|
|
778
|
+
existingContent.slice(endIdx + SECTION_END.length).trimStart();
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
else {
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
// Backup existing file
|
|
786
|
+
const backup = backupFile(CLAUDE_MD_PATH);
|
|
787
|
+
if (backup) {
|
|
788
|
+
info(`Backed up existing CLAUDE.md to ${basename(backup)}`);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
// Append claudetools section
|
|
792
|
+
const newContent = existingContent.trimEnd() + '\n' + GLOBAL_TEMPLATE;
|
|
793
|
+
writeFileSync(CLAUDE_MD_PATH, newContent);
|
|
794
|
+
success('Added ClaudeTools section to CLAUDE.md');
|
|
795
|
+
}
|
|
796
|
+
function removeCLAUDEMDSection() {
|
|
797
|
+
if (!existsSync(CLAUDE_MD_PATH)) {
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
try {
|
|
801
|
+
let content = readFileSync(CLAUDE_MD_PATH, 'utf-8');
|
|
802
|
+
if (!content.includes(SECTION_START)) {
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
const startIdx = content.indexOf(SECTION_START);
|
|
806
|
+
const endIdx = content.indexOf(SECTION_END);
|
|
807
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
808
|
+
content =
|
|
809
|
+
content.slice(0, startIdx).trimEnd() +
|
|
810
|
+
'\n' +
|
|
811
|
+
content.slice(endIdx + SECTION_END.length).trimStart();
|
|
812
|
+
// If content is now empty (only whitespace), remove the file
|
|
813
|
+
if (content.trim() === '') {
|
|
814
|
+
const { unlinkSync } = require('fs');
|
|
815
|
+
unlinkSync(CLAUDE_MD_PATH);
|
|
816
|
+
success('Removed CLAUDE.md (was only claudetools content)');
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
writeFileSync(CLAUDE_MD_PATH, content.trim() + '\n');
|
|
820
|
+
success('Removed ClaudeTools section from CLAUDE.md');
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
catch {
|
|
825
|
+
error('Could not update CLAUDE.md');
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
// -----------------------------------------------------------------------------
|
|
665
829
|
// Verification
|
|
666
830
|
// -----------------------------------------------------------------------------
|
|
667
831
|
async function verifySetup(config) {
|
|
@@ -712,6 +876,19 @@ async function verifySetup(config) {
|
|
|
712
876
|
else {
|
|
713
877
|
error('Settings not found');
|
|
714
878
|
}
|
|
879
|
+
// Check CLAUDE.md configured
|
|
880
|
+
if (existsSync(CLAUDE_MD_PATH)) {
|
|
881
|
+
const content = readFileSync(CLAUDE_MD_PATH, 'utf-8');
|
|
882
|
+
if (content.includes(SECTION_START)) {
|
|
883
|
+
success('CLAUDE.md configured');
|
|
884
|
+
}
|
|
885
|
+
else {
|
|
886
|
+
error('CLAUDE.md missing ClaudeTools section');
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
else {
|
|
890
|
+
error('CLAUDE.md not found');
|
|
891
|
+
}
|
|
715
892
|
}
|
|
716
893
|
// -----------------------------------------------------------------------------
|
|
717
894
|
// Main Setup Flow
|
|
@@ -801,7 +978,9 @@ export async function runSetup() {
|
|
|
801
978
|
await installHooks();
|
|
802
979
|
// Step 8: Configure Settings
|
|
803
980
|
await configureSettings();
|
|
804
|
-
// Step 9:
|
|
981
|
+
// Step 9: Configure CLAUDE.md
|
|
982
|
+
await configureCLAUDEMD();
|
|
983
|
+
// Step 10: Verify
|
|
805
984
|
await verifySetup(extendedConfig);
|
|
806
985
|
// Done
|
|
807
986
|
header('Setup Complete');
|
|
@@ -889,6 +1068,128 @@ export async function runUninstall() {
|
|
|
889
1068
|
// Process might already be dead
|
|
890
1069
|
}
|
|
891
1070
|
}
|
|
1071
|
+
// Remove CLAUDE.md section
|
|
1072
|
+
removeCLAUDEMDSection();
|
|
892
1073
|
console.log('\n' + chalk.green('ClaudeTools removed from Claude Code.'));
|
|
893
1074
|
console.log(chalk.dim('Your ~/.claudetools/ config and data are preserved.\n'));
|
|
894
1075
|
}
|
|
1076
|
+
// -----------------------------------------------------------------------------
|
|
1077
|
+
// Project Init
|
|
1078
|
+
// -----------------------------------------------------------------------------
|
|
1079
|
+
export async function runInit() {
|
|
1080
|
+
console.log('\n' + chalk.bold.cyan(' ClaudeTools Project Init') + '\n');
|
|
1081
|
+
const cwd = process.cwd();
|
|
1082
|
+
const projectName = basename(cwd);
|
|
1083
|
+
const projectClaudeDir = join(cwd, '.claude');
|
|
1084
|
+
const projectClaudeMd = join(projectClaudeDir, 'CLAUDE.md');
|
|
1085
|
+
// Check if config exists
|
|
1086
|
+
const config = await loadConfigFromFile();
|
|
1087
|
+
if (!config?.apiKey) {
|
|
1088
|
+
error('ClaudeTools not configured. Run "claudetools --setup" first.');
|
|
1089
|
+
process.exit(1);
|
|
1090
|
+
}
|
|
1091
|
+
// Try to register project with API
|
|
1092
|
+
const spinner = ora('Registering project...').start();
|
|
1093
|
+
let projectId;
|
|
1094
|
+
try {
|
|
1095
|
+
const response = await fetch(`${config.apiUrl || DEFAULT_CONFIG.apiUrl}/api/v1/projects/register`, {
|
|
1096
|
+
method: 'POST',
|
|
1097
|
+
headers: {
|
|
1098
|
+
'Content-Type': 'application/json',
|
|
1099
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
1100
|
+
},
|
|
1101
|
+
body: JSON.stringify({
|
|
1102
|
+
name: projectName,
|
|
1103
|
+
local_path: cwd,
|
|
1104
|
+
}),
|
|
1105
|
+
});
|
|
1106
|
+
if (response.ok) {
|
|
1107
|
+
const data = await response.json();
|
|
1108
|
+
projectId = data.project_id;
|
|
1109
|
+
spinner.succeed(`Registered project: ${projectId}`);
|
|
1110
|
+
// Update local projects.json
|
|
1111
|
+
try {
|
|
1112
|
+
const projectsData = existsSync(PROJECTS_FILE)
|
|
1113
|
+
? JSON.parse(readFileSync(PROJECTS_FILE, 'utf-8'))
|
|
1114
|
+
: { bindings: [] };
|
|
1115
|
+
// Check if already in bindings
|
|
1116
|
+
const existingIdx = projectsData.bindings.findIndex((b) => b.local_path === cwd);
|
|
1117
|
+
if (existingIdx >= 0) {
|
|
1118
|
+
projectsData.bindings[existingIdx].project_id = projectId;
|
|
1119
|
+
}
|
|
1120
|
+
else {
|
|
1121
|
+
projectsData.bindings.push({
|
|
1122
|
+
project_id: projectId,
|
|
1123
|
+
local_path: cwd,
|
|
1124
|
+
project_name: projectName,
|
|
1125
|
+
cached_at: new Date().toISOString(),
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
projectsData.last_sync = new Date().toISOString();
|
|
1129
|
+
writeFileSync(PROJECTS_FILE, JSON.stringify(projectsData, null, 2));
|
|
1130
|
+
}
|
|
1131
|
+
catch {
|
|
1132
|
+
// Non-fatal
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
else {
|
|
1136
|
+
spinner.warn('Could not register with API, using local ID');
|
|
1137
|
+
projectId = `local_${projectName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
catch {
|
|
1141
|
+
spinner.warn('Could not reach API, using local ID');
|
|
1142
|
+
projectId = `local_${projectName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
|
|
1143
|
+
}
|
|
1144
|
+
// Create .claude directory if needed
|
|
1145
|
+
if (!existsSync(projectClaudeDir)) {
|
|
1146
|
+
mkdirSync(projectClaudeDir, { recursive: true });
|
|
1147
|
+
success('Created .claude/ directory');
|
|
1148
|
+
}
|
|
1149
|
+
// Create or update CLAUDE.md
|
|
1150
|
+
let existingContent = '';
|
|
1151
|
+
if (existsSync(projectClaudeMd)) {
|
|
1152
|
+
existingContent = readFileSync(projectClaudeMd, 'utf-8');
|
|
1153
|
+
// Check if claudetools section already exists
|
|
1154
|
+
if (existingContent.includes(SECTION_START)) {
|
|
1155
|
+
info('ClaudeTools section already exists');
|
|
1156
|
+
const { update } = await prompts({
|
|
1157
|
+
type: 'confirm',
|
|
1158
|
+
name: 'update',
|
|
1159
|
+
message: 'Update existing ClaudeTools section?',
|
|
1160
|
+
initial: true,
|
|
1161
|
+
});
|
|
1162
|
+
if (update) {
|
|
1163
|
+
// Remove existing section
|
|
1164
|
+
const startIdx = existingContent.indexOf(SECTION_START);
|
|
1165
|
+
const endIdx = existingContent.indexOf(SECTION_END);
|
|
1166
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
1167
|
+
existingContent =
|
|
1168
|
+
existingContent.slice(0, startIdx).trimEnd() +
|
|
1169
|
+
'\n' +
|
|
1170
|
+
existingContent.slice(endIdx + SECTION_END.length).trimStart();
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
else {
|
|
1174
|
+
console.log('\n' + chalk.green('Project already initialized.'));
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
// Backup existing file
|
|
1179
|
+
const backup = backupFile(projectClaudeMd);
|
|
1180
|
+
if (backup) {
|
|
1181
|
+
info(`Backed up existing CLAUDE.md to ${basename(backup)}`);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
// Write project CLAUDE.md
|
|
1185
|
+
const projectContent = getProjectTemplate(projectId, projectName);
|
|
1186
|
+
const newContent = existingContent.trimEnd() + '\n' + projectContent;
|
|
1187
|
+
writeFileSync(projectClaudeMd, newContent);
|
|
1188
|
+
success('Created .claude/CLAUDE.md');
|
|
1189
|
+
// Summary
|
|
1190
|
+
console.log('\n' + chalk.green(' Project initialized!\n'));
|
|
1191
|
+
console.log(' ' + chalk.bold('Project:') + ` ${projectName}`);
|
|
1192
|
+
console.log(' ' + chalk.bold('ID:') + ` ${projectId}`);
|
|
1193
|
+
console.log(' ' + chalk.bold('Config:') + ` ${projectClaudeMd}\n`);
|
|
1194
|
+
console.log(chalk.dim(' Memory tools are now configured for this project.\n'));
|
|
1195
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const SECTION_START = "<!-- CLAUDETOOLS:START -->";
|
|
2
|
+
export declare const SECTION_END = "<!-- CLAUDETOOLS:END -->";
|
|
3
|
+
export declare const PROJECT_SECTION_START = "<!-- CLAUDETOOLS:PROJECT:START -->";
|
|
4
|
+
export declare const PROJECT_SECTION_END = "<!-- CLAUDETOOLS:PROJECT:END -->";
|
|
5
|
+
/**
|
|
6
|
+
* Global CLAUDE.md content - added to ~/.claude/CLAUDE.md
|
|
7
|
+
*/
|
|
8
|
+
export declare const GLOBAL_TEMPLATE = "\n<!-- CLAUDETOOLS:START -->\n# ClaudeTools Memory System\n\nYou have access to a persistent memory system via the `claudetools_memory` MCP server. Use it to remember context across sessions.\n\n## Memory Tools\n\n### Searching Memory\n```\nmemory_search(query: \"authentication patterns\")\n```\nSearch for relevant facts, entities, and past context. Use this when:\n- Starting work on a feature to recall past decisions\n- Looking for patterns or conventions used before\n- Finding related code or architectural context\n\n### Storing Facts\n```\nmemory_store_fact(\n entity1: \"UserService\",\n relationship: \"USES\",\n entity2: \"bcrypt\",\n context: \"Password hashing uses bcrypt with 12 rounds\"\n)\n```\nStore important facts as relationships between entities. Use for:\n- Architectural decisions\n- Code patterns and conventions\n- Dependencies and relationships\n- User preferences learned during conversation\n\n### Context Injection\nContext is automatically injected at the start of each session based on the current project. Check `~/.claudetools/session-context.md` for project-specific context.\n\n## Task Management\n\n### Creating Work Plans\n```\ntask_plan(\n goal: \"Add user authentication\",\n epic_title: \"User Auth System\",\n tasks: [...]\n)\n```\nBreak down complex work into tracked tasks.\n\n### Starting Tasks\n```\ntask_start(task_id: \"task_xxx\")\n```\nClaim a task before working on it.\n\n### Completing Tasks\n```\ntask_complete(task_id: \"task_xxx\", summary: \"Implemented JWT auth with refresh tokens\")\n```\nMark tasks done with a summary of work completed.\n\n## Codebase Intelligence\n\n### Finding Code\n```\ncodebase_map() # Get overview of project structure\ncodebase_find(\"UserService\") # Find symbols/files\ncodebase_context(\"src/auth.ts\") # Get file dependencies\n```\n\n### Impact Analysis\n```\nanalyze_impact(function_name: \"validateToken\")\n```\nSee what would be affected by changing a function.\n\n## Best Practices\n\n1. **Search before implementing** - Check memory for existing patterns\n2. **Store decisions** - Save architectural choices as facts\n3. **Use task tracking** - Break complex work into tasks\n4. **Complete tasks** - Always mark tasks done with summaries\n<!-- CLAUDETOOLS:END -->\n";
|
|
9
|
+
/**
|
|
10
|
+
* Project-level CLAUDE.md content - added to .claude/CLAUDE.md
|
|
11
|
+
*/
|
|
12
|
+
export declare function getProjectTemplate(projectId: string, projectName: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Session context template - written to ~/.claudetools/session-context.md
|
|
15
|
+
*/
|
|
16
|
+
export declare function getSessionContextTemplate(projectName: string, projectId: string, facts: Array<{
|
|
17
|
+
entity1: string;
|
|
18
|
+
relationship: string;
|
|
19
|
+
entity2: string;
|
|
20
|
+
context: string;
|
|
21
|
+
}>, patterns: Array<{
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
}>): string;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// CLAUDE.md Template Content
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Templates for global and project-level CLAUDE.md integration
|
|
5
|
+
// Markers for identifying claudetools sections
|
|
6
|
+
export const SECTION_START = '<!-- CLAUDETOOLS:START -->';
|
|
7
|
+
export const SECTION_END = '<!-- CLAUDETOOLS:END -->';
|
|
8
|
+
export const PROJECT_SECTION_START = '<!-- CLAUDETOOLS:PROJECT:START -->';
|
|
9
|
+
export const PROJECT_SECTION_END = '<!-- CLAUDETOOLS:PROJECT:END -->';
|
|
10
|
+
/**
|
|
11
|
+
* Global CLAUDE.md content - added to ~/.claude/CLAUDE.md
|
|
12
|
+
*/
|
|
13
|
+
export const GLOBAL_TEMPLATE = `
|
|
14
|
+
${SECTION_START}
|
|
15
|
+
# ClaudeTools Memory System
|
|
16
|
+
|
|
17
|
+
You have access to a persistent memory system via the \`claudetools_memory\` MCP server. Use it to remember context across sessions.
|
|
18
|
+
|
|
19
|
+
## Memory Tools
|
|
20
|
+
|
|
21
|
+
### Searching Memory
|
|
22
|
+
\`\`\`
|
|
23
|
+
memory_search(query: "authentication patterns")
|
|
24
|
+
\`\`\`
|
|
25
|
+
Search for relevant facts, entities, and past context. Use this when:
|
|
26
|
+
- Starting work on a feature to recall past decisions
|
|
27
|
+
- Looking for patterns or conventions used before
|
|
28
|
+
- Finding related code or architectural context
|
|
29
|
+
|
|
30
|
+
### Storing Facts
|
|
31
|
+
\`\`\`
|
|
32
|
+
memory_store_fact(
|
|
33
|
+
entity1: "UserService",
|
|
34
|
+
relationship: "USES",
|
|
35
|
+
entity2: "bcrypt",
|
|
36
|
+
context: "Password hashing uses bcrypt with 12 rounds"
|
|
37
|
+
)
|
|
38
|
+
\`\`\`
|
|
39
|
+
Store important facts as relationships between entities. Use for:
|
|
40
|
+
- Architectural decisions
|
|
41
|
+
- Code patterns and conventions
|
|
42
|
+
- Dependencies and relationships
|
|
43
|
+
- User preferences learned during conversation
|
|
44
|
+
|
|
45
|
+
### Context Injection
|
|
46
|
+
Context is automatically injected at the start of each session based on the current project. Check \`~/.claudetools/session-context.md\` for project-specific context.
|
|
47
|
+
|
|
48
|
+
## Task Management
|
|
49
|
+
|
|
50
|
+
### Creating Work Plans
|
|
51
|
+
\`\`\`
|
|
52
|
+
task_plan(
|
|
53
|
+
goal: "Add user authentication",
|
|
54
|
+
epic_title: "User Auth System",
|
|
55
|
+
tasks: [...]
|
|
56
|
+
)
|
|
57
|
+
\`\`\`
|
|
58
|
+
Break down complex work into tracked tasks.
|
|
59
|
+
|
|
60
|
+
### Starting Tasks
|
|
61
|
+
\`\`\`
|
|
62
|
+
task_start(task_id: "task_xxx")
|
|
63
|
+
\`\`\`
|
|
64
|
+
Claim a task before working on it.
|
|
65
|
+
|
|
66
|
+
### Completing Tasks
|
|
67
|
+
\`\`\`
|
|
68
|
+
task_complete(task_id: "task_xxx", summary: "Implemented JWT auth with refresh tokens")
|
|
69
|
+
\`\`\`
|
|
70
|
+
Mark tasks done with a summary of work completed.
|
|
71
|
+
|
|
72
|
+
## Codebase Intelligence
|
|
73
|
+
|
|
74
|
+
### Finding Code
|
|
75
|
+
\`\`\`
|
|
76
|
+
codebase_map() # Get overview of project structure
|
|
77
|
+
codebase_find("UserService") # Find symbols/files
|
|
78
|
+
codebase_context("src/auth.ts") # Get file dependencies
|
|
79
|
+
\`\`\`
|
|
80
|
+
|
|
81
|
+
### Impact Analysis
|
|
82
|
+
\`\`\`
|
|
83
|
+
analyze_impact(function_name: "validateToken")
|
|
84
|
+
\`\`\`
|
|
85
|
+
See what would be affected by changing a function.
|
|
86
|
+
|
|
87
|
+
## Best Practices
|
|
88
|
+
|
|
89
|
+
1. **Search before implementing** - Check memory for existing patterns
|
|
90
|
+
2. **Store decisions** - Save architectural choices as facts
|
|
91
|
+
3. **Use task tracking** - Break complex work into tasks
|
|
92
|
+
4. **Complete tasks** - Always mark tasks done with summaries
|
|
93
|
+
${SECTION_END}
|
|
94
|
+
`;
|
|
95
|
+
/**
|
|
96
|
+
* Project-level CLAUDE.md content - added to .claude/CLAUDE.md
|
|
97
|
+
*/
|
|
98
|
+
export function getProjectTemplate(projectId, projectName) {
|
|
99
|
+
return `
|
|
100
|
+
${SECTION_START}
|
|
101
|
+
# Project: ${projectName}
|
|
102
|
+
|
|
103
|
+
This project is registered with ClaudeTools Memory.
|
|
104
|
+
|
|
105
|
+
**Project ID:** \`${projectId}\`
|
|
106
|
+
|
|
107
|
+
## Project Memory
|
|
108
|
+
|
|
109
|
+
Use memory tools to search and store project-specific context:
|
|
110
|
+
|
|
111
|
+
\`\`\`
|
|
112
|
+
# Search this project's memory
|
|
113
|
+
memory_search(query: "your search", project_id: "${projectId}")
|
|
114
|
+
|
|
115
|
+
# Store a project fact
|
|
116
|
+
memory_store_fact(
|
|
117
|
+
entity1: "ComponentName",
|
|
118
|
+
relationship: "IMPLEMENTS",
|
|
119
|
+
entity2: "PatternName",
|
|
120
|
+
context: "Description of the relationship",
|
|
121
|
+
project_id: "${projectId}"
|
|
122
|
+
)
|
|
123
|
+
\`\`\`
|
|
124
|
+
|
|
125
|
+
## Session Context
|
|
126
|
+
|
|
127
|
+
Project-specific context is injected automatically. Check \`~/.claudetools/session-context.md\` for current context.
|
|
128
|
+
${SECTION_END}
|
|
129
|
+
`;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Session context template - written to ~/.claudetools/session-context.md
|
|
133
|
+
*/
|
|
134
|
+
export function getSessionContextTemplate(projectName, projectId, facts, patterns) {
|
|
135
|
+
const factsList = facts.length > 0
|
|
136
|
+
? facts.map(f => `- ${f.entity1} ${f.relationship} ${f.entity2}: ${f.context}`).join('\n')
|
|
137
|
+
: '- No facts stored yet';
|
|
138
|
+
const patternsList = patterns.length > 0
|
|
139
|
+
? patterns.map(p => `- **${p.name}**: ${p.description}`).join('\n')
|
|
140
|
+
: '- No patterns detected yet';
|
|
141
|
+
return `# Session Context: ${projectName}
|
|
142
|
+
|
|
143
|
+
**Project ID:** ${projectId}
|
|
144
|
+
**Generated:** ${new Date().toISOString()}
|
|
145
|
+
|
|
146
|
+
## Relevant Facts
|
|
147
|
+
|
|
148
|
+
${factsList}
|
|
149
|
+
|
|
150
|
+
## Detected Patterns
|
|
151
|
+
|
|
152
|
+
${patternsList}
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
*This file is regenerated each session. Do not edit manually.*
|
|
156
|
+
`;
|
|
157
|
+
}
|