@stackmemoryai/stackmemory 0.3.17 → 0.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/claude-sm.js +51 -5
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/codex-sm.js +52 -19
- package/dist/cli/codex-sm.js.map +2 -2
- package/dist/cli/commands/db.js +143 -0
- package/dist/cli/commands/db.js.map +7 -0
- package/dist/cli/commands/login.js +50 -0
- package/dist/cli/commands/login.js.map +7 -0
- package/dist/cli/commands/migrate.js +178 -0
- package/dist/cli/commands/migrate.js.map +7 -0
- package/dist/cli/commands/onboard.js +158 -2
- package/dist/cli/commands/onboard.js.map +2 -2
- package/dist/cli/commands/skills.js +15 -2
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/index.js +118 -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-database.js +1 -0
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-manager.js +59 -2
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/database/database-adapter.js +6 -1
- package/dist/core/database/database-adapter.js.map +2 -2
- package/dist/core/database/sqlite-adapter.js +60 -2
- package/dist/core/database/sqlite-adapter.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/index.js +843 -82
- package/dist/servers/railway/index.js.map +3 -3
- 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 +13 -21
- 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-railway-deployment.sh +37 -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/scripts/verify-railway-schema.ts +35 -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,455 @@
|
|
|
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 { S3Client, PutObjectCommand, GetObjectCommand, ListObjectsCommand } from "@aws-sdk/client-s3";
|
|
7
|
+
const { Client } = pg;
|
|
8
|
+
async function startServer() {
|
|
9
|
+
const config = {
|
|
10
|
+
port: parseInt(process.env.PORT || "3000"),
|
|
11
|
+
databaseUrl: process.env.DATABASE_URL,
|
|
12
|
+
redisUrl: process.env.REDIS_URL || (process.env.REDISHOST ? `redis://${process.env.REDISHOST}:${process.env.REDISPORT || 6379}` : null),
|
|
13
|
+
corsOrigins: process.env.CORS_ORIGINS?.split(",") || ["*"]
|
|
14
|
+
};
|
|
15
|
+
console.log("\u{1F680} Starting StackMemory Storage Test Server");
|
|
16
|
+
console.log(`\u{1F4CD} Port: ${config.port}`);
|
|
17
|
+
console.log(`\u{1F4BE} PostgreSQL: ${config.databaseUrl ? "configured" : "not configured"}`);
|
|
18
|
+
console.log(`\u{1F534} Redis: ${config.redisUrl ? "configured" : "not configured"}`);
|
|
19
|
+
const app = express();
|
|
20
|
+
app.use(cors({ origin: config.corsOrigins }));
|
|
21
|
+
app.use(express.json());
|
|
22
|
+
app.get("/health", (req, res) => {
|
|
23
|
+
res.json({
|
|
24
|
+
status: "healthy",
|
|
25
|
+
service: "stackmemory-storage-test",
|
|
26
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
app.get("/api/health", (req, res) => {
|
|
30
|
+
res.json({
|
|
31
|
+
status: "healthy",
|
|
32
|
+
service: "stackmemory-storage-test",
|
|
33
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
app.get("/", (req, res) => {
|
|
37
|
+
res.json({
|
|
38
|
+
name: "StackMemory Core API",
|
|
39
|
+
version: "0.3.17",
|
|
40
|
+
description: "Core API with Redis, PostgreSQL, and Railway Buckets",
|
|
41
|
+
endpoints: [
|
|
42
|
+
"/health",
|
|
43
|
+
"/api/health",
|
|
44
|
+
"/api/login",
|
|
45
|
+
"/api/status",
|
|
46
|
+
"/test-storage",
|
|
47
|
+
"/create-frame",
|
|
48
|
+
"/list-frames",
|
|
49
|
+
"/api/frames"
|
|
50
|
+
],
|
|
51
|
+
storage_tiers: {
|
|
52
|
+
hot: "Redis (< 24 hours)",
|
|
53
|
+
warm: "Railway Buckets (1-30 days)",
|
|
54
|
+
cold: "PostgreSQL (30+ days)"
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
app.post("/api/login", async (req, res) => {
|
|
59
|
+
try {
|
|
60
|
+
const { username, api_key } = req.body;
|
|
61
|
+
const validApiKey = process.env.API_KEY_SECRET || "development-secret";
|
|
62
|
+
if (api_key === validApiKey) {
|
|
63
|
+
const sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
64
|
+
const sessionData = {
|
|
65
|
+
username: username || "api_user",
|
|
66
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
67
|
+
api_key_hash: "valid",
|
|
68
|
+
permissions: ["read", "write", "admin"]
|
|
69
|
+
};
|
|
70
|
+
if (config.redisUrl) {
|
|
71
|
+
const redisClient = createClient({ url: config.redisUrl });
|
|
72
|
+
await redisClient.connect();
|
|
73
|
+
await redisClient.setEx(`session:${sessionId}`, 3600, JSON.stringify(sessionData));
|
|
74
|
+
await redisClient.disconnect();
|
|
75
|
+
}
|
|
76
|
+
res.json({
|
|
77
|
+
success: true,
|
|
78
|
+
session_id: sessionId,
|
|
79
|
+
message: "Automatically logged into StackMemory Core API",
|
|
80
|
+
access: {
|
|
81
|
+
redis: config.redisUrl ? "available" : "not_configured",
|
|
82
|
+
postgresql: config.databaseUrl ? "available" : "not_configured",
|
|
83
|
+
buckets: "configurable"
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
} else {
|
|
87
|
+
res.status(401).json({
|
|
88
|
+
success: false,
|
|
89
|
+
message: "Invalid API key"
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
res.status(500).json({
|
|
94
|
+
success: false,
|
|
95
|
+
message: "Login failed",
|
|
96
|
+
error: error.message
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
app.get("/api/status", async (req, res) => {
|
|
101
|
+
const status = {
|
|
102
|
+
service: "stackmemory-core-api",
|
|
103
|
+
version: "0.3.17",
|
|
104
|
+
environment: process.env.NODE_ENV || "production",
|
|
105
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
106
|
+
storage: {
|
|
107
|
+
tiers: {}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
if (config.redisUrl) {
|
|
111
|
+
try {
|
|
112
|
+
const redisClient = createClient({ url: config.redisUrl });
|
|
113
|
+
await redisClient.connect();
|
|
114
|
+
const info = await redisClient.info("memory");
|
|
115
|
+
const keys = await redisClient.keys("*");
|
|
116
|
+
const usedMemory = info.match(/used_memory_human:(.+)/)?.[1];
|
|
117
|
+
status.storage.tiers.hot_redis = {
|
|
118
|
+
status: "connected",
|
|
119
|
+
memory_used: usedMemory?.trim(),
|
|
120
|
+
keys: keys.length,
|
|
121
|
+
ttl_policy: "auto-expire"
|
|
122
|
+
};
|
|
123
|
+
await redisClient.disconnect();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
status.storage.tiers.hot_redis = { status: "error", message: error.message };
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
status.storage.tiers.hot_redis = { status: "not_configured" };
|
|
129
|
+
}
|
|
130
|
+
if (config.databaseUrl) {
|
|
131
|
+
try {
|
|
132
|
+
const pgClient = new Client({ connectionString: config.databaseUrl });
|
|
133
|
+
await pgClient.connect();
|
|
134
|
+
const result = await pgClient.query("SELECT COUNT(*) as frames FROM frames WHERE created_at > NOW() - INTERVAL '24 hours'");
|
|
135
|
+
const totalFrames = await pgClient.query("SELECT COUNT(*) as total FROM frames");
|
|
136
|
+
status.storage.tiers.cold_postgresql = {
|
|
137
|
+
status: "connected",
|
|
138
|
+
recent_frames: parseInt(result.rows[0].frames),
|
|
139
|
+
total_frames: parseInt(totalFrames.rows[0].total)
|
|
140
|
+
};
|
|
141
|
+
await pgClient.end();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
status.storage.tiers.cold_postgresql = { status: "error", message: error.message };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
res.json(status);
|
|
147
|
+
});
|
|
148
|
+
app.get("/test-storage", async (req, res) => {
|
|
149
|
+
const results = {
|
|
150
|
+
postgresql: {},
|
|
151
|
+
redis: {},
|
|
152
|
+
buckets: {},
|
|
153
|
+
summary: {}
|
|
154
|
+
};
|
|
155
|
+
try {
|
|
156
|
+
if (config.databaseUrl) {
|
|
157
|
+
console.log("\u{1F418} Testing PostgreSQL...");
|
|
158
|
+
try {
|
|
159
|
+
const pgClient = new Client({ connectionString: config.databaseUrl });
|
|
160
|
+
await pgClient.connect();
|
|
161
|
+
const timeResult = await pgClient.query("SELECT NOW() as time, version() as version");
|
|
162
|
+
await pgClient.query(`
|
|
163
|
+
CREATE TABLE IF NOT EXISTS frames (
|
|
164
|
+
frame_id TEXT PRIMARY KEY,
|
|
165
|
+
run_id TEXT NOT NULL,
|
|
166
|
+
project_id TEXT NOT NULL,
|
|
167
|
+
type TEXT NOT NULL,
|
|
168
|
+
name TEXT NOT NULL,
|
|
169
|
+
state TEXT DEFAULT 'active',
|
|
170
|
+
inputs JSONB DEFAULT '{}',
|
|
171
|
+
outputs JSONB DEFAULT '{}',
|
|
172
|
+
created_at TIMESTAMP DEFAULT NOW()
|
|
173
|
+
)
|
|
174
|
+
`);
|
|
175
|
+
const testId = `pg-test-${Date.now()}`;
|
|
176
|
+
await pgClient.query(
|
|
177
|
+
"INSERT INTO frames (frame_id, run_id, project_id, type, name) VALUES ($1, $2, $3, $4, $5)",
|
|
178
|
+
[testId, "test-run", "storage-test", "test", "PostgreSQL Test Frame"]
|
|
179
|
+
);
|
|
180
|
+
const frameResult = await pgClient.query("SELECT COUNT(*) as count FROM frames");
|
|
181
|
+
results.postgresql = {
|
|
182
|
+
status: "connected",
|
|
183
|
+
server_time: timeResult.rows[0].time,
|
|
184
|
+
version: timeResult.rows[0].version.split(" ")[0],
|
|
185
|
+
total_frames: parseInt(frameResult.rows[0].count),
|
|
186
|
+
test_frame_id: testId
|
|
187
|
+
};
|
|
188
|
+
await pgClient.end();
|
|
189
|
+
} catch (error) {
|
|
190
|
+
results.postgresql = { status: "error", message: error.message };
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
results.postgresql = { status: "not_configured" };
|
|
194
|
+
}
|
|
195
|
+
if (config.redisUrl) {
|
|
196
|
+
console.log("\u{1F534} Testing Redis...");
|
|
197
|
+
try {
|
|
198
|
+
const redisClient = createClient({ url: config.redisUrl });
|
|
199
|
+
await redisClient.connect();
|
|
200
|
+
const testKey = `redis-test:${Date.now()}`;
|
|
201
|
+
const testData = {
|
|
202
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
203
|
+
test: "Redis connectivity test",
|
|
204
|
+
frame_count: 1
|
|
205
|
+
};
|
|
206
|
+
await redisClient.setEx(testKey, 300, JSON.stringify(testData));
|
|
207
|
+
const retrieved = await redisClient.get(testKey);
|
|
208
|
+
const info = await redisClient.info("server");
|
|
209
|
+
const memory = await redisClient.info("memory");
|
|
210
|
+
const version = info.match(/redis_version:(.+)/)?.[1];
|
|
211
|
+
const usedMemory = memory.match(/used_memory_human:(.+)/)?.[1];
|
|
212
|
+
const keys = await redisClient.keys("*");
|
|
213
|
+
results.redis = {
|
|
214
|
+
status: "connected",
|
|
215
|
+
version,
|
|
216
|
+
memory_used: usedMemory?.trim(),
|
|
217
|
+
total_keys: keys.length,
|
|
218
|
+
test_key: testKey,
|
|
219
|
+
test_data_retrieved: retrieved ? JSON.parse(retrieved) : null
|
|
220
|
+
};
|
|
221
|
+
await redisClient.disconnect();
|
|
222
|
+
} catch (error) {
|
|
223
|
+
results.redis = { status: "error", message: error.message };
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
results.redis = { status: "not_configured" };
|
|
227
|
+
}
|
|
228
|
+
console.log("\u{1FAA3} Testing Railway Buckets...");
|
|
229
|
+
const bucketConfig = {
|
|
230
|
+
endpoint: process.env.RAILWAY_BUCKET_ENDPOINT,
|
|
231
|
+
accessKeyId: process.env.RAILWAY_BUCKET_ACCESS_KEY,
|
|
232
|
+
secretAccessKey: process.env.RAILWAY_BUCKET_SECRET_KEY,
|
|
233
|
+
bucket: process.env.RAILWAY_BUCKET_NAME || "stackmemory-warm"
|
|
234
|
+
};
|
|
235
|
+
if (bucketConfig.endpoint && bucketConfig.accessKeyId && bucketConfig.secretAccessKey) {
|
|
236
|
+
try {
|
|
237
|
+
const s3Client = new S3Client({
|
|
238
|
+
endpoint: bucketConfig.endpoint,
|
|
239
|
+
region: "us-east-1",
|
|
240
|
+
credentials: {
|
|
241
|
+
accessKeyId: bucketConfig.accessKeyId,
|
|
242
|
+
secretAccessKey: bucketConfig.secretAccessKey
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
const testKey = `storage-test/frame-${Date.now()}.json`;
|
|
246
|
+
const testFrame = {
|
|
247
|
+
frame_id: `bucket-test-${Date.now()}`,
|
|
248
|
+
type: "test",
|
|
249
|
+
name: "Railway Bucket Test",
|
|
250
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
251
|
+
data: "This is a test frame stored in Railway Buckets"
|
|
252
|
+
};
|
|
253
|
+
await s3Client.send(new PutObjectCommand({
|
|
254
|
+
Bucket: bucketConfig.bucket,
|
|
255
|
+
Key: testKey,
|
|
256
|
+
Body: JSON.stringify(testFrame),
|
|
257
|
+
ContentType: "application/json"
|
|
258
|
+
}));
|
|
259
|
+
const getResult = await s3Client.send(new GetObjectCommand({
|
|
260
|
+
Bucket: bucketConfig.bucket,
|
|
261
|
+
Key: testKey
|
|
262
|
+
}));
|
|
263
|
+
const listResult = await s3Client.send(new ListObjectsCommand({
|
|
264
|
+
Bucket: bucketConfig.bucket,
|
|
265
|
+
MaxKeys: 10
|
|
266
|
+
}));
|
|
267
|
+
results.buckets = {
|
|
268
|
+
status: "connected",
|
|
269
|
+
endpoint: bucketConfig.endpoint,
|
|
270
|
+
bucket: bucketConfig.bucket,
|
|
271
|
+
test_key: testKey,
|
|
272
|
+
object_count: listResult.Contents?.length || 0,
|
|
273
|
+
test_frame: testFrame
|
|
274
|
+
};
|
|
275
|
+
} catch (error) {
|
|
276
|
+
results.buckets = { status: "error", message: error.message };
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
results.buckets = {
|
|
280
|
+
status: "not_configured",
|
|
281
|
+
missing: Object.entries(bucketConfig).filter(([key, value]) => !value).map(([key]) => key)
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
results.summary = {
|
|
285
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
286
|
+
tiers: {
|
|
287
|
+
hot: results.redis.status === "connected" ? "available" : "unavailable",
|
|
288
|
+
warm: results.buckets.status === "connected" ? "available" : "unavailable",
|
|
289
|
+
cold: results.postgresql.status === "connected" ? "available" : "unavailable"
|
|
290
|
+
},
|
|
291
|
+
ready_for_production: results.postgresql.status === "connected" && results.redis.status === "connected"
|
|
292
|
+
};
|
|
293
|
+
res.json(results);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
console.error("Storage test error:", error);
|
|
296
|
+
res.status(500).json({
|
|
297
|
+
error: "Storage test failed",
|
|
298
|
+
message: error.message,
|
|
299
|
+
partial_results: results
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
app.post("/create-frame", async (req, res) => {
|
|
304
|
+
const frameData = {
|
|
305
|
+
frame_id: `frame-${Date.now()}`,
|
|
306
|
+
run_id: req.body.run_id || "test-run",
|
|
307
|
+
project_id: req.body.project_id || "storage-test",
|
|
308
|
+
type: req.body.type || "test",
|
|
309
|
+
name: req.body.name || "Multi-tier Test Frame",
|
|
310
|
+
inputs: req.body.inputs || {},
|
|
311
|
+
outputs: req.body.outputs || { status: "created" },
|
|
312
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
313
|
+
};
|
|
314
|
+
const results = { frame: frameData, storage: {} };
|
|
315
|
+
try {
|
|
316
|
+
if (config.databaseUrl) {
|
|
317
|
+
const pgClient = new Client({ connectionString: config.databaseUrl });
|
|
318
|
+
await pgClient.connect();
|
|
319
|
+
await pgClient.query(
|
|
320
|
+
"INSERT INTO frames (frame_id, run_id, project_id, type, name, inputs, outputs) VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
|
321
|
+
[frameData.frame_id, frameData.run_id, frameData.project_id, frameData.type, frameData.name, frameData.inputs, frameData.outputs]
|
|
322
|
+
);
|
|
323
|
+
await pgClient.end();
|
|
324
|
+
results.storage.postgresql = "stored";
|
|
325
|
+
}
|
|
326
|
+
if (config.redisUrl) {
|
|
327
|
+
const redisClient = createClient({ url: config.redisUrl });
|
|
328
|
+
await redisClient.connect();
|
|
329
|
+
await redisClient.setEx(`frame:${frameData.frame_id}`, 3600, JSON.stringify(frameData));
|
|
330
|
+
await redisClient.disconnect();
|
|
331
|
+
results.storage.redis = "stored";
|
|
332
|
+
}
|
|
333
|
+
res.json(results);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
res.status(500).json({
|
|
336
|
+
error: "Failed to create frame",
|
|
337
|
+
message: error.message,
|
|
338
|
+
partial_results: results
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
app.get("/api/frames", async (req, res) => {
|
|
343
|
+
try {
|
|
344
|
+
const limit = parseInt(req.query.limit) || 10;
|
|
345
|
+
const source = req.query.source || "all";
|
|
346
|
+
const results = {
|
|
347
|
+
frames: [],
|
|
348
|
+
sources_checked: [],
|
|
349
|
+
total_count: 0
|
|
350
|
+
};
|
|
351
|
+
if ((source === "all" || source === "redis") && config.redisUrl) {
|
|
352
|
+
try {
|
|
353
|
+
const redisClient = createClient({ url: config.redisUrl });
|
|
354
|
+
await redisClient.connect();
|
|
355
|
+
const redisKeys = await redisClient.keys("frame:*");
|
|
356
|
+
const redisFrames = [];
|
|
357
|
+
for (const key of redisKeys.slice(0, limit)) {
|
|
358
|
+
const data = await redisClient.get(key);
|
|
359
|
+
if (data) {
|
|
360
|
+
const frame = JSON.parse(data);
|
|
361
|
+
frame.source = "redis";
|
|
362
|
+
frame.tier = "hot";
|
|
363
|
+
redisFrames.push(frame);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
await redisClient.disconnect();
|
|
367
|
+
results.frames.push(...redisFrames);
|
|
368
|
+
results.sources_checked.push("redis");
|
|
369
|
+
} catch (error) {
|
|
370
|
+
results.redis_error = error.message;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if ((source === "all" || source === "postgresql") && config.databaseUrl) {
|
|
374
|
+
try {
|
|
375
|
+
const pgClient = new Client({ connectionString: config.databaseUrl });
|
|
376
|
+
await pgClient.connect();
|
|
377
|
+
const pgFrames = await pgClient.query(
|
|
378
|
+
"SELECT *, 'postgresql' as source, 'cold' as tier FROM frames ORDER BY created_at DESC LIMIT $1",
|
|
379
|
+
[limit]
|
|
380
|
+
);
|
|
381
|
+
await pgClient.end();
|
|
382
|
+
results.frames.push(...pgFrames.rows);
|
|
383
|
+
results.sources_checked.push("postgresql");
|
|
384
|
+
results.total_count = pgFrames.rowCount;
|
|
385
|
+
} catch (error) {
|
|
386
|
+
results.postgresql_error = error.message;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (results.frames.length > 1) {
|
|
390
|
+
results.frames.sort(
|
|
391
|
+
(a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
res.json({
|
|
395
|
+
count: results.frames.length,
|
|
396
|
+
frames: results.frames.slice(0, limit),
|
|
397
|
+
metadata: {
|
|
398
|
+
sources_checked: results.sources_checked,
|
|
399
|
+
total_in_postgresql: results.total_count,
|
|
400
|
+
tier_explanation: {
|
|
401
|
+
hot: "Redis - Recent frames (< 24 hours)",
|
|
402
|
+
cold: "PostgreSQL - All frames (persistent storage)"
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
} catch (error) {
|
|
407
|
+
res.status(500).json({
|
|
408
|
+
error: "Failed to fetch frames",
|
|
409
|
+
message: error.message
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
app.get("/list-frames", async (req, res) => {
|
|
414
|
+
const results = { sources: {} };
|
|
415
|
+
try {
|
|
416
|
+
if (config.databaseUrl) {
|
|
417
|
+
const pgClient = new Client({ connectionString: config.databaseUrl });
|
|
418
|
+
await pgClient.connect();
|
|
419
|
+
const pgFrames = await pgClient.query("SELECT * FROM frames ORDER BY created_at DESC LIMIT 5");
|
|
420
|
+
await pgClient.end();
|
|
421
|
+
results.sources.postgresql = pgFrames.rows;
|
|
422
|
+
}
|
|
423
|
+
if (config.redisUrl) {
|
|
424
|
+
const redisClient = createClient({ url: config.redisUrl });
|
|
425
|
+
await redisClient.connect();
|
|
426
|
+
const redisKeys = await redisClient.keys("frame:*");
|
|
427
|
+
const redisFrames = [];
|
|
428
|
+
for (const key of redisKeys.slice(0, 5)) {
|
|
429
|
+
const data = await redisClient.get(key);
|
|
430
|
+
if (data) redisFrames.push(JSON.parse(data));
|
|
431
|
+
}
|
|
432
|
+
await redisClient.disconnect();
|
|
433
|
+
results.sources.redis = redisFrames;
|
|
434
|
+
}
|
|
435
|
+
res.json(results);
|
|
436
|
+
} catch (error) {
|
|
437
|
+
res.status(500).json({
|
|
438
|
+
error: "Failed to list frames",
|
|
439
|
+
message: error.message
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
app.listen(config.port, "0.0.0.0", () => {
|
|
444
|
+
console.log(`\u2705 Storage Test Server running on port ${config.port}`);
|
|
445
|
+
console.log("\n\u{1F4CA} Available endpoints:");
|
|
446
|
+
console.log(" - GET /test-storage (comprehensive storage test)");
|
|
447
|
+
console.log(" - POST /create-frame (create test frame)");
|
|
448
|
+
console.log(" - GET /list-frames (list recent frames)");
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
startServer().catch((error) => {
|
|
452
|
+
console.error("Failed to start storage test server:", error);
|
|
453
|
+
process.exit(1);
|
|
454
|
+
});
|
|
455
|
+
//# sourceMappingURL=storage-test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/servers/railway/storage-test.ts"],
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n/**\n * Enhanced Railway Server with Full Storage Testing\n * Tests PostgreSQL, Redis, and Railway Buckets (3-tier system)\n */\n\nimport express from 'express';\nimport cors from 'cors';\nimport { createClient } from 'redis';\nimport pg from 'pg';\nimport { S3Client, PutObjectCommand, GetObjectCommand, ListObjectsCommand } from '@aws-sdk/client-s3';\n\nconst { Client } = pg;\n\ninterface StorageTestResult {\n postgresql: any;\n redis: any;\n buckets: any;\n summary: any;\n}\n\nasync function startServer() {\n const config = {\n port: parseInt(process.env.PORT || '3000'),\n databaseUrl: process.env.DATABASE_URL,\n redisUrl: process.env.REDIS_URL || \n (process.env.REDISHOST ? `redis://${process.env.REDISHOST}:${process.env.REDISPORT || 6379}` : null),\n corsOrigins: process.env.CORS_ORIGINS?.split(',') || ['*']\n };\n \n console.log('\uD83D\uDE80 Starting StackMemory Storage Test Server');\n console.log(`\uD83D\uDCCD Port: ${config.port}`);\n console.log(`\uD83D\uDCBE PostgreSQL: ${config.databaseUrl ? 'configured' : 'not configured'}`);\n console.log(`\uD83D\uDD34 Redis: ${config.redisUrl ? 'configured' : 'not configured'}`);\n \n const app = express();\n \n // Middleware\n app.use(cors({ origin: config.corsOrigins }));\n app.use(express.json());\n \n // Health endpoint\n app.get('/health', (req, res) => {\n res.json({ \n status: 'healthy',\n service: 'stackmemory-storage-test',\n timestamp: new Date().toISOString()\n });\n });\n \n app.get('/api/health', (req, res) => {\n res.json({ \n status: 'healthy',\n service: 'stackmemory-storage-test',\n timestamp: new Date().toISOString()\n });\n });\n \n // Root endpoint\n app.get('/', (req, res) => {\n res.json({\n name: 'StackMemory Core API',\n version: '0.3.17',\n description: 'Core API with Redis, PostgreSQL, and Railway Buckets',\n endpoints: [\n '/health',\n '/api/health',\n '/api/login',\n '/api/status',\n '/test-storage',\n '/create-frame',\n '/list-frames',\n '/api/frames'\n ],\n storage_tiers: {\n hot: 'Redis (< 24 hours)',\n warm: 'Railway Buckets (1-30 days)', \n cold: 'PostgreSQL (30+ days)'\n }\n });\n });\n \n // Auto-login endpoint for seamless API access\n app.post('/api/login', async (req, res) => {\n try {\n const { username, api_key } = req.body;\n \n // Simple API key validation (in production, use proper JWT/OAuth)\n const validApiKey = process.env.API_KEY_SECRET || 'development-secret';\n \n if (api_key === validApiKey) {\n // Store session in Redis if available\n const sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n const sessionData = {\n username: username || 'api_user',\n created_at: new Date().toISOString(),\n api_key_hash: 'valid',\n permissions: ['read', 'write', 'admin']\n };\n \n if (config.redisUrl) {\n const redisClient = createClient({ url: config.redisUrl });\n await redisClient.connect();\n await redisClient.setEx(`session:${sessionId}`, 3600, JSON.stringify(sessionData)); // 1 hour\n await redisClient.disconnect();\n }\n \n res.json({\n success: true,\n session_id: sessionId,\n message: 'Automatically logged into StackMemory Core API',\n access: {\n redis: config.redisUrl ? 'available' : 'not_configured',\n postgresql: config.databaseUrl ? 'available' : 'not_configured',\n buckets: 'configurable'\n }\n });\n } else {\n res.status(401).json({\n success: false,\n message: 'Invalid API key'\n });\n }\n } catch (error: any) {\n res.status(500).json({\n success: false,\n message: 'Login failed',\n error: error.message\n });\n }\n });\n \n // Core API status endpoint\n app.get('/api/status', async (req, res) => {\n const status: any = {\n service: 'stackmemory-core-api',\n version: '0.3.17',\n environment: process.env.NODE_ENV || 'production',\n timestamp: new Date().toISOString(),\n storage: {\n tiers: {}\n }\n };\n \n // Check Redis (Hot Tier)\n if (config.redisUrl) {\n try {\n const redisClient = createClient({ url: config.redisUrl });\n await redisClient.connect();\n \n const info = await redisClient.info('memory');\n const keys = await redisClient.keys('*');\n const usedMemory = info.match(/used_memory_human:(.+)/)?.[1];\n \n status.storage.tiers.hot_redis = {\n status: 'connected',\n memory_used: usedMemory?.trim(),\n keys: keys.length,\n ttl_policy: 'auto-expire'\n };\n \n await redisClient.disconnect();\n } catch (error: any) {\n status.storage.tiers.hot_redis = { status: 'error', message: error.message };\n }\n } else {\n status.storage.tiers.hot_redis = { status: 'not_configured' };\n }\n \n // Check PostgreSQL (Cold Tier)\n if (config.databaseUrl) {\n try {\n const pgClient = new Client({ connectionString: config.databaseUrl });\n await pgClient.connect();\n \n const result = await pgClient.query('SELECT COUNT(*) as frames FROM frames WHERE created_at > NOW() - INTERVAL \\'24 hours\\'');\n const totalFrames = await pgClient.query('SELECT COUNT(*) as total FROM frames');\n \n status.storage.tiers.cold_postgresql = {\n status: 'connected',\n recent_frames: parseInt(result.rows[0].frames),\n total_frames: parseInt(totalFrames.rows[0].total)\n };\n \n await pgClient.end();\n } catch (error: any) {\n status.storage.tiers.cold_postgresql = { status: 'error', message: error.message };\n }\n }\n \n res.json(status);\n });\n \n // Comprehensive storage test endpoint\n app.get('/test-storage', async (req, res) => {\n const results: StorageTestResult = {\n postgresql: {},\n redis: {},\n buckets: {},\n summary: {}\n };\n \n try {\n // Test PostgreSQL\n if (config.databaseUrl) {\n console.log('\uD83D\uDC18 Testing PostgreSQL...');\n try {\n const pgClient = new Client({ connectionString: config.databaseUrl });\n await pgClient.connect();\n \n // Basic connectivity\n const timeResult = await pgClient.query('SELECT NOW() as time, version() as version');\n \n // Create frames table\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 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 // Test insert/select\n const testId = `pg-test-${Date.now()}`;\n await pgClient.query(\n 'INSERT INTO frames (frame_id, run_id, project_id, type, name) VALUES ($1, $2, $3, $4, $5)',\n [testId, 'test-run', 'storage-test', 'test', 'PostgreSQL Test Frame']\n );\n \n const frameResult = await pgClient.query('SELECT COUNT(*) as count FROM frames');\n \n results.postgresql = {\n status: 'connected',\n server_time: timeResult.rows[0].time,\n version: timeResult.rows[0].version.split(' ')[0],\n total_frames: parseInt(frameResult.rows[0].count),\n test_frame_id: testId\n };\n \n await pgClient.end();\n } catch (error: any) {\n results.postgresql = { status: 'error', message: error.message };\n }\n } else {\n results.postgresql = { status: 'not_configured' };\n }\n \n // Test Redis\n if (config.redisUrl) {\n console.log('\uD83D\uDD34 Testing Redis...');\n try {\n const redisClient = createClient({ url: config.redisUrl });\n await redisClient.connect();\n \n // Test basic operations\n const testKey = `redis-test:${Date.now()}`;\n const testData = {\n timestamp: new Date().toISOString(),\n test: 'Redis connectivity test',\n frame_count: 1\n };\n \n await redisClient.setEx(testKey, 300, JSON.stringify(testData)); // 5 min expiry\n const retrieved = await redisClient.get(testKey);\n \n // Get server info\n const info = await redisClient.info('server');\n const memory = await redisClient.info('memory');\n const version = info.match(/redis_version:(.+)/)?.[1];\n const usedMemory = memory.match(/used_memory_human:(.+)/)?.[1];\n \n // Count keys\n const keys = await redisClient.keys('*');\n \n results.redis = {\n status: 'connected',\n version: version,\n memory_used: usedMemory?.trim(),\n total_keys: keys.length,\n test_key: testKey,\n test_data_retrieved: retrieved ? JSON.parse(retrieved) : null\n };\n \n await redisClient.disconnect();\n } catch (error: any) {\n results.redis = { status: 'error', message: error.message };\n }\n } else {\n results.redis = { status: 'not_configured' };\n }\n \n // Test Railway Buckets (S3-compatible)\n console.log('\uD83E\uDEA3 Testing Railway Buckets...');\n const bucketConfig = {\n endpoint: process.env.RAILWAY_BUCKET_ENDPOINT,\n accessKeyId: process.env.RAILWAY_BUCKET_ACCESS_KEY,\n secretAccessKey: process.env.RAILWAY_BUCKET_SECRET_KEY,\n bucket: process.env.RAILWAY_BUCKET_NAME || 'stackmemory-warm'\n };\n \n if (bucketConfig.endpoint && bucketConfig.accessKeyId && bucketConfig.secretAccessKey) {\n try {\n const s3Client = new S3Client({\n endpoint: bucketConfig.endpoint,\n region: 'us-east-1',\n credentials: {\n accessKeyId: bucketConfig.accessKeyId,\n secretAccessKey: bucketConfig.secretAccessKey\n }\n });\n \n // Test write\n const testKey = `storage-test/frame-${Date.now()}.json`;\n const testFrame = {\n frame_id: `bucket-test-${Date.now()}`,\n type: 'test',\n name: 'Railway Bucket Test',\n created_at: new Date().toISOString(),\n data: 'This is a test frame stored in Railway Buckets'\n };\n \n await s3Client.send(new PutObjectCommand({\n Bucket: bucketConfig.bucket,\n Key: testKey,\n Body: JSON.stringify(testFrame),\n ContentType: 'application/json'\n }));\n \n // Test read\n const getResult = await s3Client.send(new GetObjectCommand({\n Bucket: bucketConfig.bucket,\n Key: testKey\n }));\n \n // List objects\n const listResult = await s3Client.send(new ListObjectsCommand({\n Bucket: bucketConfig.bucket,\n MaxKeys: 10\n }));\n \n results.buckets = {\n status: 'connected',\n endpoint: bucketConfig.endpoint,\n bucket: bucketConfig.bucket,\n test_key: testKey,\n object_count: listResult.Contents?.length || 0,\n test_frame: testFrame\n };\n } catch (error: any) {\n results.buckets = { status: 'error', message: error.message };\n }\n } else {\n results.buckets = { \n status: 'not_configured',\n missing: Object.entries(bucketConfig)\n .filter(([key, value]) => !value)\n .map(([key]) => key)\n };\n }\n \n // Summary\n results.summary = {\n timestamp: new Date().toISOString(),\n tiers: {\n hot: results.redis.status === 'connected' ? 'available' : 'unavailable',\n warm: results.buckets.status === 'connected' ? 'available' : 'unavailable',\n cold: results.postgresql.status === 'connected' ? 'available' : 'unavailable'\n },\n ready_for_production: \n results.postgresql.status === 'connected' && \n results.redis.status === 'connected'\n };\n \n res.json(results);\n \n } catch (error: any) {\n console.error('Storage test error:', error);\n res.status(500).json({\n error: 'Storage test failed',\n message: error.message,\n partial_results: results\n });\n }\n });\n \n // Create a test frame across all tiers\n app.post('/create-frame', async (req, res) => {\n const frameData = {\n frame_id: `frame-${Date.now()}`,\n run_id: req.body.run_id || 'test-run',\n project_id: req.body.project_id || 'storage-test',\n type: req.body.type || 'test',\n name: req.body.name || 'Multi-tier Test Frame',\n inputs: req.body.inputs || {},\n outputs: req.body.outputs || { status: 'created' },\n created_at: new Date().toISOString()\n };\n \n const results: any = { frame: frameData, storage: {} };\n \n try {\n // Store in PostgreSQL (cold tier)\n if (config.databaseUrl) {\n const pgClient = new Client({ connectionString: config.databaseUrl });\n await pgClient.connect();\n await pgClient.query(\n 'INSERT INTO frames (frame_id, run_id, project_id, type, name, inputs, outputs) VALUES ($1, $2, $3, $4, $5, $6, $7)',\n [frameData.frame_id, frameData.run_id, frameData.project_id, frameData.type, frameData.name, frameData.inputs, frameData.outputs]\n );\n await pgClient.end();\n results.storage.postgresql = 'stored';\n }\n \n // Store in Redis (hot tier)\n if (config.redisUrl) {\n const redisClient = createClient({ url: config.redisUrl });\n await redisClient.connect();\n await redisClient.setEx(`frame:${frameData.frame_id}`, 3600, JSON.stringify(frameData));\n await redisClient.disconnect();\n results.storage.redis = 'stored';\n }\n \n res.json(results);\n } catch (error: any) {\n res.status(500).json({\n error: 'Failed to create frame',\n message: error.message,\n partial_results: results\n });\n }\n });\n \n // Core API frames endpoint\n app.get('/api/frames', async (req, res) => {\n try {\n const limit = parseInt(req.query.limit as string) || 10;\n const source = req.query.source as string || 'all'; // 'redis', 'postgresql', 'all'\n \n const results: any = { \n frames: [],\n sources_checked: [],\n total_count: 0\n };\n \n // From Redis (hot tier) - most recent\n if ((source === 'all' || source === 'redis') && config.redisUrl) {\n try {\n const redisClient = createClient({ url: config.redisUrl });\n await redisClient.connect();\n const redisKeys = await redisClient.keys('frame:*');\n const redisFrames = [];\n for (const key of redisKeys.slice(0, limit)) {\n const data = await redisClient.get(key);\n if (data) {\n const frame = JSON.parse(data);\n frame.source = 'redis';\n frame.tier = 'hot';\n redisFrames.push(frame);\n }\n }\n await redisClient.disconnect();\n results.frames.push(...redisFrames);\n results.sources_checked.push('redis');\n } catch (error: any) {\n results.redis_error = error.message;\n }\n }\n \n // From PostgreSQL (cold tier) - persistent storage\n if ((source === 'all' || source === 'postgresql') && config.databaseUrl) {\n try {\n const pgClient = new Client({ connectionString: config.databaseUrl });\n await pgClient.connect();\n const pgFrames = await pgClient.query(\n 'SELECT *, \\'postgresql\\' as source, \\'cold\\' as tier FROM frames ORDER BY created_at DESC LIMIT $1',\n [limit]\n );\n await pgClient.end();\n results.frames.push(...pgFrames.rows);\n results.sources_checked.push('postgresql');\n results.total_count = pgFrames.rowCount;\n } catch (error: any) {\n results.postgresql_error = error.message;\n }\n }\n \n // Sort by created_at if multiple sources\n if (results.frames.length > 1) {\n results.frames.sort((a: any, b: any) => \n new Date(b.created_at).getTime() - new Date(a.created_at).getTime()\n );\n }\n \n res.json({\n count: results.frames.length,\n frames: results.frames.slice(0, limit),\n metadata: {\n sources_checked: results.sources_checked,\n total_in_postgresql: results.total_count,\n tier_explanation: {\n hot: 'Redis - Recent frames (< 24 hours)',\n cold: 'PostgreSQL - All frames (persistent storage)'\n }\n }\n });\n } catch (error: any) {\n res.status(500).json({\n error: 'Failed to fetch frames',\n message: error.message\n });\n }\n });\n\n // List recent frames (legacy endpoint)\n app.get('/list-frames', async (req, res) => {\n const results: any = { sources: {} };\n \n try {\n // From PostgreSQL\n if (config.databaseUrl) {\n const pgClient = new Client({ connectionString: config.databaseUrl });\n await pgClient.connect();\n const pgFrames = await pgClient.query('SELECT * FROM frames ORDER BY created_at DESC LIMIT 5');\n await pgClient.end();\n results.sources.postgresql = pgFrames.rows;\n }\n \n // From Redis\n if (config.redisUrl) {\n const redisClient = createClient({ url: config.redisUrl });\n await redisClient.connect();\n const redisKeys = await redisClient.keys('frame:*');\n const redisFrames = [];\n for (const key of redisKeys.slice(0, 5)) {\n const data = await redisClient.get(key);\n if (data) redisFrames.push(JSON.parse(data));\n }\n await redisClient.disconnect();\n results.sources.redis = redisFrames;\n }\n \n res.json(results);\n } catch (error: any) {\n res.status(500).json({\n error: 'Failed to list frames',\n message: error.message\n });\n }\n });\n \n // Start server\n app.listen(config.port, '0.0.0.0', () => {\n console.log(`\u2705 Storage Test Server running on port ${config.port}`);\n console.log('\\n\uD83D\uDCCA Available endpoints:');\n console.log(' - GET /test-storage (comprehensive storage test)');\n console.log(' - POST /create-frame (create test frame)');\n console.log(' - GET /list-frames (list recent frames)');\n });\n}\n\nstartServer().catch(error => {\n console.error('Failed to start storage test server:', error);\n process.exit(1);\n});"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -606,9 +606,7 @@ class ClaudeSkillsManager {
|
|
|
606
606
|
this.archaeologistSkill = new ArchaeologistSkill(context);
|
|
607
607
|
import("./dashboard-launcher.js").then((module) => {
|
|
608
608
|
this.dashboardLauncher = new module.DashboardLauncherSkill();
|
|
609
|
-
|
|
610
|
-
logger.warn("Dashboard auto-launch failed:", error);
|
|
611
|
-
});
|
|
609
|
+
logger.info("Dashboard launcher initialized (manual launch required)");
|
|
612
610
|
});
|
|
613
611
|
const chromaConfig = {
|
|
614
612
|
apiKey: process.env["CHROMADB_API_KEY"] || "",
|
|
@@ -628,16 +626,19 @@ class ClaudeSkillsManager {
|
|
|
628
626
|
}
|
|
629
627
|
import("../features/tasks/linear-task-manager.js").then((module) => {
|
|
630
628
|
const taskStore = new module.LinearTaskManager();
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
context.dualStackManager,
|
|
636
|
-
context.contextRetriever,
|
|
637
|
-
taskStore
|
|
629
|
+
const frameManager = context.frameManager;
|
|
630
|
+
if (!frameManager) {
|
|
631
|
+
throw new Error(
|
|
632
|
+
"FrameManager not provided in context - required for RLM orchestrator"
|
|
638
633
|
);
|
|
639
|
-
|
|
640
|
-
|
|
634
|
+
}
|
|
635
|
+
this.rlmOrchestrator = new RecursiveAgentOrchestrator(
|
|
636
|
+
frameManager,
|
|
637
|
+
context.dualStackManager,
|
|
638
|
+
context.contextRetriever,
|
|
639
|
+
taskStore
|
|
640
|
+
);
|
|
641
|
+
logger.info("RLM Orchestrator initialized");
|
|
641
642
|
}).catch((error) => {
|
|
642
643
|
logger.warn("RLM Orchestrator initialization failed:", error);
|
|
643
644
|
});
|