@claudetools/tools 0.8.3 → 0.8.4
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 +41 -0
- package/dist/context/deduplication.d.ts +72 -0
- package/dist/context/deduplication.js +77 -0
- package/dist/context/deduplication.test.d.ts +6 -0
- package/dist/context/deduplication.test.js +84 -0
- package/dist/context/emergency-eviction.d.ts +73 -0
- package/dist/context/emergency-eviction.example.d.ts +13 -0
- package/dist/context/emergency-eviction.example.js +94 -0
- package/dist/context/emergency-eviction.js +226 -0
- package/dist/context/eviction-engine.d.ts +76 -0
- package/dist/context/eviction-engine.example.d.ts +7 -0
- package/dist/context/eviction-engine.example.js +144 -0
- package/dist/context/eviction-engine.js +176 -0
- package/dist/context/example-usage.d.ts +1 -0
- package/dist/context/example-usage.js +128 -0
- package/dist/context/exchange-summariser.d.ts +80 -0
- package/dist/context/exchange-summariser.js +261 -0
- package/dist/context/health-monitor.d.ts +97 -0
- package/dist/context/health-monitor.example.d.ts +1 -0
- package/dist/context/health-monitor.example.js +164 -0
- package/dist/context/health-monitor.js +210 -0
- package/dist/context/importance-scorer.d.ts +94 -0
- package/dist/context/importance-scorer.example.d.ts +1 -0
- package/dist/context/importance-scorer.example.js +140 -0
- package/dist/context/importance-scorer.js +187 -0
- package/dist/context/index.d.ts +9 -0
- package/dist/context/index.js +16 -0
- package/dist/context/session-helper.d.ts +10 -0
- package/dist/context/session-helper.js +51 -0
- package/dist/context/session-store.d.ts +94 -0
- package/dist/context/session-store.js +286 -0
- package/dist/context/usage-estimator.d.ts +131 -0
- package/dist/context/usage-estimator.js +260 -0
- package/dist/context/usage-estimator.test.d.ts +1 -0
- package/dist/context/usage-estimator.test.js +208 -0
- package/dist/context-cli.d.ts +16 -0
- package/dist/context-cli.js +309 -0
- package/dist/handlers/codedna-handlers.d.ts +1 -1
- package/dist/handlers/tool-handlers.js +82 -10
- package/dist/helpers/api-client.d.ts +5 -1
- package/dist/helpers/api-client.js +3 -1
- package/dist/helpers/error-tracking.js +1 -1
- package/dist/helpers/usage-analytics.js +1 -1
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/post-tool-use-hook-cli.d.ts +2 -0
- package/dist/hooks/post-tool-use-hook-cli.js +34 -0
- package/dist/hooks/post-tool-use.d.ts +67 -0
- package/dist/hooks/post-tool-use.js +234 -0
- package/dist/hooks/stop-hook-cli.d.ts +2 -0
- package/dist/hooks/stop-hook-cli.js +34 -0
- package/dist/hooks/stop.d.ts +64 -0
- package/dist/hooks/stop.js +192 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +4 -0
- package/dist/setup.js +206 -2
- package/dist/tools.js +4 -0
- package/package.json +3 -1
package/dist/setup.js
CHANGED
|
@@ -747,11 +747,22 @@ fi
|
|
|
747
747
|
# Escape the query for JSON (handle quotes and newlines)
|
|
748
748
|
ESCAPED_QUERY=$(echo "$USER_QUERY" | head -c 500 | jq -Rs '.')
|
|
749
749
|
|
|
750
|
+
# Get session state for query-aware budget allocation (if SESSION_ID available)
|
|
751
|
+
SESSION_STATE_JSON='{}'
|
|
752
|
+
if [ -n "$SESSION_ID" ]; then
|
|
753
|
+
# Try to get session state from SessionStore
|
|
754
|
+
TOOLS_DIR="$HOME/.claudetools/node_modules/@claudetools/tools"
|
|
755
|
+
if [ -f "$TOOLS_DIR/dist/context/session-helper.js" ]; then
|
|
756
|
+
SESSION_STATE_JSON=$(node "$TOOLS_DIR/dist/context/session-helper.js" "$SESSION_ID" 2>/dev/null || echo '{}')
|
|
757
|
+
fi
|
|
758
|
+
fi
|
|
759
|
+
|
|
750
760
|
# Inject context with semantic search based on the user's prompt
|
|
761
|
+
# Include session_state if available for dynamic budget calculation
|
|
751
762
|
RESULT=$(curl -s --max-time 2 -X POST "$API_URL/api/v1/context/inject" \\
|
|
752
763
|
-H "Authorization: Bearer $API_KEY" \\
|
|
753
764
|
-H "Content-Type: application/json" \\
|
|
754
|
-
-d "{\\"query\\": $ESCAPED_QUERY, \\"project_id\\": \\"$PROJECT_ID\\", \\"cwd\\": \\"$CWD\\"}" \\
|
|
765
|
+
-d "{\\"query\\": $ESCAPED_QUERY, \\"project_id\\": \\"$PROJECT_ID\\", \\"cwd\\": \\"$CWD\\", \\"session_state\\": $SESSION_STATE_JSON}" \\
|
|
755
766
|
2>/dev/null)
|
|
756
767
|
|
|
757
768
|
# Output context as additionalContext JSON for Claude Code
|
|
@@ -1330,6 +1341,170 @@ export async function runUninstall() {
|
|
|
1330
1341
|
console.log('\n' + chalk.green('ClaudeTools removed from Claude Code.'));
|
|
1331
1342
|
console.log(chalk.dim('Your ~/.claudetools/ config and data are preserved.\n'));
|
|
1332
1343
|
}
|
|
1344
|
+
async function runOnboarding(apiUrl, apiKey, projectId, projectName) {
|
|
1345
|
+
header('Project Onboarding');
|
|
1346
|
+
info('Answer a few questions to help Claude understand your project better.');
|
|
1347
|
+
console.log(chalk.dim('This creates memory facts that provide context in future sessions.\n'));
|
|
1348
|
+
const spinner = ora('Starting onboarding session...').start();
|
|
1349
|
+
try {
|
|
1350
|
+
// Start onboarding session
|
|
1351
|
+
const startResponse = await fetch(`${apiUrl}/api/v1/onboarding/start`, {
|
|
1352
|
+
method: 'POST',
|
|
1353
|
+
headers: {
|
|
1354
|
+
'Content-Type': 'application/json',
|
|
1355
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
1356
|
+
},
|
|
1357
|
+
body: JSON.stringify({ project_id: projectId }),
|
|
1358
|
+
});
|
|
1359
|
+
if (!startResponse.ok) {
|
|
1360
|
+
spinner.fail('Could not start onboarding');
|
|
1361
|
+
const errorData = await startResponse.json().catch(() => ({}));
|
|
1362
|
+
error(errorData.error || `HTTP ${startResponse.status}`);
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
const startData = await startResponse.json();
|
|
1366
|
+
if (!startData.success || !startData.data) {
|
|
1367
|
+
spinner.fail('Failed to start onboarding');
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
spinner.succeed('Onboarding session started');
|
|
1371
|
+
const sessionId = startData.data.session_id;
|
|
1372
|
+
let questions = startData.data.questions;
|
|
1373
|
+
let state = startData.data.state;
|
|
1374
|
+
let questionCount = 0;
|
|
1375
|
+
const maxQuestions = 8; // Limit to avoid fatigue
|
|
1376
|
+
// Interactive question loop
|
|
1377
|
+
while (questions.length > 0 && questionCount < maxQuestions) {
|
|
1378
|
+
const question = questions[0];
|
|
1379
|
+
questionCount++;
|
|
1380
|
+
console.log('');
|
|
1381
|
+
console.log(chalk.cyan(`Question ${questionCount}`) + (question.category ? chalk.dim(` [${question.category}]`) : ''));
|
|
1382
|
+
console.log(chalk.bold(question.question));
|
|
1383
|
+
let answer;
|
|
1384
|
+
if (question.options && question.options.length > 0) {
|
|
1385
|
+
// Multiple choice question
|
|
1386
|
+
const { selected } = await prompts({
|
|
1387
|
+
type: 'select',
|
|
1388
|
+
name: 'selected',
|
|
1389
|
+
message: 'Select an option:',
|
|
1390
|
+
choices: [
|
|
1391
|
+
...question.options.map(opt => ({ title: opt, value: opt })),
|
|
1392
|
+
{ title: 'Skip this question', value: '__skip__' },
|
|
1393
|
+
],
|
|
1394
|
+
});
|
|
1395
|
+
if (selected === '__skip__' || !selected) {
|
|
1396
|
+
questions.shift();
|
|
1397
|
+
continue;
|
|
1398
|
+
}
|
|
1399
|
+
answer = selected;
|
|
1400
|
+
}
|
|
1401
|
+
else {
|
|
1402
|
+
// Free text question
|
|
1403
|
+
const { response } = await prompts({
|
|
1404
|
+
type: 'text',
|
|
1405
|
+
name: 'response',
|
|
1406
|
+
message: '>',
|
|
1407
|
+
validate: (v) => v.length > 0 || 'Please enter a response (or type "skip" to skip)',
|
|
1408
|
+
});
|
|
1409
|
+
if (!response || response.toLowerCase() === 'skip') {
|
|
1410
|
+
questions.shift();
|
|
1411
|
+
continue;
|
|
1412
|
+
}
|
|
1413
|
+
answer = response;
|
|
1414
|
+
}
|
|
1415
|
+
// Submit answer
|
|
1416
|
+
const answerSpinner = ora('Processing...').start();
|
|
1417
|
+
try {
|
|
1418
|
+
const answerResponse = await fetch(`${apiUrl}/api/v1/onboarding/answer`, {
|
|
1419
|
+
method: 'POST',
|
|
1420
|
+
headers: {
|
|
1421
|
+
'Content-Type': 'application/json',
|
|
1422
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
1423
|
+
},
|
|
1424
|
+
body: JSON.stringify({
|
|
1425
|
+
session_id: sessionId,
|
|
1426
|
+
question_id: question.id,
|
|
1427
|
+
answer,
|
|
1428
|
+
}),
|
|
1429
|
+
});
|
|
1430
|
+
if (answerResponse.ok) {
|
|
1431
|
+
const answerData = await answerResponse.json();
|
|
1432
|
+
if (answerData.success && answerData.data) {
|
|
1433
|
+
const factsCount = answerData.data.facts_extracted || 0;
|
|
1434
|
+
if (factsCount > 0) {
|
|
1435
|
+
answerSpinner.succeed(`Recorded (${factsCount} fact${factsCount > 1 ? 's' : ''} extracted)`);
|
|
1436
|
+
}
|
|
1437
|
+
else {
|
|
1438
|
+
answerSpinner.succeed('Recorded');
|
|
1439
|
+
}
|
|
1440
|
+
// Update questions and state
|
|
1441
|
+
if (answerData.data.next_questions) {
|
|
1442
|
+
questions = answerData.data.next_questions;
|
|
1443
|
+
}
|
|
1444
|
+
else {
|
|
1445
|
+
questions.shift();
|
|
1446
|
+
}
|
|
1447
|
+
if (answerData.data.state) {
|
|
1448
|
+
state = answerData.data.state;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
else {
|
|
1452
|
+
answerSpinner.warn('Answer recorded (no facts extracted)');
|
|
1453
|
+
questions.shift();
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
else {
|
|
1457
|
+
answerSpinner.fail('Could not submit answer');
|
|
1458
|
+
questions.shift();
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
catch {
|
|
1462
|
+
answerSpinner.fail('Network error');
|
|
1463
|
+
questions.shift();
|
|
1464
|
+
}
|
|
1465
|
+
// Check if we should stop
|
|
1466
|
+
if (state.phase === 'confirmation' || state.phase === 'done') {
|
|
1467
|
+
break;
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
// Complete onboarding
|
|
1471
|
+
console.log('');
|
|
1472
|
+
const completeSpinner = ora('Completing onboarding...').start();
|
|
1473
|
+
try {
|
|
1474
|
+
const completeResponse = await fetch(`${apiUrl}/api/v1/onboarding/complete`, {
|
|
1475
|
+
method: 'POST',
|
|
1476
|
+
headers: {
|
|
1477
|
+
'Content-Type': 'application/json',
|
|
1478
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
1479
|
+
},
|
|
1480
|
+
body: JSON.stringify({
|
|
1481
|
+
session_id: sessionId,
|
|
1482
|
+
project_id: projectId,
|
|
1483
|
+
}),
|
|
1484
|
+
});
|
|
1485
|
+
if (completeResponse.ok) {
|
|
1486
|
+
const completeData = await completeResponse.json();
|
|
1487
|
+
if (completeData.success && completeData.data) {
|
|
1488
|
+
const totalFacts = completeData.data.facts_extracted || 0;
|
|
1489
|
+
completeSpinner.succeed(`Onboarding complete! ${totalFacts} facts stored in memory.`);
|
|
1490
|
+
}
|
|
1491
|
+
else {
|
|
1492
|
+
completeSpinner.succeed('Onboarding complete!');
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
else {
|
|
1496
|
+
completeSpinner.warn('Onboarding session saved (completion had issues)');
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
catch {
|
|
1500
|
+
completeSpinner.warn('Could not finalize onboarding');
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
catch (err) {
|
|
1504
|
+
spinner.fail('Onboarding failed');
|
|
1505
|
+
error(err instanceof Error ? err.message : String(err));
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1333
1508
|
// -----------------------------------------------------------------------------
|
|
1334
1509
|
// Project Init
|
|
1335
1510
|
// -----------------------------------------------------------------------------
|
|
@@ -1491,12 +1666,41 @@ export async function runInit() {
|
|
|
1491
1666
|
const newContent = existingContent.trimEnd() + '\n' + projectContent;
|
|
1492
1667
|
writeFileSync(projectClaudeMd, newContent);
|
|
1493
1668
|
success('Created .claude/CLAUDE.md');
|
|
1669
|
+
// Ensure hooks are installed and configured
|
|
1670
|
+
// (User might have run init without setup, or hooks might have been deleted)
|
|
1671
|
+
header('Hook Configuration');
|
|
1672
|
+
try {
|
|
1673
|
+
await installHooks();
|
|
1674
|
+
await configureSettings();
|
|
1675
|
+
info('Hooks configured successfully');
|
|
1676
|
+
}
|
|
1677
|
+
catch (err) {
|
|
1678
|
+
// Non-fatal - just warn
|
|
1679
|
+
console.log(chalk.yellow('⚠ Warning: Could not configure hooks. Run "claudetools --setup" to fix.'));
|
|
1680
|
+
}
|
|
1494
1681
|
// Summary
|
|
1495
1682
|
console.log('\n' + chalk.green(' Project initialized!\n'));
|
|
1496
1683
|
console.log(' ' + chalk.bold('Project:') + ` ${projectName}`);
|
|
1497
1684
|
console.log(' ' + chalk.bold('ID:') + ` ${projectId}`);
|
|
1498
1685
|
console.log(' ' + chalk.bold('Config:') + ` ${projectClaudeMd}\n`);
|
|
1499
|
-
|
|
1686
|
+
// Offer onboarding
|
|
1687
|
+
if (config.apiKey) {
|
|
1688
|
+
const { runOnboard } = await prompts({
|
|
1689
|
+
type: 'confirm',
|
|
1690
|
+
name: 'runOnboard',
|
|
1691
|
+
message: 'Run project onboarding? (Helps Claude understand your project)',
|
|
1692
|
+
initial: true,
|
|
1693
|
+
});
|
|
1694
|
+
if (runOnboard) {
|
|
1695
|
+
await runOnboarding(config.apiUrl || DEFAULT_CONFIG.apiUrl, config.apiKey, projectId, projectName);
|
|
1696
|
+
}
|
|
1697
|
+
else {
|
|
1698
|
+
console.log(chalk.dim('\n You can run onboarding later with: claudetools onboard\n'));
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
else {
|
|
1702
|
+
console.log(chalk.dim(' Memory tools are now configured for this project.\n'));
|
|
1703
|
+
}
|
|
1500
1704
|
}
|
|
1501
1705
|
// -----------------------------------------------------------------------------
|
|
1502
1706
|
// Cleanup Command (standalone)
|
package/dist/tools.js
CHANGED
|
@@ -146,6 +146,10 @@ EXAMPLES:
|
|
|
146
146
|
type: 'string',
|
|
147
147
|
description: 'Project ID (optional, uses default if not provided)',
|
|
148
148
|
},
|
|
149
|
+
is_critical: {
|
|
150
|
+
type: 'boolean',
|
|
151
|
+
description: 'Mark as critical fact - always injected regardless of query relevance. Use sparingly for truly essential facts.',
|
|
152
|
+
},
|
|
149
153
|
},
|
|
150
154
|
required: ['entity1', 'relationship', 'entity2', 'context'],
|
|
151
155
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudetools/tools",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"description": "Persistent AI memory, task management, and codebase intelligence for Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -65,10 +65,12 @@
|
|
|
65
65
|
"typescript": "^5.3.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
68
69
|
"@types/node": "^20.10.0",
|
|
69
70
|
"@types/nunjucks": "^3.2.6",
|
|
70
71
|
"@types/prompts": "^2.4.9",
|
|
71
72
|
"@vitest/ui": "^4.0.15",
|
|
73
|
+
"better-sqlite3": "^12.5.0",
|
|
72
74
|
"tsx": "^4.7.0",
|
|
73
75
|
"typescript": "^5.3.0",
|
|
74
76
|
"vitest": "^4.0.15"
|