@stackmemoryai/stackmemory 0.5.25 ā 0.5.27
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 +94 -4
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/index.js +0 -2
- package/dist/cli/index.js.map +2 -2
- package/dist/hooks/events.js +4 -1
- package/dist/hooks/events.js.map +2 -2
- package/dist/hooks/sms-webhook.js +116 -2
- package/dist/hooks/sms-webhook.js.map +2 -2
- package/dist/skills/api-discovery.js +3 -2
- package/dist/skills/api-discovery.js.map +2 -2
- package/package.json +3 -8
- package/scripts/debug-railway-build.js +0 -87
- package/scripts/deployment/railway.sh +0 -352
- package/scripts/railway-env-setup.sh +0 -39
- package/scripts/setup-railway-deployment.sh +0 -37
- package/scripts/sync-frames-from-railway.js +0 -228
- package/scripts/test-railway-db.js +0 -222
- package/scripts/validate-railway-deployment.js +0 -137
- package/scripts/verify-railway-schema.ts +0 -35
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import 'dotenv/config';
|
|
3
|
-
import pg from 'pg';
|
|
4
|
-
import { createClient } from 'redis';
|
|
5
|
-
|
|
6
|
-
const { Client } = pg;
|
|
7
|
-
|
|
8
|
-
// Railway PostgreSQL URL from environment
|
|
9
|
-
const DATABASE_URL = process.env.DATABASE_URL ||
|
|
10
|
-
'postgresql://postgres:YTSFXqPzFhghOcefgwPvJyWOBTYHbYxd@postgres.railway.internal:5432/railway';
|
|
11
|
-
|
|
12
|
-
async function testPostgreSQL() {
|
|
13
|
-
console.log('š Testing PostgreSQL Connection...\n');
|
|
14
|
-
|
|
15
|
-
const pgClient = new Client({
|
|
16
|
-
connectionString: DATABASE_URL
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
console.log('š” Connecting to PostgreSQL...');
|
|
21
|
-
await pgClient.connect();
|
|
22
|
-
console.log('ā
Connected to PostgreSQL!\n');
|
|
23
|
-
|
|
24
|
-
// Test basic query
|
|
25
|
-
const timeResult = await pgClient.query('SELECT NOW() as current_time');
|
|
26
|
-
console.log('ā° Database time:', timeResult.rows[0].current_time);
|
|
27
|
-
|
|
28
|
-
// Create frames table if it doesn't exist
|
|
29
|
-
console.log('\nš Creating frames table...');
|
|
30
|
-
await pgClient.query(`
|
|
31
|
-
CREATE TABLE IF NOT EXISTS frames (
|
|
32
|
-
frame_id TEXT PRIMARY KEY,
|
|
33
|
-
run_id TEXT NOT NULL,
|
|
34
|
-
project_id TEXT NOT NULL,
|
|
35
|
-
parent_frame_id TEXT,
|
|
36
|
-
depth INTEGER DEFAULT 0,
|
|
37
|
-
type TEXT NOT NULL,
|
|
38
|
-
name TEXT NOT NULL,
|
|
39
|
-
state TEXT DEFAULT 'active',
|
|
40
|
-
inputs JSONB DEFAULT '{}',
|
|
41
|
-
outputs JSONB DEFAULT '{}',
|
|
42
|
-
digest_text TEXT,
|
|
43
|
-
digest_json JSONB DEFAULT '{}',
|
|
44
|
-
created_at TIMESTAMP DEFAULT NOW(),
|
|
45
|
-
closed_at TIMESTAMP
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
CREATE INDEX IF NOT EXISTS idx_frames_project ON frames(project_id);
|
|
49
|
-
CREATE INDEX IF NOT EXISTS idx_frames_state ON frames(state);
|
|
50
|
-
CREATE INDEX IF NOT EXISTS idx_frames_created ON frames(created_at);
|
|
51
|
-
`);
|
|
52
|
-
console.log('ā
Frames table ready!\n');
|
|
53
|
-
|
|
54
|
-
// Check existing frames
|
|
55
|
-
const countResult = await pgClient.query('SELECT COUNT(*) as count FROM frames');
|
|
56
|
-
console.log('š Existing frames:', countResult.rows[0].count);
|
|
57
|
-
|
|
58
|
-
// Insert a test frame
|
|
59
|
-
const testFrameId = `test-frame-${Date.now()}`;
|
|
60
|
-
console.log('\nš§ Inserting test frame...');
|
|
61
|
-
await pgClient.query(`
|
|
62
|
-
INSERT INTO frames (
|
|
63
|
-
frame_id, run_id, project_id, type, name, state,
|
|
64
|
-
inputs, outputs, digest_text
|
|
65
|
-
) VALUES (
|
|
66
|
-
$1, $2, $3, $4, $5, $6, $7, $8, $9
|
|
67
|
-
)
|
|
68
|
-
`, [
|
|
69
|
-
testFrameId,
|
|
70
|
-
'test-run-001',
|
|
71
|
-
'stackmemory-test',
|
|
72
|
-
'test',
|
|
73
|
-
'Database Connection Test',
|
|
74
|
-
'active',
|
|
75
|
-
JSON.stringify({ test: true, timestamp: new Date().toISOString() }),
|
|
76
|
-
JSON.stringify({ success: true }),
|
|
77
|
-
'Test frame for Railway PostgreSQL connection'
|
|
78
|
-
]);
|
|
79
|
-
console.log('ā
Test frame inserted:', testFrameId);
|
|
80
|
-
|
|
81
|
-
// Retrieve the test frame
|
|
82
|
-
console.log('\nš Retrieving test frame...');
|
|
83
|
-
const frameResult = await pgClient.query(
|
|
84
|
-
'SELECT * FROM frames WHERE frame_id = $1',
|
|
85
|
-
[testFrameId]
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
if (frameResult.rows.length > 0) {
|
|
89
|
-
const frame = frameResult.rows[0];
|
|
90
|
-
console.log('ā
Frame retrieved successfully!');
|
|
91
|
-
console.log(' - Name:', frame.name);
|
|
92
|
-
console.log(' - Type:', frame.type);
|
|
93
|
-
console.log(' - State:', frame.state);
|
|
94
|
-
console.log(' - Created:', frame.created_at);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Get recent frames
|
|
98
|
-
console.log('\nš Recent frames:');
|
|
99
|
-
const recentFrames = await pgClient.query(`
|
|
100
|
-
SELECT frame_id, name, type, state, created_at
|
|
101
|
-
FROM frames
|
|
102
|
-
ORDER BY created_at DESC
|
|
103
|
-
LIMIT 5
|
|
104
|
-
`);
|
|
105
|
-
|
|
106
|
-
if (recentFrames.rows.length > 0) {
|
|
107
|
-
recentFrames.rows.forEach((frame, index) => {
|
|
108
|
-
console.log(` ${index + 1}. ${frame.name} (${frame.type}) - ${frame.state}`);
|
|
109
|
-
});
|
|
110
|
-
} else {
|
|
111
|
-
console.log(' No frames found');
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Check table information
|
|
115
|
-
console.log('\nš Database tables:');
|
|
116
|
-
const tables = await pgClient.query(`
|
|
117
|
-
SELECT table_name
|
|
118
|
-
FROM information_schema.tables
|
|
119
|
-
WHERE table_schema = 'public'
|
|
120
|
-
ORDER BY table_name
|
|
121
|
-
`);
|
|
122
|
-
|
|
123
|
-
tables.rows.forEach(row => {
|
|
124
|
-
console.log(` - ${row.table_name}`);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
} catch (error) {
|
|
128
|
-
console.error('ā PostgreSQL Error:', error.message);
|
|
129
|
-
if (error.message.includes('ENOTFOUND')) {
|
|
130
|
-
console.log('\nš” Note: postgres.railway.internal only works from within Railway');
|
|
131
|
-
console.log(' For local testing, you need the external DATABASE_URL');
|
|
132
|
-
}
|
|
133
|
-
} finally {
|
|
134
|
-
await pgClient.end();
|
|
135
|
-
console.log('\nš PostgreSQL connection closed');
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async function testRedis() {
|
|
140
|
-
console.log('\n\nš“ Testing Redis Connection...\n');
|
|
141
|
-
|
|
142
|
-
// Try to build Redis URL from environment
|
|
143
|
-
const REDIS_URL = process.env.REDIS_URL ||
|
|
144
|
-
process.env.REDISHOST ? `redis://${process.env.REDISHOST}:${process.env.REDISPORT || 6379}` : null;
|
|
145
|
-
|
|
146
|
-
if (!REDIS_URL) {
|
|
147
|
-
console.log('ā ļø No Redis configuration found in environment');
|
|
148
|
-
console.log(' Add REDIS_URL or REDISHOST to Railway variables');
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const redisClient = createClient({ url: REDIS_URL });
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
console.log('š” Connecting to Redis...');
|
|
156
|
-
await redisClient.connect();
|
|
157
|
-
console.log('ā
Connected to Redis!\n');
|
|
158
|
-
|
|
159
|
-
// Test basic operations
|
|
160
|
-
console.log('š§ Testing Redis operations...');
|
|
161
|
-
|
|
162
|
-
// Set a test key
|
|
163
|
-
const testKey = `test:connection:${Date.now()}`;
|
|
164
|
-
await redisClient.set(testKey, JSON.stringify({
|
|
165
|
-
test: true,
|
|
166
|
-
timestamp: new Date().toISOString(),
|
|
167
|
-
message: 'Railway Redis connection test'
|
|
168
|
-
}), { EX: 60 }); // Expire after 60 seconds
|
|
169
|
-
console.log('ā
Set test key:', testKey);
|
|
170
|
-
|
|
171
|
-
// Get the test key
|
|
172
|
-
const value = await redisClient.get(testKey);
|
|
173
|
-
const parsed = JSON.parse(value);
|
|
174
|
-
console.log('ā
Retrieved value:', parsed);
|
|
175
|
-
|
|
176
|
-
// Test Redis info
|
|
177
|
-
const info = await redisClient.info('server');
|
|
178
|
-
const version = info.match(/redis_version:(.+)/)?.[1];
|
|
179
|
-
console.log('\nš Redis Server Info:');
|
|
180
|
-
console.log(' - Version:', version);
|
|
181
|
-
|
|
182
|
-
// Check memory usage
|
|
183
|
-
const memoryInfo = await redisClient.info('memory');
|
|
184
|
-
const usedMemory = memoryInfo.match(/used_memory_human:(.+)/)?.[1];
|
|
185
|
-
console.log(' - Memory used:', usedMemory);
|
|
186
|
-
|
|
187
|
-
// List all keys (be careful in production!)
|
|
188
|
-
const keys = await redisClient.keys('*');
|
|
189
|
-
console.log(' - Total keys:', keys.length);
|
|
190
|
-
|
|
191
|
-
if (keys.length > 0 && keys.length <= 10) {
|
|
192
|
-
console.log(' - Keys:', keys);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
} catch (error) {
|
|
196
|
-
console.error('ā Redis Error:', error.message);
|
|
197
|
-
if (error.message.includes('ENOTFOUND')) {
|
|
198
|
-
console.log('\nš” Note: Redis host not found');
|
|
199
|
-
console.log(' Make sure Redis variables are configured in Railway');
|
|
200
|
-
}
|
|
201
|
-
} finally {
|
|
202
|
-
await redisClient.disconnect();
|
|
203
|
-
console.log('\nš Redis connection closed');
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Run tests
|
|
208
|
-
async function runTests() {
|
|
209
|
-
console.log('š Railway Database Connection Tests\n');
|
|
210
|
-
console.log('=' .repeat(50));
|
|
211
|
-
|
|
212
|
-
await testPostgreSQL();
|
|
213
|
-
await testRedis();
|
|
214
|
-
|
|
215
|
-
console.log('\n' + '=' .repeat(50));
|
|
216
|
-
console.log('ā
Tests complete!\n');
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
runTests().catch(error => {
|
|
220
|
-
console.error('Fatal error:', error);
|
|
221
|
-
process.exit(1);
|
|
222
|
-
});
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Validate Railway deployment and check all services
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
async function checkEndpoint(url, expectedKeys = []) {
|
|
8
|
-
try {
|
|
9
|
-
console.log(`\nš Checking: ${url}`);
|
|
10
|
-
const response = await fetch(url);
|
|
11
|
-
const data = await response.json();
|
|
12
|
-
|
|
13
|
-
console.log(` Status: ${response.status}`);
|
|
14
|
-
console.log(` Response:`, JSON.stringify(data, null, 2));
|
|
15
|
-
|
|
16
|
-
// Check for expected keys
|
|
17
|
-
for (const key of expectedKeys) {
|
|
18
|
-
if (key in data) {
|
|
19
|
-
console.log(` ā
Found key: ${key}`);
|
|
20
|
-
} else {
|
|
21
|
-
console.log(` ā Missing key: ${key}`);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return { success: response.ok, data };
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.log(` ā Error: ${error.message}`);
|
|
28
|
-
return { success: false, error: error.message };
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async function testAuth(baseUrl) {
|
|
33
|
-
console.log('\nš Testing Authentication Endpoints:');
|
|
34
|
-
|
|
35
|
-
// Test signup
|
|
36
|
-
const signupData = {
|
|
37
|
-
email: `test${Date.now()}@example.com`,
|
|
38
|
-
password: 'TestPass123!',
|
|
39
|
-
name: 'Test User'
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
console.log('\nš Testing POST /auth/signup');
|
|
43
|
-
try {
|
|
44
|
-
const response = await fetch(`${baseUrl}/auth/signup`, {
|
|
45
|
-
method: 'POST',
|
|
46
|
-
headers: { 'Content-Type': 'application/json' },
|
|
47
|
-
body: JSON.stringify(signupData)
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const data = await response.json();
|
|
51
|
-
console.log(` Status: ${response.status}`);
|
|
52
|
-
|
|
53
|
-
if (response.ok) {
|
|
54
|
-
console.log(' ā
Signup endpoint works!');
|
|
55
|
-
console.log(` Response:`, JSON.stringify(data, null, 2));
|
|
56
|
-
} else {
|
|
57
|
-
console.log(' ā Signup failed:', data.error || data.message);
|
|
58
|
-
}
|
|
59
|
-
} catch (error) {
|
|
60
|
-
console.log(' ā Signup endpoint not available:', error.message);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Test login
|
|
64
|
-
console.log('\nš Testing POST /auth/login');
|
|
65
|
-
try {
|
|
66
|
-
const response = await fetch(`${baseUrl}/auth/login`, {
|
|
67
|
-
method: 'POST',
|
|
68
|
-
headers: { 'Content-Type': 'application/json' },
|
|
69
|
-
body: JSON.stringify({
|
|
70
|
-
email: signupData.email,
|
|
71
|
-
password: signupData.password
|
|
72
|
-
})
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const data = await response.json();
|
|
76
|
-
console.log(` Status: ${response.status}`);
|
|
77
|
-
|
|
78
|
-
if (response.ok) {
|
|
79
|
-
console.log(' ā
Login endpoint works!');
|
|
80
|
-
console.log(` Token received:`, data.token ? 'Yes' : 'No');
|
|
81
|
-
console.log(` API Key:`, data.apiKey ? 'Yes' : 'No');
|
|
82
|
-
} else {
|
|
83
|
-
console.log(' ā Login failed:', data.error || data.message);
|
|
84
|
-
}
|
|
85
|
-
} catch (error) {
|
|
86
|
-
console.log(' ā Login endpoint not available:', error.message);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async function main() {
|
|
91
|
-
const baseUrl = process.argv[2] || 'https://stackmemory-production.up.railway.app';
|
|
92
|
-
|
|
93
|
-
console.log('š StackMemory Railway Deployment Validator');
|
|
94
|
-
console.log('==========================================');
|
|
95
|
-
console.log(`Base URL: ${baseUrl}`);
|
|
96
|
-
console.log(`Timestamp: ${new Date().toISOString()}`);
|
|
97
|
-
|
|
98
|
-
// Check root endpoint
|
|
99
|
-
const root = await checkEndpoint(baseUrl, ['message', 'version', 'endpoints']);
|
|
100
|
-
|
|
101
|
-
// Detect server type
|
|
102
|
-
if (root.data?.message?.includes('Minimal')) {
|
|
103
|
-
console.log('\nā ļø WARNING: Minimal server is running!');
|
|
104
|
-
console.log(' The full server with auth endpoints is not deployed.');
|
|
105
|
-
} else if (root.data?.message?.includes('API Server')) {
|
|
106
|
-
console.log('\nā
Full API server is running!');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Check health
|
|
110
|
-
await checkEndpoint(`${baseUrl}/health`, ['status']);
|
|
111
|
-
|
|
112
|
-
// Check database connections
|
|
113
|
-
const dbTest = await checkEndpoint(`${baseUrl}/test-db`, ['postgresql', 'redis']);
|
|
114
|
-
|
|
115
|
-
if (dbTest.data) {
|
|
116
|
-
console.log('\nš Database Status:');
|
|
117
|
-
if (dbTest.data.postgresql?.status === 'connected') {
|
|
118
|
-
console.log(' ā
PostgreSQL: Connected');
|
|
119
|
-
} else {
|
|
120
|
-
console.log(' ā PostgreSQL:', dbTest.data.postgresql?.status || 'Not configured');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (dbTest.data.redis?.status === 'connected') {
|
|
124
|
-
console.log(' ā
Redis: Connected');
|
|
125
|
-
} else {
|
|
126
|
-
console.log(' ā Redis:', dbTest.data.redis?.status || 'Not configured');
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Test auth endpoints
|
|
131
|
-
await testAuth(baseUrl);
|
|
132
|
-
|
|
133
|
-
console.log('\n==========================================');
|
|
134
|
-
console.log('Validation complete!');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
main().catch(console.error);
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Verify Railway schema version; exits non-zero if below latest
|
|
4
|
-
*/
|
|
5
|
-
import { Pool } from 'pg';
|
|
6
|
-
import Database from 'better-sqlite3';
|
|
7
|
-
|
|
8
|
-
function isPg(url: string): boolean {
|
|
9
|
-
return url.startsWith('postgres://') || url.startsWith('postgresql://');
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async function main() {
|
|
13
|
-
const url = process.env.DATABASE_URL || '.stackmemory/railway.db';
|
|
14
|
-
const latest = 3; // keep in sync with CLI
|
|
15
|
-
|
|
16
|
-
if (isPg(url)) {
|
|
17
|
-
const pool = new Pool({ connectionString: url });
|
|
18
|
-
await pool.query('CREATE TABLE IF NOT EXISTS railway_schema_version (version INTEGER PRIMARY KEY, applied_at TIMESTAMPTZ DEFAULT NOW(), description TEXT)');
|
|
19
|
-
const r = await pool.query('SELECT COALESCE(MAX(version), 0) AS v FROM railway_schema_version');
|
|
20
|
-
const current = Number(r.rows[0]?.v || 0);
|
|
21
|
-
console.log(JSON.stringify({ database: 'postgres', current, latest }));
|
|
22
|
-
await pool.end();
|
|
23
|
-
if (current < latest) process.exit(2);
|
|
24
|
-
} else {
|
|
25
|
-
const db = new Database(url);
|
|
26
|
-
db.exec('CREATE TABLE IF NOT EXISTS railway_schema_version (version INTEGER PRIMARY KEY, applied_at DATETIME DEFAULT CURRENT_TIMESTAMP, description TEXT)');
|
|
27
|
-
const row = db.prepare('SELECT COALESCE(MAX(version), 0) AS v FROM railway_schema_version').get() as any;
|
|
28
|
-
const current = Number(row?.v || 0);
|
|
29
|
-
console.log(JSON.stringify({ database: 'sqlite', current, latest }));
|
|
30
|
-
if (current < latest) process.exit(2);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
main().catch((e) => { console.error(e); process.exit(1); });
|
|
35
|
-
|