@stackmemoryai/stackmemory 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,201 @@
1
+ import { SimpleRalphPlugin } from "../simple-ralph-plugin.js";
2
+ import * as fs from "fs/promises";
3
+ import * as path from "path";
4
+ import { execSync } from "child_process";
5
+ class TestGenerator {
6
+ ralphPlugin;
7
+ constructor(ralphPlugin) {
8
+ this.ralphPlugin = ralphPlugin;
9
+ }
10
+ /**
11
+ * Generate tests iteratively until coverage target is met
12
+ */
13
+ async generateTests(request) {
14
+ const coverageTarget = request.coverageTarget || 80;
15
+ const task = {
16
+ id: `testgen-${Date.now()}`,
17
+ description: `Generate ${request.framework} tests for ${request.targetFile}`,
18
+ acceptanceCriteria: [
19
+ "All tests pass",
20
+ `Test coverage >= ${coverageTarget}%`,
21
+ "No test duplication",
22
+ "Tests are maintainable and clear"
23
+ ],
24
+ maxIterations: 7
25
+ };
26
+ if (request.includeEdgeCases) {
27
+ task.acceptanceCriteria.push("Edge cases covered");
28
+ task.acceptanceCriteria.push("Error conditions tested");
29
+ }
30
+ if (request.includeIntegrationTests) {
31
+ task.acceptanceCriteria.push("Integration tests included");
32
+ }
33
+ const result = await this.ralphPlugin.runTask(task);
34
+ const analysis = await this.analyzeGeneratedTests(request.targetFile, request.framework);
35
+ return {
36
+ testFiles: analysis.files,
37
+ coverage: analysis.coverage,
38
+ testCount: analysis.testCount,
39
+ passRate: analysis.passRate,
40
+ iterations: result.iterations
41
+ };
42
+ }
43
+ /**
44
+ * Analyze generated tests
45
+ */
46
+ async analyzeGeneratedTests(targetFile, framework) {
47
+ const analysis = {
48
+ files: [],
49
+ coverage: 0,
50
+ testCount: 0,
51
+ passRate: 0
52
+ };
53
+ try {
54
+ const testDir = path.dirname(targetFile);
55
+ const baseName = path.basename(targetFile, path.extname(targetFile));
56
+ const testPatterns = [
57
+ `${baseName}.test.*`,
58
+ `${baseName}.spec.*`,
59
+ `test_${baseName}.*`,
60
+ `${baseName}_test.*`
61
+ ];
62
+ for (const pattern of testPatterns) {
63
+ const files = await this.findFiles(testDir, pattern);
64
+ analysis.files.push(...files);
65
+ }
66
+ analysis.coverage = await this.runCoverageAnalysis(framework);
67
+ const testResults = await this.runTests(framework);
68
+ analysis.testCount = testResults.total;
69
+ analysis.passRate = testResults.passed / testResults.total * 100;
70
+ } catch (error) {
71
+ console.error("Error analyzing tests:", error);
72
+ }
73
+ return analysis;
74
+ }
75
+ /**
76
+ * Find files matching pattern
77
+ */
78
+ async findFiles(dir, pattern) {
79
+ const files = [];
80
+ try {
81
+ const entries = await fs.readdir(dir);
82
+ for (const entry of entries) {
83
+ if (this.matchesPattern(entry, pattern)) {
84
+ files.push(path.join(dir, entry));
85
+ }
86
+ }
87
+ } catch (error) {
88
+ console.error("Error finding files:", error);
89
+ }
90
+ return files;
91
+ }
92
+ /**
93
+ * Simple pattern matching
94
+ */
95
+ matchesPattern(filename, pattern) {
96
+ const regex = new RegExp(pattern.replace(/\*/g, ".*"));
97
+ return regex.test(filename);
98
+ }
99
+ /**
100
+ * Run coverage analysis
101
+ */
102
+ async runCoverageAnalysis(framework) {
103
+ try {
104
+ let command = "";
105
+ switch (framework) {
106
+ case "jest":
107
+ command = "npx jest --coverage --silent";
108
+ break;
109
+ case "vitest":
110
+ command = "npx vitest run --coverage --silent";
111
+ break;
112
+ case "mocha":
113
+ command = "npx nyc mocha";
114
+ break;
115
+ case "pytest":
116
+ command = "pytest --cov --cov-report=json";
117
+ break;
118
+ }
119
+ if (command) {
120
+ const output = execSync(command, { encoding: "utf-8", stdio: "pipe" });
121
+ const match = output.match(/(\d+(?:\.\d+)?)\s*%/);
122
+ if (match) {
123
+ return parseFloat(match[1]);
124
+ }
125
+ }
126
+ } catch (error) {
127
+ console.error("Coverage analysis failed:", error);
128
+ }
129
+ return 0;
130
+ }
131
+ /**
132
+ * Run tests and get results
133
+ */
134
+ async runTests(framework) {
135
+ try {
136
+ let command = "";
137
+ switch (framework) {
138
+ case "jest":
139
+ command = "npx jest --json";
140
+ break;
141
+ case "vitest":
142
+ command = "npx vitest run --reporter=json";
143
+ break;
144
+ case "mocha":
145
+ command = "npx mocha --reporter json";
146
+ break;
147
+ case "pytest":
148
+ command = "pytest --json-report";
149
+ break;
150
+ }
151
+ if (command) {
152
+ const output = execSync(command, { encoding: "utf-8", stdio: "pipe" });
153
+ try {
154
+ const json = JSON.parse(output);
155
+ return {
156
+ total: json.numTotalTests || json.tests || 0,
157
+ passed: json.numPassedTests || json.passes || 0
158
+ };
159
+ } catch {
160
+ const totalMatch = output.match(/(\d+)\s+tests?/i);
161
+ const passedMatch = output.match(/(\d+)\s+pass/i);
162
+ return {
163
+ total: totalMatch ? parseInt(totalMatch[1]) : 0,
164
+ passed: passedMatch ? parseInt(passedMatch[1]) : 0
165
+ };
166
+ }
167
+ }
168
+ } catch (error) {
169
+ console.error("Test execution failed:", error);
170
+ }
171
+ return { total: 0, passed: 0 };
172
+ }
173
+ }
174
+ async function generateTestsForModule() {
175
+ const ralphPlugin = new SimpleRalphPlugin();
176
+ await ralphPlugin.initialize({
177
+ eventBus: {},
178
+ config: { name: "simple-ralph", version: "2.0.0", enabled: true },
179
+ dataDir: ".ralph",
180
+ getRepository: () => null,
181
+ registerRepository: () => {
182
+ }
183
+ });
184
+ const generator = new TestGenerator(ralphPlugin);
185
+ const result = await generator.generateTests({
186
+ targetFile: "./src/utils/validator.ts",
187
+ framework: "jest",
188
+ coverageTarget: 90,
189
+ includeEdgeCases: true,
190
+ includeIntegrationTests: false,
191
+ mockStrategy: "partial"
192
+ });
193
+ console.log(`Generated ${result.testCount} tests with ${result.coverage}% coverage`);
194
+ console.log(`Pass rate: ${result.passRate}%`);
195
+ console.log(`Completed in ${result.iterations} iterations`);
196
+ }
197
+ export {
198
+ TestGenerator,
199
+ generateTestsForModule
200
+ };
201
+ //# sourceMappingURL=test-generator.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/plugins/ralph/use-cases/test-generator.ts"],
4
+ "sourcesContent": ["/**\n * Test Generator - Iteratively generate comprehensive test suites\n * Focuses on achieving high coverage and catching edge cases\n */\n\nimport { SimpleRalphPlugin, SimpleTask } from '../simple-ralph-plugin.js';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { execSync } from 'child_process';\n\nexport interface TestGenRequest {\n targetFile: string;\n framework: 'jest' | 'mocha' | 'vitest' | 'pytest';\n coverageTarget?: number;\n includeEdgeCases?: boolean;\n includeIntegrationTests?: boolean;\n mockStrategy?: 'full' | 'partial' | 'none';\n}\n\nexport interface GeneratedTests {\n testFiles: string[];\n coverage: number;\n testCount: number;\n passRate: number;\n iterations: number;\n}\n\nexport class TestGenerator {\n private ralphPlugin: SimpleRalphPlugin;\n\n constructor(ralphPlugin: SimpleRalphPlugin) {\n this.ralphPlugin = ralphPlugin;\n }\n\n /**\n * Generate tests iteratively until coverage target is met\n */\n async generateTests(request: TestGenRequest): Promise<GeneratedTests> {\n const coverageTarget = request.coverageTarget || 80;\n\n const task: SimpleTask = {\n id: `testgen-${Date.now()}`,\n description: `Generate ${request.framework} tests for ${request.targetFile}`,\n acceptanceCriteria: [\n 'All tests pass',\n `Test coverage >= ${coverageTarget}%`,\n 'No test duplication',\n 'Tests are maintainable and clear'\n ],\n maxIterations: 7\n };\n\n // Add edge case criteria if requested\n if (request.includeEdgeCases) {\n task.acceptanceCriteria.push('Edge cases covered');\n task.acceptanceCriteria.push('Error conditions tested');\n }\n\n if (request.includeIntegrationTests) {\n task.acceptanceCriteria.push('Integration tests included');\n }\n\n // Run iterative test generation\n const result = await this.ralphPlugin.runTask(task);\n\n // Analyze generated tests\n const analysis = await this.analyzeGeneratedTests(request.targetFile, request.framework);\n\n return {\n testFiles: analysis.files,\n coverage: analysis.coverage,\n testCount: analysis.testCount,\n passRate: analysis.passRate,\n iterations: result.iterations\n };\n }\n\n /**\n * Analyze generated tests\n */\n private async analyzeGeneratedTests(\n targetFile: string, \n framework: string\n ): Promise<{\n files: string[];\n coverage: number;\n testCount: number;\n passRate: number;\n }> {\n const analysis = {\n files: [] as string[],\n coverage: 0,\n testCount: 0,\n passRate: 0\n };\n\n try {\n // Find test files\n const testDir = path.dirname(targetFile);\n const baseName = path.basename(targetFile, path.extname(targetFile));\n \n const testPatterns = [\n `${baseName}.test.*`,\n `${baseName}.spec.*`,\n `test_${baseName}.*`,\n `${baseName}_test.*`\n ];\n\n for (const pattern of testPatterns) {\n const files = await this.findFiles(testDir, pattern);\n analysis.files.push(...files);\n }\n\n // Run coverage analysis\n analysis.coverage = await this.runCoverageAnalysis(framework);\n \n // Count tests and check pass rate\n const testResults = await this.runTests(framework);\n analysis.testCount = testResults.total;\n analysis.passRate = testResults.passed / testResults.total * 100;\n\n } catch (error) {\n console.error('Error analyzing tests:', error);\n }\n\n return analysis;\n }\n\n /**\n * Find files matching pattern\n */\n private async findFiles(dir: string, pattern: string): Promise<string[]> {\n const files: string[] = [];\n try {\n const entries = await fs.readdir(dir);\n for (const entry of entries) {\n if (this.matchesPattern(entry, pattern)) {\n files.push(path.join(dir, entry));\n }\n }\n } catch (error) {\n console.error('Error finding files:', error);\n }\n return files;\n }\n\n /**\n * Simple pattern matching\n */\n private matchesPattern(filename: string, pattern: string): boolean {\n const regex = new RegExp(pattern.replace(/\\*/g, '.*'));\n return regex.test(filename);\n }\n\n /**\n * Run coverage analysis\n */\n private async runCoverageAnalysis(framework: string): Promise<number> {\n try {\n let command = '';\n switch (framework) {\n case 'jest':\n command = 'npx jest --coverage --silent';\n break;\n case 'vitest':\n command = 'npx vitest run --coverage --silent';\n break;\n case 'mocha':\n command = 'npx nyc mocha';\n break;\n case 'pytest':\n command = 'pytest --cov --cov-report=json';\n break;\n }\n\n if (command) {\n const output = execSync(command, { encoding: 'utf-8', stdio: 'pipe' });\n \n // Parse coverage from output (simplified)\n const match = output.match(/(\\d+(?:\\.\\d+)?)\\s*%/);\n if (match) {\n return parseFloat(match[1]);\n }\n }\n } catch (error) {\n console.error('Coverage analysis failed:', error);\n }\n \n return 0;\n }\n\n /**\n * Run tests and get results\n */\n private async runTests(framework: string): Promise<{ total: number; passed: number }> {\n try {\n let command = '';\n switch (framework) {\n case 'jest':\n command = 'npx jest --json';\n break;\n case 'vitest':\n command = 'npx vitest run --reporter=json';\n break;\n case 'mocha':\n command = 'npx mocha --reporter json';\n break;\n case 'pytest':\n command = 'pytest --json-report';\n break;\n }\n\n if (command) {\n const output = execSync(command, { encoding: 'utf-8', stdio: 'pipe' });\n \n try {\n const json = JSON.parse(output);\n // Parse based on framework (simplified)\n return {\n total: json.numTotalTests || json.tests || 0,\n passed: json.numPassedTests || json.passes || 0\n };\n } catch {\n // Fallback to regex parsing\n const totalMatch = output.match(/(\\d+)\\s+tests?/i);\n const passedMatch = output.match(/(\\d+)\\s+pass/i);\n \n return {\n total: totalMatch ? parseInt(totalMatch[1]) : 0,\n passed: passedMatch ? parseInt(passedMatch[1]) : 0\n };\n }\n }\n } catch (error) {\n console.error('Test execution failed:', error);\n }\n \n return { total: 0, passed: 0 };\n }\n}\n\n// Example: Generate tests for a TypeScript module\nexport async function generateTestsForModule(): Promise<void> {\n const ralphPlugin = new SimpleRalphPlugin();\n await ralphPlugin.initialize({\n eventBus: {} as any,\n config: { name: 'simple-ralph', version: '2.0.0', enabled: true },\n dataDir: '.ralph',\n getRepository: () => null as any,\n registerRepository: () => {}\n });\n\n const generator = new TestGenerator(ralphPlugin);\n \n const result = await generator.generateTests({\n targetFile: './src/utils/validator.ts',\n framework: 'jest',\n coverageTarget: 90,\n includeEdgeCases: true,\n includeIntegrationTests: false,\n mockStrategy: 'partial'\n });\n\n console.log(`Generated ${result.testCount} tests with ${result.coverage}% coverage`);\n console.log(`Pass rate: ${result.passRate}%`);\n console.log(`Completed in ${result.iterations} iterations`);\n}"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackmemoryai/stackmemory",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Lossless memory runtime for AI coding tools - organizes context as a call stack instead of linear chat logs, with team collaboration and infinite retention",
5
5
  "engines": {
6
6
  "node": ">=20.0.0",
@@ -86,11 +86,9 @@
86
86
  "@linear/sdk": "^68.1.0",
87
87
  "@modelcontextprotocol/sdk": "^0.5.0",
88
88
  "@stackmemoryai/stackmemory": "^0.3.19",
89
- "@types/bcryptjs": "^2.4.6",
90
89
  "@types/blessed": "^0.1.27",
91
90
  "@types/inquirer": "^9.0.9",
92
91
  "@types/pg": "^8.16.0",
93
- "bcryptjs": "^3.0.3",
94
92
  "better-sqlite3": "^9.2.2",
95
93
  "chalk": "^5.3.0",
96
94
  "chromadb": "^3.2.2",
@@ -105,17 +103,12 @@
105
103
  "helmet": "^8.1.0",
106
104
  "ignore": "^7.0.5",
107
105
  "inquirer": "^9.3.8",
108
- "ioredis": "^5.8.2",
109
- "jsonwebtoken": "^9.0.3",
110
- "jwks-rsa": "^3.2.0",
111
106
  "msgpackr": "^1.10.1",
112
107
  "ngrok": "^5.0.0-beta.2",
113
108
  "open": "^11.0.0",
114
109
  "ora": "^9.0.0",
115
110
  "pg": "^8.17.1",
116
- "puppeteer": "^24.34.0",
117
111
  "rate-limiter-flexible": "^9.0.1",
118
- "redis": "^5.10.0",
119
112
  "shell-escape": "^0.2.0",
120
113
  "socket.io": "^4.6.0",
121
114
  "socket.io-client": "^4.6.0",
@@ -1,90 +0,0 @@
1
- {
2
- "timestamp": "2026-01-06T15:16:51.046Z",
3
- "tests": [
4
- {
5
- "test": "status_command",
6
- "iterations": 3,
7
- "measurements": [
8
- 393.8040000000001,
9
- 396.434667,
10
- 393.71524999999997
11
- ],
12
- "average": 394.6513056666667,
13
- "unit": "ms"
14
- },
15
- {
16
- "test": "context_operations",
17
- "operations": [
18
- {
19
- "operation": "version_check",
20
- "duration": 398.65762500000005,
21
- "success": true
22
- },
23
- {
24
- "operation": "tasks_list",
25
- "duration": 518.715792,
26
- "success": true
27
- }
28
- ],
29
- "totalTime": 917.373417,
30
- "unit": "ms"
31
- },
32
- {
33
- "test": "task_operations",
34
- "operations": [
35
- {
36
- "operation": "add_task",
37
- "duration": 518.383875,
38
- "success": true,
39
- "outputSize": 245
40
- },
41
- {
42
- "operation": "list_tasks",
43
- "duration": 526.2628340000001,
44
- "success": true,
45
- "outputSize": 2751
46
- },
47
- {
48
- "operation": "show_task",
49
- "duration": 395.6398339999996,
50
- "success": true,
51
- "outputSize": 92
52
- }
53
- ],
54
- "unit": "ms"
55
- },
56
- {
57
- "test": "storage_performance",
58
- "results": {
59
- "database": {
60
- "exists": true,
61
- "size": 602112,
62
- "sizeFormatted": "588.00 KB",
63
- "modified": "2026-01-06T15:16:54.814Z"
64
- },
65
- "tasks": {
66
- "exists": true,
67
- "size": 219410,
68
- "sizeFormatted": "214.27 KB",
69
- "lineCount": 249,
70
- "modified": "2026-01-06T15:16:54.286Z"
71
- }
72
- }
73
- },
74
- {
75
- "test": "baseline_comparison",
76
- "baseline": {
77
- "taskListing": {
78
- "withStackMemory": 501.72233400000005,
79
- "withoutStackMemory": 5000,
80
- "unit": "ms"
81
- },
82
- "taskCreation": {
83
- "withStackMemory": 500.09279100000003,
84
- "withoutStackMemory": 30000,
85
- "unit": "ms"
86
- }
87
- }
88
- }
89
- ]
90
- }
@@ -1,100 +0,0 @@
1
- #!/usr/bin/env node
2
- import 'dotenv/config';
3
- import Database from 'better-sqlite3';
4
- import { RailwayOptimizedStorage } from './dist/core/storage/railway-optimized-storage.js';
5
- import { ConfigManager } from './dist/core/config/config-manager.js';
6
- import { v4 as uuidv4 } from 'uuid';
7
-
8
- async function testTierMigration() {
9
- const db = new Database('.stackmemory/context.db');
10
- const configManager = new ConfigManager();
11
-
12
- // Create storage with shorter tier durations for testing
13
- const storage = new RailwayOptimizedStorage(db, configManager, {
14
- tiers: {
15
- hotHours: 0.001, // Very short for testing (3.6 seconds)
16
- warmDays: 0.0001, // Very short for testing (8.64 seconds)
17
- compressionScore: 0.5
18
- }
19
- });
20
-
21
- // Create a test trace
22
- const traceId = `test_${uuidv4()}`;
23
- const testTrace = {
24
- id: traceId,
25
- type: 'test',
26
- score: 0.7,
27
- summary: 'Test trace for tier migration',
28
- metadata: {
29
- startTime: Date.now() - 1000, // 1 second ago
30
- endTime: Date.now(),
31
- filesModified: ['test.js'],
32
- errorsEncountered: [],
33
- decisionsRecorded: [],
34
- causalChain: []
35
- },
36
- tools: [
37
- { tool: 'test', input: 'test input', output: 'test output' }
38
- ],
39
- compressed: false
40
- };
41
-
42
- console.log('📝 Creating test trace:', testTrace.id);
43
-
44
- // First, insert the trace into the traces table to satisfy foreign key
45
- db.prepare(`
46
- INSERT INTO traces (id, type, score, summary, start_time, end_time,
47
- files_modified, errors_encountered, decisions_recorded,
48
- causal_chain, compressed_data, created_at)
49
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
50
- `).run(
51
- traceId,
52
- 'test',
53
- 0.7,
54
- 'Test trace for tier migration',
55
- testTrace.metadata.startTime,
56
- testTrace.metadata.endTime,
57
- JSON.stringify(testTrace.metadata.filesModified),
58
- JSON.stringify(testTrace.metadata.errorsEncountered),
59
- JSON.stringify(testTrace.metadata.decisionsRecorded),
60
- testTrace.metadata.causalChain.length,
61
- JSON.stringify(testTrace),
62
- Date.now()
63
- );
64
-
65
- // Store the trace in storage tiers
66
- const tier = await storage.storeTrace(testTrace);
67
- console.log(`✅ Stored in ${tier} tier`);
68
-
69
- // Check storage location
70
- const location = db.prepare('SELECT * FROM storage_tiers WHERE trace_id = ?').get(testTrace.id);
71
- console.log('📍 Initial location:', location);
72
-
73
- // Wait a moment for the trace to age
74
- console.log('⏳ Waiting 5 seconds for trace to age...');
75
- await new Promise(resolve => setTimeout(resolve, 5000));
76
-
77
- // Trigger migration
78
- console.log('🔄 Triggering migration...');
79
- const results = await storage.migrateTiers();
80
- console.log('Migration results:', results);
81
-
82
- // Check new location
83
- const newLocation = db.prepare('SELECT * FROM storage_tiers WHERE trace_id = ?').get(testTrace.id);
84
- console.log('📍 New location:', newLocation);
85
-
86
- // Try to retrieve the trace
87
- console.log('🔍 Retrieving trace after migration...');
88
- const retrieved = await storage.retrieveTrace(testTrace.id);
89
- console.log('✅ Retrieved:', retrieved ? 'Success' : 'Failed');
90
-
91
- if (retrieved) {
92
- console.log(' ID matches:', retrieved.id === testTrace.id);
93
- console.log(' Summary matches:', retrieved.summary === testTrace.summary);
94
- }
95
-
96
- db.close();
97
- console.log('✨ Test complete!');
98
- }
99
-
100
- testTierMigration().catch(console.error);