@claudetools/tools 0.8.5 → 0.8.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 +14 -0
- package/dist/handlers/tool-handlers.js +7 -16
- package/dist/helpers/api-client.d.ts +2 -0
- package/dist/helpers/api-client.js +12 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/test-runner.d.ts +33 -0
- package/dist/test-runner.js +149 -0
- package/dist/testing/example.d.ts +1 -0
- package/dist/testing/example.js +63 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +13 -0
- package/dist/testing/test-runner.d.ts +220 -0
- package/dist/testing/test-runner.js +302 -0
- package/package.json +18 -17
- package/scripts/verify-prompt-compliance.sh +0 -0
package/dist/cli.js
CHANGED
|
@@ -12,6 +12,7 @@ import { startServer } from './index.js';
|
|
|
12
12
|
import { startWatcher, stopWatcher, watcherStatus } from './watcher.js';
|
|
13
13
|
import { generateCodebaseMap, generateCodebaseMapLocal } from './helpers/codebase-mapper.js';
|
|
14
14
|
import { contextStatus, contextEvict, contextSummarise, contextReset, } from './context-cli.js';
|
|
15
|
+
import { runTests } from './test-runner.js';
|
|
15
16
|
// Get version from package.json
|
|
16
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
17
18
|
const __dirname = dirname(__filename);
|
|
@@ -61,6 +62,9 @@ Commands:
|
|
|
61
62
|
context evict Manually trigger eviction cycle
|
|
62
63
|
context summarise Summarise and compress exchanges
|
|
63
64
|
context reset Clear session state
|
|
65
|
+
test Run integration test suite
|
|
66
|
+
test --verbose Run tests with detailed output
|
|
67
|
+
test --json Output results in JSON format
|
|
64
68
|
|
|
65
69
|
Running without options starts the MCP server.
|
|
66
70
|
|
|
@@ -206,6 +210,16 @@ else if (positionals[0] === 'context') {
|
|
|
206
210
|
process.exit(1);
|
|
207
211
|
}
|
|
208
212
|
}
|
|
213
|
+
else if (positionals[0] === 'test') {
|
|
214
|
+
// Handle test command
|
|
215
|
+
const testArgs = process.argv.slice(3); // Get args after 'test'
|
|
216
|
+
const verbose = testArgs.includes('--verbose');
|
|
217
|
+
const json = testArgs.includes('--json');
|
|
218
|
+
runTests({ verbose, json }).catch((error) => {
|
|
219
|
+
console.error('Test run failed:', error);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
209
223
|
else {
|
|
210
224
|
// Start MCP server
|
|
211
225
|
startServer();
|
|
@@ -133,9 +133,8 @@ export function registerToolHandlers(server) {
|
|
|
133
133
|
const entity2 = args?.entity2;
|
|
134
134
|
const context = args?.context;
|
|
135
135
|
const is_critical = args?.is_critical;
|
|
136
|
-
//
|
|
136
|
+
// Storage with read-after-write verification (DO-level)
|
|
137
137
|
const MAX_RETRIES = 3;
|
|
138
|
-
const VERIFY_DELAY_MS = 200;
|
|
139
138
|
let lastError = null;
|
|
140
139
|
let storedFactId = null;
|
|
141
140
|
let storedIsCritical = false;
|
|
@@ -144,32 +143,24 @@ export function registerToolHandlers(server) {
|
|
|
144
143
|
for (let attempt = 1; attempt <= MAX_RETRIES && !verified; attempt++) {
|
|
145
144
|
attempts = attempt;
|
|
146
145
|
try {
|
|
147
|
-
// Step 1: Store the fact
|
|
148
146
|
mcpLogger.info('STORE', `Attempt ${attempt}/${MAX_RETRIES}: Storing "${entity1} ${relationship} ${entity2}"${is_critical ? ' [CRITICAL]' : ''}`);
|
|
149
147
|
const result = await storeFact(projectId, entity1, relationship, entity2, context, { is_critical });
|
|
150
148
|
storedFactId = result.fact_id;
|
|
151
149
|
storedIsCritical = result.is_critical;
|
|
152
150
|
mcpLogger.info('STORE', `Storage response: ${JSON.stringify(result)}`);
|
|
153
151
|
if (!result.success || !result.fact_id) {
|
|
154
|
-
lastError = new Error(`Storage returned unsuccessful: ${
|
|
152
|
+
lastError = new Error(`Storage returned unsuccessful: ${result.error || 'Unknown error'}`);
|
|
155
153
|
mcpLogger.warn('STORE', `Attempt ${attempt} failed: ${lastError.message}`);
|
|
156
154
|
continue;
|
|
157
155
|
}
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
// Step 3: Verify the fact is retrievable by searching for it
|
|
161
|
-
mcpLogger.info('STORE', `Verifying fact ${storedFactId} is retrievable...`);
|
|
162
|
-
const searchQuery = `${entity1} ${relationship} ${entity2}`;
|
|
163
|
-
const searchResult = await searchMemory(projectId, searchQuery, 5);
|
|
164
|
-
// Check if our fact appears in results
|
|
165
|
-
const factFound = searchResult.relevant_facts?.some(f => f.fact?.includes(entity1) && f.fact?.includes(entity2)) || false;
|
|
166
|
-
if (factFound) {
|
|
156
|
+
// Check DO-level verification (read-after-write in Durable Object)
|
|
157
|
+
if (result.verified) {
|
|
167
158
|
verified = true;
|
|
168
|
-
mcpLogger.info('STORE', `✓ Fact verified
|
|
159
|
+
mcpLogger.info('STORE', `✓ Fact verified at storage layer (ID: ${storedFactId})`);
|
|
169
160
|
}
|
|
170
161
|
else {
|
|
171
|
-
lastError = new Error(`
|
|
172
|
-
mcpLogger.warn('STORE', `Attempt ${attempt}:
|
|
162
|
+
lastError = new Error(`Storage verification failed at DO level`);
|
|
163
|
+
mcpLogger.warn('STORE', `Attempt ${attempt}: Storage layer verification failed`);
|
|
173
164
|
}
|
|
174
165
|
}
|
|
175
166
|
catch (err) {
|
|
@@ -33,6 +33,8 @@ export declare function storeFact(projectId: string, entity1: string, relationsh
|
|
|
33
33
|
success: boolean;
|
|
34
34
|
fact_id: string;
|
|
35
35
|
is_critical: boolean;
|
|
36
|
+
verified?: boolean;
|
|
37
|
+
error?: string;
|
|
36
38
|
}>;
|
|
37
39
|
export declare function getContext(projectId: string, query?: string, userId?: string): Promise<MemoryContext>;
|
|
38
40
|
export declare function getSummary(projectId: string, userId?: string): Promise<string>;
|
|
@@ -64,7 +64,18 @@ export async function injectContext(projectId, query, userId = DEFAULT_USER_ID)
|
|
|
64
64
|
const response = await apiRequest(`/api/v1/memory/${userId}/${projectId}/inject`, 'POST', {
|
|
65
65
|
query,
|
|
66
66
|
});
|
|
67
|
-
|
|
67
|
+
// Transform API response to match expected interface
|
|
68
|
+
// Handle cases where context or metadata might be missing
|
|
69
|
+
return {
|
|
70
|
+
augmentedSystemPrompt: response.data.context || '',
|
|
71
|
+
metadata: response.data.metadata || {
|
|
72
|
+
memoryNeeded: false,
|
|
73
|
+
retrievalTimeMs: 0,
|
|
74
|
+
factsScored: 0,
|
|
75
|
+
factsIncluded: 0,
|
|
76
|
+
avgRelevanceScore: 0,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
68
79
|
}
|
|
69
80
|
/**
|
|
70
81
|
* List all cached documentation libraries (global cache)
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ export type { ExpertWorker } from './helpers/workers.js';
|
|
|
2
2
|
export type { Task, TaskContext, DispatchableTask } from './helpers/tasks.js';
|
|
3
3
|
export type { DeduplicationTracker } from './context/index.js';
|
|
4
4
|
export type { CircuitState } from './helpers/circuit-breaker.js';
|
|
5
|
+
export type { TestResult, TestSuite, TestSuiteSummary, TestFunction, TestDefinition, } from './testing/index.js';
|
|
6
|
+
export { runTest, runSuite, formatResults, formatResultsJson, assert, assertEqual, assertThrows, } from './testing/index.js';
|
|
5
7
|
export { EXPERT_WORKERS, matchTaskToWorker } from './helpers/workers.js';
|
|
6
8
|
export { parseJsonArray, getDispatchableTasks, getExecutionContext, resolveTaskDependencies, createTask, listTasks, getTask, claimTask, releaseTask, updateTaskStatus, addTaskContext, getTaskSummary, heartbeatTask } from './helpers/tasks.js';
|
|
7
9
|
export { injectContext } from './helpers/api-client.js';
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { registerToolHandlers } from './handlers/tool-handlers.js';
|
|
|
11
11
|
// Resource and prompt handlers
|
|
12
12
|
import { registerResourceHandlers } from './resources.js';
|
|
13
13
|
import { registerPromptHandlers } from './prompts.js';
|
|
14
|
+
export { runTest, runSuite, formatResults, formatResultsJson, assert, assertEqual, assertThrows, } from './testing/index.js';
|
|
14
15
|
// Re-export functions that are used by handlers
|
|
15
16
|
export { EXPERT_WORKERS, matchTaskToWorker } from './helpers/workers.js';
|
|
16
17
|
export { parseJsonArray, getDispatchableTasks, getExecutionContext, resolveTaskDependencies, createTask, listTasks, getTask, claimTask, releaseTask, updateTaskStatus, addTaskContext, getTaskSummary, heartbeatTask } from './helpers/tasks.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface TestResult {
|
|
2
|
+
name: string;
|
|
3
|
+
status: 'pass' | 'fail' | 'error';
|
|
4
|
+
duration: number;
|
|
5
|
+
error?: string;
|
|
6
|
+
details?: any;
|
|
7
|
+
}
|
|
8
|
+
export interface TestSuiteResult {
|
|
9
|
+
totalTests: number;
|
|
10
|
+
passed: number;
|
|
11
|
+
failed: number;
|
|
12
|
+
errors: number;
|
|
13
|
+
duration: number;
|
|
14
|
+
tests: TestResult[];
|
|
15
|
+
}
|
|
16
|
+
export interface TestOptions {
|
|
17
|
+
verbose?: boolean;
|
|
18
|
+
json?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Run all integration tests in the suite.
|
|
22
|
+
*
|
|
23
|
+
* This is the main entry point that imports and runs all test files:
|
|
24
|
+
* - Store-Retrieve-Verify test
|
|
25
|
+
* - Context Injection test
|
|
26
|
+
* - Task Lifecycle test
|
|
27
|
+
* - Cross-Project Isolation test
|
|
28
|
+
*/
|
|
29
|
+
export declare function runSuite(): Promise<TestSuiteResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Run tests from CLI with options.
|
|
32
|
+
*/
|
|
33
|
+
export declare function runTests(options?: TestOptions): Promise<void>;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Integration Test Runner
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Runs the full integration test suite and outputs results
|
|
5
|
+
// Supports --verbose and --json output formats
|
|
6
|
+
// -----------------------------------------------------------------------------
|
|
7
|
+
// Test Suite Runner
|
|
8
|
+
// -----------------------------------------------------------------------------
|
|
9
|
+
/**
|
|
10
|
+
* Run all integration tests in the suite.
|
|
11
|
+
*
|
|
12
|
+
* This is the main entry point that imports and runs all test files:
|
|
13
|
+
* - Store-Retrieve-Verify test
|
|
14
|
+
* - Context Injection test
|
|
15
|
+
* - Task Lifecycle test
|
|
16
|
+
* - Cross-Project Isolation test
|
|
17
|
+
*/
|
|
18
|
+
export async function runSuite() {
|
|
19
|
+
const startTime = Date.now();
|
|
20
|
+
const results = [];
|
|
21
|
+
// TODO: Import and run actual test files once they're implemented
|
|
22
|
+
// Example structure:
|
|
23
|
+
//
|
|
24
|
+
// import { runStoreRetrieveTest } from './__tests__/store-retrieve-verify.js';
|
|
25
|
+
// import { runContextInjectionTest } from './__tests__/context-injection.js';
|
|
26
|
+
// import { runTaskLifecycleTest } from './__tests__/task-lifecycle.js';
|
|
27
|
+
// import { runCrossProjectTest } from './__tests__/cross-project-isolation.js';
|
|
28
|
+
//
|
|
29
|
+
// const tests = [
|
|
30
|
+
// { name: 'Store-Retrieve-Verify', fn: runStoreRetrieveTest },
|
|
31
|
+
// { name: 'Context Injection', fn: runContextInjectionTest },
|
|
32
|
+
// { name: 'Task Lifecycle', fn: runTaskLifecycleTest },
|
|
33
|
+
// { name: 'Cross-Project Isolation', fn: runCrossProjectTest },
|
|
34
|
+
// ];
|
|
35
|
+
//
|
|
36
|
+
// for (const test of tests) {
|
|
37
|
+
// const result = await runTest(test.name, test.fn);
|
|
38
|
+
// results.push(result);
|
|
39
|
+
// }
|
|
40
|
+
// Placeholder: Add a simple test to demonstrate structure
|
|
41
|
+
results.push({
|
|
42
|
+
name: 'Placeholder Test',
|
|
43
|
+
status: 'pass',
|
|
44
|
+
duration: 0,
|
|
45
|
+
details: { message: 'Test harness ready - add actual tests' }
|
|
46
|
+
});
|
|
47
|
+
const duration = Date.now() - startTime;
|
|
48
|
+
const passed = results.filter(r => r.status === 'pass').length;
|
|
49
|
+
const failed = results.filter(r => r.status === 'fail').length;
|
|
50
|
+
const errors = results.filter(r => r.status === 'error').length;
|
|
51
|
+
return {
|
|
52
|
+
totalTests: results.length,
|
|
53
|
+
passed,
|
|
54
|
+
failed,
|
|
55
|
+
errors,
|
|
56
|
+
duration,
|
|
57
|
+
tests: results,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Run a single test and capture result.
|
|
62
|
+
*/
|
|
63
|
+
async function runTest(name, testFn) {
|
|
64
|
+
const startTime = Date.now();
|
|
65
|
+
try {
|
|
66
|
+
await testFn();
|
|
67
|
+
return {
|
|
68
|
+
name,
|
|
69
|
+
status: 'pass',
|
|
70
|
+
duration: Date.now() - startTime,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const isAssertionError = error instanceof Error && error.message.includes('AssertionError');
|
|
75
|
+
return {
|
|
76
|
+
name,
|
|
77
|
+
status: isAssertionError ? 'fail' : 'error',
|
|
78
|
+
duration: Date.now() - startTime,
|
|
79
|
+
error: error instanceof Error ? error.message : String(error),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// -----------------------------------------------------------------------------
|
|
84
|
+
// Output Formatting
|
|
85
|
+
// -----------------------------------------------------------------------------
|
|
86
|
+
/**
|
|
87
|
+
* Format results as human-readable text.
|
|
88
|
+
*/
|
|
89
|
+
function formatHumanReadable(result, verbose) {
|
|
90
|
+
const lines = [];
|
|
91
|
+
lines.push('');
|
|
92
|
+
lines.push('Integration Test Suite Results');
|
|
93
|
+
lines.push('================================');
|
|
94
|
+
lines.push('');
|
|
95
|
+
lines.push(`Total Tests: ${result.totalTests}`);
|
|
96
|
+
lines.push(`Passed: ${result.passed}`);
|
|
97
|
+
lines.push(`Failed: ${result.failed}`);
|
|
98
|
+
lines.push(`Errors: ${result.errors}`);
|
|
99
|
+
lines.push(`Duration: ${result.duration}ms`);
|
|
100
|
+
lines.push('');
|
|
101
|
+
if (verbose || result.failed > 0 || result.errors > 0) {
|
|
102
|
+
lines.push('Test Details:');
|
|
103
|
+
lines.push('');
|
|
104
|
+
for (const test of result.tests) {
|
|
105
|
+
const statusIcon = test.status === 'pass' ? '✓' : '✗';
|
|
106
|
+
lines.push(`${statusIcon} ${test.name} (${test.duration}ms)`);
|
|
107
|
+
if (test.error) {
|
|
108
|
+
lines.push(` Error: ${test.error}`);
|
|
109
|
+
}
|
|
110
|
+
if (verbose && test.details) {
|
|
111
|
+
lines.push(` Details: ${JSON.stringify(test.details, null, 2)}`);
|
|
112
|
+
}
|
|
113
|
+
lines.push('');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return lines.join('\n');
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Format results as JSON.
|
|
120
|
+
*/
|
|
121
|
+
function formatJSON(result) {
|
|
122
|
+
return JSON.stringify(result, null, 2);
|
|
123
|
+
}
|
|
124
|
+
// -----------------------------------------------------------------------------
|
|
125
|
+
// CLI Entry Point
|
|
126
|
+
// -----------------------------------------------------------------------------
|
|
127
|
+
/**
|
|
128
|
+
* Run tests from CLI with options.
|
|
129
|
+
*/
|
|
130
|
+
export async function runTests(options = {}) {
|
|
131
|
+
const { verbose = false, json = false } = options;
|
|
132
|
+
try {
|
|
133
|
+
console.error('Running integration tests...\n');
|
|
134
|
+
const result = await runSuite();
|
|
135
|
+
if (json) {
|
|
136
|
+
console.log(formatJSON(result));
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
console.log(formatHumanReadable(result, verbose));
|
|
140
|
+
}
|
|
141
|
+
// Exit with code 0 if all pass, 1 if any fail
|
|
142
|
+
const exitCode = result.failed + result.errors > 0 ? 1 : 0;
|
|
143
|
+
process.exit(exitCode);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
console.error('Fatal error running test suite:', error);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Test Runner Example Usage
|
|
3
|
+
// =============================================================================
|
|
4
|
+
//
|
|
5
|
+
// This file demonstrates how to use the test harness for integration testing.
|
|
6
|
+
// Run with: tsx src/testing/example.ts
|
|
7
|
+
//
|
|
8
|
+
import { runSuite, formatResults, formatResultsJson, assert, assertEqual, assertThrows, } from './test-runner.js';
|
|
9
|
+
// Example: Memory integration tests
|
|
10
|
+
async function exampleUsage() {
|
|
11
|
+
const suite = await runSuite('Memory Integration Example', [
|
|
12
|
+
{
|
|
13
|
+
name: 'should pass basic assertion',
|
|
14
|
+
fn: async () => {
|
|
15
|
+
const value = 42;
|
|
16
|
+
assert(value === 42, 'Value should be 42');
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'should pass equality check',
|
|
21
|
+
fn: async () => {
|
|
22
|
+
const obj = { id: '123', name: 'Test' };
|
|
23
|
+
assertEqual(obj, { id: '123', name: 'Test' });
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'should catch expected errors',
|
|
28
|
+
fn: async () => {
|
|
29
|
+
await assertThrows(async () => {
|
|
30
|
+
throw new Error('Invalid input');
|
|
31
|
+
}, 'Invalid input');
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'should fail on purpose',
|
|
36
|
+
fn: async () => {
|
|
37
|
+
// This test intentionally fails to demonstrate error handling
|
|
38
|
+
assert(false, 'This is a deliberate failure');
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'should handle async operations',
|
|
43
|
+
fn: async () => {
|
|
44
|
+
// Simulate async API call
|
|
45
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
46
|
+
const result = { success: true };
|
|
47
|
+
assert(result.success === true);
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
]);
|
|
51
|
+
// Print human-readable results
|
|
52
|
+
console.log(formatResults(suite));
|
|
53
|
+
// Example: Save JSON results to file
|
|
54
|
+
console.log('\n--- JSON Output ---\n');
|
|
55
|
+
console.log(formatResultsJson(suite));
|
|
56
|
+
// Exit with appropriate code
|
|
57
|
+
process.exit(suite.summary.failed > 0 ? 1 : 0);
|
|
58
|
+
}
|
|
59
|
+
// Run example
|
|
60
|
+
exampleUsage().catch(error => {
|
|
61
|
+
console.error('Fatal error:', error);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TestResult, TestSuite, TestSuiteSummary, TestFunction, TestDefinition, runTest, runSuite, formatResults, formatResultsJson, assert, assertEqual, assertThrows, } from './test-runner.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Agent-Based Integration Testing
|
|
3
|
+
// =============================================================================
|
|
4
|
+
//
|
|
5
|
+
// Re-exports for test runner and utilities
|
|
6
|
+
//
|
|
7
|
+
export {
|
|
8
|
+
// Core test runner functions
|
|
9
|
+
runTest, runSuite,
|
|
10
|
+
// Formatting
|
|
11
|
+
formatResults, formatResultsJson,
|
|
12
|
+
// Assertion helpers
|
|
13
|
+
assert, assertEqual, assertThrows, } from './test-runner.js';
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result of a single test execution
|
|
3
|
+
*/
|
|
4
|
+
export interface TestResult {
|
|
5
|
+
/** Test name/description */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Whether the test passed */
|
|
8
|
+
passed: boolean;
|
|
9
|
+
/** Duration in milliseconds */
|
|
10
|
+
duration_ms: number;
|
|
11
|
+
/** Error details if test failed */
|
|
12
|
+
error?: {
|
|
13
|
+
message: string;
|
|
14
|
+
stack?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Summary of test suite execution
|
|
19
|
+
*/
|
|
20
|
+
export interface TestSuiteSummary {
|
|
21
|
+
/** Total number of tests */
|
|
22
|
+
total: number;
|
|
23
|
+
/** Number of passed tests */
|
|
24
|
+
passed: number;
|
|
25
|
+
/** Number of failed tests */
|
|
26
|
+
failed: number;
|
|
27
|
+
/** Total duration in milliseconds */
|
|
28
|
+
total_duration_ms: number;
|
|
29
|
+
/** Average duration per test in milliseconds */
|
|
30
|
+
avg_duration_ms: number;
|
|
31
|
+
/** Pass rate as percentage (0-100) */
|
|
32
|
+
pass_rate: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Complete test suite results
|
|
36
|
+
*/
|
|
37
|
+
export interface TestSuite {
|
|
38
|
+
/** Suite name */
|
|
39
|
+
name: string;
|
|
40
|
+
/** Individual test results */
|
|
41
|
+
tests: TestResult[];
|
|
42
|
+
/** Aggregated summary */
|
|
43
|
+
summary: TestSuiteSummary;
|
|
44
|
+
/** Timestamp when suite started */
|
|
45
|
+
started_at: string;
|
|
46
|
+
/** Timestamp when suite completed */
|
|
47
|
+
completed_at: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Test function signature
|
|
51
|
+
*/
|
|
52
|
+
export type TestFunction = () => Promise<void> | void;
|
|
53
|
+
/**
|
|
54
|
+
* Test definition
|
|
55
|
+
*/
|
|
56
|
+
export interface TestDefinition {
|
|
57
|
+
name: string;
|
|
58
|
+
fn: TestFunction;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Run a single test with timing and error handling
|
|
62
|
+
*
|
|
63
|
+
* @param name - Test name/description
|
|
64
|
+
* @param fn - Test function to execute
|
|
65
|
+
* @returns Test result with pass/fail, duration, and error details
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const result = await runTest('should store and retrieve fact', async () => {
|
|
70
|
+
* const fact = await storeFact('test', 'RELATES_TO', 'value');
|
|
71
|
+
* assert(fact !== null);
|
|
72
|
+
* });
|
|
73
|
+
*
|
|
74
|
+
* if (!result.passed) {
|
|
75
|
+
* console.error(`Test failed: ${result.error?.message}`);
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function runTest(name: string, fn: TestFunction): Promise<TestResult>;
|
|
80
|
+
/**
|
|
81
|
+
* Run a suite of tests
|
|
82
|
+
*
|
|
83
|
+
* @param name - Suite name
|
|
84
|
+
* @param tests - Array of test definitions
|
|
85
|
+
* @returns Complete test suite results with summary
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const suite = await runSuite('Memory Integration Tests', [
|
|
90
|
+
* { name: 'should store fact', fn: async () => { ... } },
|
|
91
|
+
* { name: 'should search facts', fn: async () => { ... } },
|
|
92
|
+
* { name: 'should inject context', fn: async () => { ... } },
|
|
93
|
+
* ]);
|
|
94
|
+
*
|
|
95
|
+
* console.log(formatResults(suite));
|
|
96
|
+
*
|
|
97
|
+
* if (suite.summary.failed > 0) {
|
|
98
|
+
* process.exit(1);
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare function runSuite(name: string, tests: TestDefinition[]): Promise<TestSuite>;
|
|
103
|
+
/**
|
|
104
|
+
* Format test suite results as human-readable text
|
|
105
|
+
*
|
|
106
|
+
* @param suite - Test suite results
|
|
107
|
+
* @returns Formatted string with test results and summary
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const suite = await runSuite('My Tests', [...]);
|
|
112
|
+
* console.log(formatResults(suite));
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* Output:
|
|
116
|
+
* ```
|
|
117
|
+
* ================================================================================
|
|
118
|
+
* Test Suite: My Tests
|
|
119
|
+
* ================================================================================
|
|
120
|
+
*
|
|
121
|
+
* ✓ should pass test 1 (45.32ms)
|
|
122
|
+
* ✗ should fail test 2 (12.18ms)
|
|
123
|
+
* Error: Expected value to be true
|
|
124
|
+
*
|
|
125
|
+
* --------------------------------------------------------------------------------
|
|
126
|
+
* Summary
|
|
127
|
+
* --------------------------------------------------------------------------------
|
|
128
|
+
* Total: 2
|
|
129
|
+
* Passed: 1
|
|
130
|
+
* Failed: 1
|
|
131
|
+
* Pass Rate: 50.00%
|
|
132
|
+
* Duration: 57.50ms (avg: 28.75ms)
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export declare function formatResults(suite: TestSuite): string;
|
|
136
|
+
/**
|
|
137
|
+
* Format test suite results as JSON
|
|
138
|
+
*
|
|
139
|
+
* @param suite - Test suite results
|
|
140
|
+
* @param pretty - Whether to pretty-print the JSON (default: true)
|
|
141
|
+
* @returns JSON string
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* const suite = await runSuite('My Tests', [...]);
|
|
146
|
+
* const json = formatResultsJson(suite);
|
|
147
|
+
* await fs.writeFile('test-results.json', json);
|
|
148
|
+
* ```
|
|
149
|
+
*
|
|
150
|
+
* Output:
|
|
151
|
+
* ```json
|
|
152
|
+
* {
|
|
153
|
+
* "name": "My Tests",
|
|
154
|
+
* "started_at": "2025-01-01T12:00:00.000Z",
|
|
155
|
+
* "completed_at": "2025-01-01T12:00:01.234Z",
|
|
156
|
+
* "summary": {
|
|
157
|
+
* "total": 5,
|
|
158
|
+
* "passed": 4,
|
|
159
|
+
* "failed": 1,
|
|
160
|
+
* "pass_rate": 80.00,
|
|
161
|
+
* "total_duration_ms": 1234.56,
|
|
162
|
+
* "avg_duration_ms": 246.91
|
|
163
|
+
* },
|
|
164
|
+
* "tests": [...]
|
|
165
|
+
* }
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export declare function formatResultsJson(suite: TestSuite, pretty?: boolean): string;
|
|
169
|
+
/**
|
|
170
|
+
* Create a simple assertion helper for tests
|
|
171
|
+
*
|
|
172
|
+
* @param condition - Condition to check
|
|
173
|
+
* @param message - Error message if assertion fails
|
|
174
|
+
* @throws Error if condition is false
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* await runTest('should work', async () => {
|
|
179
|
+
* const result = await someOperation();
|
|
180
|
+
* assert(result !== null, 'Result should not be null');
|
|
181
|
+
* assert(result.value === 'expected', 'Value should be expected');
|
|
182
|
+
* });
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export declare function assert(condition: boolean, message?: string): asserts condition;
|
|
186
|
+
/**
|
|
187
|
+
* Deep equality assertion
|
|
188
|
+
*
|
|
189
|
+
* @param actual - Actual value
|
|
190
|
+
* @param expected - Expected value
|
|
191
|
+
* @param message - Error message if assertion fails
|
|
192
|
+
* @throws Error if values are not equal
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* await runTest('should match object', async () => {
|
|
197
|
+
* const result = await getUser();
|
|
198
|
+
* assertEqual(result, { id: '123', name: 'Test' });
|
|
199
|
+
* });
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
export declare function assertEqual<T>(actual: T, expected: T, message?: string): void;
|
|
203
|
+
/**
|
|
204
|
+
* Async error assertion helper
|
|
205
|
+
*
|
|
206
|
+
* @param fn - Function that should throw
|
|
207
|
+
* @param expectedMessage - Optional expected error message
|
|
208
|
+
* @throws Error if function doesn't throw
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* await runTest('should reject invalid input', async () => {
|
|
213
|
+
* await assertThrows(
|
|
214
|
+
* async () => await validateInput('invalid'),
|
|
215
|
+
* 'Invalid input format'
|
|
216
|
+
* );
|
|
217
|
+
* });
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
export declare function assertThrows(fn: () => Promise<void> | void, expectedMessage?: string): Promise<void>;
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Agent-Based Integration Test Runner
|
|
3
|
+
// =============================================================================
|
|
4
|
+
//
|
|
5
|
+
// Core test harness for running integration tests against the ClaudeTools
|
|
6
|
+
// memory system. Provides result collection, timing, and reporting.
|
|
7
|
+
//
|
|
8
|
+
/**
|
|
9
|
+
* Run a single test with timing and error handling
|
|
10
|
+
*
|
|
11
|
+
* @param name - Test name/description
|
|
12
|
+
* @param fn - Test function to execute
|
|
13
|
+
* @returns Test result with pass/fail, duration, and error details
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const result = await runTest('should store and retrieve fact', async () => {
|
|
18
|
+
* const fact = await storeFact('test', 'RELATES_TO', 'value');
|
|
19
|
+
* assert(fact !== null);
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* if (!result.passed) {
|
|
23
|
+
* console.error(`Test failed: ${result.error?.message}`);
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export async function runTest(name, fn) {
|
|
28
|
+
const startTime = performance.now();
|
|
29
|
+
try {
|
|
30
|
+
await fn();
|
|
31
|
+
const duration_ms = performance.now() - startTime;
|
|
32
|
+
return {
|
|
33
|
+
name,
|
|
34
|
+
passed: true,
|
|
35
|
+
duration_ms: Math.round(duration_ms * 100) / 100, // Round to 2 decimal places
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const duration_ms = performance.now() - startTime;
|
|
40
|
+
const err = error;
|
|
41
|
+
return {
|
|
42
|
+
name,
|
|
43
|
+
passed: false,
|
|
44
|
+
duration_ms: Math.round(duration_ms * 100) / 100,
|
|
45
|
+
error: {
|
|
46
|
+
message: err.message || String(error),
|
|
47
|
+
stack: err.stack,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Calculate summary statistics from test results
|
|
54
|
+
*
|
|
55
|
+
* @param tests - Array of test results
|
|
56
|
+
* @returns Aggregated summary with counts, duration, and pass rate
|
|
57
|
+
*/
|
|
58
|
+
function calculateSummary(tests) {
|
|
59
|
+
const total = tests.length;
|
|
60
|
+
const passed = tests.filter(t => t.passed).length;
|
|
61
|
+
const failed = total - passed;
|
|
62
|
+
const total_duration_ms = tests.reduce((sum, t) => sum + t.duration_ms, 0);
|
|
63
|
+
const avg_duration_ms = total > 0
|
|
64
|
+
? Math.round((total_duration_ms / total) * 100) / 100
|
|
65
|
+
: 0;
|
|
66
|
+
const pass_rate = total > 0
|
|
67
|
+
? Math.round((passed / total) * 10000) / 100 // Round to 2 decimal places
|
|
68
|
+
: 0;
|
|
69
|
+
return {
|
|
70
|
+
total,
|
|
71
|
+
passed,
|
|
72
|
+
failed,
|
|
73
|
+
total_duration_ms: Math.round(total_duration_ms * 100) / 100,
|
|
74
|
+
avg_duration_ms,
|
|
75
|
+
pass_rate,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Run a suite of tests
|
|
80
|
+
*
|
|
81
|
+
* @param name - Suite name
|
|
82
|
+
* @param tests - Array of test definitions
|
|
83
|
+
* @returns Complete test suite results with summary
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const suite = await runSuite('Memory Integration Tests', [
|
|
88
|
+
* { name: 'should store fact', fn: async () => { ... } },
|
|
89
|
+
* { name: 'should search facts', fn: async () => { ... } },
|
|
90
|
+
* { name: 'should inject context', fn: async () => { ... } },
|
|
91
|
+
* ]);
|
|
92
|
+
*
|
|
93
|
+
* console.log(formatResults(suite));
|
|
94
|
+
*
|
|
95
|
+
* if (suite.summary.failed > 0) {
|
|
96
|
+
* process.exit(1);
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export async function runSuite(name, tests) {
|
|
101
|
+
const started_at = new Date().toISOString();
|
|
102
|
+
// Run all tests sequentially
|
|
103
|
+
const results = [];
|
|
104
|
+
for (const test of tests) {
|
|
105
|
+
const result = await runTest(test.name, test.fn);
|
|
106
|
+
results.push(result);
|
|
107
|
+
}
|
|
108
|
+
const completed_at = new Date().toISOString();
|
|
109
|
+
const summary = calculateSummary(results);
|
|
110
|
+
return {
|
|
111
|
+
name,
|
|
112
|
+
tests: results,
|
|
113
|
+
summary,
|
|
114
|
+
started_at,
|
|
115
|
+
completed_at,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Format test suite results as human-readable text
|
|
120
|
+
*
|
|
121
|
+
* @param suite - Test suite results
|
|
122
|
+
* @returns Formatted string with test results and summary
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* const suite = await runSuite('My Tests', [...]);
|
|
127
|
+
* console.log(formatResults(suite));
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* Output:
|
|
131
|
+
* ```
|
|
132
|
+
* ================================================================================
|
|
133
|
+
* Test Suite: My Tests
|
|
134
|
+
* ================================================================================
|
|
135
|
+
*
|
|
136
|
+
* ✓ should pass test 1 (45.32ms)
|
|
137
|
+
* ✗ should fail test 2 (12.18ms)
|
|
138
|
+
* Error: Expected value to be true
|
|
139
|
+
*
|
|
140
|
+
* --------------------------------------------------------------------------------
|
|
141
|
+
* Summary
|
|
142
|
+
* --------------------------------------------------------------------------------
|
|
143
|
+
* Total: 2
|
|
144
|
+
* Passed: 1
|
|
145
|
+
* Failed: 1
|
|
146
|
+
* Pass Rate: 50.00%
|
|
147
|
+
* Duration: 57.50ms (avg: 28.75ms)
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
export function formatResults(suite) {
|
|
151
|
+
const lines = [];
|
|
152
|
+
// Header
|
|
153
|
+
lines.push('='.repeat(80));
|
|
154
|
+
lines.push(`Test Suite: ${suite.name}`);
|
|
155
|
+
lines.push('='.repeat(80));
|
|
156
|
+
lines.push('');
|
|
157
|
+
// Individual test results
|
|
158
|
+
for (const test of suite.tests) {
|
|
159
|
+
const icon = test.passed ? '✓' : '✗';
|
|
160
|
+
const status = test.passed ? 'PASS' : 'FAIL';
|
|
161
|
+
lines.push(`${icon} ${test.name} (${test.duration_ms}ms)`);
|
|
162
|
+
if (!test.passed && test.error) {
|
|
163
|
+
lines.push(` Error: ${test.error.message}`);
|
|
164
|
+
if (test.error.stack) {
|
|
165
|
+
const stackLines = test.error.stack.split('\n').slice(1, 4); // First 3 stack frames
|
|
166
|
+
stackLines.forEach(line => lines.push(` ${line.trim()}`));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Summary
|
|
171
|
+
lines.push('');
|
|
172
|
+
lines.push('-'.repeat(80));
|
|
173
|
+
lines.push('Summary');
|
|
174
|
+
lines.push('-'.repeat(80));
|
|
175
|
+
lines.push(`Total: ${suite.summary.total}`);
|
|
176
|
+
lines.push(`Passed: ${suite.summary.passed}`);
|
|
177
|
+
lines.push(`Failed: ${suite.summary.failed}`);
|
|
178
|
+
lines.push(`Pass Rate: ${suite.summary.pass_rate}%`);
|
|
179
|
+
lines.push(`Duration: ${suite.summary.total_duration_ms}ms (avg: ${suite.summary.avg_duration_ms}ms)`);
|
|
180
|
+
lines.push('');
|
|
181
|
+
// Overall result
|
|
182
|
+
const overallStatus = suite.summary.failed === 0 ? 'PASSED ✓' : 'FAILED ✗';
|
|
183
|
+
lines.push(`Overall: ${overallStatus}`);
|
|
184
|
+
lines.push('='.repeat(80));
|
|
185
|
+
return lines.join('\n');
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Format test suite results as JSON
|
|
189
|
+
*
|
|
190
|
+
* @param suite - Test suite results
|
|
191
|
+
* @param pretty - Whether to pretty-print the JSON (default: true)
|
|
192
|
+
* @returns JSON string
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const suite = await runSuite('My Tests', [...]);
|
|
197
|
+
* const json = formatResultsJson(suite);
|
|
198
|
+
* await fs.writeFile('test-results.json', json);
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* Output:
|
|
202
|
+
* ```json
|
|
203
|
+
* {
|
|
204
|
+
* "name": "My Tests",
|
|
205
|
+
* "started_at": "2025-01-01T12:00:00.000Z",
|
|
206
|
+
* "completed_at": "2025-01-01T12:00:01.234Z",
|
|
207
|
+
* "summary": {
|
|
208
|
+
* "total": 5,
|
|
209
|
+
* "passed": 4,
|
|
210
|
+
* "failed": 1,
|
|
211
|
+
* "pass_rate": 80.00,
|
|
212
|
+
* "total_duration_ms": 1234.56,
|
|
213
|
+
* "avg_duration_ms": 246.91
|
|
214
|
+
* },
|
|
215
|
+
* "tests": [...]
|
|
216
|
+
* }
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
export function formatResultsJson(suite, pretty = true) {
|
|
220
|
+
return pretty
|
|
221
|
+
? JSON.stringify(suite, null, 2)
|
|
222
|
+
: JSON.stringify(suite);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Create a simple assertion helper for tests
|
|
226
|
+
*
|
|
227
|
+
* @param condition - Condition to check
|
|
228
|
+
* @param message - Error message if assertion fails
|
|
229
|
+
* @throws Error if condition is false
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```typescript
|
|
233
|
+
* await runTest('should work', async () => {
|
|
234
|
+
* const result = await someOperation();
|
|
235
|
+
* assert(result !== null, 'Result should not be null');
|
|
236
|
+
* assert(result.value === 'expected', 'Value should be expected');
|
|
237
|
+
* });
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
export function assert(condition, message) {
|
|
241
|
+
if (!condition) {
|
|
242
|
+
throw new Error(message || 'Assertion failed');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Deep equality assertion
|
|
247
|
+
*
|
|
248
|
+
* @param actual - Actual value
|
|
249
|
+
* @param expected - Expected value
|
|
250
|
+
* @param message - Error message if assertion fails
|
|
251
|
+
* @throws Error if values are not equal
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```typescript
|
|
255
|
+
* await runTest('should match object', async () => {
|
|
256
|
+
* const result = await getUser();
|
|
257
|
+
* assertEqual(result, { id: '123', name: 'Test' });
|
|
258
|
+
* });
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
export function assertEqual(actual, expected, message) {
|
|
262
|
+
const actualJson = JSON.stringify(actual);
|
|
263
|
+
const expectedJson = JSON.stringify(expected);
|
|
264
|
+
if (actualJson !== expectedJson) {
|
|
265
|
+
const msg = message || `Expected ${expectedJson} but got ${actualJson}`;
|
|
266
|
+
throw new Error(msg);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Async error assertion helper
|
|
271
|
+
*
|
|
272
|
+
* @param fn - Function that should throw
|
|
273
|
+
* @param expectedMessage - Optional expected error message
|
|
274
|
+
* @throws Error if function doesn't throw
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* await runTest('should reject invalid input', async () => {
|
|
279
|
+
* await assertThrows(
|
|
280
|
+
* async () => await validateInput('invalid'),
|
|
281
|
+
* 'Invalid input format'
|
|
282
|
+
* );
|
|
283
|
+
* });
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
export async function assertThrows(fn, expectedMessage) {
|
|
287
|
+
try {
|
|
288
|
+
await fn();
|
|
289
|
+
throw new Error('Expected function to throw an error');
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
if (error instanceof Error && error.message === 'Expected function to throw an error') {
|
|
293
|
+
throw error;
|
|
294
|
+
}
|
|
295
|
+
if (expectedMessage) {
|
|
296
|
+
const actualMessage = error instanceof Error ? error.message : String(error);
|
|
297
|
+
if (!actualMessage.includes(expectedMessage)) {
|
|
298
|
+
throw new Error(`Expected error message to include "${expectedMessage}" but got "${actualMessage}"`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudetools/tools",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "Persistent AI memory, task management, and codebase intelligence for Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,6 +14,22 @@
|
|
|
14
14
|
"README.md",
|
|
15
15
|
"LICENSE"
|
|
16
16
|
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"start": "node dist/index.js",
|
|
20
|
+
"dev": "tsx src/index.ts",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"test:ui": "vitest --ui",
|
|
24
|
+
"prepublishOnly": "npm run build",
|
|
25
|
+
"codedna:monitor": "tsx -e \"import { runMonitoring } from './src/helpers/codedna-monitoring.js'; runMonitoring()\"",
|
|
26
|
+
"codedna:analytics": "tsx -e \"import { weeklyAnalyticsSummary } from './src/helpers/usage-analytics.js'; weeklyAnalyticsSummary()\"",
|
|
27
|
+
"codedna:analytics:24h": "tsx -e \"import { getLast24HoursAnalytics, printAnalytics } from './src/helpers/usage-analytics.js'; const r = await getLast24HoursAnalytics(); printAnalytics(r, 'Last 24 Hours')\"",
|
|
28
|
+
"codedna:analytics:30d": "tsx -e \"import { getLast30DaysAnalytics, printAnalytics } from './src/helpers/usage-analytics.js'; const r = await getLast30DaysAnalytics(); printAnalytics(r, 'Last 30 Days')\"",
|
|
29
|
+
"prompt:verify": "scripts/verify-prompt-compliance.sh",
|
|
30
|
+
"eval:build-dataset": "tsx src/evaluation/build-dataset.ts",
|
|
31
|
+
"eval:threshold": "tsx src/evaluation/threshold-eval.ts"
|
|
32
|
+
},
|
|
17
33
|
"repository": {
|
|
18
34
|
"type": "git",
|
|
19
35
|
"url": "git+https://github.com/claudetools/memory.git"
|
|
@@ -58,20 +74,5 @@
|
|
|
58
74
|
"tsx": "^4.7.0",
|
|
59
75
|
"typescript": "^5.3.0",
|
|
60
76
|
"vitest": "^4.0.15"
|
|
61
|
-
},
|
|
62
|
-
"scripts": {
|
|
63
|
-
"build": "tsc",
|
|
64
|
-
"start": "node dist/index.js",
|
|
65
|
-
"dev": "tsx src/index.ts",
|
|
66
|
-
"test": "vitest run",
|
|
67
|
-
"test:watch": "vitest",
|
|
68
|
-
"test:ui": "vitest --ui",
|
|
69
|
-
"codedna:monitor": "tsx -e \"import { runMonitoring } from './src/helpers/codedna-monitoring.js'; runMonitoring()\"",
|
|
70
|
-
"codedna:analytics": "tsx -e \"import { weeklyAnalyticsSummary } from './src/helpers/usage-analytics.js'; weeklyAnalyticsSummary()\"",
|
|
71
|
-
"codedna:analytics:24h": "tsx -e \"import { getLast24HoursAnalytics, printAnalytics } from './src/helpers/usage-analytics.js'; const r = await getLast24HoursAnalytics(); printAnalytics(r, 'Last 24 Hours')\"",
|
|
72
|
-
"codedna:analytics:30d": "tsx -e \"import { getLast30DaysAnalytics, printAnalytics } from './src/helpers/usage-analytics.js'; const r = await getLast30DaysAnalytics(); printAnalytics(r, 'Last 30 Days')\"",
|
|
73
|
-
"prompt:verify": "scripts/verify-prompt-compliance.sh",
|
|
74
|
-
"eval:build-dataset": "tsx src/evaluation/build-dataset.ts",
|
|
75
|
-
"eval:threshold": "tsx src/evaluation/threshold-eval.ts"
|
|
76
77
|
}
|
|
77
|
-
}
|
|
78
|
+
}
|
|
File without changes
|