@stackmemoryai/stackmemory 0.2.4 → 0.2.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.
Files changed (179) hide show
  1. package/README.md +108 -0
  2. package/dist/index.js +382 -0
  3. package/dist/src/analytics/api/analytics-api.d.ts +24 -0
  4. package/dist/src/analytics/api/analytics-api.d.ts.map +1 -0
  5. package/dist/src/analytics/api/analytics-api.js +279 -0
  6. package/dist/src/analytics/api/analytics-api.js.map +1 -0
  7. package/dist/src/analytics/core/analytics-service.d.ts +23 -0
  8. package/dist/src/analytics/core/analytics-service.d.ts.map +1 -0
  9. package/dist/src/analytics/core/analytics-service.js +160 -0
  10. package/dist/src/analytics/core/analytics-service.js.map +1 -0
  11. package/dist/src/analytics/index.d.ts +12 -0
  12. package/dist/src/analytics/index.d.ts.map +1 -0
  13. package/dist/src/analytics/index.js +11 -0
  14. package/dist/src/analytics/index.js.map +1 -0
  15. package/dist/src/analytics/queries/metrics-queries.d.ts +11 -0
  16. package/dist/src/analytics/queries/metrics-queries.d.ts.map +1 -0
  17. package/dist/src/analytics/queries/metrics-queries.js +179 -0
  18. package/dist/src/analytics/queries/metrics-queries.js.map +1 -0
  19. package/dist/src/analytics/types/metrics.d.ts +60 -0
  20. package/dist/src/analytics/types/metrics.d.ts.map +1 -0
  21. package/dist/src/analytics/types/metrics.js +2 -0
  22. package/dist/src/analytics/types/metrics.js.map +1 -0
  23. package/dist/src/cli/analytics-viewer.d.ts +3 -0
  24. package/dist/src/cli/analytics-viewer.d.ts.map +1 -0
  25. package/dist/src/cli/analytics-viewer.js +89 -0
  26. package/dist/src/cli/analytics-viewer.js.map +1 -0
  27. package/dist/src/cli/browser-test.d.ts +6 -0
  28. package/dist/src/cli/browser-test.d.ts.map +1 -0
  29. package/dist/src/cli/browser-test.js +32 -0
  30. package/dist/src/cli/browser-test.js.map +1 -0
  31. package/dist/src/cli/cli.js +157 -0
  32. package/dist/src/cli/cli.js.map +1 -1
  33. package/dist/src/cli/commands/projects.d.ts +8 -0
  34. package/dist/src/cli/commands/projects.d.ts.map +1 -0
  35. package/dist/src/cli/commands/projects.js +220 -0
  36. package/dist/src/cli/commands/projects.js.map +1 -0
  37. package/dist/src/cli/index.d.ts +7 -0
  38. package/dist/src/cli/index.d.ts.map +1 -0
  39. package/dist/src/cli/index.js +704 -0
  40. package/dist/src/cli/index.js.map +1 -0
  41. package/dist/src/cli/project-commands.d.ts +8 -0
  42. package/dist/src/cli/project-commands.d.ts.map +1 -0
  43. package/dist/src/cli/project-commands.js +212 -0
  44. package/dist/src/cli/project-commands.js.map +1 -0
  45. package/dist/src/cli/utils/viewer.d.ts +3 -0
  46. package/dist/src/cli/utils/viewer.d.ts.map +1 -0
  47. package/dist/src/cli/utils/viewer.js +89 -0
  48. package/dist/src/cli/utils/viewer.js.map +1 -0
  49. package/dist/src/core/context/frame-manager.d.ts +106 -0
  50. package/dist/src/core/context/frame-manager.d.ts.map +1 -0
  51. package/dist/src/core/context/frame-manager.js +387 -0
  52. package/dist/src/core/context/frame-manager.js.map +1 -0
  53. package/dist/src/core/logger.test.js +1 -1
  54. package/dist/src/core/logger.test.js.map +1 -1
  55. package/dist/src/core/monitoring/error-handler.d.ts +46 -0
  56. package/dist/src/core/monitoring/error-handler.d.ts.map +1 -0
  57. package/dist/src/core/monitoring/error-handler.js +212 -0
  58. package/dist/src/core/monitoring/error-handler.js.map +1 -0
  59. package/dist/src/core/monitoring/logger.d.ts +24 -0
  60. package/dist/src/core/monitoring/logger.d.ts.map +1 -0
  61. package/dist/src/core/monitoring/logger.js +121 -0
  62. package/dist/src/core/monitoring/logger.js.map +1 -0
  63. package/dist/src/core/monitoring/metrics.d.ts +7 -0
  64. package/dist/src/core/monitoring/metrics.d.ts.map +1 -0
  65. package/dist/src/core/monitoring/metrics.js +13 -0
  66. package/dist/src/core/monitoring/metrics.js.map +1 -0
  67. package/dist/src/core/monitoring/progress-tracker.d.ts +95 -0
  68. package/dist/src/core/monitoring/progress-tracker.d.ts.map +1 -0
  69. package/dist/src/core/monitoring/progress-tracker.js +178 -0
  70. package/dist/src/core/monitoring/progress-tracker.js.map +1 -0
  71. package/dist/src/core/project-manager.d.ts +130 -0
  72. package/dist/src/core/project-manager.d.ts.map +1 -0
  73. package/dist/src/core/project-manager.js +582 -0
  74. package/dist/src/core/project-manager.js.map +1 -0
  75. package/dist/src/core/projects/project-manager.d.ts +130 -0
  76. package/dist/src/core/projects/project-manager.d.ts.map +1 -0
  77. package/dist/src/core/projects/project-manager.js +591 -0
  78. package/dist/src/core/projects/project-manager.js.map +1 -0
  79. package/dist/src/core/utils/update-checker.d.ts +38 -0
  80. package/dist/src/core/utils/update-checker.d.ts.map +1 -0
  81. package/dist/src/core/utils/update-checker.js +156 -0
  82. package/dist/src/core/utils/update-checker.js.map +1 -0
  83. package/dist/src/features/analytics/api/analytics-api.d.ts +24 -0
  84. package/dist/src/features/analytics/api/analytics-api.d.ts.map +1 -0
  85. package/dist/src/features/analytics/api/analytics-api.js +289 -0
  86. package/dist/src/features/analytics/api/analytics-api.js.map +1 -0
  87. package/dist/src/features/analytics/core/analytics-service.d.ts +23 -0
  88. package/dist/src/features/analytics/core/analytics-service.d.ts.map +1 -0
  89. package/dist/src/features/analytics/core/analytics-service.js +160 -0
  90. package/dist/src/features/analytics/core/analytics-service.js.map +1 -0
  91. package/dist/src/features/analytics/index.d.ts +12 -0
  92. package/dist/src/features/analytics/index.d.ts.map +1 -0
  93. package/dist/src/features/analytics/index.js +11 -0
  94. package/dist/src/features/analytics/index.js.map +1 -0
  95. package/dist/src/features/analytics/queries/metrics-queries.d.ts +11 -0
  96. package/dist/src/features/analytics/queries/metrics-queries.d.ts.map +1 -0
  97. package/dist/src/features/analytics/queries/metrics-queries.js +183 -0
  98. package/dist/src/features/analytics/queries/metrics-queries.js.map +1 -0
  99. package/dist/src/features/analytics/types/metrics.d.ts +60 -0
  100. package/dist/src/features/analytics/types/metrics.d.ts.map +1 -0
  101. package/dist/src/features/analytics/types/metrics.js +2 -0
  102. package/dist/src/features/analytics/types/metrics.js.map +1 -0
  103. package/dist/src/features/browser/browser-mcp.d.ts +94 -0
  104. package/dist/src/features/browser/browser-mcp.d.ts.map +1 -0
  105. package/dist/src/features/browser/browser-mcp.js +456 -0
  106. package/dist/src/features/browser/browser-mcp.js.map +1 -0
  107. package/dist/src/features/tasks/pebbles-task-store.d.ts +117 -0
  108. package/dist/src/features/tasks/pebbles-task-store.d.ts.map +1 -0
  109. package/dist/src/features/tasks/pebbles-task-store.js +335 -0
  110. package/dist/src/features/tasks/pebbles-task-store.js.map +1 -0
  111. package/dist/src/features/tasks/task-aware-context.d.ts +103 -0
  112. package/dist/src/features/tasks/task-aware-context.d.ts.map +1 -0
  113. package/dist/src/features/tasks/task-aware-context.js +412 -0
  114. package/dist/src/features/tasks/task-aware-context.js.map +1 -0
  115. package/dist/src/index.d.ts +4 -4
  116. package/dist/src/index.d.ts.map +1 -1
  117. package/dist/src/index.js +4 -4
  118. package/dist/src/index.js.map +1 -1
  119. package/dist/src/integrations/browser-mcp.d.ts +94 -0
  120. package/dist/src/integrations/browser-mcp.d.ts.map +1 -0
  121. package/dist/src/integrations/browser-mcp.js +431 -0
  122. package/dist/src/integrations/browser-mcp.js.map +1 -0
  123. package/dist/src/integrations/linear/auth.d.ts +99 -0
  124. package/dist/src/integrations/linear/auth.d.ts.map +1 -0
  125. package/dist/src/integrations/linear/auth.js +319 -0
  126. package/dist/src/integrations/linear/auth.js.map +1 -0
  127. package/dist/src/integrations/linear/auto-sync.d.ts +77 -0
  128. package/dist/src/integrations/linear/auto-sync.d.ts.map +1 -0
  129. package/dist/src/integrations/linear/auto-sync.js +268 -0
  130. package/dist/src/integrations/linear/auto-sync.js.map +1 -0
  131. package/dist/src/integrations/linear/client.d.ts +86 -0
  132. package/dist/src/integrations/linear/client.d.ts.map +1 -0
  133. package/dist/src/integrations/linear/client.js +277 -0
  134. package/dist/src/integrations/linear/client.js.map +1 -0
  135. package/dist/src/integrations/linear/config.d.ts +51 -0
  136. package/dist/src/integrations/linear/config.d.ts.map +1 -0
  137. package/dist/src/integrations/linear/config.js +103 -0
  138. package/dist/src/integrations/linear/config.js.map +1 -0
  139. package/dist/src/integrations/linear/sync.d.ts +97 -0
  140. package/dist/src/integrations/linear/sync.d.ts.map +1 -0
  141. package/dist/src/integrations/linear/sync.js +391 -0
  142. package/dist/src/integrations/linear/sync.js.map +1 -0
  143. package/dist/src/integrations/mcp/server.d.ts +40 -0
  144. package/dist/src/integrations/mcp/server.d.ts.map +1 -0
  145. package/dist/src/integrations/mcp/server.js +828 -0
  146. package/dist/src/integrations/mcp/server.js.map +1 -0
  147. package/dist/src/mcp/mcp-server.d.ts +1 -0
  148. package/dist/src/mcp/mcp-server.d.ts.map +1 -1
  149. package/dist/src/mcp/mcp-server.js +11 -0
  150. package/dist/src/mcp/mcp-server.js.map +1 -1
  151. package/dist/src/railway/index.d.ts +7 -0
  152. package/dist/src/railway/index.d.ts.map +1 -0
  153. package/dist/src/railway/index.js +401 -0
  154. package/dist/src/railway/index.js.map +1 -0
  155. package/dist/src/runway/auth/auth-middleware.d.ts +66 -0
  156. package/dist/src/runway/auth/auth-middleware.d.ts.map +1 -0
  157. package/dist/src/runway/auth/auth-middleware.js +337 -0
  158. package/dist/src/runway/auth/auth-middleware.js.map +1 -0
  159. package/dist/src/runway/server/runway-mcp-server.d.ts +46 -0
  160. package/dist/src/runway/server/runway-mcp-server.d.ts.map +1 -0
  161. package/dist/src/runway/server/runway-mcp-server.js +601 -0
  162. package/dist/src/runway/server/runway-mcp-server.js.map +1 -0
  163. package/dist/src/runway.bak/auth/auth-middleware.d.ts +66 -0
  164. package/dist/src/runway.bak/auth/auth-middleware.d.ts.map +1 -0
  165. package/dist/src/runway.bak/auth/auth-middleware.js +337 -0
  166. package/dist/src/runway.bak/auth/auth-middleware.js.map +1 -0
  167. package/dist/src/runway.bak/server/runway-mcp-server.d.ts +46 -0
  168. package/dist/src/runway.bak/server/runway-mcp-server.d.ts.map +1 -0
  169. package/dist/src/runway.bak/server/runway-mcp-server.js +601 -0
  170. package/dist/src/runway.bak/server/runway-mcp-server.js.map +1 -0
  171. package/dist/src/servers/production/auth-middleware.d.ts +66 -0
  172. package/dist/src/servers/production/auth-middleware.d.ts.map +1 -0
  173. package/dist/src/servers/production/auth-middleware.js +346 -0
  174. package/dist/src/servers/production/auth-middleware.js.map +1 -0
  175. package/dist/src/servers/railway/index.d.ts +7 -0
  176. package/dist/src/servers/railway/index.d.ts.map +1 -0
  177. package/dist/src/servers/railway/index.js +401 -0
  178. package/dist/src/servers/railway/index.js.map +1 -0
  179. package/package.json +27 -5
package/README.md CHANGED
@@ -251,6 +251,114 @@ On every message/tool call:
251
251
 
252
252
  ---
253
253
 
254
+ ## Claude Code Integration
255
+
256
+ StackMemory can automatically save context when using Claude Code, ensuring your AI assistant always has access to previous context and decisions.
257
+
258
+ ### Quick Setup
259
+
260
+ 1. **Install the wrapper script**:
261
+ ```bash
262
+ # Make scripts executable
263
+ chmod +x scripts/claude-code-wrapper.sh scripts/stackmemory-daemon.sh
264
+
265
+ # Add alias to your shell config
266
+ echo 'alias claude="~/Dev/stackmemory/scripts/claude-code-wrapper.sh"' >> ~/.zshrc
267
+ source ~/.zshrc
268
+ ```
269
+
270
+ 2. **Use Claude Code with auto-save**:
271
+ ```bash
272
+ # Instead of: claude-code
273
+ # Use: claude
274
+
275
+ # Context is automatically saved on exit (Ctrl+C)
276
+ ```
277
+
278
+ ### Integration Methods
279
+
280
+ #### 1. Shell Wrapper (Recommended)
281
+ Automatically saves context when Claude Code exits:
282
+ ```bash
283
+ # Basic usage
284
+ claude
285
+
286
+ # With Linear auto-sync (syncs every 5 minutes)
287
+ claude --auto-sync
288
+
289
+ # Custom sync interval (10 minutes)
290
+ claude --auto-sync --sync-interval=10
291
+ ```
292
+
293
+ #### 2. Linear Auto-Sync Daemon
294
+ Continuously syncs with Linear in the background:
295
+ ```bash
296
+ # Start auto-sync (default: 5 minutes)
297
+ ./scripts/linear-auto-sync.sh start
298
+
299
+ # Custom interval (10 minutes)
300
+ ./scripts/linear-auto-sync.sh start 10
301
+
302
+ # Check status
303
+ ./scripts/linear-auto-sync.sh status
304
+
305
+ # View logs
306
+ ./scripts/linear-auto-sync.sh logs
307
+
308
+ # Stop daemon
309
+ ./scripts/linear-auto-sync.sh stop
310
+ ```
311
+
312
+ **Requirements:**
313
+ - Set `LINEAR_API_KEY` environment variable
314
+ - Run in a StackMemory-initialized project
315
+
316
+ #### 3. Background Daemon
317
+ Continuously saves context every 5 minutes:
318
+ ```bash
319
+ # Start daemon
320
+ ./scripts/stackmemory-daemon.sh &
321
+
322
+ # Custom interval (60 seconds)
323
+ ./scripts/stackmemory-daemon.sh 60 &
324
+
325
+ # Stop daemon
326
+ kill $(cat /tmp/stackmemory-daemon.pid)
327
+ ```
328
+
329
+ #### 4. Git Hooks
330
+ Save context automatically on git commits:
331
+ ```bash
332
+ # Install in current repo
333
+ ./scripts/setup-git-hooks.sh
334
+ ```
335
+
336
+ #### 5. Manual Function
337
+ Add to `~/.zshrc`:
338
+ ```bash
339
+ claude_with_sm() {
340
+ claude "$@"
341
+ local exit_code=$?
342
+ if [ -d ".stackmemory" ]; then
343
+ stackmemory status
344
+ [ -n "$LINEAR_API_KEY" ] && stackmemory linear sync
345
+ fi
346
+ return $exit_code
347
+ }
348
+ ```
349
+
350
+ ### Features
351
+
352
+ - **Automatic context preservation** - Saves on exit (including Ctrl+C)
353
+ - **Linear auto-sync** - Continuous bidirectional sync with Linear
354
+ - **Smart detection** - Only runs in StackMemory-enabled projects
355
+ - **Zero overhead** - No performance impact during Claude Code sessions
356
+ - **Flexible sync intervals** - Configure sync frequency (default: 5 minutes)
357
+ - **Background operation** - Sync continues while you work
358
+ - **Comprehensive logging** - Track all sync operations
359
+
360
+ ---
361
+
254
362
  ## Guarantees
255
363
 
256
364
  * ✅ Lossless storage (no destructive compaction)
package/dist/index.js ADDED
@@ -0,0 +1,382 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Railway MCP Server Entry Point
4
+ * Simplified production server for Railway deployment
5
+ */
6
+ import express from 'express';
7
+ import { createServer } from 'http';
8
+ import { WebSocketServer } from 'ws';
9
+ import cors from 'cors';
10
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
11
+ import Database from 'better-sqlite3';
12
+ import { join, dirname } from 'path';
13
+ import { fileURLToPath } from 'url';
14
+ import { existsSync, mkdirSync } from 'fs';
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = dirname(__filename);
17
+ // Configuration
18
+ const config = {
19
+ port: parseInt(process.env.PORT || '8080'),
20
+ environment: process.env.NODE_ENV || 'development',
21
+ corsOrigins: process.env.CORS_ORIGINS?.split(',') || ['http://localhost:3000'],
22
+ authMode: process.env.AUTH_MODE || 'api_key',
23
+ apiKeySecret: process.env.API_KEY_SECRET || 'development-secret',
24
+ jwtSecret: process.env.JWT_SECRET || 'development-jwt-secret',
25
+ databaseUrl: process.env.DATABASE_URL || join(process.cwd(), '.stackmemory', 'railway.db'),
26
+ rateLimitEnabled: process.env.RATE_LIMIT_ENABLED === 'true',
27
+ rateLimitFree: parseInt(process.env.RATE_LIMIT_FREE || '100'),
28
+ enableWebSocket: process.env.ENABLE_WEBSOCKET !== 'false',
29
+ enableAnalytics: process.env.ENABLE_ANALYTICS === 'true'
30
+ };
31
+ // Simple in-memory rate limiter
32
+ const rateLimiter = new Map();
33
+ class RailwayMCPServer {
34
+ constructor() {
35
+ this.connections = new Map();
36
+ this.app = express();
37
+ this.httpServer = createServer(this.app);
38
+ this.initializeDatabase();
39
+ this.setupMiddleware();
40
+ this.setupRoutes();
41
+ this.setupMCPServer();
42
+ if (config.enableWebSocket) {
43
+ this.setupWebSocket();
44
+ }
45
+ }
46
+ initializeDatabase() {
47
+ // Use PostgreSQL in production, SQLite for development
48
+ if (config.environment === 'production' && config.databaseUrl.startsWith('postgresql://')) {
49
+ console.log('Using PostgreSQL database');
50
+ // In production, we'd use pg client here
51
+ // For now, we'll use SQLite as fallback
52
+ const dbPath = '/tmp/stackmemory.db';
53
+ this.db = new Database(dbPath);
54
+ }
55
+ else {
56
+ // Create database directory if it doesn't exist
57
+ const dbDir = dirname(config.databaseUrl);
58
+ if (!existsSync(dbDir)) {
59
+ mkdirSync(dbDir, { recursive: true });
60
+ }
61
+ this.db = new Database(config.databaseUrl);
62
+ }
63
+ // Initialize tables
64
+ this.db.exec(`
65
+ CREATE TABLE IF NOT EXISTS contexts (
66
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
67
+ project_id TEXT NOT NULL,
68
+ content TEXT NOT NULL,
69
+ type TEXT DEFAULT 'general',
70
+ metadata TEXT DEFAULT '{}',
71
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
72
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
73
+ );
74
+
75
+ CREATE TABLE IF NOT EXISTS api_keys (
76
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
77
+ key_hash TEXT UNIQUE NOT NULL,
78
+ user_id TEXT NOT NULL,
79
+ name TEXT,
80
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
81
+ last_used DATETIME,
82
+ revoked BOOLEAN DEFAULT 0
83
+ );
84
+
85
+ CREATE INDEX IF NOT EXISTS idx_contexts_project ON contexts(project_id);
86
+ CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys(key_hash);
87
+ `);
88
+ }
89
+ setupMiddleware() {
90
+ // CORS
91
+ this.app.use(cors({
92
+ origin: config.corsOrigins,
93
+ credentials: true
94
+ }));
95
+ // Body parsing
96
+ this.app.use(express.json({ limit: '10mb' }));
97
+ // Request logging
98
+ this.app.use((req, res, next) => {
99
+ console.log(`${new Date().toISOString()} ${req.method} ${req.path}`);
100
+ next();
101
+ });
102
+ // Simple authentication middleware
103
+ this.app.use('/api', this.authenticate.bind(this));
104
+ // Rate limiting
105
+ if (config.rateLimitEnabled) {
106
+ this.app.use('/api', this.rateLimit.bind(this));
107
+ }
108
+ }
109
+ authenticate(req, res, next) {
110
+ // Skip auth for health check
111
+ if (req.path === '/health') {
112
+ return next();
113
+ }
114
+ const authHeader = req.headers.authorization;
115
+ if (config.authMode === 'api_key') {
116
+ // Simple API key authentication
117
+ if (!authHeader?.startsWith('Bearer ')) {
118
+ return res.status(401).json({ error: 'Missing API key' });
119
+ }
120
+ const apiKey = authHeader.substring(7);
121
+ // In production, validate against database
122
+ // For now, simple check
123
+ if (apiKey.length < 32) {
124
+ return res.status(403).json({ error: 'Invalid API key' });
125
+ }
126
+ req.user = { id: 'api-user', tier: 'free' };
127
+ next();
128
+ }
129
+ else {
130
+ // OAuth/JWT mode would go here
131
+ next();
132
+ }
133
+ }
134
+ rateLimit(req, res, next) {
135
+ const userId = req.user?.id || req.ip;
136
+ const now = Date.now();
137
+ const windowMs = 15 * 60 * 1000; // 15 minutes
138
+ const userLimit = rateLimiter.get(userId);
139
+ if (!userLimit || userLimit.resetTime < now) {
140
+ rateLimiter.set(userId, {
141
+ count: 1,
142
+ resetTime: now + windowMs
143
+ });
144
+ return next();
145
+ }
146
+ if (userLimit.count >= config.rateLimitFree) {
147
+ const retryAfter = Math.ceil((userLimit.resetTime - now) / 1000);
148
+ res.setHeader('Retry-After', retryAfter.toString());
149
+ return res.status(429).json({
150
+ error: 'Rate limit exceeded',
151
+ retryAfter
152
+ });
153
+ }
154
+ userLimit.count++;
155
+ next();
156
+ }
157
+ setupRoutes() {
158
+ // Health check
159
+ this.app.get('/health', (req, res) => {
160
+ const health = {
161
+ status: 'healthy',
162
+ version: '1.0.0',
163
+ timestamp: new Date().toISOString(),
164
+ uptime: process.uptime(),
165
+ environment: config.environment
166
+ };
167
+ res.json(health);
168
+ });
169
+ // API Routes
170
+ this.app.post('/api/context/save', (req, res) => {
171
+ try {
172
+ const { projectId = 'default', content, type = 'general', metadata = {} } = req.body;
173
+ const stmt = this.db.prepare(`
174
+ INSERT INTO contexts (project_id, content, type, metadata)
175
+ VALUES (?, ?, ?, ?)
176
+ `);
177
+ const result = stmt.run(projectId, content, type, JSON.stringify(metadata));
178
+ res.json({
179
+ success: true,
180
+ id: result.lastInsertRowid
181
+ });
182
+ }
183
+ catch (error) {
184
+ res.status(500).json({ error: error.message });
185
+ }
186
+ });
187
+ this.app.get('/api/context/load', (req, res) => {
188
+ try {
189
+ const { projectId = 'default', limit = 10, offset = 0 } = req.query;
190
+ const stmt = this.db.prepare(`
191
+ SELECT * FROM contexts
192
+ WHERE project_id = ?
193
+ ORDER BY created_at DESC
194
+ LIMIT ? OFFSET ?
195
+ `);
196
+ const contexts = stmt.all(projectId, limit, offset);
197
+ res.json({
198
+ success: true,
199
+ contexts: contexts.map(c => ({
200
+ ...c,
201
+ metadata: JSON.parse(c.metadata)
202
+ }))
203
+ });
204
+ }
205
+ catch (error) {
206
+ res.status(500).json({ error: error.message });
207
+ }
208
+ });
209
+ // MCP tool execution endpoint
210
+ this.app.post('/api/tools/execute', async (req, res) => {
211
+ try {
212
+ const { tool, params } = req.body;
213
+ // Execute MCP tool
214
+ const result = await this.executeMCPTool(tool, params);
215
+ res.json({
216
+ success: true,
217
+ result
218
+ });
219
+ }
220
+ catch (error) {
221
+ res.status(500).json({ error: error.message });
222
+ }
223
+ });
224
+ // Analytics endpoint
225
+ if (config.enableAnalytics) {
226
+ this.app.get('/api/analytics', (req, res) => {
227
+ try {
228
+ const { projectId = 'default' } = req.query;
229
+ const stats = this.db.prepare(`
230
+ SELECT
231
+ COUNT(*) as total_contexts,
232
+ COUNT(DISTINCT type) as unique_types,
233
+ MAX(created_at) as last_activity
234
+ FROM contexts
235
+ WHERE project_id = ?
236
+ `).get(projectId);
237
+ res.json({
238
+ success: true,
239
+ analytics: stats
240
+ });
241
+ }
242
+ catch (error) {
243
+ res.status(500).json({ error: error.message });
244
+ }
245
+ });
246
+ }
247
+ }
248
+ setupWebSocket() {
249
+ this.wss = new WebSocketServer({
250
+ server: this.httpServer,
251
+ path: '/ws'
252
+ });
253
+ this.wss.on('connection', (ws, req) => {
254
+ console.log('WebSocket connection established');
255
+ const connectionId = Math.random().toString(36).substring(7);
256
+ this.connections.set(connectionId, ws);
257
+ ws.on('message', async (data) => {
258
+ try {
259
+ const message = JSON.parse(data.toString());
260
+ const response = await this.handleWebSocketMessage(message);
261
+ ws.send(JSON.stringify(response));
262
+ }
263
+ catch (error) {
264
+ ws.send(JSON.stringify({
265
+ error: error.message
266
+ }));
267
+ }
268
+ });
269
+ ws.on('close', () => {
270
+ this.connections.delete(connectionId);
271
+ console.log('WebSocket connection closed');
272
+ });
273
+ });
274
+ }
275
+ async handleWebSocketMessage(message) {
276
+ const { type, tool, params } = message;
277
+ switch (type) {
278
+ case 'execute':
279
+ return await this.executeMCPTool(tool, params);
280
+ case 'ping':
281
+ return { type: 'pong' };
282
+ default:
283
+ throw new Error(`Unknown message type: ${type}`);
284
+ }
285
+ }
286
+ setupMCPServer() {
287
+ this.mcpServer = new Server({
288
+ name: 'stackmemory-railway',
289
+ version: '1.0.0'
290
+ }, {
291
+ capabilities: {
292
+ tools: {},
293
+ resources: {}
294
+ }
295
+ });
296
+ // Register MCP tools
297
+ this.mcpServer.setRequestHandler('tools/list', async () => {
298
+ return {
299
+ tools: [
300
+ {
301
+ name: 'save_context',
302
+ description: 'Save context to StackMemory',
303
+ inputSchema: {
304
+ type: 'object',
305
+ properties: {
306
+ content: { type: 'string' },
307
+ type: { type: 'string' }
308
+ }
309
+ }
310
+ },
311
+ {
312
+ name: 'load_context',
313
+ description: 'Load context from StackMemory',
314
+ inputSchema: {
315
+ type: 'object',
316
+ properties: {
317
+ query: { type: 'string' },
318
+ limit: { type: 'number' }
319
+ }
320
+ }
321
+ }
322
+ ]
323
+ };
324
+ });
325
+ this.mcpServer.setRequestHandler('tools/call', async (request) => {
326
+ const { name, arguments: args } = request.params;
327
+ return await this.executeMCPTool(name, args);
328
+ });
329
+ }
330
+ async executeMCPTool(tool, params) {
331
+ switch (tool) {
332
+ case 'save_context': {
333
+ const stmt = this.db.prepare(`
334
+ INSERT INTO contexts (project_id, content, type, metadata)
335
+ VALUES (?, ?, ?, ?)
336
+ `);
337
+ const result = stmt.run(params.projectId || 'default', params.content, params.type || 'general', JSON.stringify(params.metadata || {}));
338
+ return { id: result.lastInsertRowid, success: true };
339
+ }
340
+ case 'load_context': {
341
+ const stmt = this.db.prepare(`
342
+ SELECT * FROM contexts
343
+ WHERE project_id = ? AND content LIKE ?
344
+ ORDER BY created_at DESC
345
+ LIMIT ?
346
+ `);
347
+ const contexts = stmt.all(params.projectId || 'default', `%${params.query || ''}%`, params.limit || 10);
348
+ return { contexts, success: true };
349
+ }
350
+ default:
351
+ throw new Error(`Unknown tool: ${tool}`);
352
+ }
353
+ }
354
+ start() {
355
+ this.httpServer.listen(config.port, '0.0.0.0', () => {
356
+ console.log(`
357
+ 🚂 Railway MCP Server Started
358
+ ================================
359
+ Environment: ${config.environment}
360
+ Port: ${config.port}
361
+ WebSocket: ${config.enableWebSocket ? 'Enabled' : 'Disabled'}
362
+ Analytics: ${config.enableAnalytics ? 'Enabled' : 'Disabled'}
363
+ Rate Limiting: ${config.rateLimitEnabled ? 'Enabled' : 'Disabled'}
364
+ Auth Mode: ${config.authMode}
365
+ ================================
366
+ Health: http://localhost:${config.port}/health
367
+ `);
368
+ });
369
+ }
370
+ }
371
+ // Start server
372
+ const server = new RailwayMCPServer();
373
+ server.start();
374
+ // Graceful shutdown
375
+ process.on('SIGTERM', () => {
376
+ console.log('Shutting down gracefully...');
377
+ process.exit(0);
378
+ });
379
+ process.on('SIGINT', () => {
380
+ console.log('Shutting down...');
381
+ process.exit(0);
382
+ });
@@ -0,0 +1,24 @@
1
+ import { Router } from 'express';
2
+ import { Server } from 'http';
3
+ export declare class AnalyticsAPI {
4
+ private router;
5
+ private analyticsService;
6
+ private wss?;
7
+ constructor(projectPath?: string);
8
+ private setupRoutes;
9
+ private getMetrics;
10
+ private getTasks;
11
+ private getTeamMetrics;
12
+ private addTask;
13
+ private updateTask;
14
+ private syncLinear;
15
+ private exportMetrics;
16
+ private parseQuery;
17
+ private getPresetTimeRange;
18
+ private convertToCSV;
19
+ private handleError;
20
+ setupWebSocket(server: Server): void;
21
+ getRouter(): Router;
22
+ close(): void;
23
+ }
24
+ //# sourceMappingURL=analytics-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-api.d.ts","sourceRoot":"","sources":["../../../../src/analytics/api/analytics-api.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAqB,MAAM,EAAE,MAAM,SAAS,CAAC;AAI7D,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAE9B,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,GAAG,CAAC,CAAkB;gBAElB,WAAW,CAAC,EAAE,MAAM;IAMhC,OAAO,CAAC,WAAW;YAYL,UAAU;YAiBV,QAAQ;YAiBR,cAAc;YAqCd,OAAO;YAmBP,UAAU;YAoBV,UAAU;YAaV,aAAa;IAsB3B,OAAO,CAAC,UAAU;IAwClB,OAAO,CAAC,kBAAkB;IAwB1B,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,WAAW;IAQnB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAmDpC,SAAS,IAAI,MAAM;IAInB,KAAK,IAAI,IAAI;CAMd"}