@stackmemoryai/stackmemory 0.3.17 → 0.3.19

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.
Files changed (234) hide show
  1. package/dist/cli/claude-sm.js +51 -5
  2. package/dist/cli/claude-sm.js.map +2 -2
  3. package/dist/cli/codex-sm.js +52 -19
  4. package/dist/cli/codex-sm.js.map +2 -2
  5. package/dist/cli/commands/db.js +143 -0
  6. package/dist/cli/commands/db.js.map +7 -0
  7. package/dist/cli/commands/login.js +50 -0
  8. package/dist/cli/commands/login.js.map +7 -0
  9. package/dist/cli/commands/migrate.js +178 -0
  10. package/dist/cli/commands/migrate.js.map +7 -0
  11. package/dist/cli/commands/onboard.js +158 -2
  12. package/dist/cli/commands/onboard.js.map +2 -2
  13. package/dist/cli/commands/skills.js +15 -2
  14. package/dist/cli/commands/skills.js.map +2 -2
  15. package/dist/cli/index.js +118 -834
  16. package/dist/cli/index.js.map +3 -3
  17. package/dist/core/context/dual-stack-manager.js +1 -1
  18. package/dist/core/context/dual-stack-manager.js.map +1 -1
  19. package/dist/core/context/frame-database.js +1 -0
  20. package/dist/core/context/frame-database.js.map +2 -2
  21. package/dist/core/context/frame-manager.js +59 -2
  22. package/dist/core/context/frame-manager.js.map +2 -2
  23. package/dist/core/database/database-adapter.js +6 -1
  24. package/dist/core/database/database-adapter.js.map +2 -2
  25. package/dist/core/database/sqlite-adapter.js +60 -2
  26. package/dist/core/database/sqlite-adapter.js.map +2 -2
  27. package/dist/integrations/claude-code/subagent-client.js +106 -3
  28. package/dist/integrations/claude-code/subagent-client.js.map +2 -2
  29. package/dist/servers/railway/config.js +51 -0
  30. package/dist/servers/railway/config.js.map +7 -0
  31. package/dist/servers/railway/index-enhanced.js +156 -0
  32. package/dist/servers/railway/index-enhanced.js.map +7 -0
  33. package/dist/servers/railway/index.js +843 -82
  34. package/dist/servers/railway/index.js.map +3 -3
  35. package/dist/servers/railway/minimal.js +48 -3
  36. package/dist/servers/railway/minimal.js.map +2 -2
  37. package/dist/servers/railway/storage-test.js +455 -0
  38. package/dist/servers/railway/storage-test.js.map +7 -0
  39. package/dist/skills/claude-skills.js +13 -12
  40. package/dist/skills/claude-skills.js.map +2 -2
  41. package/dist/skills/recursive-agent-orchestrator.js +27 -18
  42. package/dist/skills/recursive-agent-orchestrator.js.map +2 -2
  43. package/dist/skills/unified-rlm-orchestrator.js.map +2 -2
  44. package/package.json +13 -21
  45. package/scripts/README-TESTING.md +186 -0
  46. package/scripts/analyze-cli-security.js +288 -0
  47. package/scripts/archive/add-phase-tasks-to-linear.js +163 -0
  48. package/scripts/archive/analyze-linear-duplicates.js +214 -0
  49. package/scripts/archive/analyze-remaining-duplicates.js +230 -0
  50. package/scripts/archive/analyze-sta-duplicates.js +292 -0
  51. package/scripts/archive/analyze-sta-graphql.js +399 -0
  52. package/scripts/archive/cancel-duplicate-tasks.ts +246 -0
  53. package/scripts/archive/check-all-duplicates.ts +419 -0
  54. package/scripts/archive/clean-duplicate-tasks.js +114 -0
  55. package/scripts/archive/cleanup-duplicate-tasks.ts +286 -0
  56. package/scripts/archive/create-phase-tasks.js +387 -0
  57. package/scripts/archive/delete-linear-duplicates.js +182 -0
  58. package/scripts/archive/delete-remaining-duplicates.js +158 -0
  59. package/scripts/archive/delete-sta-duplicates.js +201 -0
  60. package/scripts/archive/delete-sta-oauth.js +201 -0
  61. package/scripts/archive/export-sta-tasks.js +62 -0
  62. package/scripts/archive/install-auto-sync.js +266 -0
  63. package/scripts/archive/install-chromadb-hooks.sh +133 -0
  64. package/scripts/archive/install-enhanced-clear-hooks.sh +431 -0
  65. package/scripts/archive/install-post-task-hooks.sh +289 -0
  66. package/scripts/archive/install-stackmemory-hooks.sh +420 -0
  67. package/scripts/archive/merge-linear-duplicates-safe.ts +362 -0
  68. package/scripts/archive/merge-linear-duplicates.ts +180 -0
  69. package/scripts/archive/remove-sta-tasks.js +70 -0
  70. package/scripts/archive/setup-background-sync.sh +168 -0
  71. package/scripts/archive/setup-claude-auto-triggers.sh +181 -0
  72. package/scripts/archive/setup-claude-autostart.sh +305 -0
  73. package/scripts/archive/setup-git-hooks.sh +25 -0
  74. package/scripts/archive/setup-linear-oauth.sh +46 -0
  75. package/scripts/archive/setup-mcp.sh +113 -0
  76. package/scripts/archive/setup-railway-deployment.sh +81 -0
  77. package/scripts/auto-handoff.sh +262 -0
  78. package/scripts/background-sync-manager.js +416 -0
  79. package/scripts/benchmark-performance.ts +57 -0
  80. package/scripts/check-redis.ts +48 -0
  81. package/scripts/chromadb-auto-loader.sh +128 -0
  82. package/scripts/chromadb-context-loader.js +479 -0
  83. package/scripts/claude-chromadb-hook.js +460 -0
  84. package/scripts/claude-code-wrapper.sh +66 -0
  85. package/scripts/claude-linear-skill.js +455 -0
  86. package/scripts/claude-pre-commit.sh +302 -0
  87. package/scripts/claude-sm-autostart.js +532 -0
  88. package/scripts/claude-sm-setup.sh +367 -0
  89. package/scripts/claude-with-chromadb.sh +69 -0
  90. package/scripts/claude-worktree-manager.sh +323 -0
  91. package/scripts/claude-worktree-monitor.sh +371 -0
  92. package/scripts/claude-worktree-setup.sh +327 -0
  93. package/scripts/clean-linear-backlog.js +273 -0
  94. package/scripts/cleanup-old-sessions.sh +57 -0
  95. package/scripts/codex-wrapper.sh +88 -0
  96. package/scripts/create-sandbox.sh +269 -0
  97. package/scripts/debug-linear-update.js +174 -0
  98. package/scripts/delete-linear-tasks.js +167 -0
  99. package/scripts/deploy.sh +89 -0
  100. package/scripts/deployment/railway.sh +352 -0
  101. package/scripts/deployment/test-deployment.js +194 -0
  102. package/scripts/detect-and-rehydrate.js +162 -0
  103. package/scripts/detect-and-rehydrate.mjs +165 -0
  104. package/scripts/development/create-demo-tasks.js +143 -0
  105. package/scripts/development/debug-frame-test.js +16 -0
  106. package/scripts/development/demo-auto-sync.js +128 -0
  107. package/scripts/development/fix-all-imports.js +213 -0
  108. package/scripts/development/fix-imports.js +229 -0
  109. package/scripts/development/fix-lint-loop.cjs +103 -0
  110. package/scripts/development/fix-project-id.ts +161 -0
  111. package/scripts/development/fix-strict-mode-issues.ts +291 -0
  112. package/scripts/development/reorganize-structure.sh +228 -0
  113. package/scripts/development/test-persistence-direct.js +148 -0
  114. package/scripts/development/test-persistence.js +114 -0
  115. package/scripts/development/test-tasks.js +93 -0
  116. package/scripts/development/update-imports.js +212 -0
  117. package/scripts/fetch-linear-status.js +125 -0
  118. package/scripts/git-hooks/README.md +310 -0
  119. package/scripts/git-hooks/branch-context-manager.sh +342 -0
  120. package/scripts/git-hooks/post-checkout-stackmemory.sh +63 -0
  121. package/scripts/git-hooks/post-commit-stackmemory.sh +305 -0
  122. package/scripts/git-hooks/pre-commit-stackmemory.sh +275 -0
  123. package/scripts/hooks/cleanup-shell.sh +130 -0
  124. package/scripts/hooks/task-complete.sh +114 -0
  125. package/scripts/initialize.ts +129 -0
  126. package/scripts/install-claude-hooks-auto.js +104 -0
  127. package/scripts/install-claude-hooks.sh +133 -0
  128. package/scripts/install-global.sh +296 -0
  129. package/scripts/install.sh +235 -0
  130. package/scripts/linear-auto-sync.js +262 -0
  131. package/scripts/linear-auto-sync.sh +161 -0
  132. package/scripts/linear-sync-daemon.js +150 -0
  133. package/scripts/linear-task-review.js +237 -0
  134. package/scripts/list-linear-tasks.ts +178 -0
  135. package/scripts/mcp-proxy.js +66 -0
  136. package/scripts/opencode-wrapper.sh +85 -0
  137. package/scripts/publish-local.js +74 -0
  138. package/scripts/query-chromadb.ts +201 -0
  139. package/scripts/railway-env-setup.sh +39 -0
  140. package/scripts/reconcile-local-tasks.js +170 -0
  141. package/scripts/recreate-frames-db.js +89 -0
  142. package/scripts/setup/claude-integration.js +138 -0
  143. package/scripts/setup/configure-alias.js +125 -0
  144. package/scripts/setup/configure-codex-alias.js +161 -0
  145. package/scripts/setup/configure-opencode-alias.js +175 -0
  146. package/scripts/setup-claude-integration.js +204 -0
  147. package/scripts/setup-claude-integration.sh +183 -0
  148. package/scripts/setup-railway-deployment.sh +37 -0
  149. package/scripts/setup.sh +31 -0
  150. package/scripts/show-linear-summary.ts +172 -0
  151. package/scripts/stackmemory-auto-handoff.sh +231 -0
  152. package/scripts/stackmemory-daemon.sh +40 -0
  153. package/scripts/start-linear-sync-daemon.sh +141 -0
  154. package/scripts/start-temporal-paradox.sh +214 -0
  155. package/scripts/status.ts +159 -0
  156. package/scripts/sync-and-clean-tasks.js +258 -0
  157. package/scripts/sync-frames-from-railway.js +228 -0
  158. package/scripts/sync-linear-graphql.js +303 -0
  159. package/scripts/sync-linear-tasks.js +186 -0
  160. package/scripts/test-auto-triggers.sh +57 -0
  161. package/scripts/test-browser-mcp.js +74 -0
  162. package/scripts/test-chromadb-full.js +115 -0
  163. package/scripts/test-chromadb-hooks.sh +28 -0
  164. package/scripts/test-chromadb-sync.ts +245 -0
  165. package/scripts/test-cli-security.js +293 -0
  166. package/scripts/test-hooks-persistence.sh +220 -0
  167. package/scripts/test-installation-scenarios.sh +359 -0
  168. package/scripts/test-installation.sh +224 -0
  169. package/scripts/test-mcp.js +163 -0
  170. package/scripts/test-pre-publish-quick.sh +75 -0
  171. package/scripts/test-quality-gates.sh +263 -0
  172. package/scripts/test-railway-db.js +222 -0
  173. package/scripts/test-redis-storage.ts +490 -0
  174. package/scripts/test-rlm-basic.sh +122 -0
  175. package/scripts/test-rlm-comprehensive.sh +260 -0
  176. package/scripts/test-rlm-e2e.sh +268 -0
  177. package/scripts/test-rlm-simple.js +90 -0
  178. package/scripts/test-rlm.js +110 -0
  179. package/scripts/test-session-handoff.sh +165 -0
  180. package/scripts/test-shell-integration.sh +275 -0
  181. package/scripts/testing/ab-test-runner.ts +508 -0
  182. package/scripts/testing/collect-metrics.ts +457 -0
  183. package/scripts/testing/quick-effectiveness-demo.js +187 -0
  184. package/scripts/testing/real-performance-test.js +422 -0
  185. package/scripts/testing/run-effectiveness-tests.sh +176 -0
  186. package/scripts/testing/scripts/testing/ab-test-runner.js +363 -0
  187. package/scripts/testing/scripts/testing/collect-metrics.js +292 -0
  188. package/scripts/testing/simple-effectiveness-test.js +310 -0
  189. package/scripts/testing/src/core/context/context-bridge.js +253 -0
  190. package/scripts/testing/src/core/context/frame-manager.js +746 -0
  191. package/scripts/testing/src/core/context/shared-context-layer.js +437 -0
  192. package/scripts/testing/src/core/database/database-adapter.js +54 -0
  193. package/scripts/testing/src/core/errors/index.js +291 -0
  194. package/scripts/testing/src/core/errors/recovery.js +268 -0
  195. package/scripts/testing/src/core/monitoring/logger.js +145 -0
  196. package/scripts/testing/src/core/retrieval/context-retriever.js +516 -0
  197. package/scripts/testing/src/core/session/index.js +1 -0
  198. package/scripts/testing/src/core/session/session-manager.js +323 -0
  199. package/scripts/testing/src/core/trace/cli-trace-wrapper.js +140 -0
  200. package/scripts/testing/src/core/trace/db-trace-wrapper.js +251 -0
  201. package/scripts/testing/src/core/trace/debug-trace.js +398 -0
  202. package/scripts/testing/src/core/trace/index.js +120 -0
  203. package/scripts/testing/src/core/trace/linear-api-wrapper.js +204 -0
  204. package/scripts/update-linear-status.js +268 -0
  205. package/scripts/update-linear-tasks-fixed.js +284 -0
  206. package/scripts/verify-railway-schema.ts +35 -0
  207. package/templates/claude-hooks/hooks.json +5 -0
  208. package/templates/claude-hooks/on-clear.js +56 -0
  209. package/templates/claude-hooks/on-startup.js +56 -0
  210. package/templates/claude-hooks/tool-use-trace.js +67 -0
  211. package/dist/features/tui/components/analytics-panel.js +0 -157
  212. package/dist/features/tui/components/analytics-panel.js.map +0 -7
  213. package/dist/features/tui/components/frame-visualizer.js +0 -377
  214. package/dist/features/tui/components/frame-visualizer.js.map +0 -7
  215. package/dist/features/tui/components/pr-tracker.js +0 -135
  216. package/dist/features/tui/components/pr-tracker.js.map +0 -7
  217. package/dist/features/tui/components/session-monitor.js +0 -299
  218. package/dist/features/tui/components/session-monitor.js.map +0 -7
  219. package/dist/features/tui/components/subagent-fleet.js +0 -395
  220. package/dist/features/tui/components/subagent-fleet.js.map +0 -7
  221. package/dist/features/tui/components/task-board.js +0 -1139
  222. package/dist/features/tui/components/task-board.js.map +0 -7
  223. package/dist/features/tui/index.js +0 -408
  224. package/dist/features/tui/index.js.map +0 -7
  225. package/dist/features/tui/services/data-service.js +0 -641
  226. package/dist/features/tui/services/data-service.js.map +0 -7
  227. package/dist/features/tui/services/linear-task-reader.js +0 -102
  228. package/dist/features/tui/services/linear-task-reader.js.map +0 -7
  229. package/dist/features/tui/services/websocket-client.js +0 -162
  230. package/dist/features/tui/services/websocket-client.js.map +0 -7
  231. package/dist/features/tui/terminal-compat.js +0 -220
  232. package/dist/features/tui/terminal-compat.js.map +0 -7
  233. package/dist/features/tui/types.js +0 -1
  234. 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 "================================"