@stackmemoryai/stackmemory 0.3.17 → 0.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/skills.js +15 -2
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/index.js +113 -834
- package/dist/cli/index.js.map +3 -3
- package/dist/core/context/dual-stack-manager.js +1 -1
- package/dist/core/context/dual-stack-manager.js.map +1 -1
- package/dist/core/context/frame-manager.js +3 -0
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/integrations/claude-code/subagent-client.js +106 -3
- package/dist/integrations/claude-code/subagent-client.js.map +2 -2
- package/dist/servers/railway/config.js +51 -0
- package/dist/servers/railway/config.js.map +7 -0
- package/dist/servers/railway/index-enhanced.js +156 -0
- package/dist/servers/railway/index-enhanced.js.map +7 -0
- package/dist/servers/railway/minimal.js +48 -3
- package/dist/servers/railway/minimal.js.map +2 -2
- package/dist/servers/railway/storage-test.js +455 -0
- package/dist/servers/railway/storage-test.js.map +7 -0
- package/dist/skills/claude-skills.js +13 -12
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/recursive-agent-orchestrator.js +27 -18
- package/dist/skills/recursive-agent-orchestrator.js.map +2 -2
- package/dist/skills/unified-rlm-orchestrator.js.map +2 -2
- package/package.json +6 -18
- package/scripts/README-TESTING.md +186 -0
- package/scripts/analyze-cli-security.js +288 -0
- package/scripts/archive/add-phase-tasks-to-linear.js +163 -0
- package/scripts/archive/analyze-linear-duplicates.js +214 -0
- package/scripts/archive/analyze-remaining-duplicates.js +230 -0
- package/scripts/archive/analyze-sta-duplicates.js +292 -0
- package/scripts/archive/analyze-sta-graphql.js +399 -0
- package/scripts/archive/cancel-duplicate-tasks.ts +246 -0
- package/scripts/archive/check-all-duplicates.ts +419 -0
- package/scripts/archive/clean-duplicate-tasks.js +114 -0
- package/scripts/archive/cleanup-duplicate-tasks.ts +286 -0
- package/scripts/archive/create-phase-tasks.js +387 -0
- package/scripts/archive/delete-linear-duplicates.js +182 -0
- package/scripts/archive/delete-remaining-duplicates.js +158 -0
- package/scripts/archive/delete-sta-duplicates.js +201 -0
- package/scripts/archive/delete-sta-oauth.js +201 -0
- package/scripts/archive/export-sta-tasks.js +62 -0
- package/scripts/archive/install-auto-sync.js +266 -0
- package/scripts/archive/install-chromadb-hooks.sh +133 -0
- package/scripts/archive/install-enhanced-clear-hooks.sh +431 -0
- package/scripts/archive/install-post-task-hooks.sh +289 -0
- package/scripts/archive/install-stackmemory-hooks.sh +420 -0
- package/scripts/archive/merge-linear-duplicates-safe.ts +362 -0
- package/scripts/archive/merge-linear-duplicates.ts +180 -0
- package/scripts/archive/remove-sta-tasks.js +70 -0
- package/scripts/archive/setup-background-sync.sh +168 -0
- package/scripts/archive/setup-claude-auto-triggers.sh +181 -0
- package/scripts/archive/setup-claude-autostart.sh +305 -0
- package/scripts/archive/setup-git-hooks.sh +25 -0
- package/scripts/archive/setup-linear-oauth.sh +46 -0
- package/scripts/archive/setup-mcp.sh +113 -0
- package/scripts/archive/setup-railway-deployment.sh +81 -0
- package/scripts/auto-handoff.sh +262 -0
- package/scripts/background-sync-manager.js +416 -0
- package/scripts/benchmark-performance.ts +57 -0
- package/scripts/check-redis.ts +48 -0
- package/scripts/chromadb-auto-loader.sh +128 -0
- package/scripts/chromadb-context-loader.js +479 -0
- package/scripts/claude-chromadb-hook.js +460 -0
- package/scripts/claude-code-wrapper.sh +66 -0
- package/scripts/claude-linear-skill.js +455 -0
- package/scripts/claude-pre-commit.sh +302 -0
- package/scripts/claude-sm-autostart.js +532 -0
- package/scripts/claude-sm-setup.sh +367 -0
- package/scripts/claude-with-chromadb.sh +69 -0
- package/scripts/claude-worktree-manager.sh +323 -0
- package/scripts/claude-worktree-monitor.sh +371 -0
- package/scripts/claude-worktree-setup.sh +327 -0
- package/scripts/clean-linear-backlog.js +273 -0
- package/scripts/cleanup-old-sessions.sh +57 -0
- package/scripts/codex-wrapper.sh +88 -0
- package/scripts/create-sandbox.sh +269 -0
- package/scripts/debug-linear-update.js +174 -0
- package/scripts/delete-linear-tasks.js +167 -0
- package/scripts/deploy.sh +89 -0
- package/scripts/deployment/railway.sh +352 -0
- package/scripts/deployment/test-deployment.js +194 -0
- package/scripts/detect-and-rehydrate.js +162 -0
- package/scripts/detect-and-rehydrate.mjs +165 -0
- package/scripts/development/create-demo-tasks.js +143 -0
- package/scripts/development/debug-frame-test.js +16 -0
- package/scripts/development/demo-auto-sync.js +128 -0
- package/scripts/development/fix-all-imports.js +213 -0
- package/scripts/development/fix-imports.js +229 -0
- package/scripts/development/fix-lint-loop.cjs +103 -0
- package/scripts/development/fix-project-id.ts +161 -0
- package/scripts/development/fix-strict-mode-issues.ts +291 -0
- package/scripts/development/reorganize-structure.sh +228 -0
- package/scripts/development/test-persistence-direct.js +148 -0
- package/scripts/development/test-persistence.js +114 -0
- package/scripts/development/test-tasks.js +93 -0
- package/scripts/development/update-imports.js +212 -0
- package/scripts/fetch-linear-status.js +125 -0
- package/scripts/git-hooks/README.md +310 -0
- package/scripts/git-hooks/branch-context-manager.sh +342 -0
- package/scripts/git-hooks/post-checkout-stackmemory.sh +63 -0
- package/scripts/git-hooks/post-commit-stackmemory.sh +305 -0
- package/scripts/git-hooks/pre-commit-stackmemory.sh +275 -0
- package/scripts/hooks/cleanup-shell.sh +130 -0
- package/scripts/hooks/task-complete.sh +114 -0
- package/scripts/initialize.ts +129 -0
- package/scripts/install-claude-hooks-auto.js +104 -0
- package/scripts/install-claude-hooks.sh +133 -0
- package/scripts/install-global.sh +296 -0
- package/scripts/install.sh +235 -0
- package/scripts/linear-auto-sync.js +262 -0
- package/scripts/linear-auto-sync.sh +161 -0
- package/scripts/linear-sync-daemon.js +150 -0
- package/scripts/linear-task-review.js +237 -0
- package/scripts/list-linear-tasks.ts +178 -0
- package/scripts/mcp-proxy.js +66 -0
- package/scripts/opencode-wrapper.sh +85 -0
- package/scripts/publish-local.js +74 -0
- package/scripts/query-chromadb.ts +201 -0
- package/scripts/railway-env-setup.sh +39 -0
- package/scripts/reconcile-local-tasks.js +170 -0
- package/scripts/recreate-frames-db.js +89 -0
- package/scripts/setup/claude-integration.js +138 -0
- package/scripts/setup/configure-alias.js +125 -0
- package/scripts/setup/configure-codex-alias.js +161 -0
- package/scripts/setup/configure-opencode-alias.js +175 -0
- package/scripts/setup-claude-integration.js +204 -0
- package/scripts/setup-claude-integration.sh +183 -0
- package/scripts/setup.sh +31 -0
- package/scripts/show-linear-summary.ts +172 -0
- package/scripts/stackmemory-auto-handoff.sh +231 -0
- package/scripts/stackmemory-daemon.sh +40 -0
- package/scripts/start-linear-sync-daemon.sh +141 -0
- package/scripts/start-temporal-paradox.sh +214 -0
- package/scripts/status.ts +159 -0
- package/scripts/sync-and-clean-tasks.js +258 -0
- package/scripts/sync-frames-from-railway.js +228 -0
- package/scripts/sync-linear-graphql.js +303 -0
- package/scripts/sync-linear-tasks.js +186 -0
- package/scripts/test-auto-triggers.sh +57 -0
- package/scripts/test-browser-mcp.js +74 -0
- package/scripts/test-chromadb-full.js +115 -0
- package/scripts/test-chromadb-hooks.sh +28 -0
- package/scripts/test-chromadb-sync.ts +245 -0
- package/scripts/test-cli-security.js +293 -0
- package/scripts/test-hooks-persistence.sh +220 -0
- package/scripts/test-installation-scenarios.sh +359 -0
- package/scripts/test-installation.sh +224 -0
- package/scripts/test-mcp.js +163 -0
- package/scripts/test-pre-publish-quick.sh +75 -0
- package/scripts/test-quality-gates.sh +263 -0
- package/scripts/test-railway-db.js +222 -0
- package/scripts/test-redis-storage.ts +490 -0
- package/scripts/test-rlm-basic.sh +122 -0
- package/scripts/test-rlm-comprehensive.sh +260 -0
- package/scripts/test-rlm-e2e.sh +268 -0
- package/scripts/test-rlm-simple.js +90 -0
- package/scripts/test-rlm.js +110 -0
- package/scripts/test-session-handoff.sh +165 -0
- package/scripts/test-shell-integration.sh +275 -0
- package/scripts/testing/ab-test-runner.ts +508 -0
- package/scripts/testing/collect-metrics.ts +457 -0
- package/scripts/testing/quick-effectiveness-demo.js +187 -0
- package/scripts/testing/real-performance-test.js +422 -0
- package/scripts/testing/run-effectiveness-tests.sh +176 -0
- package/scripts/testing/scripts/testing/ab-test-runner.js +363 -0
- package/scripts/testing/scripts/testing/collect-metrics.js +292 -0
- package/scripts/testing/simple-effectiveness-test.js +310 -0
- package/scripts/testing/src/core/context/context-bridge.js +253 -0
- package/scripts/testing/src/core/context/frame-manager.js +746 -0
- package/scripts/testing/src/core/context/shared-context-layer.js +437 -0
- package/scripts/testing/src/core/database/database-adapter.js +54 -0
- package/scripts/testing/src/core/errors/index.js +291 -0
- package/scripts/testing/src/core/errors/recovery.js +268 -0
- package/scripts/testing/src/core/monitoring/logger.js +145 -0
- package/scripts/testing/src/core/retrieval/context-retriever.js +516 -0
- package/scripts/testing/src/core/session/index.js +1 -0
- package/scripts/testing/src/core/session/session-manager.js +323 -0
- package/scripts/testing/src/core/trace/cli-trace-wrapper.js +140 -0
- package/scripts/testing/src/core/trace/db-trace-wrapper.js +251 -0
- package/scripts/testing/src/core/trace/debug-trace.js +398 -0
- package/scripts/testing/src/core/trace/index.js +120 -0
- package/scripts/testing/src/core/trace/linear-api-wrapper.js +204 -0
- package/scripts/update-linear-status.js +268 -0
- package/scripts/update-linear-tasks-fixed.js +284 -0
- package/templates/claude-hooks/hooks.json +5 -0
- package/templates/claude-hooks/on-clear.js +56 -0
- package/templates/claude-hooks/on-startup.js +56 -0
- package/templates/claude-hooks/tool-use-trace.js +67 -0
- package/dist/features/tui/components/analytics-panel.js +0 -157
- package/dist/features/tui/components/analytics-panel.js.map +0 -7
- package/dist/features/tui/components/frame-visualizer.js +0 -377
- package/dist/features/tui/components/frame-visualizer.js.map +0 -7
- package/dist/features/tui/components/pr-tracker.js +0 -135
- package/dist/features/tui/components/pr-tracker.js.map +0 -7
- package/dist/features/tui/components/session-monitor.js +0 -299
- package/dist/features/tui/components/session-monitor.js.map +0 -7
- package/dist/features/tui/components/subagent-fleet.js +0 -395
- package/dist/features/tui/components/subagent-fleet.js.map +0 -7
- package/dist/features/tui/components/task-board.js +0 -1139
- package/dist/features/tui/components/task-board.js.map +0 -7
- package/dist/features/tui/index.js +0 -408
- package/dist/features/tui/index.js.map +0 -7
- package/dist/features/tui/services/data-service.js +0 -641
- package/dist/features/tui/services/data-service.js.map +0 -7
- package/dist/features/tui/services/linear-task-reader.js +0 -102
- package/dist/features/tui/services/linear-task-reader.js.map +0 -7
- package/dist/features/tui/services/websocket-client.js +0 -162
- package/dist/features/tui/services/websocket-client.js.map +0 -7
- package/dist/features/tui/terminal-compat.js +0 -220
- package/dist/features/tui/terminal-compat.js.map +0 -7
- package/dist/features/tui/types.js +0 -1
- package/dist/features/tui/types.js.map +0 -7
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import express from "express";
|
|
3
|
+
import cors from "cors";
|
|
4
|
+
import { createClient } from "redis";
|
|
5
|
+
import pg from "pg";
|
|
6
|
+
import { getRailwayConfig } from "./config.js";
|
|
7
|
+
const { Client } = pg;
|
|
8
|
+
async function startServer() {
|
|
9
|
+
const config = getRailwayConfig();
|
|
10
|
+
console.log("\u{1F680} Starting StackMemory Railway Server (Enhanced)");
|
|
11
|
+
console.log(`\u{1F4CD} Environment: ${config.environment}`);
|
|
12
|
+
console.log(`\u{1F50C} Port: ${config.port}`);
|
|
13
|
+
const app = express();
|
|
14
|
+
app.use(cors({
|
|
15
|
+
origin: config.corsOrigins,
|
|
16
|
+
credentials: true
|
|
17
|
+
}));
|
|
18
|
+
app.use(express.json());
|
|
19
|
+
app.get("/health", (req, res) => {
|
|
20
|
+
res.json({
|
|
21
|
+
status: "healthy",
|
|
22
|
+
service: "stackmemory",
|
|
23
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
app.get("/", (req, res) => {
|
|
27
|
+
res.json({
|
|
28
|
+
name: "StackMemory API",
|
|
29
|
+
version: "0.3.17",
|
|
30
|
+
status: "running",
|
|
31
|
+
endpoints: ["/health", "/api/health", "/api/status", "/api/frames"]
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
app.get("/api/health", async (req, res) => {
|
|
35
|
+
const checks = {
|
|
36
|
+
server: "ok",
|
|
37
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
38
|
+
};
|
|
39
|
+
if (config.databaseUrl) {
|
|
40
|
+
try {
|
|
41
|
+
const pgClient = new Client({ connectionString: config.databaseUrl });
|
|
42
|
+
await pgClient.connect();
|
|
43
|
+
await pgClient.query("SELECT 1");
|
|
44
|
+
await pgClient.end();
|
|
45
|
+
checks.postgres = "connected";
|
|
46
|
+
} catch (error) {
|
|
47
|
+
checks.postgres = "error";
|
|
48
|
+
checks.postgresError = error.message.substring(0, 100);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (config.redisUrl) {
|
|
52
|
+
try {
|
|
53
|
+
const redisClient = createClient({ url: config.redisUrl });
|
|
54
|
+
await redisClient.connect();
|
|
55
|
+
await redisClient.ping();
|
|
56
|
+
await redisClient.disconnect();
|
|
57
|
+
checks.redis = "connected";
|
|
58
|
+
} catch (error) {
|
|
59
|
+
checks.redis = "error";
|
|
60
|
+
checks.redisError = error.message.substring(0, 100);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const healthy = checks.postgres === "connected" || checks.redis === "connected";
|
|
64
|
+
res.status(healthy ? 200 : 503).json(checks);
|
|
65
|
+
});
|
|
66
|
+
app.get("/api/status", async (req, res) => {
|
|
67
|
+
const status = {
|
|
68
|
+
service: "stackmemory",
|
|
69
|
+
version: "0.3.17",
|
|
70
|
+
environment: config.environment,
|
|
71
|
+
storage: {}
|
|
72
|
+
};
|
|
73
|
+
if (config.databaseUrl) {
|
|
74
|
+
try {
|
|
75
|
+
const pgClient = new Client({ connectionString: config.databaseUrl });
|
|
76
|
+
await pgClient.connect();
|
|
77
|
+
await pgClient.query(`
|
|
78
|
+
CREATE TABLE IF NOT EXISTS frames (
|
|
79
|
+
frame_id TEXT PRIMARY KEY,
|
|
80
|
+
run_id TEXT NOT NULL,
|
|
81
|
+
project_id TEXT NOT NULL,
|
|
82
|
+
parent_frame_id TEXT,
|
|
83
|
+
depth INTEGER DEFAULT 0,
|
|
84
|
+
type TEXT NOT NULL,
|
|
85
|
+
name TEXT NOT NULL,
|
|
86
|
+
state TEXT DEFAULT 'active',
|
|
87
|
+
inputs JSONB DEFAULT '{}',
|
|
88
|
+
outputs JSONB DEFAULT '{}',
|
|
89
|
+
created_at TIMESTAMP DEFAULT NOW()
|
|
90
|
+
)
|
|
91
|
+
`);
|
|
92
|
+
const frameCount = await pgClient.query("SELECT COUNT(*) FROM frames");
|
|
93
|
+
status.storage.postgres = {
|
|
94
|
+
connected: true,
|
|
95
|
+
frames: parseInt(frameCount.rows[0].count)
|
|
96
|
+
};
|
|
97
|
+
await pgClient.end();
|
|
98
|
+
} catch (error) {
|
|
99
|
+
status.storage.postgres = {
|
|
100
|
+
connected: false,
|
|
101
|
+
error: error.message.substring(0, 100)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (config.redisUrl) {
|
|
106
|
+
try {
|
|
107
|
+
const redisClient = createClient({ url: config.redisUrl });
|
|
108
|
+
await redisClient.connect();
|
|
109
|
+
const keys = await redisClient.keys("*");
|
|
110
|
+
status.storage.redis = {
|
|
111
|
+
connected: true,
|
|
112
|
+
keys: keys.length
|
|
113
|
+
};
|
|
114
|
+
await redisClient.disconnect();
|
|
115
|
+
} catch (error) {
|
|
116
|
+
status.storage.redis = {
|
|
117
|
+
connected: false,
|
|
118
|
+
error: error.message.substring(0, 100)
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
res.json(status);
|
|
123
|
+
});
|
|
124
|
+
app.get("/api/frames", async (req, res) => {
|
|
125
|
+
if (!config.databaseUrl) {
|
|
126
|
+
return res.status(503).json({ error: "Database not configured" });
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
const pgClient = new Client({ connectionString: config.databaseUrl });
|
|
130
|
+
await pgClient.connect();
|
|
131
|
+
const result = await pgClient.query(
|
|
132
|
+
"SELECT * FROM frames ORDER BY created_at DESC LIMIT 10"
|
|
133
|
+
);
|
|
134
|
+
await pgClient.end();
|
|
135
|
+
res.json({
|
|
136
|
+
count: result.rows.length,
|
|
137
|
+
frames: result.rows
|
|
138
|
+
});
|
|
139
|
+
} catch (error) {
|
|
140
|
+
res.status(500).json({
|
|
141
|
+
error: "Database error",
|
|
142
|
+
message: error.message
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
app.listen(config.port, "0.0.0.0", () => {
|
|
147
|
+
console.log(`\u2705 Server running on port ${config.port}`);
|
|
148
|
+
console.log(`\u{1F4CA} Database: ${config.databaseUrl ? "configured" : "not configured"}`);
|
|
149
|
+
console.log(`\u{1F4BE} Redis: ${config.redisUrl ? "configured" : "not configured"}`);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
startServer().catch((error) => {
|
|
153
|
+
console.error("Failed to start server:", error);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
});
|
|
156
|
+
//# sourceMappingURL=index-enhanced.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/servers/railway/index-enhanced.ts"],
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n/**\n * Enhanced Railway Server with Redis and PostgreSQL\n */\n\nimport express from 'express';\nimport cors from 'cors';\nimport { createClient } from 'redis';\nimport pg from 'pg';\nimport { getRailwayConfig } from './config.js';\n\nconst { Client } = pg;\n\nasync function startServer() {\n const config = getRailwayConfig();\n \n console.log('\uD83D\uDE80 Starting StackMemory Railway Server (Enhanced)');\n console.log(`\uD83D\uDCCD Environment: ${config.environment}`);\n console.log(`\uD83D\uDD0C Port: ${config.port}`);\n \n const app = express();\n \n // Middleware\n app.use(cors({\n origin: config.corsOrigins,\n credentials: true\n }));\n app.use(express.json());\n \n // Health check endpoint - Railway uses this\n app.get('/health', (req, res) => {\n res.json({ \n status: 'healthy',\n service: 'stackmemory',\n timestamp: new Date().toISOString()\n });\n });\n \n // Root endpoint\n app.get('/', (req, res) => {\n res.json({\n name: 'StackMemory API',\n version: '0.3.17',\n status: 'running',\n endpoints: ['/health', '/api/health', '/api/status', '/api/frames']\n });\n });\n \n // Enhanced health check with service status\n app.get('/api/health', async (req, res) => {\n const checks: any = {\n server: 'ok',\n timestamp: new Date().toISOString()\n };\n \n // Test PostgreSQL\n if (config.databaseUrl) {\n try {\n const pgClient = new Client({ connectionString: config.databaseUrl });\n await pgClient.connect();\n await pgClient.query('SELECT 1');\n await pgClient.end();\n checks.postgres = 'connected';\n } catch (error: any) {\n checks.postgres = 'error';\n checks.postgresError = error.message.substring(0, 100);\n }\n }\n \n // Test Redis\n if (config.redisUrl) {\n try {\n const redisClient = createClient({ url: config.redisUrl });\n await redisClient.connect();\n await redisClient.ping();\n await redisClient.disconnect();\n checks.redis = 'connected';\n } catch (error: any) {\n checks.redis = 'error';\n checks.redisError = error.message.substring(0, 100);\n }\n }\n \n const healthy = checks.postgres === 'connected' || checks.redis === 'connected';\n res.status(healthy ? 200 : 503).json(checks);\n });\n \n // Status endpoint with detailed info\n app.get('/api/status', async (req, res) => {\n const status: any = {\n service: 'stackmemory',\n version: '0.3.17',\n environment: config.environment,\n storage: {}\n };\n \n // PostgreSQL status\n if (config.databaseUrl) {\n try {\n const pgClient = new Client({ connectionString: config.databaseUrl });\n await pgClient.connect();\n \n // Initialize frames table if needed\n await pgClient.query(`\n CREATE TABLE IF NOT EXISTS frames (\n frame_id TEXT PRIMARY KEY,\n run_id TEXT NOT NULL,\n project_id TEXT NOT NULL,\n parent_frame_id TEXT,\n depth INTEGER DEFAULT 0,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n state TEXT DEFAULT 'active',\n inputs JSONB DEFAULT '{}',\n outputs JSONB DEFAULT '{}',\n created_at TIMESTAMP DEFAULT NOW()\n )\n `);\n \n const frameCount = await pgClient.query('SELECT COUNT(*) FROM frames');\n status.storage.postgres = {\n connected: true,\n frames: parseInt(frameCount.rows[0].count)\n };\n \n await pgClient.end();\n } catch (error: any) {\n status.storage.postgres = {\n connected: false,\n error: error.message.substring(0, 100)\n };\n }\n }\n \n // Redis status\n if (config.redisUrl) {\n try {\n const redisClient = createClient({ url: config.redisUrl });\n await redisClient.connect();\n \n const keys = await redisClient.keys('*');\n status.storage.redis = {\n connected: true,\n keys: keys.length\n };\n \n await redisClient.disconnect();\n } catch (error: any) {\n status.storage.redis = {\n connected: false,\n error: error.message.substring(0, 100)\n };\n }\n }\n \n res.json(status);\n });\n \n // Frames endpoint\n app.get('/api/frames', async (req, res) => {\n if (!config.databaseUrl) {\n return res.status(503).json({ error: 'Database not configured' });\n }\n \n try {\n const pgClient = new Client({ connectionString: config.databaseUrl });\n await pgClient.connect();\n \n const result = await pgClient.query(\n 'SELECT * FROM frames ORDER BY created_at DESC LIMIT 10'\n );\n \n await pgClient.end();\n res.json({\n count: result.rows.length,\n frames: result.rows\n });\n } catch (error: any) {\n res.status(500).json({\n error: 'Database error',\n message: error.message\n });\n }\n });\n \n // Start server\n app.listen(config.port, '0.0.0.0', () => {\n console.log(`\u2705 Server running on port ${config.port}`);\n console.log(`\uD83D\uDCCA Database: ${config.databaseUrl ? 'configured' : 'not configured'}`);\n console.log(`\uD83D\uDCBE Redis: ${config.redisUrl ? 'configured' : 'not configured'}`);\n });\n}\n\nstartServer().catch(error => {\n console.error('Failed to start server:', error);\n process.exit(1);\n});"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import http from "http";
|
|
3
3
|
const PORT = process.env.PORT || 3e3;
|
|
4
|
-
const server = http.createServer((req, res) => {
|
|
4
|
+
const server = http.createServer(async (req, res) => {
|
|
5
5
|
console.log(`${(/* @__PURE__ */ new Date()).toISOString()} ${req.method} ${req.url}`);
|
|
6
|
-
if (req.url === "/health") {
|
|
6
|
+
if (req.url === "/health" || req.url === "/api/health") {
|
|
7
7
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
8
8
|
res.end(
|
|
9
9
|
JSON.stringify({
|
|
@@ -13,12 +13,57 @@ const server = http.createServer((req, res) => {
|
|
|
13
13
|
env: process.env.NODE_ENV || "development"
|
|
14
14
|
})
|
|
15
15
|
);
|
|
16
|
+
} else if (req.url === "/test-db") {
|
|
17
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
18
|
+
const testResults = { postgresql: {}, redis: {} };
|
|
19
|
+
if (process.env.DATABASE_URL) {
|
|
20
|
+
try {
|
|
21
|
+
const { Client } = (await import("pg")).default;
|
|
22
|
+
const pgClient = new Client({ connectionString: process.env.DATABASE_URL });
|
|
23
|
+
await pgClient.connect();
|
|
24
|
+
const result = await pgClient.query("SELECT NOW() as time, version() as version");
|
|
25
|
+
testResults.postgresql = {
|
|
26
|
+
status: "connected",
|
|
27
|
+
time: result.rows[0].time,
|
|
28
|
+
version: result.rows[0].version.split(" ")[0]
|
|
29
|
+
};
|
|
30
|
+
await pgClient.end();
|
|
31
|
+
} catch (error) {
|
|
32
|
+
testResults.postgresql = { status: "error", message: error.message };
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
testResults.postgresql = { status: "not_configured" };
|
|
36
|
+
}
|
|
37
|
+
const redisUrl = process.env.REDIS_URL || (process.env.REDISHOST ? `redis://${process.env.REDISHOST}:${process.env.REDISPORT || 6379}` : null);
|
|
38
|
+
if (redisUrl) {
|
|
39
|
+
try {
|
|
40
|
+
const { createClient } = await import("redis");
|
|
41
|
+
const redisClient = createClient({ url: redisUrl });
|
|
42
|
+
await redisClient.connect();
|
|
43
|
+
await redisClient.ping();
|
|
44
|
+
const info = await redisClient.info("server");
|
|
45
|
+
const version = info.match(/redis_version:(.+)/)?.[1];
|
|
46
|
+
testResults.redis = {
|
|
47
|
+
status: "connected",
|
|
48
|
+
version,
|
|
49
|
+
url: redisUrl.replace(/:\/\/[^@]+@/, "://***:***@")
|
|
50
|
+
// Hide credentials
|
|
51
|
+
};
|
|
52
|
+
await redisClient.disconnect();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
testResults.redis = { status: "error", message: error.message };
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
testResults.redis = { status: "not_configured" };
|
|
58
|
+
}
|
|
59
|
+
res.end(JSON.stringify(testResults, null, 2));
|
|
16
60
|
} else if (req.url === "/") {
|
|
17
61
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
18
62
|
res.end(
|
|
19
63
|
JSON.stringify({
|
|
20
64
|
message: "StackMemory Minimal Server Running",
|
|
21
|
-
version: "1.0.0"
|
|
65
|
+
version: "1.0.0",
|
|
66
|
+
endpoints: ["/health", "/api/health", "/test-db"]
|
|
22
67
|
})
|
|
23
68
|
);
|
|
24
69
|
} else {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/servers/railway/minimal.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\n/**\n * Minimal Railway Server - Absolute minimum for testing\n */\n\nimport http from 'http';\n\nconst PORT = process.env.PORT || 3000;\n\nconst server = http.createServer((req, res) => {\n console.log(`${new Date().toISOString()} ${req.method} ${req.url}`);\n\n if (req.url === '/health') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n status: 'healthy',\n timestamp: new Date().toISOString(),\n port: PORT,\n env: process.env.NODE_ENV || 'development',\n })\n );\n } else if (req.url === '/') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n message: 'StackMemory Minimal Server Running',\n version: '1.0.0',\n })\n );\n } else {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n});\n\nserver.listen(PORT, '0.0.0.0', () => {\n console.log(`\n=================================\nMinimal Server Started\nPort: ${PORT}\nTime: ${new Date().toISOString()}\n=================================\n `);\n});\n\n// Keep alive\nprocess.on('SIGTERM', () => {\n console.log('SIGTERM received');\n server.close(() => process.exit(0));\n});\n\nprocess.on('SIGINT', () => {\n console.log('SIGINT received');\n server.close(() => process.exit(0));\n});\n"],
|
|
5
|
-
"mappings": ";AAKA,OAAO,UAAU;AAEjB,MAAM,OAAO,QAAQ,IAAI,QAAQ;AAEjC,MAAM,SAAS,KAAK,aAAa,
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n/**\n * Minimal Railway Server - Absolute minimum for testing\n */\n\nimport http from 'http';\n\nconst PORT = process.env.PORT || 3000;\n\nconst server = http.createServer(async (req, res) => {\n console.log(`${new Date().toISOString()} ${req.method} ${req.url}`);\n\n if (req.url === '/health' || req.url === '/api/health') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n status: 'healthy',\n timestamp: new Date().toISOString(),\n port: PORT,\n env: process.env.NODE_ENV || 'development',\n })\n );\n } else if (req.url === '/test-db') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n \n // Test database connections\n const testResults = { postgresql: {}, redis: {} };\n \n // Test PostgreSQL\n if (process.env.DATABASE_URL) {\n try {\n const { Client } = (await import('pg')).default;\n const pgClient = new Client({ connectionString: process.env.DATABASE_URL });\n await pgClient.connect();\n \n const result = await pgClient.query('SELECT NOW() as time, version() as version');\n testResults.postgresql = {\n status: 'connected',\n time: result.rows[0].time,\n version: result.rows[0].version.split(' ')[0]\n };\n \n await pgClient.end();\n } catch (error) {\n testResults.postgresql = { status: 'error', message: error.message };\n }\n } else {\n testResults.postgresql = { status: 'not_configured' };\n }\n \n // Test Redis\n const redisUrl = process.env.REDIS_URL || \n (process.env.REDISHOST ? `redis://${process.env.REDISHOST}:${process.env.REDISPORT || 6379}` : null);\n \n if (redisUrl) {\n try {\n const { createClient } = await import('redis');\n const redisClient = createClient({ url: redisUrl });\n await redisClient.connect();\n \n await redisClient.ping();\n const info = await redisClient.info('server');\n const version = info.match(/redis_version:(.+)/)?.[1];\n \n testResults.redis = {\n status: 'connected',\n version: version,\n url: redisUrl.replace(/:\\/\\/[^@]+@/, '://***:***@') // Hide credentials\n };\n \n await redisClient.disconnect();\n } catch (error) {\n testResults.redis = { status: 'error', message: error.message };\n }\n } else {\n testResults.redis = { status: 'not_configured' };\n }\n \n res.end(JSON.stringify(testResults, null, 2));\n } else if (req.url === '/') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n message: 'StackMemory Minimal Server Running',\n version: '1.0.0',\n endpoints: ['/health', '/api/health', '/test-db']\n })\n );\n } else {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n});\n\nserver.listen(PORT, '0.0.0.0', () => {\n console.log(`\n=================================\nMinimal Server Started\nPort: ${PORT}\nTime: ${new Date().toISOString()}\n=================================\n `);\n});\n\n// Keep alive\nprocess.on('SIGTERM', () => {\n console.log('SIGTERM received');\n server.close(() => process.exit(0));\n});\n\nprocess.on('SIGINT', () => {\n console.log('SIGINT received');\n server.close(() => process.exit(0));\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|