@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,460 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ChromaDB Hook for Claude
|
|
5
|
+
* Automatically preserves and retrieves context using ChromaDB vector storage
|
|
6
|
+
*
|
|
7
|
+
* This hook runs automatically during Claude operations to:
|
|
8
|
+
* - Store context on saves/clears
|
|
9
|
+
* - Retrieve relevant context on queries
|
|
10
|
+
* - Maintain semantic search history
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { CloudClient } from 'chromadb';
|
|
14
|
+
import fs from 'fs';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import { fileURLToPath } from 'url';
|
|
17
|
+
import dotenv from 'dotenv';
|
|
18
|
+
|
|
19
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
|
|
21
|
+
// Load environment variables
|
|
22
|
+
dotenv.config({
|
|
23
|
+
path: path.join(__dirname, '..', '.env'),
|
|
24
|
+
override: true,
|
|
25
|
+
silent: true
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
class ChromaDBHook {
|
|
29
|
+
constructor() {
|
|
30
|
+
this.config = {
|
|
31
|
+
apiKey: process.env.CHROMADB_API_KEY,
|
|
32
|
+
tenant: process.env.CHROMADB_TENANT,
|
|
33
|
+
database: process.env.CHROMADB_DATABASE || 'stackmemory',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
this.userId = process.env.USER || 'claude';
|
|
37
|
+
this.teamId = process.env.CHROMADB_TEAM_ID;
|
|
38
|
+
this.sessionId = process.env.CLAUDE_SESSION_ID || `session_${Date.now()}`;
|
|
39
|
+
this.projectName = path.basename(process.cwd());
|
|
40
|
+
|
|
41
|
+
this.client = null;
|
|
42
|
+
this.collection = null;
|
|
43
|
+
this.initialized = false;
|
|
44
|
+
|
|
45
|
+
// Hook context from Claude
|
|
46
|
+
this.hookType = process.argv[2] || 'unknown';
|
|
47
|
+
this.hookData = process.argv[3] ? JSON.parse(process.argv[3]) : {};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async initialize() {
|
|
51
|
+
if (this.initialized) return;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
if (!this.config.apiKey || !this.config.tenant) {
|
|
55
|
+
this.log('ChromaDB not configured, skipping hook');
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.client = new CloudClient({
|
|
60
|
+
apiKey: this.config.apiKey,
|
|
61
|
+
tenant: this.config.tenant,
|
|
62
|
+
database: this.config.database,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
this.collection = await this.client.getOrCreateCollection({
|
|
66
|
+
name: 'claude_contexts',
|
|
67
|
+
metadata: {
|
|
68
|
+
description: 'Claude Code context storage',
|
|
69
|
+
version: '1.0.0',
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
this.initialized = true;
|
|
74
|
+
return true;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
this.logError('Failed to initialize ChromaDB', error);
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Store context in ChromaDB
|
|
83
|
+
*/
|
|
84
|
+
async storeContext(type, content, metadata = {}) {
|
|
85
|
+
if (!await this.initialize()) return;
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const contextId = `${type}_${this.sessionId}_${Date.now()}`;
|
|
89
|
+
|
|
90
|
+
await this.collection.add({
|
|
91
|
+
ids: [contextId],
|
|
92
|
+
documents: [content],
|
|
93
|
+
metadatas: [{
|
|
94
|
+
user_id: this.userId,
|
|
95
|
+
team_id: this.teamId,
|
|
96
|
+
session_id: this.sessionId,
|
|
97
|
+
project_name: this.projectName,
|
|
98
|
+
type: type,
|
|
99
|
+
timestamp: Date.now(),
|
|
100
|
+
hook_type: this.hookType,
|
|
101
|
+
...metadata,
|
|
102
|
+
}],
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
this.log(`Stored ${type} context`);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
this.logError(`Failed to store ${type}`, error);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Query contexts by semantic similarity
|
|
113
|
+
*/
|
|
114
|
+
async queryContexts(query, limit = 5) {
|
|
115
|
+
if (!await this.initialize()) return [];
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const results = await this.collection.query({
|
|
119
|
+
queryTexts: [query],
|
|
120
|
+
nResults: limit,
|
|
121
|
+
where: {
|
|
122
|
+
user_id: this.userId,
|
|
123
|
+
project_name: this.projectName,
|
|
124
|
+
},
|
|
125
|
+
include: ['documents', 'metadatas', 'distances'],
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
if (results.documents && results.documents[0]) {
|
|
129
|
+
return results.documents[0].map((doc, i) => ({
|
|
130
|
+
content: doc,
|
|
131
|
+
metadata: results.metadatas[0][i],
|
|
132
|
+
distance: results.distances[0][i],
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return [];
|
|
137
|
+
} catch (error) {
|
|
138
|
+
this.logError('Failed to query contexts', error);
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get recent contexts
|
|
145
|
+
*/
|
|
146
|
+
async getRecentContexts(limit = 10, type = null) {
|
|
147
|
+
if (!await this.initialize()) return [];
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const where = {
|
|
151
|
+
user_id: this.userId,
|
|
152
|
+
project_name: this.projectName,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
if (type) {
|
|
156
|
+
where.type = type;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const results = await this.collection.get({
|
|
160
|
+
where: where,
|
|
161
|
+
include: ['documents', 'metadatas'],
|
|
162
|
+
limit: limit * 2, // Get more to sort by timestamp
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
if (results.documents) {
|
|
166
|
+
const contexts = results.documents.map((doc, i) => ({
|
|
167
|
+
content: doc,
|
|
168
|
+
metadata: results.metadatas[i],
|
|
169
|
+
}));
|
|
170
|
+
|
|
171
|
+
// Sort by timestamp and limit
|
|
172
|
+
return contexts
|
|
173
|
+
.sort((a, b) => (b.metadata.timestamp || 0) - (a.metadata.timestamp || 0))
|
|
174
|
+
.slice(0, limit);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return [];
|
|
178
|
+
} catch (error) {
|
|
179
|
+
this.logError('Failed to get recent contexts', error);
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Handle different hook types
|
|
186
|
+
*/
|
|
187
|
+
async handleHook() {
|
|
188
|
+
switch (this.hookType) {
|
|
189
|
+
case 'on-save':
|
|
190
|
+
case 'on-context-save':
|
|
191
|
+
await this.handleSave();
|
|
192
|
+
break;
|
|
193
|
+
|
|
194
|
+
case 'on-clear':
|
|
195
|
+
case 'on-session-end':
|
|
196
|
+
await this.handleClear();
|
|
197
|
+
break;
|
|
198
|
+
|
|
199
|
+
case 'on-query':
|
|
200
|
+
case 'on-search':
|
|
201
|
+
await this.handleQuery();
|
|
202
|
+
break;
|
|
203
|
+
|
|
204
|
+
case 'on-task-complete':
|
|
205
|
+
await this.handleTaskComplete();
|
|
206
|
+
break;
|
|
207
|
+
|
|
208
|
+
case 'on-decision':
|
|
209
|
+
await this.handleDecision();
|
|
210
|
+
break;
|
|
211
|
+
|
|
212
|
+
case 'on-error':
|
|
213
|
+
await this.handleError();
|
|
214
|
+
break;
|
|
215
|
+
|
|
216
|
+
case 'on-file-change':
|
|
217
|
+
await this.handleFileChange();
|
|
218
|
+
break;
|
|
219
|
+
|
|
220
|
+
case 'periodic':
|
|
221
|
+
case 'on-checkpoint':
|
|
222
|
+
await this.handleCheckpoint();
|
|
223
|
+
break;
|
|
224
|
+
|
|
225
|
+
default:
|
|
226
|
+
this.log(`Unknown hook type: ${this.hookType}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async handleSave() {
|
|
231
|
+
const content = this.hookData.content || this.getCurrentContext();
|
|
232
|
+
await this.storeContext('save', content, {
|
|
233
|
+
files: this.hookData.files,
|
|
234
|
+
tags: this.hookData.tags,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async handleClear() {
|
|
239
|
+
// Save context before clear
|
|
240
|
+
const content = this.hookData.content || this.getCurrentContext();
|
|
241
|
+
await this.storeContext('clear', content, {
|
|
242
|
+
reason: this.hookData.reason || 'manual',
|
|
243
|
+
preserved: true,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Generate summary
|
|
247
|
+
const recentContexts = await this.getRecentContexts(20);
|
|
248
|
+
if (recentContexts.length > 0) {
|
|
249
|
+
const summary = this.generateSummary(recentContexts);
|
|
250
|
+
await this.storeContext('summary', summary, {
|
|
251
|
+
contexts_count: recentContexts.length,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async handleQuery() {
|
|
257
|
+
const query = this.hookData.query || this.hookData.search;
|
|
258
|
+
if (!query) return;
|
|
259
|
+
|
|
260
|
+
// Find relevant contexts
|
|
261
|
+
const contexts = await this.queryContexts(query, 5);
|
|
262
|
+
|
|
263
|
+
if (contexts.length > 0) {
|
|
264
|
+
// Store the query and results
|
|
265
|
+
await this.storeContext('query', query, {
|
|
266
|
+
results_count: contexts.length,
|
|
267
|
+
top_distance: contexts[0].distance,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Output relevant contexts for Claude
|
|
271
|
+
this.outputContextsForClaude(contexts);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async handleTaskComplete() {
|
|
276
|
+
const task = this.hookData.task || {};
|
|
277
|
+
await this.storeContext('task_complete', JSON.stringify(task), {
|
|
278
|
+
task_id: task.id,
|
|
279
|
+
task_title: task.title,
|
|
280
|
+
duration: task.duration,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async handleDecision() {
|
|
285
|
+
const decision = this.hookData.decision || this.hookData.content;
|
|
286
|
+
await this.storeContext('decision', decision, {
|
|
287
|
+
importance: this.hookData.importance || 'normal',
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async handleError() {
|
|
292
|
+
const error = this.hookData.error || this.hookData.message;
|
|
293
|
+
await this.storeContext('error', error, {
|
|
294
|
+
severity: this.hookData.severity || 'error',
|
|
295
|
+
stack: this.hookData.stack,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async handleFileChange() {
|
|
300
|
+
const file = this.hookData.file || this.hookData.path;
|
|
301
|
+
await this.storeContext('file_change', `Modified: ${file}`, {
|
|
302
|
+
file: file,
|
|
303
|
+
change_type: this.hookData.type || 'modify',
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async handleCheckpoint() {
|
|
308
|
+
// Periodic checkpoint
|
|
309
|
+
const content = this.getCurrentContext();
|
|
310
|
+
await this.storeContext('checkpoint', content, {
|
|
311
|
+
automatic: true,
|
|
312
|
+
interval: this.hookData.interval || 900000, // 15 min default
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// Clean old contexts
|
|
316
|
+
await this.cleanOldContexts();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Get current context from StackMemory
|
|
321
|
+
*/
|
|
322
|
+
getCurrentContext() {
|
|
323
|
+
try {
|
|
324
|
+
// Try to get from StackMemory
|
|
325
|
+
const contextFile = path.join(
|
|
326
|
+
process.env.HOME,
|
|
327
|
+
'.stackmemory',
|
|
328
|
+
'shared-context',
|
|
329
|
+
'projects',
|
|
330
|
+
`${this.projectName}.json`
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
if (fs.existsSync(contextFile)) {
|
|
334
|
+
const data = JSON.parse(fs.readFileSync(contextFile, 'utf8'));
|
|
335
|
+
return JSON.stringify(data.contexts || [], null, 2);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Fallback to hook data
|
|
339
|
+
return this.hookData.content || 'No context available';
|
|
340
|
+
} catch (error) {
|
|
341
|
+
return this.hookData.content || 'Context read error';
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Generate summary of contexts
|
|
347
|
+
*/
|
|
348
|
+
generateSummary(contexts) {
|
|
349
|
+
const summary = {
|
|
350
|
+
timestamp: new Date().toISOString(),
|
|
351
|
+
project: this.projectName,
|
|
352
|
+
session: this.sessionId,
|
|
353
|
+
contexts_count: contexts.length,
|
|
354
|
+
types: {},
|
|
355
|
+
key_points: [],
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
for (const ctx of contexts) {
|
|
359
|
+
const type = ctx.metadata.type || 'unknown';
|
|
360
|
+
summary.types[type] = (summary.types[type] || 0) + 1;
|
|
361
|
+
|
|
362
|
+
// Extract key points (first line or first 100 chars)
|
|
363
|
+
const point = ctx.content.split('\n')[0].substring(0, 100);
|
|
364
|
+
if (point && !summary.key_points.includes(point)) {
|
|
365
|
+
summary.key_points.push(point);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return JSON.stringify(summary, null, 2);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Output contexts for Claude to use
|
|
374
|
+
*/
|
|
375
|
+
outputContextsForClaude(contexts) {
|
|
376
|
+
console.log('\n=== Relevant Context from ChromaDB ===\n');
|
|
377
|
+
|
|
378
|
+
for (const ctx of contexts) {
|
|
379
|
+
console.log(`Type: ${ctx.metadata.type || 'unknown'}`);
|
|
380
|
+
console.log(`Time: ${new Date(ctx.metadata.timestamp).toLocaleString()}`);
|
|
381
|
+
console.log(`Relevance: ${(1 - ctx.distance).toFixed(2)}`);
|
|
382
|
+
console.log('---');
|
|
383
|
+
console.log(ctx.content.substring(0, 500));
|
|
384
|
+
console.log('\n');
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
console.log('=== End of Context ===\n');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Clean old contexts (retention policy)
|
|
392
|
+
*/
|
|
393
|
+
async cleanOldContexts() {
|
|
394
|
+
if (!await this.initialize()) return;
|
|
395
|
+
|
|
396
|
+
try {
|
|
397
|
+
const cutoffTime = Date.now() - (30 * 24 * 60 * 60 * 1000); // 30 days
|
|
398
|
+
|
|
399
|
+
const results = await this.collection.get({
|
|
400
|
+
where: {
|
|
401
|
+
user_id: this.userId,
|
|
402
|
+
timestamp: { $lt: cutoffTime },
|
|
403
|
+
},
|
|
404
|
+
include: ['ids'],
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
if (results.ids && results.ids.length > 0) {
|
|
408
|
+
await this.collection.delete({
|
|
409
|
+
ids: results.ids,
|
|
410
|
+
});
|
|
411
|
+
this.log(`Cleaned ${results.ids.length} old contexts`);
|
|
412
|
+
}
|
|
413
|
+
} catch (error) {
|
|
414
|
+
this.logError('Failed to clean old contexts', error);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
log(message) {
|
|
419
|
+
const logFile = path.join(
|
|
420
|
+
process.env.HOME,
|
|
421
|
+
'.stackmemory',
|
|
422
|
+
'logs',
|
|
423
|
+
'chromadb-hook.log'
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
const timestamp = new Date().toISOString();
|
|
427
|
+
const logMessage = `[${timestamp}] ${message}\n`;
|
|
428
|
+
|
|
429
|
+
try {
|
|
430
|
+
fs.appendFileSync(logFile, logMessage);
|
|
431
|
+
} catch {
|
|
432
|
+
// Silent fail
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
logError(message, error) {
|
|
437
|
+
this.log(`ERROR: ${message} - ${error.message}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Main execution
|
|
442
|
+
async function main() {
|
|
443
|
+
const hook = new ChromaDBHook();
|
|
444
|
+
|
|
445
|
+
try {
|
|
446
|
+
await hook.handleHook();
|
|
447
|
+
} catch (error) {
|
|
448
|
+
hook.logError('Hook execution failed', error);
|
|
449
|
+
// Don't fail the parent process
|
|
450
|
+
process.exit(0);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Run if called directly
|
|
455
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
456
|
+
main().catch(error => {
|
|
457
|
+
console.error('Fatal error:', error);
|
|
458
|
+
process.exit(0); // Don't fail the parent
|
|
459
|
+
});
|
|
460
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Claude Code wrapper with StackMemory integration
|
|
4
|
+
# Usage: Add alias to ~/.zshrc: alias claude='~/Dev/stackmemory/scripts/claude-code-wrapper.sh'
|
|
5
|
+
|
|
6
|
+
# Check for auto-sync flag
|
|
7
|
+
AUTO_SYNC=false
|
|
8
|
+
SYNC_INTERVAL=5
|
|
9
|
+
for arg in "$@"; do
|
|
10
|
+
case $arg in
|
|
11
|
+
--auto-sync)
|
|
12
|
+
AUTO_SYNC=true
|
|
13
|
+
shift
|
|
14
|
+
;;
|
|
15
|
+
--sync-interval=*)
|
|
16
|
+
SYNC_INTERVAL="${arg#*=}"
|
|
17
|
+
shift
|
|
18
|
+
;;
|
|
19
|
+
esac
|
|
20
|
+
done
|
|
21
|
+
|
|
22
|
+
# Start Linear auto-sync in background if requested
|
|
23
|
+
SYNC_PID=""
|
|
24
|
+
if [ "$AUTO_SYNC" = true ] && [ -n "$LINEAR_API_KEY" ]; then
|
|
25
|
+
echo "🔄 Starting Linear auto-sync (${SYNC_INTERVAL}min intervals)..."
|
|
26
|
+
(
|
|
27
|
+
while true; do
|
|
28
|
+
sleep $((SYNC_INTERVAL * 60))
|
|
29
|
+
if [ -d ".stackmemory" ]; then
|
|
30
|
+
stackmemory linear sync --quiet 2>/dev/null || true
|
|
31
|
+
fi
|
|
32
|
+
done
|
|
33
|
+
) &
|
|
34
|
+
SYNC_PID=$!
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
cleanup() {
|
|
38
|
+
echo "📝 Saving StackMemory context..."
|
|
39
|
+
|
|
40
|
+
# Kill auto-sync if running
|
|
41
|
+
if [ -n "$SYNC_PID" ] && kill -0 $SYNC_PID 2>/dev/null; then
|
|
42
|
+
echo "🛑 Stopping auto-sync..."
|
|
43
|
+
kill $SYNC_PID 2>/dev/null || true
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Check if in a git repo with stackmemory
|
|
47
|
+
if [ -d ".stackmemory" ] && [ -f "stackmemory.json" ]; then
|
|
48
|
+
# Save current context (without sync)
|
|
49
|
+
stackmemory status 2>/dev/null || true
|
|
50
|
+
echo "✅ StackMemory context saved"
|
|
51
|
+
fi
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Set trap for exit signals
|
|
55
|
+
trap cleanup EXIT INT TERM
|
|
56
|
+
|
|
57
|
+
# Run Claude Code (try multiple possible command names)
|
|
58
|
+
if command -v claude-code &> /dev/null; then
|
|
59
|
+
claude-code "$@"
|
|
60
|
+
elif command -v claude &> /dev/null; then
|
|
61
|
+
claude "$@"
|
|
62
|
+
else
|
|
63
|
+
echo "❌ Claude Code not found. Please install it first."
|
|
64
|
+
echo " Visit: https://github.com/anthropics/claude-code"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|