@stackmemoryai/stackmemory 0.3.6 → 0.3.7

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 (213) hide show
  1. package/dist/agents/verifiers/base-verifier.js.map +2 -2
  2. package/dist/agents/verifiers/formatter-verifier.js.map +2 -2
  3. package/dist/agents/verifiers/llm-judge.js.map +2 -2
  4. package/dist/cli/claude-sm.js +24 -13
  5. package/dist/cli/claude-sm.js.map +2 -2
  6. package/dist/cli/codex-sm.js +24 -13
  7. package/dist/cli/codex-sm.js.map +2 -2
  8. package/dist/cli/commands/agent.js.map +2 -2
  9. package/dist/cli/commands/chromadb.js +217 -32
  10. package/dist/cli/commands/chromadb.js.map +2 -2
  11. package/dist/cli/commands/clear.js +12 -1
  12. package/dist/cli/commands/clear.js.map +2 -2
  13. package/dist/cli/commands/context.js +13 -2
  14. package/dist/cli/commands/context.js.map +2 -2
  15. package/dist/cli/commands/dashboard.js.map +2 -2
  16. package/dist/cli/commands/gc.js +202 -0
  17. package/dist/cli/commands/gc.js.map +7 -0
  18. package/dist/cli/commands/handoff.js +12 -1
  19. package/dist/cli/commands/handoff.js.map +2 -2
  20. package/dist/cli/commands/infinite-storage.js +32 -21
  21. package/dist/cli/commands/infinite-storage.js.map +2 -2
  22. package/dist/cli/commands/linear-create.js +13 -2
  23. package/dist/cli/commands/linear-create.js.map +2 -2
  24. package/dist/cli/commands/linear-list.js +12 -1
  25. package/dist/cli/commands/linear-list.js.map +2 -2
  26. package/dist/cli/commands/linear-migrate.js +12 -1
  27. package/dist/cli/commands/linear-migrate.js.map +2 -2
  28. package/dist/cli/commands/linear-test.js +12 -1
  29. package/dist/cli/commands/linear-test.js.map +2 -2
  30. package/dist/cli/commands/linear-unified.js +262 -0
  31. package/dist/cli/commands/linear-unified.js.map +7 -0
  32. package/dist/cli/commands/linear.js +17 -6
  33. package/dist/cli/commands/linear.js.map +2 -2
  34. package/dist/cli/commands/monitor.js.map +2 -2
  35. package/dist/cli/commands/onboard.js.map +2 -2
  36. package/dist/cli/commands/quality.js.map +2 -2
  37. package/dist/cli/commands/search.js.map +2 -2
  38. package/dist/cli/commands/session.js.map +2 -2
  39. package/dist/cli/commands/skills.js +12 -1
  40. package/dist/cli/commands/skills.js.map +2 -2
  41. package/dist/cli/commands/storage.js +18 -7
  42. package/dist/cli/commands/storage.js.map +2 -2
  43. package/dist/cli/commands/tasks.js.map +2 -2
  44. package/dist/cli/commands/tui.js +13 -2
  45. package/dist/cli/commands/tui.js.map +2 -2
  46. package/dist/cli/commands/webhook.js +14 -3
  47. package/dist/cli/commands/webhook.js.map +2 -2
  48. package/dist/cli/commands/workflow.js +14 -3
  49. package/dist/cli/commands/workflow.js.map +2 -2
  50. package/dist/cli/commands/worktree.js.map +2 -2
  51. package/dist/cli/index.js +18 -5
  52. package/dist/cli/index.js.map +2 -2
  53. package/dist/core/config/config-manager.js.map +2 -2
  54. package/dist/core/context/auto-context.js.map +2 -2
  55. package/dist/core/context/compaction-handler.js.map +2 -2
  56. package/dist/core/context/context-bridge.js.map +2 -2
  57. package/dist/core/context/dual-stack-manager.js.map +2 -2
  58. package/dist/core/context/frame-database.js.map +2 -2
  59. package/dist/core/context/frame-digest.js.map +2 -2
  60. package/dist/core/context/frame-handoff-manager.js.map +2 -2
  61. package/dist/core/context/frame-manager.js +12 -1
  62. package/dist/core/context/frame-manager.js.map +2 -2
  63. package/dist/core/context/frame-stack.js.map +2 -2
  64. package/dist/core/context/incremental-gc.js +279 -0
  65. package/dist/core/context/incremental-gc.js.map +7 -0
  66. package/dist/core/context/permission-manager.js +12 -1
  67. package/dist/core/context/permission-manager.js.map +2 -2
  68. package/dist/core/context/refactored-frame-manager.js.map +2 -2
  69. package/dist/core/context/shared-context-layer.js +12 -1
  70. package/dist/core/context/shared-context-layer.js.map +2 -2
  71. package/dist/core/context/stack-merge-resolver.js.map +2 -2
  72. package/dist/core/context/validation.js.map +2 -2
  73. package/dist/core/database/batch-operations.js.map +2 -2
  74. package/dist/core/database/connection-pool.js.map +2 -2
  75. package/dist/core/database/migration-manager.js.map +2 -2
  76. package/dist/core/database/paradedb-adapter.js.map +2 -2
  77. package/dist/core/database/query-cache.js.map +2 -2
  78. package/dist/core/database/query-router.js.map +2 -2
  79. package/dist/core/database/sqlite-adapter.js.map +2 -2
  80. package/dist/core/digest/enhanced-hybrid-digest.js.map +2 -2
  81. package/dist/core/errors/recovery.js.map +2 -2
  82. package/dist/core/merge/resolution-engine.js.map +2 -2
  83. package/dist/core/monitoring/error-handler.js.map +2 -2
  84. package/dist/core/monitoring/logger.js +14 -3
  85. package/dist/core/monitoring/logger.js.map +2 -2
  86. package/dist/core/monitoring/metrics.js +13 -2
  87. package/dist/core/monitoring/metrics.js.map +2 -2
  88. package/dist/core/monitoring/progress-tracker.js +12 -1
  89. package/dist/core/monitoring/progress-tracker.js.map +2 -2
  90. package/dist/core/monitoring/session-monitor.js.map +2 -2
  91. package/dist/core/performance/context-cache.js.map +2 -2
  92. package/dist/core/performance/lazy-context-loader.js.map +2 -2
  93. package/dist/core/performance/monitor.js.map +2 -2
  94. package/dist/core/performance/optimized-frame-context.js.map +2 -2
  95. package/dist/core/performance/performance-benchmark.js.map +2 -2
  96. package/dist/core/performance/performance-profiler.js +12 -1
  97. package/dist/core/performance/performance-profiler.js.map +2 -2
  98. package/dist/core/performance/streaming-jsonl-parser.js.map +2 -2
  99. package/dist/core/persistence/postgres-adapter.js.map +2 -2
  100. package/dist/core/projects/project-manager.js.map +2 -2
  101. package/dist/core/retrieval/context-retriever.js.map +2 -2
  102. package/dist/core/retrieval/graph-retrieval.js.map +2 -2
  103. package/dist/core/retrieval/llm-context-retrieval.js.map +2 -2
  104. package/dist/core/retrieval/retrieval-benchmarks.js.map +2 -2
  105. package/dist/core/retrieval/summary-generator.js.map +2 -2
  106. package/dist/core/session/clear-survival.js.map +2 -2
  107. package/dist/core/session/handoff-generator.js.map +2 -2
  108. package/dist/core/session/session-manager.js +16 -5
  109. package/dist/core/session/session-manager.js.map +2 -2
  110. package/dist/core/skills/skill-storage.js +13 -2
  111. package/dist/core/skills/skill-storage.js.map +2 -2
  112. package/dist/core/storage/chromadb-adapter.js.map +2 -2
  113. package/dist/core/storage/chromadb-simple.js.map +2 -2
  114. package/dist/core/storage/infinite-storage.js.map +2 -2
  115. package/dist/core/storage/railway-optimized-storage.js +19 -8
  116. package/dist/core/storage/railway-optimized-storage.js.map +2 -2
  117. package/dist/core/storage/remote-storage.js +12 -1
  118. package/dist/core/storage/remote-storage.js.map +2 -2
  119. package/dist/core/trace/cli-trace-wrapper.js +16 -5
  120. package/dist/core/trace/cli-trace-wrapper.js.map +2 -2
  121. package/dist/core/trace/db-trace-wrapper.js.map +2 -2
  122. package/dist/core/trace/debug-trace.js +21 -10
  123. package/dist/core/trace/debug-trace.js.map +2 -2
  124. package/dist/core/trace/index.js +46 -35
  125. package/dist/core/trace/index.js.map +2 -2
  126. package/dist/core/trace/trace-demo.js +12 -1
  127. package/dist/core/trace/trace-demo.js.map +2 -2
  128. package/dist/core/trace/trace-detector.js.map +2 -2
  129. package/dist/core/trace/trace-store.js.map +2 -2
  130. package/dist/core/utils/update-checker.js.map +2 -2
  131. package/dist/core/worktree/worktree-manager.js.map +2 -2
  132. package/dist/features/analytics/api/analytics-api.js.map +2 -2
  133. package/dist/features/analytics/core/analytics-service.js +12 -1
  134. package/dist/features/analytics/core/analytics-service.js.map +2 -2
  135. package/dist/features/analytics/queries/metrics-queries.js.map +2 -2
  136. package/dist/features/tasks/pebbles-task-store.js.map +2 -2
  137. package/dist/features/tui/components/analytics-panel.js.map +2 -2
  138. package/dist/features/tui/components/pr-tracker.js.map +2 -2
  139. package/dist/features/tui/components/session-monitor.js.map +2 -2
  140. package/dist/features/tui/components/subagent-fleet.js.map +2 -2
  141. package/dist/features/tui/components/task-board.js +650 -2
  142. package/dist/features/tui/components/task-board.js.map +2 -2
  143. package/dist/features/tui/index.js +16 -5
  144. package/dist/features/tui/index.js.map +2 -2
  145. package/dist/features/tui/services/data-service.js +25 -14
  146. package/dist/features/tui/services/data-service.js.map +2 -2
  147. package/dist/features/tui/services/linear-task-reader.js.map +2 -2
  148. package/dist/features/tui/services/websocket-client.js +13 -2
  149. package/dist/features/tui/services/websocket-client.js.map +2 -2
  150. package/dist/features/tui/terminal-compat.js +27 -16
  151. package/dist/features/tui/terminal-compat.js.map +2 -2
  152. package/dist/features/web/client/stores/task-store.js.map +2 -2
  153. package/dist/features/web/server/index.js +13 -2
  154. package/dist/features/web/server/index.js.map +2 -2
  155. package/dist/integrations/claude-code/enhanced-pre-clear-hooks.js.map +2 -2
  156. package/dist/integrations/claude-code/lifecycle-hooks.js.map +2 -2
  157. package/dist/integrations/claude-code/post-task-hooks.js.map +2 -2
  158. package/dist/integrations/linear/auth.js +17 -6
  159. package/dist/integrations/linear/auth.js.map +2 -2
  160. package/dist/integrations/linear/auto-sync.js.map +2 -2
  161. package/dist/integrations/linear/client.js.map +2 -2
  162. package/dist/integrations/linear/config.js.map +2 -2
  163. package/dist/integrations/linear/migration.js.map +2 -2
  164. package/dist/integrations/linear/oauth-server.js +13 -2
  165. package/dist/integrations/linear/oauth-server.js.map +2 -2
  166. package/dist/integrations/linear/rest-client.js.map +2 -2
  167. package/dist/integrations/linear/sync-enhanced.js +202 -0
  168. package/dist/integrations/linear/sync-enhanced.js.map +7 -0
  169. package/dist/integrations/linear/sync-manager.js.map +2 -2
  170. package/dist/integrations/linear/sync-service.js +12 -1
  171. package/dist/integrations/linear/sync-service.js.map +2 -2
  172. package/dist/integrations/linear/sync.js +34 -3
  173. package/dist/integrations/linear/sync.js.map +2 -2
  174. package/dist/integrations/linear/unified-sync.js +560 -0
  175. package/dist/integrations/linear/unified-sync.js.map +7 -0
  176. package/dist/integrations/linear/webhook-handler.js +12 -1
  177. package/dist/integrations/linear/webhook-handler.js.map +2 -2
  178. package/dist/integrations/linear/webhook-server.js +14 -3
  179. package/dist/integrations/linear/webhook-server.js.map +2 -2
  180. package/dist/integrations/linear/webhook.js +12 -1
  181. package/dist/integrations/linear/webhook.js.map +2 -2
  182. package/dist/integrations/mcp/handlers/context-handlers.js.map +2 -2
  183. package/dist/integrations/mcp/handlers/linear-handlers.js.map +2 -2
  184. package/dist/integrations/mcp/handlers/skill-handlers.js +13 -2
  185. package/dist/integrations/mcp/handlers/skill-handlers.js.map +2 -2
  186. package/dist/integrations/mcp/handlers/task-handlers.js.map +2 -2
  187. package/dist/integrations/mcp/handlers/trace-handlers.js.map +2 -2
  188. package/dist/integrations/mcp/middleware/tool-scoring.js.map +2 -2
  189. package/dist/integrations/mcp/refactored-server.js +15 -4
  190. package/dist/integrations/mcp/refactored-server.js.map +2 -2
  191. package/dist/integrations/mcp/server.js +12 -1
  192. package/dist/integrations/mcp/server.js.map +2 -2
  193. package/dist/integrations/mcp/tool-definitions.js.map +2 -2
  194. package/dist/integrations/pg-aiguide/embedding-provider.js +13 -2
  195. package/dist/integrations/pg-aiguide/embedding-provider.js.map +2 -2
  196. package/dist/integrations/pg-aiguide/semantic-search.js.map +2 -2
  197. package/dist/mcp/stackmemory-mcp-server.js +12 -1
  198. package/dist/mcp/stackmemory-mcp-server.js.map +2 -2
  199. package/dist/middleware/exponential-rate-limiter.js.map +2 -2
  200. package/dist/servers/production/auth-middleware.js +13 -2
  201. package/dist/servers/production/auth-middleware.js.map +2 -2
  202. package/dist/servers/railway/index.js +22 -11
  203. package/dist/servers/railway/index.js.map +2 -2
  204. package/dist/services/config-service.js.map +2 -2
  205. package/dist/services/context-service.js.map +2 -2
  206. package/dist/skills/claude-skills.js +105 -2
  207. package/dist/skills/claude-skills.js.map +2 -2
  208. package/dist/skills/dashboard-launcher.js.map +2 -2
  209. package/dist/skills/repo-ingestion-skill.js +561 -0
  210. package/dist/skills/repo-ingestion-skill.js.map +7 -0
  211. package/dist/utils/logger.js +12 -1
  212. package/dist/utils/logger.js.map +2 -2
  213. package/package.json +5 -1
@@ -8,20 +8,31 @@ import Database from "better-sqlite3";
8
8
  import { BrowserMCPIntegration } from "../../features/browser/browser-mcp.js";
9
9
  import { join, dirname } from "path";
10
10
  import { existsSync, mkdirSync } from "fs";
11
+ function getEnv(key, defaultValue) {
12
+ const value = process.env[key];
13
+ if (value === void 0) {
14
+ if (defaultValue !== void 0) return defaultValue;
15
+ throw new Error(`Environment variable ${key} is required`);
16
+ }
17
+ return value;
18
+ }
19
+ function getOptionalEnv(key) {
20
+ return process.env[key];
21
+ }
11
22
  const config = {
12
- port: parseInt(process.env.PORT || "3000"),
13
- environment: process.env.NODE_ENV || "development",
14
- corsOrigins: process.env.CORS_ORIGINS?.split(",") || [
23
+ port: parseInt(process.env["PORT"] || "3000"),
24
+ environment: process.env["NODE_ENV"] || "development",
25
+ corsOrigins: process.env["CORS_ORIGINS"]?.split(",") || [
15
26
  "http://localhost:3000"
16
27
  ],
17
- authMode: process.env.AUTH_MODE || "api_key",
18
- apiKeySecret: process.env.API_KEY_SECRET || "development-secret",
19
- jwtSecret: process.env.JWT_SECRET || "development-jwt-secret",
20
- databaseUrl: process.env.DATABASE_URL || join(process.cwd(), ".stackmemory", "railway.db"),
21
- rateLimitEnabled: process.env.RATE_LIMIT_ENABLED === "true",
22
- rateLimitFree: parseInt(process.env.RATE_LIMIT_FREE || "100"),
23
- enableWebSocket: process.env.ENABLE_WEBSOCKET !== "false",
24
- enableAnalytics: process.env.ENABLE_ANALYTICS === "true"
28
+ authMode: process.env["AUTH_MODE"] || "api_key",
29
+ apiKeySecret: process.env["API_KEY_SECRET"] || "development-secret",
30
+ jwtSecret: process.env["JWT_SECRET"] || "development-jwt-secret",
31
+ databaseUrl: process.env["DATABASE_URL"] || join(process.cwd(), ".stackmemory", "railway.db"),
32
+ rateLimitEnabled: process.env["RATE_LIMIT_ENABLED"] === "true",
33
+ rateLimitFree: parseInt(process.env["RATE_LIMIT_FREE"] || "100"),
34
+ enableWebSocket: process.env["ENABLE_WEBSOCKET"] !== "false",
35
+ enableAnalytics: process.env["ENABLE_ANALYTICS"] === "true"
25
36
  };
26
37
  const rateLimiter = /* @__PURE__ */ new Map();
27
38
  class RailwayMCPServer {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/servers/railway/index.ts"],
4
- "sourcesContent": ["#!/usr/bin/env node\n/**\n * Railway MCP Server Entry Point\n * Simplified production server for Railway deployment\n */\n\nimport express from 'express';\nimport { createServer } from 'http';\nimport { WebSocketServer } from 'ws';\nimport cors from 'cors';\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\n// WebSocket transport will be handled differently for Railway\nimport Database from 'better-sqlite3';\nimport { BrowserMCPIntegration } from '../../features/browser/browser-mcp.js';\nimport { join, dirname } from 'path';\nimport { existsSync, mkdirSync } from 'fs';\n\n// Configuration\nconst config = {\n port: parseInt(process.env.PORT || '3000'),\n environment: process.env.NODE_ENV || 'development',\n corsOrigins: process.env.CORS_ORIGINS?.split(',') || [\n 'http://localhost:3000',\n ],\n authMode: process.env.AUTH_MODE || 'api_key',\n apiKeySecret: process.env.API_KEY_SECRET || 'development-secret',\n jwtSecret: process.env.JWT_SECRET || 'development-jwt-secret',\n databaseUrl:\n process.env.DATABASE_URL ||\n join(process.cwd(), '.stackmemory', 'railway.db'),\n rateLimitEnabled: process.env.RATE_LIMIT_ENABLED === 'true',\n rateLimitFree: parseInt(process.env.RATE_LIMIT_FREE || '100'),\n enableWebSocket: process.env.ENABLE_WEBSOCKET !== 'false',\n enableAnalytics: process.env.ENABLE_ANALYTICS === 'true',\n};\n\n// Simple in-memory rate limiter\nconst rateLimiter = new Map<string, { count: number; resetTime: number }>();\n\nclass RailwayMCPServer {\n private app: express.Application;\n private httpServer: any;\n private wss?: WebSocketServer;\n private mcpServer!: Server;\n private db!: Database.Database;\n private connections: Map<string, any> = new Map();\n private browserMCP: BrowserMCPIntegration;\n\n constructor() {\n this.app = express();\n this.httpServer = createServer(this.app);\n this.initializeDatabase();\n this.setupMiddleware();\n this.setupRoutes();\n this.setupMCPServer();\n\n // Initialize Browser MCP for Railway\n this.browserMCP = new BrowserMCPIntegration({\n headless: true, // Always headless in production\n defaultViewport: { width: 1280, height: 720 },\n });\n\n if (config.enableWebSocket) {\n this.setupWebSocket();\n }\n }\n\n private initializeDatabase(): void {\n // Use PostgreSQL in production, SQLite for development\n if (\n config.environment === 'production' &&\n config.databaseUrl.startsWith('postgresql://')\n ) {\n console.log('Using PostgreSQL database');\n // In production, we'd use pg client here\n // For now, we'll use SQLite as fallback\n const dbPath = '/tmp/stackmemory.db';\n this.db = new Database(dbPath);\n } else {\n // Create database directory if it doesn't exist\n const dbDir = dirname(config.databaseUrl);\n if (!existsSync(dbDir)) {\n mkdirSync(dbDir, { recursive: true });\n }\n this.db = new Database(config.databaseUrl);\n }\n\n // Initialize tables\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS contexts (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id TEXT NOT NULL,\n content TEXT NOT NULL,\n type TEXT DEFAULT 'general',\n metadata TEXT DEFAULT '{}',\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE TABLE IF NOT EXISTS api_keys (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n key_hash TEXT UNIQUE NOT NULL,\n user_id TEXT NOT NULL,\n name TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n last_used DATETIME,\n revoked BOOLEAN DEFAULT 0\n );\n\n CREATE INDEX IF NOT EXISTS idx_contexts_project ON contexts(project_id);\n CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys(key_hash);\n `);\n }\n\n private setupMiddleware(): void {\n // CORS\n this.app.use(\n cors({\n origin: config.corsOrigins,\n credentials: true,\n })\n );\n\n // Body parsing\n this.app.use(express.json({ limit: '10mb' }));\n\n // Request logging\n this.app.use((req, res, next) => {\n console.log(`${new Date().toISOString()} ${req.method} ${req.path}`);\n next();\n });\n\n // Simple authentication middleware\n this.app.use('/api', this.authenticate.bind(this));\n\n // Rate limiting\n if (config.rateLimitEnabled) {\n this.app.use('/api', this.rateLimit.bind(this));\n }\n }\n\n private authenticate(\n req: express.Request,\n res: express.Response,\n next: express.NextFunction\n ): any {\n // Skip auth for health check\n if (req.path === '/health') {\n return next();\n }\n\n const authHeader = req.headers.authorization;\n\n if (config.authMode === 'api_key') {\n // Simple API key authentication\n if (!authHeader?.startsWith('Bearer ')) {\n return res.status(401).json({ error: 'Missing API key' });\n }\n\n const apiKey = authHeader.substring(7);\n\n // In production, validate against database\n // For now, simple check\n if (apiKey.length < 32) {\n return res.status(403).json({ error: 'Invalid API key' });\n }\n\n (req as any).user = { id: 'api-user', tier: 'free' };\n next();\n } else {\n // OAuth/JWT mode would go here\n next();\n }\n }\n\n private rateLimit(\n req: express.Request,\n res: express.Response,\n next: express.NextFunction\n ): any {\n const userId = (req as any).user?.id || req.ip;\n const now = Date.now();\n const windowMs = 15 * 60 * 1000; // 15 minutes\n\n const userLimit = rateLimiter.get(userId);\n\n if (!userLimit || userLimit.resetTime < now) {\n rateLimiter.set(userId, {\n count: 1,\n resetTime: now + windowMs,\n });\n return next();\n }\n\n if (userLimit.count >= config.rateLimitFree) {\n const retryAfter = Math.ceil((userLimit.resetTime - now) / 1000);\n res.setHeader('Retry-After', retryAfter.toString());\n return res.status(429).json({\n error: 'Rate limit exceeded',\n retryAfter,\n });\n }\n\n userLimit.count++;\n next();\n }\n\n private setupRoutes(): void {\n // Health check\n this.app.get('/health', (req, res) => {\n const health = {\n status: 'healthy',\n version: '1.0.0',\n timestamp: new Date().toISOString(),\n uptime: process.uptime(),\n environment: config.environment,\n };\n res.json(health);\n });\n\n // API Routes\n this.app.post('/api/context/save', (req, res) => {\n try {\n const {\n projectId = 'default',\n content,\n type = 'general',\n metadata = {},\n } = req.body;\n\n const stmt = this.db.prepare(`\n INSERT INTO contexts (project_id, content, type, metadata)\n VALUES (?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n projectId,\n content,\n type,\n JSON.stringify(metadata)\n );\n\n res.json({\n success: true,\n id: result.lastInsertRowid,\n });\n } catch (error: any) {\n res.status(500).json({ error: error.message });\n }\n });\n\n this.app.get('/api/context/load', (req, res) => {\n try {\n const { projectId = 'default', limit = 10, offset = 0 } = req.query;\n\n const stmt = this.db.prepare(`\n SELECT * FROM contexts\n WHERE project_id = ?\n ORDER BY created_at DESC\n LIMIT ? OFFSET ?\n `);\n\n const contexts = stmt.all(projectId, limit, offset);\n\n res.json({\n success: true,\n contexts: contexts.map((c: any) => ({\n ...c,\n metadata: JSON.parse(c.metadata || '{}'),\n })),\n });\n } catch (error: any) {\n res.status(500).json({ error: error.message });\n }\n });\n\n // MCP tool execution endpoint\n this.app.post('/api/tools/execute', async (req, res) => {\n try {\n const { tool, params } = req.body;\n\n // Execute MCP tool\n const result = await this.executeMCPTool(tool, params);\n\n res.json({\n success: true,\n result,\n });\n } catch (error: any) {\n res.status(500).json({ error: error.message });\n }\n });\n\n // Analytics endpoint\n if (config.enableAnalytics) {\n this.app.get('/api/analytics', (req, res) => {\n try {\n const { projectId = 'default' } = req.query;\n\n const stats = this.db\n .prepare(\n `\n SELECT \n COUNT(*) as total_contexts,\n COUNT(DISTINCT type) as unique_types,\n MAX(created_at) as last_activity\n FROM contexts\n WHERE project_id = ?\n `\n )\n .get(projectId);\n\n res.json({\n success: true,\n analytics: stats,\n });\n } catch (error: any) {\n res.status(500).json({ error: error.message });\n }\n });\n }\n }\n\n private setupWebSocket(): void {\n this.wss = new WebSocketServer({\n server: this.httpServer,\n path: '/ws',\n });\n\n this.wss.on('connection', (ws, _req) => {\n console.log('WebSocket connection established');\n\n const connectionId = Math.random().toString(36).substring(7);\n this.connections.set(connectionId, ws);\n\n ws.on('message', async (data) => {\n try {\n const message = JSON.parse(data.toString());\n const response = await this.handleWebSocketMessage(message);\n ws.send(JSON.stringify(response));\n } catch (error: any) {\n ws.send(\n JSON.stringify({\n error: error.message,\n })\n );\n }\n });\n\n ws.on('close', () => {\n this.connections.delete(connectionId);\n console.log('WebSocket connection closed');\n });\n });\n }\n\n private async handleWebSocketMessage(message: any): Promise<any> {\n const { type, tool, params } = message;\n\n switch (type) {\n case 'execute':\n return await this.executeMCPTool(tool, params);\n\n case 'ping':\n return { type: 'pong' };\n\n default:\n throw new Error(`Unknown message type: ${type}`);\n }\n }\n\n private async setupMCPServer(): Promise<void> {\n this.mcpServer = new Server(\n {\n name: 'stackmemory-railway',\n version: '1.0.0',\n },\n {\n capabilities: {\n tools: {},\n resources: {},\n },\n }\n );\n\n // Initialize Browser MCP with the server\n await this.browserMCP.initialize(this.mcpServer);\n\n // Register MCP tools\n this.mcpServer.setRequestHandler('tools/list' as any, async () => {\n return {\n tools: [\n {\n name: 'save_context',\n description: 'Save context to StackMemory',\n inputSchema: {\n type: 'object',\n properties: {\n content: { type: 'string' },\n type: { type: 'string' },\n },\n },\n },\n {\n name: 'load_context',\n description: 'Load context from StackMemory',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string' },\n limit: { type: 'number' },\n },\n },\n },\n ],\n };\n });\n\n this.mcpServer.setRequestHandler(\n 'tools/call' as any,\n async (request: any) => {\n const { name, arguments: args } = request.params;\n return await this.executeMCPTool(name, args);\n }\n );\n }\n\n private async executeMCPTool(tool: string, params: any): Promise<any> {\n switch (tool) {\n case 'save_context': {\n const stmt = this.db.prepare(`\n INSERT INTO contexts (project_id, content, type, metadata)\n VALUES (?, ?, ?, ?)\n `);\n const result = stmt.run(\n params.projectId || 'default',\n params.content,\n params.type || 'general',\n JSON.stringify(params.metadata || {})\n );\n return { id: result.lastInsertRowid, success: true };\n }\n\n case 'load_context': {\n const stmt = this.db.prepare(`\n SELECT * FROM contexts\n WHERE project_id = ? AND content LIKE ?\n ORDER BY created_at DESC\n LIMIT ?\n `);\n const contexts = stmt.all(\n params.projectId || 'default',\n `%${params.query || ''}%`,\n params.limit || 10\n );\n return { contexts, success: true };\n }\n\n default:\n throw new Error(`Unknown tool: ${tool}`);\n }\n }\n\n public start(): void {\n this.httpServer.listen(config.port, '0.0.0.0', () => {\n console.log(`\n\uD83D\uDE82 Railway MCP Server Started\n================================\nEnvironment: ${config.environment}\nPort: ${config.port}\nWebSocket: ${config.enableWebSocket ? 'Enabled' : 'Disabled'}\nAnalytics: ${config.enableAnalytics ? 'Enabled' : 'Disabled'}\nRate Limiting: ${config.rateLimitEnabled ? 'Enabled' : 'Disabled'}\nAuth Mode: ${config.authMode}\n================================\nHealth: http://localhost:${config.port}/health\n `);\n });\n }\n}\n\n// Start server\nconst server = new RailwayMCPServer();\nserver.start();\n\n// Graceful shutdown\nprocess.on('SIGTERM', () => {\n console.log('Shutting down gracefully...');\n process.exit(0);\n});\n\nprocess.on('SIGINT', () => {\n console.log('Shutting down...');\n process.exit(0);\n});\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["#!/usr/bin/env node\n/**\n * Railway MCP Server Entry Point\n * Simplified production server for Railway deployment\n */\n\nimport express from 'express';\nimport { createServer } from 'http';\nimport { WebSocketServer } from 'ws';\nimport cors from 'cors';\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\n// WebSocket transport will be handled differently for Railway\nimport Database from 'better-sqlite3';\nimport { BrowserMCPIntegration } from '../../features/browser/browser-mcp.js';\nimport { join, dirname } from 'path';\nimport { existsSync, mkdirSync } from 'fs';\n// Type-safe environment variable access\nfunction getEnv(key: string, defaultValue?: string): string {\n const value = process.env[key];\n if (value === undefined) {\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Environment variable ${key} is required`);\n }\n return value;\n}\n\nfunction getOptionalEnv(key: string): string | undefined {\n return process.env[key];\n}\n\n\n// Configuration\nconst config = {\n port: parseInt(process.env['PORT'] || '3000'),\n environment: process.env['NODE_ENV'] || 'development',\n corsOrigins: process.env['CORS_ORIGINS']?.split(',') || [\n 'http://localhost:3000',\n ],\n authMode: process.env['AUTH_MODE'] || 'api_key',\n apiKeySecret: process.env['API_KEY_SECRET'] || 'development-secret',\n jwtSecret: process.env['JWT_SECRET'] || 'development-jwt-secret',\n databaseUrl:\n process.env['DATABASE_URL'] ||\n join(process.cwd(), '.stackmemory', 'railway.db'),\n rateLimitEnabled: process.env['RATE_LIMIT_ENABLED'] === 'true',\n rateLimitFree: parseInt(process.env['RATE_LIMIT_FREE'] || '100'),\n enableWebSocket: process.env['ENABLE_WEBSOCKET'] !== 'false',\n enableAnalytics: process.env['ENABLE_ANALYTICS'] === 'true',\n};\n\n// Simple in-memory rate limiter\nconst rateLimiter = new Map<string, { count: number; resetTime: number }>();\n\nclass RailwayMCPServer {\n private app: express.Application;\n private httpServer: any;\n private wss?: WebSocketServer;\n private mcpServer!: Server;\n private db!: Database.Database;\n private connections: Map<string, any> = new Map();\n private browserMCP: BrowserMCPIntegration;\n\n constructor() {\n this.app = express();\n this.httpServer = createServer(this.app);\n this.initializeDatabase();\n this.setupMiddleware();\n this.setupRoutes();\n this.setupMCPServer();\n\n // Initialize Browser MCP for Railway\n this.browserMCP = new BrowserMCPIntegration({\n headless: true, // Always headless in production\n defaultViewport: { width: 1280, height: 720 },\n });\n\n if (config.enableWebSocket) {\n this.setupWebSocket();\n }\n }\n\n private initializeDatabase(): void {\n // Use PostgreSQL in production, SQLite for development\n if (\n config.environment === 'production' &&\n config.databaseUrl.startsWith('postgresql://')\n ) {\n console.log('Using PostgreSQL database');\n // In production, we'd use pg client here\n // For now, we'll use SQLite as fallback\n const dbPath = '/tmp/stackmemory.db';\n this.db = new Database(dbPath);\n } else {\n // Create database directory if it doesn't exist\n const dbDir = dirname(config.databaseUrl);\n if (!existsSync(dbDir)) {\n mkdirSync(dbDir, { recursive: true });\n }\n this.db = new Database(config.databaseUrl);\n }\n\n // Initialize tables\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS contexts (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id TEXT NOT NULL,\n content TEXT NOT NULL,\n type TEXT DEFAULT 'general',\n metadata TEXT DEFAULT '{}',\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE TABLE IF NOT EXISTS api_keys (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n key_hash TEXT UNIQUE NOT NULL,\n user_id TEXT NOT NULL,\n name TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n last_used DATETIME,\n revoked BOOLEAN DEFAULT 0\n );\n\n CREATE INDEX IF NOT EXISTS idx_contexts_project ON contexts(project_id);\n CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys(key_hash);\n `);\n }\n\n private setupMiddleware(): void {\n // CORS\n this.app.use(\n cors({\n origin: config.corsOrigins,\n credentials: true,\n })\n );\n\n // Body parsing\n this.app.use(express.json({ limit: '10mb' }));\n\n // Request logging\n this.app.use((req, res, next) => {\n console.log(`${new Date().toISOString()} ${req.method} ${req.path}`);\n next();\n });\n\n // Simple authentication middleware\n this.app.use('/api', this.authenticate.bind(this));\n\n // Rate limiting\n if (config.rateLimitEnabled) {\n this.app.use('/api', this.rateLimit.bind(this));\n }\n }\n\n private authenticate(\n req: express.Request,\n res: express.Response,\n next: express.NextFunction\n ): any {\n // Skip auth for health check\n if (req.path === '/health') {\n return next();\n }\n\n const authHeader = req.headers.authorization;\n\n if (config.authMode === 'api_key') {\n // Simple API key authentication\n if (!authHeader?.startsWith('Bearer ')) {\n return res.status(401).json({ error: 'Missing API key' });\n }\n\n const apiKey = authHeader.substring(7);\n\n // In production, validate against database\n // For now, simple check\n if (apiKey.length < 32) {\n return res.status(403).json({ error: 'Invalid API key' });\n }\n\n (req as any).user = { id: 'api-user', tier: 'free' };\n next();\n } else {\n // OAuth/JWT mode would go here\n next();\n }\n }\n\n private rateLimit(\n req: express.Request,\n res: express.Response,\n next: express.NextFunction\n ): any {\n const userId = (req as any).user?.id || req.ip;\n const now = Date.now();\n const windowMs = 15 * 60 * 1000; // 15 minutes\n\n const userLimit = rateLimiter.get(userId);\n\n if (!userLimit || userLimit.resetTime < now) {\n rateLimiter.set(userId, {\n count: 1,\n resetTime: now + windowMs,\n });\n return next();\n }\n\n if (userLimit.count >= config.rateLimitFree) {\n const retryAfter = Math.ceil((userLimit.resetTime - now) / 1000);\n res.setHeader('Retry-After', retryAfter.toString());\n return res.status(429).json({\n error: 'Rate limit exceeded',\n retryAfter,\n });\n }\n\n userLimit.count++;\n next();\n }\n\n private setupRoutes(): void {\n // Health check\n this.app.get('/health', (req, res) => {\n const health = {\n status: 'healthy',\n version: '1.0.0',\n timestamp: new Date().toISOString(),\n uptime: process.uptime(),\n environment: config.environment,\n };\n res.json(health);\n });\n\n // API Routes\n this.app.post('/api/context/save', (req, res) => {\n try {\n const {\n projectId = 'default',\n content,\n type = 'general',\n metadata = {},\n } = req.body;\n\n const stmt = this.db.prepare(`\n INSERT INTO contexts (project_id, content, type, metadata)\n VALUES (?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n projectId,\n content,\n type,\n JSON.stringify(metadata)\n );\n\n res.json({\n success: true,\n id: result.lastInsertRowid,\n });\n } catch (error: any) {\n res.status(500).json({ error: error.message });\n }\n });\n\n this.app.get('/api/context/load', (req, res) => {\n try {\n const { projectId = 'default', limit = 10, offset = 0 } = req.query;\n\n const stmt = this.db.prepare(`\n SELECT * FROM contexts\n WHERE project_id = ?\n ORDER BY created_at DESC\n LIMIT ? OFFSET ?\n `);\n\n const contexts = stmt.all(projectId, limit, offset);\n\n res.json({\n success: true,\n contexts: contexts.map((c: any) => ({\n ...c,\n metadata: JSON.parse(c.metadata || '{}'),\n })),\n });\n } catch (error: any) {\n res.status(500).json({ error: error.message });\n }\n });\n\n // MCP tool execution endpoint\n this.app.post('/api/tools/execute', async (req, res) => {\n try {\n const { tool, params } = req.body;\n\n // Execute MCP tool\n const result = await this.executeMCPTool(tool, params);\n\n res.json({\n success: true,\n result,\n });\n } catch (error: any) {\n res.status(500).json({ error: error.message });\n }\n });\n\n // Analytics endpoint\n if (config.enableAnalytics) {\n this.app.get('/api/analytics', (req, res) => {\n try {\n const { projectId = 'default' } = req.query;\n\n const stats = this.db\n .prepare(\n `\n SELECT \n COUNT(*) as total_contexts,\n COUNT(DISTINCT type) as unique_types,\n MAX(created_at) as last_activity\n FROM contexts\n WHERE project_id = ?\n `\n )\n .get(projectId);\n\n res.json({\n success: true,\n analytics: stats,\n });\n } catch (error: any) {\n res.status(500).json({ error: error.message });\n }\n });\n }\n }\n\n private setupWebSocket(): void {\n this.wss = new WebSocketServer({\n server: this.httpServer,\n path: '/ws',\n });\n\n this.wss.on('connection', (ws, _req) => {\n console.log('WebSocket connection established');\n\n const connectionId = Math.random().toString(36).substring(7);\n this.connections.set(connectionId, ws);\n\n ws.on('message', async (data) => {\n try {\n const message = JSON.parse(data.toString());\n const response = await this.handleWebSocketMessage(message);\n ws.send(JSON.stringify(response));\n } catch (error: any) {\n ws.send(\n JSON.stringify({\n error: error.message,\n })\n );\n }\n });\n\n ws.on('close', () => {\n this.connections.delete(connectionId);\n console.log('WebSocket connection closed');\n });\n });\n }\n\n private async handleWebSocketMessage(message: any): Promise<any> {\n const { type, tool, params } = message;\n\n switch (type) {\n case 'execute':\n return await this.executeMCPTool(tool, params);\n\n case 'ping':\n return { type: 'pong' };\n\n default:\n throw new Error(`Unknown message type: ${type}`);\n }\n }\n\n private async setupMCPServer(): Promise<void> {\n this.mcpServer = new Server(\n {\n name: 'stackmemory-railway',\n version: '1.0.0',\n },\n {\n capabilities: {\n tools: {},\n resources: {},\n },\n }\n );\n\n // Initialize Browser MCP with the server\n await this.browserMCP.initialize(this.mcpServer);\n\n // Register MCP tools\n this.mcpServer.setRequestHandler('tools/list' as any, async () => {\n return {\n tools: [\n {\n name: 'save_context',\n description: 'Save context to StackMemory',\n inputSchema: {\n type: 'object',\n properties: {\n content: { type: 'string' },\n type: { type: 'string' },\n },\n },\n },\n {\n name: 'load_context',\n description: 'Load context from StackMemory',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string' },\n limit: { type: 'number' },\n },\n },\n },\n ],\n };\n });\n\n this.mcpServer.setRequestHandler(\n 'tools/call' as any,\n async (request: any) => {\n const { name, arguments: args } = request.params;\n return await this.executeMCPTool(name, args);\n }\n );\n }\n\n private async executeMCPTool(tool: string, params: any): Promise<any> {\n switch (tool) {\n case 'save_context': {\n const stmt = this.db.prepare(`\n INSERT INTO contexts (project_id, content, type, metadata)\n VALUES (?, ?, ?, ?)\n `);\n const result = stmt.run(\n params.projectId || 'default',\n params.content,\n params.type || 'general',\n JSON.stringify(params.metadata || {})\n );\n return { id: result.lastInsertRowid, success: true };\n }\n\n case 'load_context': {\n const stmt = this.db.prepare(`\n SELECT * FROM contexts\n WHERE project_id = ? AND content LIKE ?\n ORDER BY created_at DESC\n LIMIT ?\n `);\n const contexts = stmt.all(\n params.projectId || 'default',\n `%${params.query || ''}%`,\n params.limit || 10\n );\n return { contexts, success: true };\n }\n\n default:\n throw new Error(`Unknown tool: ${tool}`);\n }\n }\n\n public start(): void {\n this.httpServer.listen(config.port, '0.0.0.0', () => {\n console.log(`\n\uD83D\uDE82 Railway MCP Server Started\n================================\nEnvironment: ${config.environment}\nPort: ${config.port}\nWebSocket: ${config.enableWebSocket ? 'Enabled' : 'Disabled'}\nAnalytics: ${config.enableAnalytics ? 'Enabled' : 'Disabled'}\nRate Limiting: ${config.rateLimitEnabled ? 'Enabled' : 'Disabled'}\nAuth Mode: ${config.authMode}\n================================\nHealth: http://localhost:${config.port}/health\n `);\n });\n }\n}\n\n// Start server\nconst server = new RailwayMCPServer();\nserver.start();\n\n// Graceful shutdown\nprocess.on('SIGTERM', () => {\n console.log('Shutting down gracefully...');\n process.exit(0);\n});\n\nprocess.on('SIGINT', () => {\n console.log('Shutting down...');\n process.exit(0);\n});\n"],
5
+ "mappings": ";AAMA,OAAO,aAAa;AACpB,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,OAAO,UAAU;AACjB,SAAS,cAAc;AAEvB,OAAO,cAAc;AACrB,SAAS,6BAA6B;AACtC,SAAS,MAAM,eAAe;AAC9B,SAAS,YAAY,iBAAiB;AAEtC,SAAS,OAAO,KAAa,cAA+B;AAC1D,QAAM,QAAQ,QAAQ,IAAI,GAAG;AAC7B,MAAI,UAAU,QAAW;AACvB,QAAI,iBAAiB,OAAW,QAAO;AACvC,UAAM,IAAI,MAAM,wBAAwB,GAAG,cAAc;AAAA,EAC3D;AACA,SAAO;AACT;AAEA,SAAS,eAAe,KAAiC;AACvD,SAAO,QAAQ,IAAI,GAAG;AACxB;AAIA,MAAM,SAAS;AAAA,EACb,MAAM,SAAS,QAAQ,IAAI,MAAM,KAAK,MAAM;AAAA,EAC5C,aAAa,QAAQ,IAAI,UAAU,KAAK;AAAA,EACxC,aAAa,QAAQ,IAAI,cAAc,GAAG,MAAM,GAAG,KAAK;AAAA,IACtD;AAAA,EACF;AAAA,EACA,UAAU,QAAQ,IAAI,WAAW,KAAK;AAAA,EACtC,cAAc,QAAQ,IAAI,gBAAgB,KAAK;AAAA,EAC/C,WAAW,QAAQ,IAAI,YAAY,KAAK;AAAA,EACxC,aACE,QAAQ,IAAI,cAAc,KAC1B,KAAK,QAAQ,IAAI,GAAG,gBAAgB,YAAY;AAAA,EAClD,kBAAkB,QAAQ,IAAI,oBAAoB,MAAM;AAAA,EACxD,eAAe,SAAS,QAAQ,IAAI,iBAAiB,KAAK,KAAK;AAAA,EAC/D,iBAAiB,QAAQ,IAAI,kBAAkB,MAAM;AAAA,EACrD,iBAAiB,QAAQ,IAAI,kBAAkB,MAAM;AACvD;AAGA,MAAM,cAAc,oBAAI,IAAkD;AAE1E,MAAM,iBAAiB;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAgC,oBAAI,IAAI;AAAA,EACxC;AAAA,EAER,cAAc;AACZ,SAAK,MAAM,QAAQ;AACnB,SAAK,aAAa,aAAa,KAAK,GAAG;AACvC,SAAK,mBAAmB;AACxB,SAAK,gBAAgB;AACrB,SAAK,YAAY;AACjB,SAAK,eAAe;AAGpB,SAAK,aAAa,IAAI,sBAAsB;AAAA,MAC1C,UAAU;AAAA;AAAA,MACV,iBAAiB,EAAE,OAAO,MAAM,QAAQ,IAAI;AAAA,IAC9C,CAAC;AAED,QAAI,OAAO,iBAAiB;AAC1B,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA,EAEQ,qBAA2B;AAEjC,QACE,OAAO,gBAAgB,gBACvB,OAAO,YAAY,WAAW,eAAe,GAC7C;AACA,cAAQ,IAAI,2BAA2B;AAGvC,YAAM,SAAS;AACf,WAAK,KAAK,IAAI,SAAS,MAAM;AAAA,IAC/B,OAAO;AAEL,YAAM,QAAQ,QAAQ,OAAO,WAAW;AACxC,UAAI,CAAC,WAAW,KAAK,GAAG;AACtB,kBAAU,OAAO,EAAE,WAAW,KAAK,CAAC;AAAA,MACtC;AACA,WAAK,KAAK,IAAI,SAAS,OAAO,WAAW;AAAA,IAC3C;AAGA,SAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAuBZ;AAAA,EACH;AAAA,EAEQ,kBAAwB;AAE9B,SAAK,IAAI;AAAA,MACP,KAAK;AAAA,QACH,QAAQ,OAAO;AAAA,QACf,aAAa;AAAA,MACf,CAAC;AAAA,IACH;AAGA,SAAK,IAAI,IAAI,QAAQ,KAAK,EAAE,OAAO,OAAO,CAAC,CAAC;AAG5C,SAAK,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;AAC/B,cAAQ,IAAI,IAAG,oBAAI,KAAK,GAAE,YAAY,CAAC,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,EAAE;AACnE,WAAK;AAAA,IACP,CAAC;AAGD,SAAK,IAAI,IAAI,QAAQ,KAAK,aAAa,KAAK,IAAI,CAAC;AAGjD,QAAI,OAAO,kBAAkB;AAC3B,WAAK,IAAI,IAAI,QAAQ,KAAK,UAAU,KAAK,IAAI,CAAC;AAAA,IAChD;AAAA,EACF;AAAA,EAEQ,aACN,KACA,KACA,MACK;AAEL,QAAI,IAAI,SAAS,WAAW;AAC1B,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,aAAa,IAAI,QAAQ;AAE/B,QAAI,OAAO,aAAa,WAAW;AAEjC,UAAI,CAAC,YAAY,WAAW,SAAS,GAAG;AACtC,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MAC1D;AAEA,YAAM,SAAS,WAAW,UAAU,CAAC;AAIrC,UAAI,OAAO,SAAS,IAAI;AACtB,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MAC1D;AAEA,MAAC,IAAY,OAAO,EAAE,IAAI,YAAY,MAAM,OAAO;AACnD,WAAK;AAAA,IACP,OAAO;AAEL,WAAK;AAAA,IACP;AAAA,EACF;AAAA,EAEQ,UACN,KACA,KACA,MACK;AACL,UAAM,SAAU,IAAY,MAAM,MAAM,IAAI;AAC5C,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,WAAW,KAAK,KAAK;AAE3B,UAAM,YAAY,YAAY,IAAI,MAAM;AAExC,QAAI,CAAC,aAAa,UAAU,YAAY,KAAK;AAC3C,kBAAY,IAAI,QAAQ;AAAA,QACtB,OAAO;AAAA,QACP,WAAW,MAAM;AAAA,MACnB,CAAC;AACD,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,UAAU,SAAS,OAAO,eAAe;AAC3C,YAAM,aAAa,KAAK,MAAM,UAAU,YAAY,OAAO,GAAI;AAC/D,UAAI,UAAU,eAAe,WAAW,SAAS,CAAC;AAClD,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QAC1B,OAAO;AAAA,QACP;AAAA,MACF,CAAC;AAAA,IACH;AAEA,cAAU;AACV,SAAK;AAAA,EACP;AAAA,EAEQ,cAAoB;AAE1B,SAAK,IAAI,IAAI,WAAW,CAAC,KAAK,QAAQ;AACpC,YAAM,SAAS;AAAA,QACb,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC,QAAQ,QAAQ,OAAO;AAAA,QACvB,aAAa,OAAO;AAAA,MACtB;AACA,UAAI,KAAK,MAAM;AAAA,IACjB,CAAC;AAGD,SAAK,IAAI,KAAK,qBAAqB,CAAC,KAAK,QAAQ;AAC/C,UAAI;AACF,cAAM;AAAA,UACJ,YAAY;AAAA,UACZ;AAAA,UACA,OAAO;AAAA,UACP,WAAW,CAAC;AAAA,QACd,IAAI,IAAI;AAER,cAAM,OAAO,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA,SAG5B;AAED,cAAM,SAAS,KAAK;AAAA,UAClB;AAAA,UACA;AAAA,UACA;AAAA,UACA,KAAK,UAAU,QAAQ;AAAA,QACzB;AAEA,YAAI,KAAK;AAAA,UACP,SAAS;AAAA,UACT,IAAI,OAAO;AAAA,QACb,CAAC;AAAA,MACH,SAAS,OAAY;AACnB,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,MAAM,QAAQ,CAAC;AAAA,MAC/C;AAAA,IACF,CAAC;AAED,SAAK,IAAI,IAAI,qBAAqB,CAAC,KAAK,QAAQ;AAC9C,UAAI;AACF,cAAM,EAAE,YAAY,WAAW,QAAQ,IAAI,SAAS,EAAE,IAAI,IAAI;AAE9D,cAAM,OAAO,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,SAK5B;AAED,cAAM,WAAW,KAAK,IAAI,WAAW,OAAO,MAAM;AAElD,YAAI,KAAK;AAAA,UACP,SAAS;AAAA,UACT,UAAU,SAAS,IAAI,CAAC,OAAY;AAAA,YAClC,GAAG;AAAA,YACH,UAAU,KAAK,MAAM,EAAE,YAAY,IAAI;AAAA,UACzC,EAAE;AAAA,QACJ,CAAC;AAAA,MACH,SAAS,OAAY;AACnB,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,MAAM,QAAQ,CAAC;AAAA,MAC/C;AAAA,IACF,CAAC;AAGD,SAAK,IAAI,KAAK,sBAAsB,OAAO,KAAK,QAAQ;AACtD,UAAI;AACF,cAAM,EAAE,MAAM,OAAO,IAAI,IAAI;AAG7B,cAAM,SAAS,MAAM,KAAK,eAAe,MAAM,MAAM;AAErD,YAAI,KAAK;AAAA,UACP,SAAS;AAAA,UACT;AAAA,QACF,CAAC;AAAA,MACH,SAAS,OAAY;AACnB,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,MAAM,QAAQ,CAAC;AAAA,MAC/C;AAAA,IACF,CAAC;AAGD,QAAI,OAAO,iBAAiB;AAC1B,WAAK,IAAI,IAAI,kBAAkB,CAAC,KAAK,QAAQ;AAC3C,YAAI;AACF,gBAAM,EAAE,YAAY,UAAU,IAAI,IAAI;AAEtC,gBAAM,QAAQ,KAAK,GAChB;AAAA,YACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAQF,EACC,IAAI,SAAS;AAEhB,cAAI,KAAK;AAAA,YACP,SAAS;AAAA,YACT,WAAW;AAAA,UACb,CAAC;AAAA,QACH,SAAS,OAAY;AACnB,cAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,MAAM,QAAQ,CAAC;AAAA,QAC/C;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,iBAAuB;AAC7B,SAAK,MAAM,IAAI,gBAAgB;AAAA,MAC7B,QAAQ,KAAK;AAAA,MACb,MAAM;AAAA,IACR,CAAC;AAED,SAAK,IAAI,GAAG,cAAc,CAAC,IAAI,SAAS;AACtC,cAAQ,IAAI,kCAAkC;AAE9C,YAAM,eAAe,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC;AAC3D,WAAK,YAAY,IAAI,cAAc,EAAE;AAErC,SAAG,GAAG,WAAW,OAAO,SAAS;AAC/B,YAAI;AACF,gBAAM,UAAU,KAAK,MAAM,KAAK,SAAS,CAAC;AAC1C,gBAAM,WAAW,MAAM,KAAK,uBAAuB,OAAO;AAC1D,aAAG,KAAK,KAAK,UAAU,QAAQ,CAAC;AAAA,QAClC,SAAS,OAAY;AACnB,aAAG;AAAA,YACD,KAAK,UAAU;AAAA,cACb,OAAO,MAAM;AAAA,YACf,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF,CAAC;AAED,SAAG,GAAG,SAAS,MAAM;AACnB,aAAK,YAAY,OAAO,YAAY;AACpC,gBAAQ,IAAI,6BAA6B;AAAA,MAC3C,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,uBAAuB,SAA4B;AAC/D,UAAM,EAAE,MAAM,MAAM,OAAO,IAAI;AAE/B,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,eAAO,MAAM,KAAK,eAAe,MAAM,MAAM;AAAA,MAE/C,KAAK;AACH,eAAO,EAAE,MAAM,OAAO;AAAA,MAExB;AACE,cAAM,IAAI,MAAM,yBAAyB,IAAI,EAAE;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,MAAc,iBAAgC;AAC5C,SAAK,YAAY,IAAI;AAAA,MACnB;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,cAAc;AAAA,UACZ,OAAO,CAAC;AAAA,UACR,WAAW,CAAC;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAGA,UAAM,KAAK,WAAW,WAAW,KAAK,SAAS;AAG/C,SAAK,UAAU,kBAAkB,cAAqB,YAAY;AAChE,aAAO;AAAA,QACL,OAAO;AAAA,UACL;AAAA,YACE,MAAM;AAAA,YACN,aAAa;AAAA,YACb,aAAa;AAAA,cACX,MAAM;AAAA,cACN,YAAY;AAAA,gBACV,SAAS,EAAE,MAAM,SAAS;AAAA,gBAC1B,MAAM,EAAE,MAAM,SAAS;AAAA,cACzB;AAAA,YACF;AAAA,UACF;AAAA,UACA;AAAA,YACE,MAAM;AAAA,YACN,aAAa;AAAA,YACb,aAAa;AAAA,cACX,MAAM;AAAA,cACN,YAAY;AAAA,gBACV,OAAO,EAAE,MAAM,SAAS;AAAA,gBACxB,OAAO,EAAE,MAAM,SAAS;AAAA,cAC1B;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAED,SAAK,UAAU;AAAA,MACb;AAAA,MACA,OAAO,YAAiB;AACtB,cAAM,EAAE,MAAM,WAAW,KAAK,IAAI,QAAQ;AAC1C,eAAO,MAAM,KAAK,eAAe,MAAM,IAAI;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,eAAe,MAAc,QAA2B;AACpE,YAAQ,MAAM;AAAA,MACZ,KAAK,gBAAgB;AACnB,cAAM,OAAO,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA,SAG5B;AACD,cAAM,SAAS,KAAK;AAAA,UAClB,OAAO,aAAa;AAAA,UACpB,OAAO;AAAA,UACP,OAAO,QAAQ;AAAA,UACf,KAAK,UAAU,OAAO,YAAY,CAAC,CAAC;AAAA,QACtC;AACA,eAAO,EAAE,IAAI,OAAO,iBAAiB,SAAS,KAAK;AAAA,MACrD;AAAA,MAEA,KAAK,gBAAgB;AACnB,cAAM,OAAO,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,SAK5B;AACD,cAAM,WAAW,KAAK;AAAA,UACpB,OAAO,aAAa;AAAA,UACpB,IAAI,OAAO,SAAS,EAAE;AAAA,UACtB,OAAO,SAAS;AAAA,QAClB;AACA,eAAO,EAAE,UAAU,SAAS,KAAK;AAAA,MACnC;AAAA,MAEA;AACE,cAAM,IAAI,MAAM,iBAAiB,IAAI,EAAE;AAAA,IAC3C;AAAA,EACF;AAAA,EAEO,QAAc;AACnB,SAAK,WAAW,OAAO,OAAO,MAAM,WAAW,MAAM;AACnD,cAAQ,IAAI;AAAA;AAAA;AAAA,eAGH,OAAO,WAAW;AAAA,QACzB,OAAO,IAAI;AAAA,aACN,OAAO,kBAAkB,YAAY,UAAU;AAAA,aAC/C,OAAO,kBAAkB,YAAY,UAAU;AAAA,iBAC3C,OAAO,mBAAmB,YAAY,UAAU;AAAA,aACpD,OAAO,QAAQ;AAAA;AAAA,2BAED,OAAO,IAAI;AAAA,OAC/B;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAGA,MAAM,SAAS,IAAI,iBAAiB;AACpC,OAAO,MAAM;AAGb,QAAQ,GAAG,WAAW,MAAM;AAC1B,UAAQ,IAAI,6BAA6B;AACzC,UAAQ,KAAK,CAAC;AAChB,CAAC;AAED,QAAQ,GAAG,UAAU,MAAM;AACzB,UAAQ,IAAI,kBAAkB;AAC9B,UAAQ,KAAK,CAAC;AAChB,CAAC;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/services/config-service.ts"],
4
- "sourcesContent": ["import { Logger } from '../utils/logger.js';\nimport { readFileSync, writeFileSync, existsSync } from 'fs';\nimport { join } from 'path';\n\nexport interface StackMemoryConfig {\n version?: string;\n projectId?: string;\n integrations?: {\n linear?: {\n enabled?: boolean;\n apiKey?: string;\n teamId?: string;\n projectId?: string;\n syncInterval?: number;\n webhookSecret?: string;\n };\n };\n webhook?: {\n port?: number;\n host?: string;\n ngrokSubdomain?: string;\n };\n features?: {\n autoSync?: boolean;\n realTimeSync?: boolean;\n conflictResolution?: 'manual' | 'auto' | 'prompt';\n };\n}\n\nexport class ConfigService {\n private logger: Logger;\n private config: StackMemoryConfig = {};\n private configPath: string;\n\n constructor() {\n this.logger = new Logger('ConfigService');\n this.configPath = join(process.cwd(), '.stackmemory', 'config.json');\n this.loadConfig();\n }\n\n private loadConfig(): void {\n try {\n if (existsSync(this.configPath)) {\n const content = readFileSync(this.configPath, 'utf-8');\n this.config = JSON.parse(content);\n this.logger.debug('Loaded configuration', this.config);\n }\n } catch (error) {\n this.logger.warn('Failed to load configuration, using defaults', error);\n }\n }\n\n private saveConfig(): void {\n try {\n writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));\n this.logger.debug('Saved configuration');\n } catch (error) {\n this.logger.error('Failed to save configuration', error);\n }\n }\n\n public async getConfig(): Promise<StackMemoryConfig> {\n return this.config;\n }\n\n public async updateConfig(\n updates: Partial<StackMemoryConfig>\n ): Promise<void> {\n this.config = {\n ...this.config,\n ...updates,\n };\n this.saveConfig();\n }\n\n public async getLinearConfig() {\n return this.config.integrations?.linear || {};\n }\n\n public async updateLinearConfig(\n updates: Record<string, unknown>\n ): Promise<void> {\n if (!this.config.integrations) {\n this.config.integrations = {};\n }\n if (!this.config.integrations.linear) {\n this.config.integrations.linear = {};\n }\n\n this.config.integrations.linear = {\n ...this.config.integrations.linear,\n ...updates,\n };\n\n this.saveConfig();\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,cAAc;AACvB,SAAS,cAAc,eAAe,kBAAkB;AACxD,SAAS,YAAY;AA2Bd,MAAM,cAAc;AAAA,EACjB;AAAA,EACA,SAA4B,CAAC;AAAA,EAC7B;AAAA,EAER,cAAc;AACZ,SAAK,SAAS,IAAI,OAAO,eAAe;AACxC,SAAK,aAAa,KAAK,QAAQ,IAAI,GAAG,gBAAgB,aAAa;AACnE,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,aAAmB;AACzB,QAAI;AACF,UAAI,WAAW,KAAK,UAAU,GAAG;AAC/B,cAAM,UAAU,aAAa,KAAK,YAAY,OAAO;AACrD,aAAK,SAAS,KAAK,MAAM,OAAO;AAChC,aAAK,OAAO,MAAM,wBAAwB,KAAK,MAAM;AAAA,MACvD;AAAA,IACF,SAAS,OAAO;AACd,WAAK,OAAO,KAAK,gDAAgD,KAAK;AAAA,IACxE;AAAA,EACF;AAAA,EAEQ,aAAmB;AACzB,QAAI;AACF,oBAAc,KAAK,YAAY,KAAK,UAAU,KAAK,QAAQ,MAAM,CAAC,CAAC;AACnE,WAAK,OAAO,MAAM,qBAAqB;AAAA,IACzC,SAAS,OAAO;AACd,WAAK,OAAO,MAAM,gCAAgC,KAAK;AAAA,IACzD;AAAA,EACF;AAAA,EAEA,MAAa,YAAwC;AACnD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAa,aACX,SACe;AACf,SAAK,SAAS;AAAA,MACZ,GAAG,KAAK;AAAA,MACR,GAAG;AAAA,IACL;AACA,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAa,kBAAkB;AAC7B,WAAO,KAAK,OAAO,cAAc,UAAU,CAAC;AAAA,EAC9C;AAAA,EAEA,MAAa,mBACX,SACe;AACf,QAAI,CAAC,KAAK,OAAO,cAAc;AAC7B,WAAK,OAAO,eAAe,CAAC;AAAA,IAC9B;AACA,QAAI,CAAC,KAAK,OAAO,aAAa,QAAQ;AACpC,WAAK,OAAO,aAAa,SAAS,CAAC;AAAA,IACrC;AAEA,SAAK,OAAO,aAAa,SAAS;AAAA,MAChC,GAAG,KAAK,OAAO,aAAa;AAAA,MAC5B,GAAG;AAAA,IACL;AAEA,SAAK,WAAW;AAAA,EAClB;AACF;",
4
+ "sourcesContent": ["import { Logger } from '../utils/logger.js';\nimport { readFileSync, writeFileSync, existsSync } from 'fs';\nimport { join } from 'path';\n\nexport interface StackMemoryConfig {\n version?: string;\n projectId?: string;\n integrations?: {\n linear?: {\n enabled?: boolean;\n apiKey?: string;\n teamId?: string;\n projectId?: string;\n syncInterval?: number;\n webhookSecret?: string;\n };\n };\n webhook?: {\n port?: number;\n host?: string;\n ngrokSubdomain?: string;\n };\n features?: {\n autoSync?: boolean;\n realTimeSync?: boolean;\n conflictResolution?: 'manual' | 'auto' | 'prompt';\n };\n}\n\nexport class ConfigService {\n private logger: Logger;\n private config: StackMemoryConfig = {};\n private configPath: string;\n\n constructor() {\n this.logger = new Logger('ConfigService');\n this.configPath = join(process.cwd(), '.stackmemory', 'config.json');\n this.loadConfig();\n }\n\n private loadConfig(): void {\n try {\n if (existsSync(this.configPath)) {\n const content = readFileSync(this.configPath, 'utf-8');\n this.config = JSON.parse(content);\n this.logger.debug('Loaded configuration', this.config);\n }\n } catch (error: unknown) {\n this.logger.warn('Failed to load configuration, using defaults', error);\n }\n }\n\n private saveConfig(): void {\n try {\n writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));\n this.logger.debug('Saved configuration');\n } catch (error: unknown) {\n this.logger.error('Failed to save configuration', error);\n }\n }\n\n public async getConfig(): Promise<StackMemoryConfig> {\n return this.config;\n }\n\n public async updateConfig(\n updates: Partial<StackMemoryConfig>\n ): Promise<void> {\n this.config = {\n ...this.config,\n ...updates,\n };\n this.saveConfig();\n }\n\n public async getLinearConfig() {\n return this.config.integrations?.linear || {};\n }\n\n public async updateLinearConfig(\n updates: Record<string, unknown>\n ): Promise<void> {\n if (!this.config.integrations) {\n this.config.integrations = {};\n }\n if (!this.config.integrations.linear) {\n this.config.integrations.linear = {};\n }\n\n this.config.integrations.linear = {\n ...this.config.integrations.linear,\n ...updates,\n };\n\n this.saveConfig();\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAc;AACvB,SAAS,cAAc,eAAe,kBAAkB;AACxD,SAAS,YAAY;AA2Bd,MAAM,cAAc;AAAA,EACjB;AAAA,EACA,SAA4B,CAAC;AAAA,EAC7B;AAAA,EAER,cAAc;AACZ,SAAK,SAAS,IAAI,OAAO,eAAe;AACxC,SAAK,aAAa,KAAK,QAAQ,IAAI,GAAG,gBAAgB,aAAa;AACnE,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,aAAmB;AACzB,QAAI;AACF,UAAI,WAAW,KAAK,UAAU,GAAG;AAC/B,cAAM,UAAU,aAAa,KAAK,YAAY,OAAO;AACrD,aAAK,SAAS,KAAK,MAAM,OAAO;AAChC,aAAK,OAAO,MAAM,wBAAwB,KAAK,MAAM;AAAA,MACvD;AAAA,IACF,SAAS,OAAgB;AACvB,WAAK,OAAO,KAAK,gDAAgD,KAAK;AAAA,IACxE;AAAA,EACF;AAAA,EAEQ,aAAmB;AACzB,QAAI;AACF,oBAAc,KAAK,YAAY,KAAK,UAAU,KAAK,QAAQ,MAAM,CAAC,CAAC;AACnE,WAAK,OAAO,MAAM,qBAAqB;AAAA,IACzC,SAAS,OAAgB;AACvB,WAAK,OAAO,MAAM,gCAAgC,KAAK;AAAA,IACzD;AAAA,EACF;AAAA,EAEA,MAAa,YAAwC;AACnD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAa,aACX,SACe;AACf,SAAK,SAAS;AAAA,MACZ,GAAG,KAAK;AAAA,MACR,GAAG;AAAA,IACL;AACA,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAa,kBAAkB;AAC7B,WAAO,KAAK,OAAO,cAAc,UAAU,CAAC;AAAA,EAC9C;AAAA,EAEA,MAAa,mBACX,SACe;AACf,QAAI,CAAC,KAAK,OAAO,cAAc;AAC7B,WAAK,OAAO,eAAe,CAAC;AAAA,IAC9B;AACA,QAAI,CAAC,KAAK,OAAO,aAAa,QAAQ;AACpC,WAAK,OAAO,aAAa,SAAS,CAAC;AAAA,IACrC;AAEA,SAAK,OAAO,aAAa,SAAS;AAAA,MAChC,GAAG,KAAK,OAAO,aAAa;AAAA,MAC5B,GAAG;AAAA,IACL;AAEA,SAAK,WAAW;AAAA,EAClB;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/services/context-service.ts"],
4
- "sourcesContent": ["import { Task } from '../types/task.js';\n// TaskStatus and TaskPriority will be used in future implementations\n// import { TaskStatus, TaskPriority } from '../types/task.js';\nimport { Logger } from '../utils/logger.js';\nimport Database from 'better-sqlite3';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\n\ninterface TaskRow {\n id: string;\n title: string;\n description?: string;\n status?: string;\n priority?: string;\n tags?: string;\n external_id?: string;\n external_identifier?: string;\n external_url?: string;\n metadata?: string;\n created_at: number;\n updated_at: number;\n}\n\nexport class ContextService {\n private logger: Logger;\n private db: Database.Database | null = null;\n private tasks: Map<string, Task> = new Map();\n\n constructor() {\n this.logger = new Logger('ContextService');\n this.initializeDatabase();\n }\n\n private initializeDatabase(): void {\n try {\n const dbPath = join(process.cwd(), '.stackmemory', 'context.db');\n if (existsSync(dbPath)) {\n this.db = new Database(dbPath);\n this.loadTasksFromDatabase();\n }\n } catch (error) {\n this.logger.warn(\n 'Could not connect to database, using in-memory storage',\n error\n );\n }\n }\n\n private loadTasksFromDatabase(): void {\n if (!this.db) return;\n\n try {\n // Create tasks table if it doesn't exist\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS tasks (\n id TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n description TEXT,\n status TEXT DEFAULT 'todo',\n priority TEXT,\n tags TEXT,\n external_id TEXT,\n external_identifier TEXT,\n external_url TEXT,\n metadata TEXT,\n created_at INTEGER,\n updated_at INTEGER\n )\n `);\n\n // Load all tasks from database\n const stmt = this.db.prepare('SELECT * FROM tasks');\n const rows = stmt.all() as TaskRow[];\n\n for (const row of rows) {\n const task: Task = {\n id: row.id,\n title: row.title,\n description: row.description || '',\n status: row.status || 'todo',\n priority: row.priority || undefined,\n tags: row.tags ? JSON.parse(row.tags) : [],\n externalId: row.external_id || undefined,\n externalIdentifier: row.external_identifier || undefined,\n externalUrl: row.external_url || undefined,\n metadata: row.metadata ? JSON.parse(row.metadata) : undefined,\n createdAt: new Date(row.created_at),\n updatedAt: new Date(row.updated_at),\n };\n this.tasks.set(task.id, task);\n }\n\n this.logger.info(`Loaded ${rows.length} tasks from database`);\n } catch (error) {\n this.logger.error('Failed to load tasks from database', error);\n }\n }\n\n public async getTask(id: string): Promise<Task | null> {\n return this.tasks.get(id) || null;\n }\n\n public async getTaskByExternalId(externalId: string): Promise<Task | null> {\n for (const task of this.tasks.values()) {\n if (task.externalId === externalId) {\n return task;\n }\n }\n return null;\n }\n\n public async getAllTasks(): Promise<Task[]> {\n return Array.from(this.tasks.values());\n }\n\n public async createTask(taskData: Partial<Task>): Promise<Task> {\n const task: Task = {\n id: this.generateId(),\n title: taskData.title || 'Untitled Task',\n description: taskData.description || '',\n status: taskData.status || 'todo',\n priority: taskData.priority,\n tags: taskData.tags || [],\n externalId: taskData.externalId,\n externalIdentifier: taskData.externalIdentifier,\n externalUrl: taskData.externalUrl,\n metadata: taskData.metadata,\n createdAt: taskData.createdAt || new Date(),\n updatedAt: taskData.updatedAt || new Date(),\n };\n\n this.tasks.set(task.id, task);\n\n // Persist to database if available\n if (this.db) {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO tasks (id, title, description, status, priority, tags, \n external_id, external_identifier, external_url, \n metadata, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n task.id,\n task.title,\n task.description,\n task.status,\n task.priority || null,\n JSON.stringify(task.tags),\n task.externalId || null,\n task.externalIdentifier || null,\n task.externalUrl || null,\n task.metadata ? JSON.stringify(task.metadata) : null,\n task.createdAt.getTime(),\n task.updatedAt.getTime()\n );\n } catch (error) {\n this.logger.error('Failed to persist task to database', error);\n }\n }\n\n this.logger.debug(`Created task: ${task.id} - ${task.title}`);\n return task;\n }\n\n public async updateTask(\n id: string,\n updates: Partial<Task>\n ): Promise<Task | null> {\n const task = this.tasks.get(id);\n if (!task) {\n return null;\n }\n\n const updatedTask = {\n ...task,\n ...updates,\n updatedAt: new Date(),\n };\n\n this.tasks.set(id, updatedTask);\n\n // Update in database if available\n if (this.db) {\n try {\n const stmt = this.db.prepare(`\n UPDATE tasks SET title = ?, description = ?, status = ?, \n priority = ?, tags = ?, external_id = ?, \n external_identifier = ?, external_url = ?, \n metadata = ?, updated_at = ?\n WHERE id = ?\n `);\n stmt.run(\n updatedTask.title,\n updatedTask.description,\n updatedTask.status,\n updatedTask.priority || null,\n JSON.stringify(updatedTask.tags),\n updatedTask.externalId || null,\n updatedTask.externalIdentifier || null,\n updatedTask.externalUrl || null,\n updatedTask.metadata ? JSON.stringify(updatedTask.metadata) : null,\n updatedTask.updatedAt.getTime(),\n id\n );\n } catch (error) {\n this.logger.error('Failed to update task in database', error);\n }\n }\n\n this.logger.debug(`Updated task: ${id} - ${updatedTask.title}`);\n return updatedTask;\n }\n\n public async deleteTask(id: string): Promise<boolean> {\n const deleted = this.tasks.delete(id);\n\n if (deleted) {\n // Delete from database if available\n if (this.db) {\n try {\n const stmt = this.db.prepare('DELETE FROM tasks WHERE id = ?');\n stmt.run(id);\n } catch (error) {\n this.logger.error('Failed to delete task from database', error);\n }\n }\n this.logger.debug(`Deleted task: ${id}`);\n }\n return deleted;\n }\n\n private generateId(): string {\n return 'task_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Task } from '../types/task.js';\n// TaskStatus and TaskPriority will be used in future implementations\n// import { TaskStatus, TaskPriority } from '../types/task.js';\nimport { Logger } from '../utils/logger.js';\nimport Database from 'better-sqlite3';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\n\ninterface TaskRow {\n id: string;\n title: string;\n description?: string;\n status?: string;\n priority?: string;\n tags?: string;\n external_id?: string;\n external_identifier?: string;\n external_url?: string;\n metadata?: string;\n created_at: number;\n updated_at: number;\n}\n\nexport class ContextService {\n private logger: Logger;\n private db: Database.Database | null = null;\n private tasks: Map<string, Task> = new Map();\n\n constructor() {\n this.logger = new Logger('ContextService');\n this.initializeDatabase();\n }\n\n private initializeDatabase(): void {\n try {\n const dbPath = join(process.cwd(), '.stackmemory', 'context.db');\n if (existsSync(dbPath)) {\n this.db = new Database(dbPath);\n this.loadTasksFromDatabase();\n }\n } catch (error: unknown) {\n this.logger.warn(\n 'Could not connect to database, using in-memory storage',\n error\n );\n }\n }\n\n private loadTasksFromDatabase(): void {\n if (!this.db) return;\n\n try {\n // Create tasks table if it doesn't exist\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS tasks (\n id TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n description TEXT,\n status TEXT DEFAULT 'todo',\n priority TEXT,\n tags TEXT,\n external_id TEXT,\n external_identifier TEXT,\n external_url TEXT,\n metadata TEXT,\n created_at INTEGER,\n updated_at INTEGER\n )\n `);\n\n // Load all tasks from database\n const stmt = this.db.prepare('SELECT * FROM tasks');\n const rows = stmt.all() as TaskRow[];\n\n for (const row of rows) {\n const task: Task = {\n id: row.id,\n title: row.title,\n description: row.description || '',\n status: row.status || 'todo',\n priority: row.priority || undefined,\n tags: row.tags ? JSON.parse(row.tags) : [],\n externalId: row.external_id || undefined,\n externalIdentifier: row.external_identifier || undefined,\n externalUrl: row.external_url || undefined,\n metadata: row.metadata ? JSON.parse(row.metadata) : undefined,\n createdAt: new Date(row.created_at),\n updatedAt: new Date(row.updated_at),\n };\n this.tasks.set(task.id, task);\n }\n\n this.logger.info(`Loaded ${rows.length} tasks from database`);\n } catch (error: unknown) {\n this.logger.error('Failed to load tasks from database', error);\n }\n }\n\n public async getTask(id: string): Promise<Task | null> {\n return this.tasks.get(id) || null;\n }\n\n public async getTaskByExternalId(externalId: string): Promise<Task | null> {\n for (const task of this.tasks.values()) {\n if (task.externalId === externalId) {\n return task;\n }\n }\n return null;\n }\n\n public async getAllTasks(): Promise<Task[]> {\n return Array.from(this.tasks.values());\n }\n\n public async createTask(taskData: Partial<Task>): Promise<Task> {\n const task: Task = {\n id: this.generateId(),\n title: taskData.title || 'Untitled Task',\n description: taskData.description || '',\n status: taskData.status || 'todo',\n priority: taskData.priority,\n tags: taskData.tags || [],\n externalId: taskData.externalId,\n externalIdentifier: taskData.externalIdentifier,\n externalUrl: taskData.externalUrl,\n metadata: taskData.metadata,\n createdAt: taskData.createdAt || new Date(),\n updatedAt: taskData.updatedAt || new Date(),\n };\n\n this.tasks.set(task.id, task);\n\n // Persist to database if available\n if (this.db) {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO tasks (id, title, description, status, priority, tags, \n external_id, external_identifier, external_url, \n metadata, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n task.id,\n task.title,\n task.description,\n task.status,\n task.priority || null,\n JSON.stringify(task.tags),\n task.externalId || null,\n task.externalIdentifier || null,\n task.externalUrl || null,\n task.metadata ? JSON.stringify(task.metadata) : null,\n task.createdAt.getTime(),\n task.updatedAt.getTime()\n );\n } catch (error: unknown) {\n this.logger.error('Failed to persist task to database', error);\n }\n }\n\n this.logger.debug(`Created task: ${task.id} - ${task.title}`);\n return task;\n }\n\n public async updateTask(\n id: string,\n updates: Partial<Task>\n ): Promise<Task | null> {\n const task = this.tasks.get(id);\n if (!task) {\n return null;\n }\n\n const updatedTask = {\n ...task,\n ...updates,\n updatedAt: new Date(),\n };\n\n this.tasks.set(id, updatedTask);\n\n // Update in database if available\n if (this.db) {\n try {\n const stmt = this.db.prepare(`\n UPDATE tasks SET title = ?, description = ?, status = ?, \n priority = ?, tags = ?, external_id = ?, \n external_identifier = ?, external_url = ?, \n metadata = ?, updated_at = ?\n WHERE id = ?\n `);\n stmt.run(\n updatedTask.title,\n updatedTask.description,\n updatedTask.status,\n updatedTask.priority || null,\n JSON.stringify(updatedTask.tags),\n updatedTask.externalId || null,\n updatedTask.externalIdentifier || null,\n updatedTask.externalUrl || null,\n updatedTask.metadata ? JSON.stringify(updatedTask.metadata) : null,\n updatedTask.updatedAt.getTime(),\n id\n );\n } catch (error: unknown) {\n this.logger.error('Failed to update task in database', error);\n }\n }\n\n this.logger.debug(`Updated task: ${id} - ${updatedTask.title}`);\n return updatedTask;\n }\n\n public async deleteTask(id: string): Promise<boolean> {\n const deleted = this.tasks.delete(id);\n\n if (deleted) {\n // Delete from database if available\n if (this.db) {\n try {\n const stmt = this.db.prepare('DELETE FROM tasks WHERE id = ?');\n stmt.run(id);\n } catch (error: unknown) {\n this.logger.error('Failed to delete task from database', error);\n }\n }\n this.logger.debug(`Deleted task: ${id}`);\n }\n return deleted;\n }\n\n private generateId(): string {\n return 'task_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,7 @@
1
1
  import { logger } from "../core/monitoring/logger.js";
2
+ import {
3
+ RepoIngestionSkill
4
+ } from "./repo-ingestion-skill.js";
2
5
  import * as fs from "fs";
3
6
  import * as path from "path";
4
7
  import * as os from "os";
@@ -590,7 +593,6 @@ class ArchaeologistSkill {
590
593
  }
591
594
  }
592
595
  class ClaudeSkillsManager {
593
- // DashboardLauncherSkill
594
596
  constructor(context) {
595
597
  this.context = context;
596
598
  this.handoffSkill = new HandoffSkill(context);
@@ -602,11 +604,29 @@ class ClaudeSkillsManager {
602
604
  logger.warn("Dashboard auto-launch failed:", error);
603
605
  });
604
606
  });
607
+ const chromaConfig = {
608
+ apiKey: process.env["CHROMADB_API_KEY"] || "",
609
+ tenant: process.env["CHROMADB_TENANT"] || "",
610
+ database: process.env["CHROMADB_DATABASE"] || "stackmemory",
611
+ collectionName: process.env["CHROMADB_COLLECTION"] || "stackmemory_repos"
612
+ };
613
+ if (chromaConfig.apiKey && chromaConfig.tenant) {
614
+ this.repoIngestionSkill = new RepoIngestionSkill(
615
+ chromaConfig,
616
+ context.userId,
617
+ process.env["CHROMADB_TEAM_ID"]
618
+ );
619
+ this.repoIngestionSkill.initialize().catch((error) => {
620
+ logger.warn("Repo ingestion skill initialization failed:", error);
621
+ });
622
+ }
605
623
  }
606
624
  handoffSkill;
607
625
  checkpointSkill;
608
626
  archaeologistSkill;
609
627
  dashboardLauncher;
628
+ // DashboardLauncherSkill
629
+ repoIngestionSkill = null;
610
630
  async executeSkill(skillName, args, options) {
611
631
  switch (skillName) {
612
632
  case "handoff":
@@ -630,6 +650,64 @@ class ClaudeSkillsManager {
630
650
  }
631
651
  case "dig":
632
652
  return this.archaeologistSkill.dig(args[0], options);
653
+ case "repo":
654
+ case "ingest":
655
+ if (!this.repoIngestionSkill) {
656
+ return {
657
+ success: false,
658
+ message: "Repo ingestion skill not initialized. Please configure ChromaDB."
659
+ };
660
+ }
661
+ const repoCommand = args[0];
662
+ switch (repoCommand) {
663
+ case "ingest":
664
+ const repoPath = args[1] || process.cwd();
665
+ const repoName = args[2] || path.basename(repoPath);
666
+ return await this.repoIngestionSkill.ingestRepository(
667
+ repoPath,
668
+ repoName,
669
+ options
670
+ );
671
+ case "update":
672
+ const updatePath = args[1] || process.cwd();
673
+ const updateName = args[2] || path.basename(updatePath);
674
+ return await this.repoIngestionSkill.updateRepository(
675
+ updatePath,
676
+ updateName,
677
+ options
678
+ );
679
+ case "search":
680
+ const query = args[1];
681
+ if (!query) {
682
+ return {
683
+ success: false,
684
+ message: "Search query required"
685
+ };
686
+ }
687
+ const results = await this.repoIngestionSkill.searchCode(query, {
688
+ repoName: options?.repoName,
689
+ language: options?.language,
690
+ limit: options?.limit,
691
+ includeContext: options?.includeContext
692
+ });
693
+ return {
694
+ success: true,
695
+ message: `Found ${results.length} results`,
696
+ data: results
697
+ };
698
+ case "stats":
699
+ const stats = await this.repoIngestionSkill.getRepoStats(args[1]);
700
+ return {
701
+ success: true,
702
+ message: "Repository statistics",
703
+ data: stats
704
+ };
705
+ default:
706
+ return {
707
+ success: false,
708
+ message: `Unknown repo command: ${repoCommand}. Use: ingest, update, search, or stats`
709
+ };
710
+ }
633
711
  case "dashboard":
634
712
  const dashboardCmd = args[0];
635
713
  if (!this.dashboardLauncher) {
@@ -668,7 +746,11 @@ class ClaudeSkillsManager {
668
746
  }
669
747
  }
670
748
  getAvailableSkills() {
671
- return ["handoff", "checkpoint", "dig", "dashboard"];
749
+ const skills = ["handoff", "checkpoint", "dig", "dashboard"];
750
+ if (this.repoIngestionSkill) {
751
+ skills.push("repo");
752
+ }
753
+ return skills;
672
754
  }
673
755
  getSkillHelp(skillName) {
674
756
  switch (skillName) {
@@ -697,6 +779,27 @@ Launch the StackMemory web dashboard for real-time monitoring
697
779
  - launch: Start the web dashboard and open in browser (default)
698
780
  - stop: Stop the dashboard server
699
781
  Auto-launches on new sessions when configured
782
+ `;
783
+ case "repo":
784
+ return `
785
+ /repo ingest [path] [name] [--incremental] [--include-tests] [--include-docs]
786
+ /repo update [path] [name] [--force-update]
787
+ /repo search "query" [--repo-name name] [--language lang] [--limit n]
788
+ /repo stats [repo-name]
789
+
790
+ Ingest and search code repositories in ChromaDB:
791
+ - ingest: Index a new repository (defaults to current directory)
792
+ - update: Update an existing repository with changes
793
+ - search: Semantic search across ingested code
794
+ - stats: View statistics about ingested repositories
795
+
796
+ Options:
797
+ - --incremental: Only process changed files
798
+ - --include-tests: Include test files in indexing
799
+ - --include-docs: Include documentation files
800
+ - --force-update: Force re-indexing of all files
801
+ - --language: Filter search by programming language
802
+ - --limit: Maximum search results (default: 20)
700
803
  `;
701
804
  default:
702
805
  return `Unknown skill: ${skillName}`;