@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,201 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Query ChromaDB for stored contexts
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ChromaClient } from 'chromadb';
|
|
8
|
+
import dotenv from 'dotenv';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
|
|
11
|
+
// Load environment variables
|
|
12
|
+
dotenv.config();
|
|
13
|
+
|
|
14
|
+
async function queryChromaDB() {
|
|
15
|
+
const apiKey = process.env.CHROMADB_API_KEY;
|
|
16
|
+
const tenant = process.env.CHROMADB_TENANT;
|
|
17
|
+
const database = process.env.CHROMADB_DATABASE || 'stackmemory';
|
|
18
|
+
|
|
19
|
+
console.log(chalk.cyan('🔍 Querying ChromaDB Contexts\n'));
|
|
20
|
+
|
|
21
|
+
// Connect to ChromaDB
|
|
22
|
+
const client = new ChromaClient({
|
|
23
|
+
ssl: true,
|
|
24
|
+
host: 'api.trychroma.com',
|
|
25
|
+
port: 443,
|
|
26
|
+
headers: {
|
|
27
|
+
'X-Chroma-Token': apiKey
|
|
28
|
+
},
|
|
29
|
+
tenant: tenant,
|
|
30
|
+
database: database
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// List all collections first
|
|
34
|
+
const collections = await client.listCollections();
|
|
35
|
+
console.log(chalk.yellow('📚 Available Collections:'));
|
|
36
|
+
collections.forEach(col => {
|
|
37
|
+
console.log(` - ${col.name}`);
|
|
38
|
+
});
|
|
39
|
+
console.log();
|
|
40
|
+
|
|
41
|
+
// Get collection - try claude_context first (from hooks), then stackmemory_contexts
|
|
42
|
+
let collection;
|
|
43
|
+
try {
|
|
44
|
+
collection = await client.getCollection({
|
|
45
|
+
name: 'claude_context'
|
|
46
|
+
});
|
|
47
|
+
console.log(chalk.green('✓ Using collection: claude_context\n'));
|
|
48
|
+
} catch {
|
|
49
|
+
collection = await client.getCollection({
|
|
50
|
+
name: 'stackmemory_contexts'
|
|
51
|
+
});
|
|
52
|
+
console.log(chalk.green('✓ Using collection: stackmemory_contexts\n'));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log(chalk.yellow('📊 Collection Stats:'));
|
|
56
|
+
const count = await collection.count();
|
|
57
|
+
console.log(` Total documents: ${count}\n`);
|
|
58
|
+
|
|
59
|
+
// Query 1: Get all documents
|
|
60
|
+
console.log(chalk.cyan('📚 All Stored Contexts:\n'));
|
|
61
|
+
|
|
62
|
+
const allDocs = await collection.get({
|
|
63
|
+
limit: 100
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
if (allDocs.ids.length > 0) {
|
|
67
|
+
for (let i = 0; i < allDocs.ids.length; i++) {
|
|
68
|
+
const metadata = allDocs.metadatas[i];
|
|
69
|
+
const document = allDocs.documents[i];
|
|
70
|
+
|
|
71
|
+
console.log(chalk.green(`${i + 1}. ${allDocs.ids[i]}`));
|
|
72
|
+
console.log(` Type: ${metadata.type}`);
|
|
73
|
+
console.log(` Timestamp: ${metadata.timestamp}`);
|
|
74
|
+
console.log(` User: ${metadata.user_id}`);
|
|
75
|
+
console.log(` Project: ${metadata.project}`);
|
|
76
|
+
console.log(` Content: ${document?.substring(0, 100)}...`);
|
|
77
|
+
console.log();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Query 2: Search for specific content
|
|
82
|
+
console.log(chalk.cyan('\n🔎 Search Results for "TypeScript lint error":\n'));
|
|
83
|
+
|
|
84
|
+
const searchResults = await collection.query({
|
|
85
|
+
queryTexts: ['TypeScript lint error fix'],
|
|
86
|
+
nResults: 5
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
if (searchResults.ids[0].length > 0) {
|
|
90
|
+
for (let i = 0; i < searchResults.ids[0].length; i++) {
|
|
91
|
+
const metadata = searchResults.metadatas[0][i];
|
|
92
|
+
const document = searchResults.documents[0][i];
|
|
93
|
+
const distance = searchResults.distances[0][i];
|
|
94
|
+
|
|
95
|
+
console.log(chalk.yellow(`Match ${i + 1} (distance: ${distance.toFixed(3)}):`));
|
|
96
|
+
console.log(` ID: ${searchResults.ids[0][i]}`);
|
|
97
|
+
console.log(` Type: ${metadata.type}`);
|
|
98
|
+
console.log(` Timestamp: ${metadata.timestamp}`);
|
|
99
|
+
console.log(` Content: ${document?.substring(0, 150)}...`);
|
|
100
|
+
console.log();
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
console.log('No results found');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Query 3: Filter by metadata
|
|
107
|
+
console.log(chalk.cyan('\n📋 Recent Task Completions:\n'));
|
|
108
|
+
|
|
109
|
+
const taskCompletions = await collection.get({
|
|
110
|
+
where: {
|
|
111
|
+
type: 'task_complete'
|
|
112
|
+
},
|
|
113
|
+
limit: 10
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
if (taskCompletions.ids.length > 0) {
|
|
117
|
+
for (let i = 0; i < taskCompletions.ids.length; i++) {
|
|
118
|
+
const metadata = taskCompletions.metadatas[i];
|
|
119
|
+
const document = taskCompletions.documents[i];
|
|
120
|
+
|
|
121
|
+
console.log(chalk.green(`Task ${i + 1}:`));
|
|
122
|
+
console.log(` ID: ${taskCompletions.ids[i]}`);
|
|
123
|
+
console.log(` Timestamp: ${metadata.timestamp}`);
|
|
124
|
+
console.log(` Task ID: ${metadata.task_id}`);
|
|
125
|
+
console.log(` Duration: ${metadata.duration}ms`);
|
|
126
|
+
console.log(` Files Changed: ${metadata.files_changed}`);
|
|
127
|
+
console.log(` Content: ${document?.substring(0, 100)}...`);
|
|
128
|
+
console.log();
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
console.log('No task completions found');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Query 4: Get periodic saves
|
|
135
|
+
console.log(chalk.cyan('\n⏰ Periodic Checkpoints:\n'));
|
|
136
|
+
|
|
137
|
+
const periodicSaves = await collection.get({
|
|
138
|
+
where: {
|
|
139
|
+
type: 'periodic_save'
|
|
140
|
+
},
|
|
141
|
+
limit: 10
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
if (periodicSaves.ids.length > 0) {
|
|
145
|
+
for (let i = 0; i < periodicSaves.ids.length; i++) {
|
|
146
|
+
const metadata = periodicSaves.metadatas[i];
|
|
147
|
+
const document = periodicSaves.documents[i];
|
|
148
|
+
|
|
149
|
+
console.log(chalk.blue(`Checkpoint ${i + 1}:`));
|
|
150
|
+
console.log(` Timestamp: ${metadata.timestamp}`);
|
|
151
|
+
console.log(` Interval: ${metadata.interval}`);
|
|
152
|
+
console.log(` Active Files: ${metadata.active_files}`);
|
|
153
|
+
console.log(` Git Status: ${document?.substring(0, 150)}...`);
|
|
154
|
+
console.log();
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
console.log('No periodic saves found');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Query 5: Get decisions
|
|
161
|
+
console.log(chalk.cyan('\n💡 Decisions Made:\n'));
|
|
162
|
+
|
|
163
|
+
const decisions = await collection.get({
|
|
164
|
+
where: {
|
|
165
|
+
type: 'decision_made'
|
|
166
|
+
},
|
|
167
|
+
limit: 10
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (decisions.ids.length > 0) {
|
|
171
|
+
for (let i = 0; i < decisions.ids.length; i++) {
|
|
172
|
+
const metadata = decisions.metadatas[i];
|
|
173
|
+
const document = decisions.documents[i];
|
|
174
|
+
|
|
175
|
+
console.log(chalk.magenta(`Decision ${i + 1}:`));
|
|
176
|
+
console.log(` Category: ${metadata.category}`);
|
|
177
|
+
console.log(` Alternatives: ${metadata.alternatives}`);
|
|
178
|
+
console.log(` Reasoning: ${metadata.reasoning}`);
|
|
179
|
+
console.log(` Decision: ${document?.substring(0, 200)}...`);
|
|
180
|
+
console.log();
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
console.log('No decisions found');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Query 6: Group by type
|
|
187
|
+
console.log(chalk.cyan('\n📈 Context Types Summary:\n'));
|
|
188
|
+
|
|
189
|
+
const types = new Map();
|
|
190
|
+
for (let i = 0; i < allDocs.ids.length; i++) {
|
|
191
|
+
const type = allDocs.metadatas[i].type || 'unknown';
|
|
192
|
+
types.set(type, (types.get(type) || 0) + 1);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
for (const [type, count] of types.entries()) {
|
|
196
|
+
console.log(` ${type}: ${count} documents`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Run query
|
|
201
|
+
queryChromaDB().catch(console.error);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
echo "🚂 Railway Environment Variables Setup"
|
|
4
|
+
echo "======================================"
|
|
5
|
+
echo ""
|
|
6
|
+
echo "You need to add these environment variables in the Railway dashboard:"
|
|
7
|
+
echo "https://railway.app/project/90d5083a-4adf-49b8-b2ff-95adfbb610f2/service/b2a145c3-065e-4225-8c84-aa0d8f49d243/settings"
|
|
8
|
+
echo ""
|
|
9
|
+
echo "Copy and paste these into Railway's environment variables section:"
|
|
10
|
+
echo ""
|
|
11
|
+
|
|
12
|
+
# Load .env file
|
|
13
|
+
if [ -f .env ]; then
|
|
14
|
+
source .env
|
|
15
|
+
|
|
16
|
+
echo "REDIS_URL=$REDIS_URL"
|
|
17
|
+
echo "LINEAR_API_KEY=$LINEAR_API_KEY"
|
|
18
|
+
echo "CHROMADB_API_KEY=$CHROMADB_API_KEY"
|
|
19
|
+
echo "CHROMADB_TENANT=$CHROMADB_TENANT"
|
|
20
|
+
echo "CHROMADB_DATABASE=$CHROMADB_DATABASE"
|
|
21
|
+
echo "LINEAR_TEAM_ID=$LINEAR_TEAM_ID"
|
|
22
|
+
echo "LINEAR_ORGANIZATION=$LINEAR_ORGANIZATION"
|
|
23
|
+
echo ""
|
|
24
|
+
echo "Optional (for cold storage tier):"
|
|
25
|
+
echo "GCS_BUCKET_NAME=stackmemory-cold-storage"
|
|
26
|
+
echo "GCS_PROJECT_ID=your-gcp-project-id"
|
|
27
|
+
echo "GCS_CLIENT_EMAIL=your-service-account@project.iam.gserviceaccount.com"
|
|
28
|
+
echo "GCS_PRIVATE_KEY=your-gcs-private-key"
|
|
29
|
+
else
|
|
30
|
+
echo "❌ .env file not found. Please create one first."
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
echo ""
|
|
35
|
+
echo "After adding these variables:"
|
|
36
|
+
echo "1. Click 'Deploy' in Railway dashboard"
|
|
37
|
+
echo "2. Or run: railway up"
|
|
38
|
+
echo "3. Check deployment: railway logs"
|
|
39
|
+
echo "4. Visit: https://stackmemory-production.up.railway.app/health"
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
function reconcileLocalTasks() {
|
|
10
|
+
const tasksFile = path.join(__dirname, '..', '.stackmemory', 'tasks.jsonl');
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(tasksFile)) {
|
|
13
|
+
console.error('❌ Tasks file not found:', tasksFile);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Read all tasks
|
|
18
|
+
const lines = fs.readFileSync(tasksFile, 'utf8').split('\n').filter(l => l.trim());
|
|
19
|
+
const tasks = new Map();
|
|
20
|
+
const tasksByLinearId = new Map();
|
|
21
|
+
const tasksByTitle = new Map();
|
|
22
|
+
|
|
23
|
+
console.log('📊 Analyzing local tasks...\n');
|
|
24
|
+
|
|
25
|
+
// Parse and organize tasks
|
|
26
|
+
for (const line of lines) {
|
|
27
|
+
try {
|
|
28
|
+
const task = JSON.parse(line);
|
|
29
|
+
|
|
30
|
+
// Store latest version of each task
|
|
31
|
+
if (!tasks.has(task.id) || task.timestamp > tasks.get(task.id).timestamp) {
|
|
32
|
+
tasks.set(task.id, task);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Extract Linear ID if present
|
|
36
|
+
const linearMatch = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/);
|
|
37
|
+
if (linearMatch) {
|
|
38
|
+
const linearId = linearMatch[1];
|
|
39
|
+
if (!tasksByLinearId.has(linearId)) {
|
|
40
|
+
tasksByLinearId.set(linearId, []);
|
|
41
|
+
}
|
|
42
|
+
tasksByLinearId.get(linearId).push(task);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Normalize title for duplicate detection
|
|
46
|
+
const normalizedTitle = task.title
|
|
47
|
+
?.replace(/^\[[^\]]+\]\s*/, '') // Remove [STA-XXX] or [ENG-XXX]
|
|
48
|
+
?.replace(/^\[.*?\]\s*/, '') // Remove priority markers
|
|
49
|
+
?.trim();
|
|
50
|
+
|
|
51
|
+
if (normalizedTitle) {
|
|
52
|
+
if (!tasksByTitle.has(normalizedTitle)) {
|
|
53
|
+
tasksByTitle.set(normalizedTitle, []);
|
|
54
|
+
}
|
|
55
|
+
tasksByTitle.get(normalizedTitle).push(task);
|
|
56
|
+
}
|
|
57
|
+
} catch (e) {
|
|
58
|
+
// Skip invalid lines
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log(`📋 Total unique tasks: ${tasks.size}`);
|
|
63
|
+
console.log(`🔗 Tasks with Linear IDs: ${tasksByLinearId.size}`);
|
|
64
|
+
|
|
65
|
+
// Find duplicates by Linear ID
|
|
66
|
+
const duplicateLinearIds = [];
|
|
67
|
+
for (const [linearId, taskList] of tasksByLinearId.entries()) {
|
|
68
|
+
if (taskList.length > 1) {
|
|
69
|
+
duplicateLinearIds.push({ linearId, count: taskList.length, tasks: taskList });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (duplicateLinearIds.length > 0) {
|
|
74
|
+
console.log(`\n⚠️ Duplicate Linear IDs found (${duplicateLinearIds.length}):`);
|
|
75
|
+
for (const dup of duplicateLinearIds.slice(0, 5)) {
|
|
76
|
+
console.log(` - ${dup.linearId}: ${dup.count} duplicates`);
|
|
77
|
+
for (const task of dup.tasks) {
|
|
78
|
+
console.log(` • ${task.id}: ${task.status} (${new Date(task.timestamp).toISOString()})`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Find duplicate titles
|
|
84
|
+
const duplicateTitles = [];
|
|
85
|
+
for (const [title, taskList] of tasksByTitle.entries()) {
|
|
86
|
+
if (taskList.length > 1) {
|
|
87
|
+
// Check if they have different Linear IDs
|
|
88
|
+
const linearIds = new Set();
|
|
89
|
+
for (const task of taskList) {
|
|
90
|
+
const match = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/);
|
|
91
|
+
if (match) linearIds.add(match[1]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (linearIds.size > 1 || linearIds.size === 0) {
|
|
95
|
+
duplicateTitles.push({ title, count: taskList.length, tasks: taskList });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (duplicateTitles.length > 0) {
|
|
101
|
+
console.log(`\n⚠️ Duplicate titles found (${duplicateTitles.length}):`);
|
|
102
|
+
for (const dup of duplicateTitles.slice(0, 5)) {
|
|
103
|
+
console.log(` - "${dup.title}": ${dup.count} duplicates`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Show task status breakdown
|
|
108
|
+
const statusCounts = {};
|
|
109
|
+
for (const task of tasks.values()) {
|
|
110
|
+
const status = task.status || 'unknown';
|
|
111
|
+
statusCounts[status] = (statusCounts[status] || 0) + 1;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
console.log('\n📊 Task Status Breakdown:');
|
|
115
|
+
for (const [status, count] of Object.entries(statusCounts)) {
|
|
116
|
+
const emoji = status === 'completed' ? '✅' :
|
|
117
|
+
status === 'in_progress' ? '🔄' :
|
|
118
|
+
status === 'cancelled' ? '❌' : '⏳';
|
|
119
|
+
console.log(` ${emoji} ${status}: ${count}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Priority breakdown
|
|
123
|
+
const priorityCounts = {};
|
|
124
|
+
for (const task of tasks.values()) {
|
|
125
|
+
const priority = task.priority || 'none';
|
|
126
|
+
priorityCounts[priority] = (priorityCounts[priority] || 0) + 1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log('\n🎯 Priority Breakdown:');
|
|
130
|
+
for (const [priority, count] of Object.entries(priorityCounts)) {
|
|
131
|
+
console.log(` - ${priority}: ${count}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Recent active tasks
|
|
135
|
+
const recentTasks = Array.from(tasks.values())
|
|
136
|
+
.filter(t => t.status === 'in_progress' || (t.timestamp > Date.now() - 7 * 24 * 60 * 60 * 1000))
|
|
137
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
138
|
+
.slice(0, 10);
|
|
139
|
+
|
|
140
|
+
console.log('\n🕒 Recent Active Tasks:');
|
|
141
|
+
for (const task of recentTasks) {
|
|
142
|
+
const status = task.status === 'completed' ? '✅' :
|
|
143
|
+
task.status === 'in_progress' ? '🔄' : '⏳';
|
|
144
|
+
const linearId = task.title?.match(/\[(STA-\d+|ENG-\d+)\]/)?.[1] || '';
|
|
145
|
+
console.log(` ${status} ${linearId ? `[${linearId}]` : ''} ${task.title}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Recommendations
|
|
149
|
+
console.log('\n💡 Recommendations:');
|
|
150
|
+
if (duplicateLinearIds.length > 0) {
|
|
151
|
+
console.log(` - ${duplicateLinearIds.length} tasks have duplicate Linear IDs - consider deduplication`);
|
|
152
|
+
}
|
|
153
|
+
if (duplicateTitles.length > 0) {
|
|
154
|
+
console.log(` - ${duplicateTitles.length} task titles are duplicated - review for consolidation`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const pendingCount = statusCounts.pending || 0;
|
|
158
|
+
const inProgressCount = statusCounts.in_progress || 0;
|
|
159
|
+
|
|
160
|
+
if (pendingCount > 20) {
|
|
161
|
+
console.log(` - ${pendingCount} pending tasks - consider prioritizing or archiving old tasks`);
|
|
162
|
+
}
|
|
163
|
+
if (inProgressCount > 5) {
|
|
164
|
+
console.log(` - ${inProgressCount} tasks in progress - consider focusing on completion`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
console.log('\n✅ Task reconciliation complete!');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
reconcileLocalTasks();
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import Database from 'better-sqlite3';
|
|
4
|
+
import { mkdirSync } from 'fs';
|
|
5
|
+
import { dirname, join } from 'path';
|
|
6
|
+
import { homedir } from 'os';
|
|
7
|
+
|
|
8
|
+
// Create the database directory if it doesn't exist
|
|
9
|
+
const dbPath = join(homedir(), '.stackmemory', 'context.db');
|
|
10
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
11
|
+
|
|
12
|
+
// Connect to the database
|
|
13
|
+
const db = new Database(dbPath);
|
|
14
|
+
|
|
15
|
+
// Create frames table with proper schema
|
|
16
|
+
db.exec(`
|
|
17
|
+
CREATE TABLE IF NOT EXISTS frames (
|
|
18
|
+
frame_id TEXT PRIMARY KEY,
|
|
19
|
+
run_id TEXT NOT NULL,
|
|
20
|
+
project_id TEXT NOT NULL,
|
|
21
|
+
parent_frame_id TEXT REFERENCES frames(frame_id),
|
|
22
|
+
depth INTEGER NOT NULL DEFAULT 0,
|
|
23
|
+
type TEXT NOT NULL,
|
|
24
|
+
name TEXT NOT NULL,
|
|
25
|
+
state TEXT DEFAULT 'active',
|
|
26
|
+
inputs TEXT DEFAULT '{}',
|
|
27
|
+
outputs TEXT DEFAULT '{}',
|
|
28
|
+
digest_text TEXT,
|
|
29
|
+
digest_json TEXT DEFAULT '{}',
|
|
30
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
31
|
+
closed_at INTEGER
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
35
|
+
event_id TEXT PRIMARY KEY,
|
|
36
|
+
run_id TEXT NOT NULL,
|
|
37
|
+
frame_id TEXT NOT NULL,
|
|
38
|
+
seq INTEGER NOT NULL,
|
|
39
|
+
event_type TEXT NOT NULL,
|
|
40
|
+
payload TEXT NOT NULL,
|
|
41
|
+
ts INTEGER DEFAULT (unixepoch()),
|
|
42
|
+
FOREIGN KEY(frame_id) REFERENCES frames(frame_id)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
CREATE TABLE IF NOT EXISTS anchors (
|
|
46
|
+
anchor_id TEXT PRIMARY KEY,
|
|
47
|
+
frame_id TEXT NOT NULL,
|
|
48
|
+
project_id TEXT NOT NULL,
|
|
49
|
+
type TEXT NOT NULL,
|
|
50
|
+
text TEXT NOT NULL,
|
|
51
|
+
priority INTEGER DEFAULT 0,
|
|
52
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
53
|
+
metadata TEXT DEFAULT '{}',
|
|
54
|
+
FOREIGN KEY(frame_id) REFERENCES frames(frame_id)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
CREATE TABLE IF NOT EXISTS handoff_requests (
|
|
58
|
+
request_id TEXT PRIMARY KEY,
|
|
59
|
+
source_stack_id TEXT NOT NULL,
|
|
60
|
+
target_stack_id TEXT NOT NULL,
|
|
61
|
+
frame_ids TEXT NOT NULL,
|
|
62
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
63
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
64
|
+
expires_at INTEGER,
|
|
65
|
+
target_user_id TEXT,
|
|
66
|
+
message TEXT
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
CREATE INDEX IF NOT EXISTS idx_frames_run ON frames(run_id);
|
|
70
|
+
CREATE INDEX IF NOT EXISTS idx_frames_parent ON frames(parent_frame_id);
|
|
71
|
+
CREATE INDEX IF NOT EXISTS idx_frames_state ON frames(state);
|
|
72
|
+
CREATE INDEX IF NOT EXISTS idx_events_frame ON events(frame_id);
|
|
73
|
+
CREATE INDEX IF NOT EXISTS idx_events_seq ON events(frame_id, seq);
|
|
74
|
+
CREATE INDEX IF NOT EXISTS idx_anchors_frame ON anchors(frame_id);
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_handoff_requests_status ON handoff_requests(status);
|
|
76
|
+
CREATE INDEX IF NOT EXISTS idx_handoff_requests_target ON handoff_requests(target_stack_id);
|
|
77
|
+
`);
|
|
78
|
+
|
|
79
|
+
console.log('✅ Frames database recreated at:', dbPath);
|
|
80
|
+
|
|
81
|
+
// Verify tables exist
|
|
82
|
+
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
|
|
83
|
+
console.log('📊 Tables created:', tables.map(t => t.name).join(', '));
|
|
84
|
+
|
|
85
|
+
// Check if we have any existing frames
|
|
86
|
+
const frameCount = db.prepare('SELECT COUNT(*) as count FROM frames').get();
|
|
87
|
+
console.log('📈 Existing frames:', frameCount.count);
|
|
88
|
+
|
|
89
|
+
db.close();
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Automatically configure Claude Desktop to use StackMemory MCP
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import os from 'os';
|
|
9
|
+
|
|
10
|
+
function setupClaudeIntegration() {
|
|
11
|
+
console.log('🔧 Setting up Claude Desktop integration...\n');
|
|
12
|
+
|
|
13
|
+
// Find Claude Desktop config path
|
|
14
|
+
const configPaths = [
|
|
15
|
+
path.join(
|
|
16
|
+
os.homedir(),
|
|
17
|
+
'Library',
|
|
18
|
+
'Application Support',
|
|
19
|
+
'Claude',
|
|
20
|
+
'claude_desktop_config.json'
|
|
21
|
+
), // macOS
|
|
22
|
+
path.join(os.homedir(), '.config', 'claude', 'claude_desktop_config.json'), // Linux
|
|
23
|
+
path.join(
|
|
24
|
+
os.homedir(),
|
|
25
|
+
'AppData',
|
|
26
|
+
'Roaming',
|
|
27
|
+
'Claude',
|
|
28
|
+
'claude_desktop_config.json'
|
|
29
|
+
), // Windows
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
let configPath = null;
|
|
33
|
+
for (const p of configPaths) {
|
|
34
|
+
if (fs.existsSync(p) || fs.existsSync(path.dirname(p))) {
|
|
35
|
+
configPath = p;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!configPath) {
|
|
41
|
+
console.log('❌ Claude Desktop config directory not found');
|
|
42
|
+
console.log('📝 Manual setup required - add this to your Claude config:');
|
|
43
|
+
printManualConfig();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Current project path
|
|
48
|
+
const projectRoot = process.cwd();
|
|
49
|
+
const mcpServerPath = path.join(
|
|
50
|
+
projectRoot,
|
|
51
|
+
'dist',
|
|
52
|
+
'src',
|
|
53
|
+
'mcp',
|
|
54
|
+
'mcp-server.js'
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Read existing config or create new
|
|
58
|
+
let config = { mcpServers: {} };
|
|
59
|
+
if (fs.existsSync(configPath)) {
|
|
60
|
+
try {
|
|
61
|
+
const existing = fs.readFileSync(configPath, 'utf8');
|
|
62
|
+
config = JSON.parse(existing);
|
|
63
|
+
if (!config.mcpServers) config.mcpServers = {};
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.log('⚠️ Could not parse existing config, creating new one');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Add/update StackMemory MCP server
|
|
70
|
+
config.mcpServers.stackmemory = {
|
|
71
|
+
command: 'node',
|
|
72
|
+
args: [mcpServerPath],
|
|
73
|
+
env: {
|
|
74
|
+
PROJECT_ROOT: projectRoot,
|
|
75
|
+
STACKMEMORY_AUTO_CHECK: 'true',
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Ensure directory exists
|
|
80
|
+
const configDir = path.dirname(configPath);
|
|
81
|
+
if (!fs.existsSync(configDir)) {
|
|
82
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Write config
|
|
86
|
+
try {
|
|
87
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
88
|
+
console.log('✅ Claude Desktop config updated successfully!');
|
|
89
|
+
console.log(`📁 Config location: ${configPath}\n`);
|
|
90
|
+
|
|
91
|
+
console.log(
|
|
92
|
+
'🔄 Please restart Claude Desktop to activate StackMemory integration\n'
|
|
93
|
+
);
|
|
94
|
+
console.log('🎯 StackMemory will now automatically:');
|
|
95
|
+
console.log(' • Save context every 15 minutes');
|
|
96
|
+
console.log(' • Load previous context on startup');
|
|
97
|
+
console.log(' • Track tasks and decisions');
|
|
98
|
+
console.log(' • Enable seamless context persistence\n');
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.log('❌ Failed to write config file:', error.message);
|
|
101
|
+
console.log('📝 Manual setup required:');
|
|
102
|
+
printManualConfig();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function printManualConfig() {
|
|
107
|
+
const projectRoot = process.cwd();
|
|
108
|
+
const mcpServerPath = path.join(
|
|
109
|
+
projectRoot,
|
|
110
|
+
'dist',
|
|
111
|
+
'src',
|
|
112
|
+
'mcp',
|
|
113
|
+
'mcp-server.js'
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
console.log(
|
|
117
|
+
'\n' +
|
|
118
|
+
JSON.stringify(
|
|
119
|
+
{
|
|
120
|
+
mcpServers: {
|
|
121
|
+
stackmemory: {
|
|
122
|
+
command: 'node',
|
|
123
|
+
args: [mcpServerPath],
|
|
124
|
+
env: {
|
|
125
|
+
PROJECT_ROOT: projectRoot,
|
|
126
|
+
STACKMEMORY_AUTO_CHECK: 'true',
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
null,
|
|
132
|
+
2
|
|
133
|
+
) +
|
|
134
|
+
'\n'
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
setupClaudeIntegration();
|