@stackmemoryai/stackmemory 0.2.3 → 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.
- package/README.md +108 -0
- package/dist/index.js +382 -0
- package/dist/src/analytics/api/analytics-api.d.ts +24 -0
- package/dist/src/analytics/api/analytics-api.d.ts.map +1 -0
- package/dist/src/analytics/api/analytics-api.js +279 -0
- package/dist/src/analytics/api/analytics-api.js.map +1 -0
- package/dist/src/analytics/core/analytics-service.d.ts +23 -0
- package/dist/src/analytics/core/analytics-service.d.ts.map +1 -0
- package/dist/src/analytics/core/analytics-service.js +160 -0
- package/dist/src/analytics/core/analytics-service.js.map +1 -0
- package/dist/src/analytics/index.d.ts +12 -0
- package/dist/src/analytics/index.d.ts.map +1 -0
- package/dist/src/analytics/index.js +11 -0
- package/dist/src/analytics/index.js.map +1 -0
- package/dist/src/analytics/queries/metrics-queries.d.ts +11 -0
- package/dist/src/analytics/queries/metrics-queries.d.ts.map +1 -0
- package/dist/src/analytics/queries/metrics-queries.js +179 -0
- package/dist/src/analytics/queries/metrics-queries.js.map +1 -0
- package/dist/src/analytics/types/metrics.d.ts +60 -0
- package/dist/src/analytics/types/metrics.d.ts.map +1 -0
- package/dist/src/analytics/types/metrics.js +2 -0
- package/dist/src/analytics/types/metrics.js.map +1 -0
- package/dist/src/cli/analytics-viewer.d.ts +3 -0
- package/dist/src/cli/analytics-viewer.d.ts.map +1 -0
- package/dist/src/cli/analytics-viewer.js +89 -0
- package/dist/src/cli/analytics-viewer.js.map +1 -0
- package/dist/src/cli/browser-test.d.ts +6 -0
- package/dist/src/cli/browser-test.d.ts.map +1 -0
- package/dist/src/cli/browser-test.js +32 -0
- package/dist/src/cli/browser-test.js.map +1 -0
- package/dist/src/cli/cli.js +233 -1
- package/dist/src/cli/cli.js.map +1 -1
- package/dist/src/cli/commands/projects.d.ts +8 -0
- package/dist/src/cli/commands/projects.d.ts.map +1 -0
- package/dist/src/cli/commands/projects.js +220 -0
- package/dist/src/cli/commands/projects.js.map +1 -0
- package/dist/src/cli/index.d.ts +7 -0
- package/dist/src/cli/index.d.ts.map +1 -0
- package/dist/src/cli/index.js +704 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/project-commands.d.ts +8 -0
- package/dist/src/cli/project-commands.d.ts.map +1 -0
- package/dist/src/cli/project-commands.js +212 -0
- package/dist/src/cli/project-commands.js.map +1 -0
- package/dist/src/cli/utils/viewer.d.ts +3 -0
- package/dist/src/cli/utils/viewer.d.ts.map +1 -0
- package/dist/src/cli/utils/viewer.js +89 -0
- package/dist/src/cli/utils/viewer.js.map +1 -0
- package/dist/src/core/context/frame-manager.d.ts +106 -0
- package/dist/src/core/context/frame-manager.d.ts.map +1 -0
- package/dist/src/core/context/frame-manager.js +387 -0
- package/dist/src/core/context/frame-manager.js.map +1 -0
- package/dist/src/core/logger.test.js +1 -1
- package/dist/src/core/logger.test.js.map +1 -1
- package/dist/src/core/monitoring/error-handler.d.ts +46 -0
- package/dist/src/core/monitoring/error-handler.d.ts.map +1 -0
- package/dist/src/core/monitoring/error-handler.js +212 -0
- package/dist/src/core/monitoring/error-handler.js.map +1 -0
- package/dist/src/core/monitoring/logger.d.ts +24 -0
- package/dist/src/core/monitoring/logger.d.ts.map +1 -0
- package/dist/src/core/monitoring/logger.js +121 -0
- package/dist/src/core/monitoring/logger.js.map +1 -0
- package/dist/src/core/monitoring/metrics.d.ts +7 -0
- package/dist/src/core/monitoring/metrics.d.ts.map +1 -0
- package/dist/src/core/monitoring/metrics.js +13 -0
- package/dist/src/core/monitoring/metrics.js.map +1 -0
- package/dist/src/core/monitoring/progress-tracker.d.ts +95 -0
- package/dist/src/core/monitoring/progress-tracker.d.ts.map +1 -0
- package/dist/src/core/monitoring/progress-tracker.js +178 -0
- package/dist/src/core/monitoring/progress-tracker.js.map +1 -0
- package/dist/src/core/progress-tracker.d.ts +95 -0
- package/dist/src/core/progress-tracker.d.ts.map +1 -0
- package/dist/src/core/progress-tracker.js +178 -0
- package/dist/src/core/progress-tracker.js.map +1 -0
- package/dist/src/core/project-manager.d.ts +130 -0
- package/dist/src/core/project-manager.d.ts.map +1 -0
- package/dist/src/core/project-manager.js +582 -0
- package/dist/src/core/project-manager.js.map +1 -0
- package/dist/src/core/projects/project-manager.d.ts +130 -0
- package/dist/src/core/projects/project-manager.d.ts.map +1 -0
- package/dist/src/core/projects/project-manager.js +591 -0
- package/dist/src/core/projects/project-manager.js.map +1 -0
- package/dist/src/core/update-checker.d.ts +38 -0
- package/dist/src/core/update-checker.d.ts.map +1 -0
- package/dist/src/core/update-checker.js +156 -0
- package/dist/src/core/update-checker.js.map +1 -0
- package/dist/src/core/utils/update-checker.d.ts +38 -0
- package/dist/src/core/utils/update-checker.d.ts.map +1 -0
- package/dist/src/core/utils/update-checker.js +156 -0
- package/dist/src/core/utils/update-checker.js.map +1 -0
- package/dist/src/features/analytics/api/analytics-api.d.ts +24 -0
- package/dist/src/features/analytics/api/analytics-api.d.ts.map +1 -0
- package/dist/src/features/analytics/api/analytics-api.js +289 -0
- package/dist/src/features/analytics/api/analytics-api.js.map +1 -0
- package/dist/src/features/analytics/core/analytics-service.d.ts +23 -0
- package/dist/src/features/analytics/core/analytics-service.d.ts.map +1 -0
- package/dist/src/features/analytics/core/analytics-service.js +160 -0
- package/dist/src/features/analytics/core/analytics-service.js.map +1 -0
- package/dist/src/features/analytics/index.d.ts +12 -0
- package/dist/src/features/analytics/index.d.ts.map +1 -0
- package/dist/src/features/analytics/index.js +11 -0
- package/dist/src/features/analytics/index.js.map +1 -0
- package/dist/src/features/analytics/queries/metrics-queries.d.ts +11 -0
- package/dist/src/features/analytics/queries/metrics-queries.d.ts.map +1 -0
- package/dist/src/features/analytics/queries/metrics-queries.js +183 -0
- package/dist/src/features/analytics/queries/metrics-queries.js.map +1 -0
- package/dist/src/features/analytics/types/metrics.d.ts +60 -0
- package/dist/src/features/analytics/types/metrics.d.ts.map +1 -0
- package/dist/src/features/analytics/types/metrics.js +2 -0
- package/dist/src/features/analytics/types/metrics.js.map +1 -0
- package/dist/src/features/browser/browser-mcp.d.ts +94 -0
- package/dist/src/features/browser/browser-mcp.d.ts.map +1 -0
- package/dist/src/features/browser/browser-mcp.js +456 -0
- package/dist/src/features/browser/browser-mcp.js.map +1 -0
- package/dist/src/features/tasks/pebbles-task-store.d.ts +117 -0
- package/dist/src/features/tasks/pebbles-task-store.d.ts.map +1 -0
- package/dist/src/features/tasks/pebbles-task-store.js +335 -0
- package/dist/src/features/tasks/pebbles-task-store.js.map +1 -0
- package/dist/src/features/tasks/task-aware-context.d.ts +103 -0
- package/dist/src/features/tasks/task-aware-context.d.ts.map +1 -0
- package/dist/src/features/tasks/task-aware-context.js +412 -0
- package/dist/src/features/tasks/task-aware-context.js.map +1 -0
- package/dist/src/index.d.ts +4 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -4
- package/dist/src/index.js.map +1 -1
- package/dist/src/integrations/browser-mcp.d.ts +94 -0
- package/dist/src/integrations/browser-mcp.d.ts.map +1 -0
- package/dist/src/integrations/browser-mcp.js +431 -0
- package/dist/src/integrations/browser-mcp.js.map +1 -0
- package/dist/src/integrations/linear/auth.d.ts +99 -0
- package/dist/src/integrations/linear/auth.d.ts.map +1 -0
- package/dist/src/integrations/linear/auth.js +319 -0
- package/dist/src/integrations/linear/auth.js.map +1 -0
- package/dist/src/integrations/linear/auto-sync.d.ts +77 -0
- package/dist/src/integrations/linear/auto-sync.d.ts.map +1 -0
- package/dist/src/integrations/linear/auto-sync.js +268 -0
- package/dist/src/integrations/linear/auto-sync.js.map +1 -0
- package/dist/src/integrations/linear/client.d.ts +86 -0
- package/dist/src/integrations/linear/client.d.ts.map +1 -0
- package/dist/src/integrations/linear/client.js +277 -0
- package/dist/src/integrations/linear/client.js.map +1 -0
- package/dist/src/integrations/linear/config.d.ts +51 -0
- package/dist/src/integrations/linear/config.d.ts.map +1 -0
- package/dist/src/integrations/linear/config.js +103 -0
- package/dist/src/integrations/linear/config.js.map +1 -0
- package/dist/src/integrations/linear/sync.d.ts +97 -0
- package/dist/src/integrations/linear/sync.d.ts.map +1 -0
- package/dist/src/integrations/linear/sync.js +391 -0
- package/dist/src/integrations/linear/sync.js.map +1 -0
- package/dist/src/integrations/mcp/server.d.ts +40 -0
- package/dist/src/integrations/mcp/server.d.ts.map +1 -0
- package/dist/src/integrations/mcp/server.js +828 -0
- package/dist/src/integrations/mcp/server.js.map +1 -0
- package/dist/src/mcp/mcp-server.d.ts +2 -0
- package/dist/src/mcp/mcp-server.d.ts.map +1 -1
- package/dist/src/mcp/mcp-server.js +16 -0
- package/dist/src/mcp/mcp-server.js.map +1 -1
- package/dist/src/railway/index.d.ts +7 -0
- package/dist/src/railway/index.d.ts.map +1 -0
- package/dist/src/railway/index.js +401 -0
- package/dist/src/railway/index.js.map +1 -0
- package/dist/src/runway/auth/auth-middleware.d.ts +66 -0
- package/dist/src/runway/auth/auth-middleware.d.ts.map +1 -0
- package/dist/src/runway/auth/auth-middleware.js +337 -0
- package/dist/src/runway/auth/auth-middleware.js.map +1 -0
- package/dist/src/runway/server/runway-mcp-server.d.ts +46 -0
- package/dist/src/runway/server/runway-mcp-server.d.ts.map +1 -0
- package/dist/src/runway/server/runway-mcp-server.js +601 -0
- package/dist/src/runway/server/runway-mcp-server.js.map +1 -0
- package/dist/src/runway.bak/auth/auth-middleware.d.ts +66 -0
- package/dist/src/runway.bak/auth/auth-middleware.d.ts.map +1 -0
- package/dist/src/runway.bak/auth/auth-middleware.js +337 -0
- package/dist/src/runway.bak/auth/auth-middleware.js.map +1 -0
- package/dist/src/runway.bak/server/runway-mcp-server.d.ts +46 -0
- package/dist/src/runway.bak/server/runway-mcp-server.d.ts.map +1 -0
- package/dist/src/runway.bak/server/runway-mcp-server.js +601 -0
- package/dist/src/runway.bak/server/runway-mcp-server.js.map +1 -0
- package/dist/src/servers/production/auth-middleware.d.ts +66 -0
- package/dist/src/servers/production/auth-middleware.d.ts.map +1 -0
- package/dist/src/servers/production/auth-middleware.js +346 -0
- package/dist/src/servers/production/auth-middleware.js.map +1 -0
- package/dist/src/servers/railway/index.d.ts +7 -0
- package/dist/src/servers/railway/index.d.ts.map +1 -0
- package/dist/src/servers/railway/index.js +401 -0
- package/dist/src/servers/railway/index.js.map +1 -0
- 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"}
|