@stackmemoryai/stackmemory 0.3.17 ā 0.3.18
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/commands/skills.js +15 -2
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/index.js +113 -834
- package/dist/cli/index.js.map +3 -3
- package/dist/core/context/dual-stack-manager.js +1 -1
- package/dist/core/context/dual-stack-manager.js.map +1 -1
- package/dist/core/context/frame-manager.js +3 -0
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/integrations/claude-code/subagent-client.js +106 -3
- package/dist/integrations/claude-code/subagent-client.js.map +2 -2
- package/dist/servers/railway/config.js +51 -0
- package/dist/servers/railway/config.js.map +7 -0
- package/dist/servers/railway/index-enhanced.js +156 -0
- package/dist/servers/railway/index-enhanced.js.map +7 -0
- package/dist/servers/railway/minimal.js +48 -3
- package/dist/servers/railway/minimal.js.map +2 -2
- package/dist/servers/railway/storage-test.js +455 -0
- package/dist/servers/railway/storage-test.js.map +7 -0
- package/dist/skills/claude-skills.js +13 -12
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/recursive-agent-orchestrator.js +27 -18
- package/dist/skills/recursive-agent-orchestrator.js.map +2 -2
- package/dist/skills/unified-rlm-orchestrator.js.map +2 -2
- package/package.json +6 -18
- package/scripts/README-TESTING.md +186 -0
- package/scripts/analyze-cli-security.js +288 -0
- package/scripts/archive/add-phase-tasks-to-linear.js +163 -0
- package/scripts/archive/analyze-linear-duplicates.js +214 -0
- package/scripts/archive/analyze-remaining-duplicates.js +230 -0
- package/scripts/archive/analyze-sta-duplicates.js +292 -0
- package/scripts/archive/analyze-sta-graphql.js +399 -0
- package/scripts/archive/cancel-duplicate-tasks.ts +246 -0
- package/scripts/archive/check-all-duplicates.ts +419 -0
- package/scripts/archive/clean-duplicate-tasks.js +114 -0
- package/scripts/archive/cleanup-duplicate-tasks.ts +286 -0
- package/scripts/archive/create-phase-tasks.js +387 -0
- package/scripts/archive/delete-linear-duplicates.js +182 -0
- package/scripts/archive/delete-remaining-duplicates.js +158 -0
- package/scripts/archive/delete-sta-duplicates.js +201 -0
- package/scripts/archive/delete-sta-oauth.js +201 -0
- package/scripts/archive/export-sta-tasks.js +62 -0
- package/scripts/archive/install-auto-sync.js +266 -0
- package/scripts/archive/install-chromadb-hooks.sh +133 -0
- package/scripts/archive/install-enhanced-clear-hooks.sh +431 -0
- package/scripts/archive/install-post-task-hooks.sh +289 -0
- package/scripts/archive/install-stackmemory-hooks.sh +420 -0
- package/scripts/archive/merge-linear-duplicates-safe.ts +362 -0
- package/scripts/archive/merge-linear-duplicates.ts +180 -0
- package/scripts/archive/remove-sta-tasks.js +70 -0
- package/scripts/archive/setup-background-sync.sh +168 -0
- package/scripts/archive/setup-claude-auto-triggers.sh +181 -0
- package/scripts/archive/setup-claude-autostart.sh +305 -0
- package/scripts/archive/setup-git-hooks.sh +25 -0
- package/scripts/archive/setup-linear-oauth.sh +46 -0
- package/scripts/archive/setup-mcp.sh +113 -0
- package/scripts/archive/setup-railway-deployment.sh +81 -0
- package/scripts/auto-handoff.sh +262 -0
- package/scripts/background-sync-manager.js +416 -0
- package/scripts/benchmark-performance.ts +57 -0
- package/scripts/check-redis.ts +48 -0
- package/scripts/chromadb-auto-loader.sh +128 -0
- package/scripts/chromadb-context-loader.js +479 -0
- package/scripts/claude-chromadb-hook.js +460 -0
- package/scripts/claude-code-wrapper.sh +66 -0
- package/scripts/claude-linear-skill.js +455 -0
- package/scripts/claude-pre-commit.sh +302 -0
- package/scripts/claude-sm-autostart.js +532 -0
- package/scripts/claude-sm-setup.sh +367 -0
- package/scripts/claude-with-chromadb.sh +69 -0
- package/scripts/claude-worktree-manager.sh +323 -0
- package/scripts/claude-worktree-monitor.sh +371 -0
- package/scripts/claude-worktree-setup.sh +327 -0
- package/scripts/clean-linear-backlog.js +273 -0
- package/scripts/cleanup-old-sessions.sh +57 -0
- package/scripts/codex-wrapper.sh +88 -0
- package/scripts/create-sandbox.sh +269 -0
- package/scripts/debug-linear-update.js +174 -0
- package/scripts/delete-linear-tasks.js +167 -0
- package/scripts/deploy.sh +89 -0
- package/scripts/deployment/railway.sh +352 -0
- package/scripts/deployment/test-deployment.js +194 -0
- package/scripts/detect-and-rehydrate.js +162 -0
- package/scripts/detect-and-rehydrate.mjs +165 -0
- package/scripts/development/create-demo-tasks.js +143 -0
- package/scripts/development/debug-frame-test.js +16 -0
- package/scripts/development/demo-auto-sync.js +128 -0
- package/scripts/development/fix-all-imports.js +213 -0
- package/scripts/development/fix-imports.js +229 -0
- package/scripts/development/fix-lint-loop.cjs +103 -0
- package/scripts/development/fix-project-id.ts +161 -0
- package/scripts/development/fix-strict-mode-issues.ts +291 -0
- package/scripts/development/reorganize-structure.sh +228 -0
- package/scripts/development/test-persistence-direct.js +148 -0
- package/scripts/development/test-persistence.js +114 -0
- package/scripts/development/test-tasks.js +93 -0
- package/scripts/development/update-imports.js +212 -0
- package/scripts/fetch-linear-status.js +125 -0
- package/scripts/git-hooks/README.md +310 -0
- package/scripts/git-hooks/branch-context-manager.sh +342 -0
- package/scripts/git-hooks/post-checkout-stackmemory.sh +63 -0
- package/scripts/git-hooks/post-commit-stackmemory.sh +305 -0
- package/scripts/git-hooks/pre-commit-stackmemory.sh +275 -0
- package/scripts/hooks/cleanup-shell.sh +130 -0
- package/scripts/hooks/task-complete.sh +114 -0
- package/scripts/initialize.ts +129 -0
- package/scripts/install-claude-hooks-auto.js +104 -0
- package/scripts/install-claude-hooks.sh +133 -0
- package/scripts/install-global.sh +296 -0
- package/scripts/install.sh +235 -0
- package/scripts/linear-auto-sync.js +262 -0
- package/scripts/linear-auto-sync.sh +161 -0
- package/scripts/linear-sync-daemon.js +150 -0
- package/scripts/linear-task-review.js +237 -0
- package/scripts/list-linear-tasks.ts +178 -0
- package/scripts/mcp-proxy.js +66 -0
- package/scripts/opencode-wrapper.sh +85 -0
- package/scripts/publish-local.js +74 -0
- package/scripts/query-chromadb.ts +201 -0
- package/scripts/railway-env-setup.sh +39 -0
- package/scripts/reconcile-local-tasks.js +170 -0
- package/scripts/recreate-frames-db.js +89 -0
- package/scripts/setup/claude-integration.js +138 -0
- package/scripts/setup/configure-alias.js +125 -0
- package/scripts/setup/configure-codex-alias.js +161 -0
- package/scripts/setup/configure-opencode-alias.js +175 -0
- package/scripts/setup-claude-integration.js +204 -0
- package/scripts/setup-claude-integration.sh +183 -0
- package/scripts/setup.sh +31 -0
- package/scripts/show-linear-summary.ts +172 -0
- package/scripts/stackmemory-auto-handoff.sh +231 -0
- package/scripts/stackmemory-daemon.sh +40 -0
- package/scripts/start-linear-sync-daemon.sh +141 -0
- package/scripts/start-temporal-paradox.sh +214 -0
- package/scripts/status.ts +159 -0
- package/scripts/sync-and-clean-tasks.js +258 -0
- package/scripts/sync-frames-from-railway.js +228 -0
- package/scripts/sync-linear-graphql.js +303 -0
- package/scripts/sync-linear-tasks.js +186 -0
- package/scripts/test-auto-triggers.sh +57 -0
- package/scripts/test-browser-mcp.js +74 -0
- package/scripts/test-chromadb-full.js +115 -0
- package/scripts/test-chromadb-hooks.sh +28 -0
- package/scripts/test-chromadb-sync.ts +245 -0
- package/scripts/test-cli-security.js +293 -0
- package/scripts/test-hooks-persistence.sh +220 -0
- package/scripts/test-installation-scenarios.sh +359 -0
- package/scripts/test-installation.sh +224 -0
- package/scripts/test-mcp.js +163 -0
- package/scripts/test-pre-publish-quick.sh +75 -0
- package/scripts/test-quality-gates.sh +263 -0
- package/scripts/test-railway-db.js +222 -0
- package/scripts/test-redis-storage.ts +490 -0
- package/scripts/test-rlm-basic.sh +122 -0
- package/scripts/test-rlm-comprehensive.sh +260 -0
- package/scripts/test-rlm-e2e.sh +268 -0
- package/scripts/test-rlm-simple.js +90 -0
- package/scripts/test-rlm.js +110 -0
- package/scripts/test-session-handoff.sh +165 -0
- package/scripts/test-shell-integration.sh +275 -0
- package/scripts/testing/ab-test-runner.ts +508 -0
- package/scripts/testing/collect-metrics.ts +457 -0
- package/scripts/testing/quick-effectiveness-demo.js +187 -0
- package/scripts/testing/real-performance-test.js +422 -0
- package/scripts/testing/run-effectiveness-tests.sh +176 -0
- package/scripts/testing/scripts/testing/ab-test-runner.js +363 -0
- package/scripts/testing/scripts/testing/collect-metrics.js +292 -0
- package/scripts/testing/simple-effectiveness-test.js +310 -0
- package/scripts/testing/src/core/context/context-bridge.js +253 -0
- package/scripts/testing/src/core/context/frame-manager.js +746 -0
- package/scripts/testing/src/core/context/shared-context-layer.js +437 -0
- package/scripts/testing/src/core/database/database-adapter.js +54 -0
- package/scripts/testing/src/core/errors/index.js +291 -0
- package/scripts/testing/src/core/errors/recovery.js +268 -0
- package/scripts/testing/src/core/monitoring/logger.js +145 -0
- package/scripts/testing/src/core/retrieval/context-retriever.js +516 -0
- package/scripts/testing/src/core/session/index.js +1 -0
- package/scripts/testing/src/core/session/session-manager.js +323 -0
- package/scripts/testing/src/core/trace/cli-trace-wrapper.js +140 -0
- package/scripts/testing/src/core/trace/db-trace-wrapper.js +251 -0
- package/scripts/testing/src/core/trace/debug-trace.js +398 -0
- package/scripts/testing/src/core/trace/index.js +120 -0
- package/scripts/testing/src/core/trace/linear-api-wrapper.js +204 -0
- package/scripts/update-linear-status.js +268 -0
- package/scripts/update-linear-tasks-fixed.js +284 -0
- package/templates/claude-hooks/hooks.json +5 -0
- package/templates/claude-hooks/on-clear.js +56 -0
- package/templates/claude-hooks/on-startup.js +56 -0
- package/templates/claude-hooks/tool-use-trace.js +67 -0
- package/dist/features/tui/components/analytics-panel.js +0 -157
- package/dist/features/tui/components/analytics-panel.js.map +0 -7
- package/dist/features/tui/components/frame-visualizer.js +0 -377
- package/dist/features/tui/components/frame-visualizer.js.map +0 -7
- package/dist/features/tui/components/pr-tracker.js +0 -135
- package/dist/features/tui/components/pr-tracker.js.map +0 -7
- package/dist/features/tui/components/session-monitor.js +0 -299
- package/dist/features/tui/components/session-monitor.js.map +0 -7
- package/dist/features/tui/components/subagent-fleet.js +0 -395
- package/dist/features/tui/components/subagent-fleet.js.map +0 -7
- package/dist/features/tui/components/task-board.js +0 -1139
- package/dist/features/tui/components/task-board.js.map +0 -7
- package/dist/features/tui/index.js +0 -408
- package/dist/features/tui/index.js.map +0 -7
- package/dist/features/tui/services/data-service.js +0 -641
- package/dist/features/tui/services/data-service.js.map +0 -7
- package/dist/features/tui/services/linear-task-reader.js +0 -102
- package/dist/features/tui/services/linear-task-reader.js.map +0 -7
- package/dist/features/tui/services/websocket-client.js +0 -162
- package/dist/features/tui/services/websocket-client.js.map +0 -7
- package/dist/features/tui/terminal-compat.js +0 -220
- package/dist/features/tui/terminal-compat.js.map +0 -7
- package/dist/features/tui/types.js +0 -1
- package/dist/features/tui/types.js.map +0 -7
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Test script for Redis trace storage
|
|
4
|
+
* Tests the 3-tier storage system with Redis hot tier
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createClient } from 'redis';
|
|
8
|
+
import Database from 'better-sqlite3';
|
|
9
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import ora from 'ora';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
14
|
+
import { RailwayOptimizedStorage } from '../src/core/storage/railway-optimized-storage.js';
|
|
15
|
+
import { ConfigManager } from '../src/core/config/config-manager.js';
|
|
16
|
+
import { Trace, TraceType, ToolCall } from '../src/core/trace/types.js';
|
|
17
|
+
|
|
18
|
+
// Load environment variables
|
|
19
|
+
import dotenv from 'dotenv';
|
|
20
|
+
// Type-safe environment variable access
|
|
21
|
+
function getEnv(key: string, defaultValue?: string): string {
|
|
22
|
+
const value = process.env[key];
|
|
23
|
+
if (value === undefined) {
|
|
24
|
+
if (defaultValue !== undefined) return defaultValue;
|
|
25
|
+
throw new Error(`Environment variable ${key} is required`);
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getOptionalEnv(key: string): string | undefined {
|
|
31
|
+
return process.env[key];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
dotenv.config();
|
|
35
|
+
|
|
36
|
+
async function testRedisConnection() {
|
|
37
|
+
const spinner = ora('Testing Redis connection...').start();
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const redisUrl = process.env['REDIS_URL'] || 'redis://localhost:6379';
|
|
41
|
+
console.log(
|
|
42
|
+
chalk.gray(
|
|
43
|
+
` Using Redis URL: ${redisUrl.replace(/:[^:@]+@/, ':****@')})`
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
const client = createClient({ url: redisUrl });
|
|
47
|
+
|
|
48
|
+
await client.connect();
|
|
49
|
+
|
|
50
|
+
// Test basic operations
|
|
51
|
+
const testKey = 'test:connection';
|
|
52
|
+
await client.set(testKey, 'connected');
|
|
53
|
+
const result = await client.get(testKey);
|
|
54
|
+
await client.del(testKey);
|
|
55
|
+
|
|
56
|
+
if (result === 'connected') {
|
|
57
|
+
spinner.succeed(`Redis connected successfully at ${redisUrl}`);
|
|
58
|
+
|
|
59
|
+
// Get Redis info
|
|
60
|
+
const info = await client.info('memory');
|
|
61
|
+
const memoryUsed = info.match(/used_memory_human:(\S+)/)?.[1];
|
|
62
|
+
console.log(chalk.gray(` Memory used: ${memoryUsed || 'unknown'}`));
|
|
63
|
+
} else {
|
|
64
|
+
spinner.fail('Redis connection test failed');
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
await client.quit();
|
|
69
|
+
return true;
|
|
70
|
+
} catch (error: unknown) {
|
|
71
|
+
spinner.fail(`Redis connection failed: ${error}`);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function createMockTrace(index: number): Trace {
|
|
77
|
+
const now = Date.now() - index * 60 * 60 * 1000; // Offset by hours
|
|
78
|
+
const tools: ToolCall[] = [
|
|
79
|
+
{
|
|
80
|
+
id: uuidv4(),
|
|
81
|
+
tool: 'search',
|
|
82
|
+
timestamp: now,
|
|
83
|
+
arguments: { query: `test query ${index}` },
|
|
84
|
+
filesAffected: ['src/test.ts', 'src/index.ts'],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: uuidv4(),
|
|
88
|
+
tool: 'read',
|
|
89
|
+
timestamp: now + 1000,
|
|
90
|
+
arguments: { file: 'src/test.ts' },
|
|
91
|
+
result: 'file contents',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: uuidv4(),
|
|
95
|
+
tool: 'edit',
|
|
96
|
+
timestamp: now + 2000,
|
|
97
|
+
arguments: { file: 'src/test.ts', changes: 'some changes' },
|
|
98
|
+
filesAffected: ['src/test.ts'],
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: uuidv4(),
|
|
102
|
+
tool: 'test',
|
|
103
|
+
timestamp: now + 3000,
|
|
104
|
+
arguments: { command: 'npm test' },
|
|
105
|
+
result: 'tests passed',
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
const trace: Trace = {
|
|
110
|
+
id: uuidv4(),
|
|
111
|
+
type: TraceType.SEARCH_DRIVEN,
|
|
112
|
+
tools,
|
|
113
|
+
score: 0.5 + Math.random() * 0.5, // Random score 0.5-1.0
|
|
114
|
+
summary: `Test trace #${index}: Search-driven modification`,
|
|
115
|
+
metadata: {
|
|
116
|
+
startTime: now,
|
|
117
|
+
endTime: now + 4000,
|
|
118
|
+
filesModified: ['src/test.ts'],
|
|
119
|
+
errorsEncountered: index % 3 === 0 ? ['Test error'] : [],
|
|
120
|
+
decisionsRecorded: index % 2 === 0 ? ['Use async pattern'] : [],
|
|
121
|
+
causalChain: index % 3 === 0,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
return trace;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function testStorageOperations() {
|
|
129
|
+
console.log(chalk.blue('\nš¦ Testing Storage Operations'));
|
|
130
|
+
console.log(chalk.gray('ā'.repeat(50)));
|
|
131
|
+
|
|
132
|
+
// Setup database
|
|
133
|
+
const dbDir = join(process.cwd(), '.stackmemory');
|
|
134
|
+
if (!existsSync(dbDir)) {
|
|
135
|
+
mkdirSync(dbDir, { recursive: true });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const dbPath = join(dbDir, 'test-context.db');
|
|
139
|
+
const db = new Database(dbPath);
|
|
140
|
+
|
|
141
|
+
// Initialize trace tables
|
|
142
|
+
db.exec(`
|
|
143
|
+
CREATE TABLE IF NOT EXISTS traces (
|
|
144
|
+
id TEXT PRIMARY KEY,
|
|
145
|
+
type TEXT NOT NULL,
|
|
146
|
+
score REAL NOT NULL,
|
|
147
|
+
summary TEXT NOT NULL,
|
|
148
|
+
start_time INTEGER NOT NULL,
|
|
149
|
+
end_time INTEGER NOT NULL,
|
|
150
|
+
frame_id TEXT,
|
|
151
|
+
user_id TEXT,
|
|
152
|
+
files_modified TEXT,
|
|
153
|
+
errors_encountered TEXT,
|
|
154
|
+
decisions_recorded TEXT,
|
|
155
|
+
causal_chain INTEGER,
|
|
156
|
+
compressed_data TEXT,
|
|
157
|
+
created_at INTEGER DEFAULT (unixepoch())
|
|
158
|
+
)
|
|
159
|
+
`);
|
|
160
|
+
|
|
161
|
+
db.exec(`
|
|
162
|
+
CREATE TABLE IF NOT EXISTS tool_calls (
|
|
163
|
+
id TEXT PRIMARY KEY,
|
|
164
|
+
trace_id TEXT NOT NULL,
|
|
165
|
+
tool TEXT NOT NULL,
|
|
166
|
+
arguments TEXT,
|
|
167
|
+
timestamp INTEGER NOT NULL,
|
|
168
|
+
result TEXT,
|
|
169
|
+
error TEXT,
|
|
170
|
+
files_affected TEXT,
|
|
171
|
+
duration INTEGER,
|
|
172
|
+
sequence_number INTEGER NOT NULL,
|
|
173
|
+
FOREIGN KEY (trace_id) REFERENCES traces(id) ON DELETE CASCADE
|
|
174
|
+
)
|
|
175
|
+
`);
|
|
176
|
+
|
|
177
|
+
// Create storage_tiers table required by RailwayOptimizedStorage
|
|
178
|
+
db.exec(`
|
|
179
|
+
CREATE TABLE IF NOT EXISTS storage_tiers (
|
|
180
|
+
trace_id TEXT PRIMARY KEY,
|
|
181
|
+
tier TEXT NOT NULL,
|
|
182
|
+
location TEXT NOT NULL,
|
|
183
|
+
original_size INTEGER,
|
|
184
|
+
compressed_size INTEGER,
|
|
185
|
+
compression_ratio REAL,
|
|
186
|
+
access_count INTEGER DEFAULT 0,
|
|
187
|
+
last_accessed INTEGER DEFAULT (unixepoch()),
|
|
188
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
189
|
+
migrated_at INTEGER,
|
|
190
|
+
score REAL,
|
|
191
|
+
migration_score REAL,
|
|
192
|
+
metadata TEXT,
|
|
193
|
+
FOREIGN KEY (trace_id) REFERENCES traces(id) ON DELETE CASCADE
|
|
194
|
+
)
|
|
195
|
+
`);
|
|
196
|
+
|
|
197
|
+
// Create indexes for storage_tiers
|
|
198
|
+
db.exec(`
|
|
199
|
+
CREATE INDEX IF NOT EXISTS idx_storage_tier ON storage_tiers(tier);
|
|
200
|
+
CREATE INDEX IF NOT EXISTS idx_storage_created ON storage_tiers(created_at);
|
|
201
|
+
CREATE INDEX IF NOT EXISTS idx_storage_accessed ON storage_tiers(last_accessed);
|
|
202
|
+
`);
|
|
203
|
+
|
|
204
|
+
const configManager = new ConfigManager();
|
|
205
|
+
|
|
206
|
+
// Initialize storage with Redis URL from environment
|
|
207
|
+
const storage = new RailwayOptimizedStorage(db, configManager, {
|
|
208
|
+
redis: {
|
|
209
|
+
url: process.env['REDIS_URL'],
|
|
210
|
+
ttlSeconds: 24 * 60 * 60, // 24 hours
|
|
211
|
+
maxMemory: '100mb',
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Test storing traces
|
|
216
|
+
const traces: Trace[] = [];
|
|
217
|
+
const results: { id: string; tier: string; score: number }[] = [];
|
|
218
|
+
|
|
219
|
+
console.log(chalk.yellow('\nāļø Creating and storing test traces...'));
|
|
220
|
+
|
|
221
|
+
for (let i = 0; i < 10; i++) {
|
|
222
|
+
const trace = createMockTrace(i);
|
|
223
|
+
traces.push(trace);
|
|
224
|
+
|
|
225
|
+
const spinner = ora(`Storing trace #${i + 1}...`).start();
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
// First insert the trace into the traces table
|
|
229
|
+
const insertTrace = db.prepare(`
|
|
230
|
+
INSERT INTO traces (
|
|
231
|
+
id, type, score, summary, start_time, end_time,
|
|
232
|
+
files_modified, errors_encountered, decisions_recorded, causal_chain,
|
|
233
|
+
created_at
|
|
234
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
235
|
+
`);
|
|
236
|
+
|
|
237
|
+
insertTrace.run(
|
|
238
|
+
trace.id,
|
|
239
|
+
trace.type,
|
|
240
|
+
trace.score,
|
|
241
|
+
trace.summary,
|
|
242
|
+
trace.metadata.startTime,
|
|
243
|
+
trace.metadata.endTime,
|
|
244
|
+
JSON.stringify(trace.metadata.filesModified || []),
|
|
245
|
+
JSON.stringify(trace.metadata.errorsEncountered || []),
|
|
246
|
+
JSON.stringify(trace.metadata.decisionsRecorded || []),
|
|
247
|
+
trace.metadata.causalChain ? 1 : 0,
|
|
248
|
+
Date.now()
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
// Insert tool calls
|
|
252
|
+
const insertToolCall = db.prepare(`
|
|
253
|
+
INSERT INTO tool_calls (
|
|
254
|
+
id, trace_id, tool, arguments, timestamp, result, files_affected, sequence_number
|
|
255
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
256
|
+
`);
|
|
257
|
+
|
|
258
|
+
trace.tools.forEach((tool, index) => {
|
|
259
|
+
insertToolCall.run(
|
|
260
|
+
tool.id,
|
|
261
|
+
trace.id,
|
|
262
|
+
tool.tool,
|
|
263
|
+
JSON.stringify(tool.arguments),
|
|
264
|
+
tool.timestamp,
|
|
265
|
+
tool.result || null,
|
|
266
|
+
JSON.stringify(tool.filesAffected || []),
|
|
267
|
+
index
|
|
268
|
+
);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Now store in tiered storage
|
|
272
|
+
const tier = await storage.storeTrace(trace);
|
|
273
|
+
results.push({ id: trace.id, tier, score: trace.score });
|
|
274
|
+
|
|
275
|
+
const tierIcon = tier === 'hot' ? 'š„' : tier === 'warm' ? 'āļø' : 'āļø';
|
|
276
|
+
spinner.succeed(
|
|
277
|
+
`Trace #${i + 1} stored in ${tierIcon} ${tier} tier (score: ${trace.score.toFixed(2)})`
|
|
278
|
+
);
|
|
279
|
+
} catch (error: unknown) {
|
|
280
|
+
spinner.fail(`Failed to store trace #${i + 1}: ${error}`);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Small delay
|
|
284
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Test retrieval
|
|
288
|
+
console.log(chalk.yellow('\nš Testing trace retrieval...'));
|
|
289
|
+
|
|
290
|
+
for (let i = 0; i < 3; i++) {
|
|
291
|
+
const result = results[i];
|
|
292
|
+
const spinner = ora(
|
|
293
|
+
`Retrieving trace ${result.id.substring(0, 8)}...`
|
|
294
|
+
).start();
|
|
295
|
+
|
|
296
|
+
try {
|
|
297
|
+
const retrieved = await storage.retrieveTrace(result.id);
|
|
298
|
+
|
|
299
|
+
if (retrieved) {
|
|
300
|
+
spinner.succeed(
|
|
301
|
+
`Retrieved from ${result.tier} tier: ${retrieved.summary}`
|
|
302
|
+
);
|
|
303
|
+
} else {
|
|
304
|
+
spinner.fail('Trace not found');
|
|
305
|
+
}
|
|
306
|
+
} catch (error: unknown) {
|
|
307
|
+
spinner.fail(`Retrieval failed: ${error}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Get storage statistics
|
|
312
|
+
console.log(chalk.yellow('\nš Storage Statistics:'));
|
|
313
|
+
|
|
314
|
+
const stats = storage.getStorageStats();
|
|
315
|
+
|
|
316
|
+
console.log(chalk.gray('ā'.repeat(50)));
|
|
317
|
+
for (const tier of stats.byTier) {
|
|
318
|
+
const icon =
|
|
319
|
+
tier.tier === 'hot' ? 'š„' : tier.tier === 'warm' ? 'āļø' : 'āļø';
|
|
320
|
+
console.log(`${icon} ${chalk.bold(tier.tier.toUpperCase())} Tier:`);
|
|
321
|
+
console.log(` Traces: ${tier.count}`);
|
|
322
|
+
console.log(` Original Size: ${formatBytes(tier.total_original || 0)}`);
|
|
323
|
+
console.log(` Compressed: ${formatBytes(tier.total_compressed || 0)}`);
|
|
324
|
+
if (tier.avg_compression) {
|
|
325
|
+
console.log(
|
|
326
|
+
` Compression: ${(tier.avg_compression * 100).toFixed(1)}%`
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Test Redis-specific operations
|
|
332
|
+
console.log(chalk.yellow('\nš„ Testing Redis Hot Tier...'));
|
|
333
|
+
|
|
334
|
+
const redisClient = createClient({ url: process.env['REDIS_URL'] });
|
|
335
|
+
await redisClient.connect();
|
|
336
|
+
|
|
337
|
+
// Check stored traces in Redis
|
|
338
|
+
const keys = await redisClient.keys('trace:*');
|
|
339
|
+
console.log(` Traces in Redis: ${chalk.green(keys.length)}`);
|
|
340
|
+
|
|
341
|
+
// Check sorted sets
|
|
342
|
+
const byScore = await redisClient.zCard('traces:by_score');
|
|
343
|
+
const byTime = await redisClient.zCard('traces:by_time');
|
|
344
|
+
console.log(` Score index: ${chalk.green(byScore)} entries`);
|
|
345
|
+
console.log(` Time index: ${chalk.green(byTime)} entries`);
|
|
346
|
+
|
|
347
|
+
// Get top traces by score
|
|
348
|
+
const topTraces = await redisClient.zRangeWithScores(
|
|
349
|
+
'traces:by_score',
|
|
350
|
+
-3,
|
|
351
|
+
-1
|
|
352
|
+
);
|
|
353
|
+
if (topTraces.length > 0) {
|
|
354
|
+
console.log(chalk.yellow('\nš Top Traces by Score:'));
|
|
355
|
+
for (const trace of topTraces.reverse()) {
|
|
356
|
+
console.log(
|
|
357
|
+
` ${trace.value.substring(0, 8)}... - Score: ${trace.score.toFixed(3)}`
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Memory usage
|
|
363
|
+
const memInfo = await redisClient.memoryUsage('trace:' + results[0]?.id);
|
|
364
|
+
if (memInfo) {
|
|
365
|
+
console.log(chalk.yellow('\nš¾ Memory Usage:'));
|
|
366
|
+
console.log(` Sample trace memory: ${formatBytes(memInfo)}`);
|
|
367
|
+
console.log(` Estimated total: ${formatBytes(memInfo * keys.length)}`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
await redisClient.quit();
|
|
371
|
+
|
|
372
|
+
// Test migration
|
|
373
|
+
console.log(chalk.yellow('\nš Testing tier migration...'));
|
|
374
|
+
|
|
375
|
+
const migrationResults = await storage.migrateTiers();
|
|
376
|
+
console.log(
|
|
377
|
+
` Hot ā Warm: ${chalk.yellow(migrationResults.hotToWarm)} traces`
|
|
378
|
+
);
|
|
379
|
+
console.log(
|
|
380
|
+
` Warm ā Cold: ${chalk.cyan(migrationResults.warmToCold)} traces`
|
|
381
|
+
);
|
|
382
|
+
if (migrationResults.errors.length > 0) {
|
|
383
|
+
console.log(chalk.red(` Errors: ${migrationResults.errors.length}`));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Cleanup
|
|
387
|
+
db.close();
|
|
388
|
+
|
|
389
|
+
console.log(chalk.green('\nā
Storage tests completed successfully!'));
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function formatBytes(bytes: number): string {
|
|
393
|
+
if (bytes === 0) return '0 B';
|
|
394
|
+
const k = 1024;
|
|
395
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
396
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
397
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async function main() {
|
|
401
|
+
console.log(chalk.blue.bold('\nš§Ŗ StackMemory Redis Storage Test\n'));
|
|
402
|
+
|
|
403
|
+
// Test Redis connection
|
|
404
|
+
const redisConnected = await testRedisConnection();
|
|
405
|
+
|
|
406
|
+
if (!redisConnected) {
|
|
407
|
+
console.log(chalk.red('\nā Cannot proceed without Redis connection'));
|
|
408
|
+
console.log(chalk.yellow('\nTo fix:'));
|
|
409
|
+
console.log('1. Ensure Redis is running');
|
|
410
|
+
console.log('2. Check REDIS_URL in .env file');
|
|
411
|
+
console.log('3. For Railway: Ensure Redis addon is provisioned');
|
|
412
|
+
process.exit(1);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Test storage operations
|
|
416
|
+
await testStorageOperations();
|
|
417
|
+
|
|
418
|
+
// Interactive test
|
|
419
|
+
console.log(chalk.blue('\nš® Interactive Test'));
|
|
420
|
+
console.log(chalk.gray('ā'.repeat(50)));
|
|
421
|
+
console.log(
|
|
422
|
+
chalk.cyan('You can now use the CLI to interact with the stored traces:')
|
|
423
|
+
);
|
|
424
|
+
console.log();
|
|
425
|
+
console.log(
|
|
426
|
+
' ' +
|
|
427
|
+
chalk.white('stackmemory storage status') +
|
|
428
|
+
' - View storage statistics'
|
|
429
|
+
);
|
|
430
|
+
console.log(
|
|
431
|
+
' ' +
|
|
432
|
+
chalk.white('stackmemory storage migrate') +
|
|
433
|
+
' - Migrate traces between tiers'
|
|
434
|
+
);
|
|
435
|
+
console.log(
|
|
436
|
+
' ' +
|
|
437
|
+
chalk.white('stackmemory storage retrieve <id>') +
|
|
438
|
+
' - Retrieve a specific trace'
|
|
439
|
+
);
|
|
440
|
+
console.log();
|
|
441
|
+
console.log(chalk.gray('Trace IDs from this test:'));
|
|
442
|
+
|
|
443
|
+
// Show first 3 trace IDs for testing
|
|
444
|
+
const dbPath = join(process.cwd(), '.stackmemory', 'test-context.db');
|
|
445
|
+
const db = new Database(dbPath);
|
|
446
|
+
|
|
447
|
+
// Make sure storage_tiers table exists before querying
|
|
448
|
+
db.exec(`
|
|
449
|
+
CREATE TABLE IF NOT EXISTS storage_tiers (
|
|
450
|
+
trace_id TEXT PRIMARY KEY,
|
|
451
|
+
tier TEXT NOT NULL,
|
|
452
|
+
location TEXT NOT NULL,
|
|
453
|
+
original_size INTEGER,
|
|
454
|
+
compressed_size INTEGER,
|
|
455
|
+
compression_ratio REAL,
|
|
456
|
+
access_count INTEGER DEFAULT 0,
|
|
457
|
+
last_accessed INTEGER DEFAULT (unixepoch()),
|
|
458
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
459
|
+
migrated_at INTEGER,
|
|
460
|
+
score REAL,
|
|
461
|
+
migration_score REAL,
|
|
462
|
+
metadata TEXT
|
|
463
|
+
)
|
|
464
|
+
`);
|
|
465
|
+
|
|
466
|
+
const recentTraces = db
|
|
467
|
+
.prepare(
|
|
468
|
+
`
|
|
469
|
+
SELECT trace_id, tier FROM storage_tiers
|
|
470
|
+
ORDER BY created_at DESC LIMIT 3
|
|
471
|
+
`
|
|
472
|
+
)
|
|
473
|
+
.all() as Array<{ trace_id: string; tier: string }>;
|
|
474
|
+
|
|
475
|
+
for (const trace of recentTraces) {
|
|
476
|
+
const tierIcon =
|
|
477
|
+
trace.tier === 'hot' ? 'š„' : trace.tier === 'warm' ? 'āļø' : 'āļø';
|
|
478
|
+
console.log(` ${tierIcon} ${trace.trace_id}`);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
db.close();
|
|
482
|
+
|
|
483
|
+
console.log(chalk.green('\n⨠Test complete!'));
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Run the test
|
|
487
|
+
main().catch((error) => {
|
|
488
|
+
console.error(chalk.red('Test failed:'), error);
|
|
489
|
+
process.exit(1);
|
|
490
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Basic RLM functionality test
|
|
4
|
+
echo "================================"
|
|
5
|
+
echo "Basic RLM End-to-End Test"
|
|
6
|
+
echo "================================"
|
|
7
|
+
echo ""
|
|
8
|
+
|
|
9
|
+
# Colors
|
|
10
|
+
GREEN='\033[0;32m'
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
YELLOW='\033[1;33m'
|
|
13
|
+
NC='\033[0m'
|
|
14
|
+
|
|
15
|
+
# Build first
|
|
16
|
+
echo "Building project..."
|
|
17
|
+
npm run build > /dev/null 2>&1
|
|
18
|
+
|
|
19
|
+
echo ""
|
|
20
|
+
echo "Test 1: Basic RLM Execution"
|
|
21
|
+
echo "----------------------------"
|
|
22
|
+
OUTPUT=$(stackmemory skills rlm "Create a hello world function" 2>&1)
|
|
23
|
+
echo "$OUTPUT" | head -20
|
|
24
|
+
|
|
25
|
+
# Check for key components
|
|
26
|
+
echo ""
|
|
27
|
+
echo "Checking key components:"
|
|
28
|
+
|
|
29
|
+
if echo "$OUTPUT" | grep -q "RLM execution completed"; then
|
|
30
|
+
echo -e "${GREEN}ā RLM execution completed${NC}"
|
|
31
|
+
else
|
|
32
|
+
echo -e "${RED}ā RLM execution did not complete${NC}"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
if echo "$OUTPUT" | grep -q "Created frame"; then
|
|
36
|
+
echo -e "${GREEN}ā Frame created${NC}"
|
|
37
|
+
else
|
|
38
|
+
echo -e "${RED}ā Frame not created${NC}"
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
if echo "$OUTPUT" | grep -q "Closed frame"; then
|
|
42
|
+
echo -e "${GREEN}ā Frame closed${NC}"
|
|
43
|
+
else
|
|
44
|
+
echo -e "${RED}ā Frame not closed${NC}"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
if echo "$OUTPUT" | grep -q "planning subagent"; then
|
|
48
|
+
echo -e "${GREEN}ā Planning subagent spawned${NC}"
|
|
49
|
+
else
|
|
50
|
+
echo -e "${RED}ā Planning subagent not spawned${NC}"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if echo "$OUTPUT" | grep -q "Review stage.*complete"; then
|
|
54
|
+
echo -e "${GREEN}ā Review stage completed${NC}"
|
|
55
|
+
else
|
|
56
|
+
echo -e "${RED}ā Review stage not completed${NC}"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
if echo "$OUTPUT" | grep -q "Quality threshold met"; then
|
|
60
|
+
echo -e "${GREEN}ā Quality threshold met${NC}"
|
|
61
|
+
else
|
|
62
|
+
echo -e "${RED}ā Quality threshold not met${NC}"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
if echo "$OUTPUT" | grep -q "mockMode: true"; then
|
|
66
|
+
echo -e "${GREEN}ā Mock mode active${NC}"
|
|
67
|
+
else
|
|
68
|
+
echo -e "${RED}ā Mock mode not active${NC}"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
echo ""
|
|
72
|
+
echo "Test 2: Execution Summary"
|
|
73
|
+
echo "-------------------------"
|
|
74
|
+
echo "$OUTPUT" | grep -A 10 "Execution Summary"
|
|
75
|
+
|
|
76
|
+
echo ""
|
|
77
|
+
echo "Test 3: Frame Persistence"
|
|
78
|
+
echo "-------------------------"
|
|
79
|
+
FRAMES_BEFORE=$(stackmemory status 2>&1 | grep -oE "Frames: [0-9]+" | awk '{print $2}')
|
|
80
|
+
stackmemory skills rlm "Test task for frame counting" > /dev/null 2>&1
|
|
81
|
+
FRAMES_AFTER=$(stackmemory status 2>&1 | grep -oE "Frames: [0-9]+" | awk '{print $2}')
|
|
82
|
+
|
|
83
|
+
echo "Frames before: ${FRAMES_BEFORE:-0}"
|
|
84
|
+
echo "Frames after: ${FRAMES_AFTER:-0}"
|
|
85
|
+
|
|
86
|
+
if [ "${FRAMES_AFTER:-0}" -gt "${FRAMES_BEFORE:-0}" ]; then
|
|
87
|
+
echo -e "${GREEN}ā Frames persisted to database${NC}"
|
|
88
|
+
else
|
|
89
|
+
echo -e "${YELLOW}ā Frame count unchanged (may be cleaned up)${NC}"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
echo ""
|
|
93
|
+
echo "Test 4: Mock Subagent Responses"
|
|
94
|
+
echo "-------------------------------"
|
|
95
|
+
OUTPUT=$(stackmemory skills rlm "Create a REST API" 2>&1)
|
|
96
|
+
|
|
97
|
+
if echo "$OUTPUT" | grep -q "Mock .* subagent completed"; then
|
|
98
|
+
echo -e "${GREEN}ā Mock subagents responding${NC}"
|
|
99
|
+
else
|
|
100
|
+
echo -e "${RED}ā Mock subagents not responding${NC}"
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# Extract improvements if present
|
|
104
|
+
echo ""
|
|
105
|
+
echo "Improvements found:"
|
|
106
|
+
echo "$OUTPUT" | grep -A 5 "Improvements:" | head -6
|
|
107
|
+
|
|
108
|
+
echo ""
|
|
109
|
+
echo "Test 5: Error Handling"
|
|
110
|
+
echo "----------------------"
|
|
111
|
+
# This should handle gracefully even with problematic input
|
|
112
|
+
OUTPUT=$(stackmemory skills rlm "" 2>&1)
|
|
113
|
+
if echo "$OUTPUT" | grep -q "RLM execution completed\|failed"; then
|
|
114
|
+
echo -e "${GREEN}ā Empty input handled gracefully${NC}"
|
|
115
|
+
else
|
|
116
|
+
echo -e "${RED}ā Empty input caused crash${NC}"
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
echo ""
|
|
120
|
+
echo "================================"
|
|
121
|
+
echo "Test Complete"
|
|
122
|
+
echo "================================"
|