@stackmemoryai/stackmemory 1.2.2 → 1.2.6

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.
Files changed (77) hide show
  1. package/README.md +10 -6
  2. package/dist/src/cli/claude-sm.js +33 -4
  3. package/dist/src/cli/codex-sm-danger.js +4 -1
  4. package/dist/src/cli/codex-sm.js +6 -8
  5. package/dist/src/cli/commands/config.js +0 -81
  6. package/dist/src/cli/commands/context-rehydrate.js +133 -47
  7. package/dist/src/cli/commands/db.js +35 -8
  8. package/dist/src/cli/commands/handoff.js +1 -1
  9. package/dist/src/cli/commands/linear.js +9 -0
  10. package/dist/src/cli/commands/ralph.js +2 -2
  11. package/dist/src/cli/commands/setup.js +2 -2
  12. package/dist/src/cli/commands/signup.js +3 -1
  13. package/dist/src/cli/commands/skills.js +108 -1
  14. package/dist/src/cli/commands/storage-tier.js +26 -8
  15. package/dist/src/cli/index.js +1 -57
  16. package/dist/src/core/config/feature-flags.js +0 -4
  17. package/dist/src/core/context/dual-stack-manager.js +10 -3
  18. package/dist/src/core/context/frame-database.js +32 -0
  19. package/dist/src/core/context/frame-handoff-manager.js +2 -2
  20. package/dist/src/core/context/{refactored-frame-manager.js → frame-manager.js} +3 -3
  21. package/dist/src/core/context/index.js +2 -2
  22. package/dist/src/core/database/sqlite-adapter.js +161 -1
  23. package/dist/src/core/digest/frame-digest-integration.js +1 -1
  24. package/dist/src/core/digest/index.js +1 -1
  25. package/dist/src/core/execution/parallel-executor.js +5 -1
  26. package/dist/src/core/projects/project-isolation.js +18 -4
  27. package/dist/src/core/security/index.js +2 -0
  28. package/dist/src/core/security/input-sanitizer.js +23 -0
  29. package/dist/src/core/utils/update-checker.js +10 -6
  30. package/dist/src/daemon/daemon-config.js +2 -1
  31. package/dist/src/daemon/services/auto-save-service.js +121 -0
  32. package/dist/src/daemon/services/maintenance-service.js +76 -1
  33. package/dist/src/features/sweep/prompt-builder.js +2 -2
  34. package/dist/src/hooks/daemon.js +0 -8
  35. package/dist/src/integrations/linear/config.js +3 -1
  36. package/dist/src/integrations/linear/sync.js +18 -5
  37. package/dist/src/integrations/linear/webhook.js +0 -16
  38. package/dist/src/integrations/mcp/handlers/code-execution-handlers.js +33 -7
  39. package/dist/src/integrations/mcp/handlers/cord-handlers.js +397 -0
  40. package/dist/src/integrations/mcp/handlers/index.js +55 -9
  41. package/dist/src/integrations/mcp/handlers/task-handlers.js +55 -12
  42. package/dist/src/integrations/mcp/handlers/team-handlers.js +211 -0
  43. package/dist/src/integrations/mcp/handlers/trace-handlers.js +28 -9
  44. package/dist/src/integrations/mcp/index.js +2 -2
  45. package/dist/src/integrations/mcp/refactored-server.js +31 -10
  46. package/dist/src/integrations/mcp/server.js +0 -130
  47. package/dist/src/integrations/mcp/tool-definitions.js +196 -67
  48. package/dist/src/integrations/ralph/context/context-budget-manager.js +10 -2
  49. package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +54 -22
  50. package/dist/src/integrations/ralph/learning/pattern-learner.js +59 -24
  51. package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +81 -35
  52. package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +12 -4
  53. package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +32 -9
  54. package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +25 -8
  55. package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +17 -5
  56. package/dist/src/integrations/ralph/visualization/ralph-debugger.js +73 -22
  57. package/dist/src/skills/claude-skills.js +37 -103
  58. package/dist/src/skills/theory-skill.js +191 -0
  59. package/dist/src/utils/hook-installer.js +16 -0
  60. package/package.json +6 -6
  61. package/scripts/install-claude-hooks-auto.js +8 -0
  62. package/templates/claude-hooks/cord-trace.js +225 -0
  63. package/templates/claude-hooks/theory-capture.js +100 -0
  64. package/dist/src/core/config/storage-config.js +0 -114
  65. package/dist/src/core/storage/chromadb-adapter.js +0 -379
  66. package/dist/src/hooks/graphiti-hooks.js +0 -253
  67. package/dist/src/integrations/claude-code/enhanced-pre-clear-hooks.js +0 -458
  68. package/dist/src/integrations/graphiti/client.js +0 -115
  69. package/dist/src/integrations/graphiti/config.js +0 -17
  70. package/dist/src/integrations/graphiti/linear-graphiti-bridge.js +0 -115
  71. package/dist/src/integrations/graphiti/types.js +0 -4
  72. package/dist/src/integrations/ralph/coordination/enhanced-coordination.js +0 -409
  73. package/dist/src/skills/repo-ingestion-skill.js +0 -631
  74. package/templates/claude-hooks/chromadb-wrapper +0 -21
  75. /package/dist/src/core/context/{enhanced-rehydration.js → rehydration.js} +0 -0
  76. /package/dist/src/core/digest/{enhanced-hybrid-digest.js → hybrid-digest.js} +0 -0
  77. /package/dist/src/core/session/{enhanced-handoff.js → handoff.js} +0 -0
@@ -1,631 +0,0 @@
1
- import { fileURLToPath as __fileURLToPath } from 'url';
2
- import { dirname as __pathDirname } from 'path';
3
- const __filename = __fileURLToPath(import.meta.url);
4
- const __dirname = __pathDirname(__filename);
5
- import { Logger } from "../core/monitoring/logger.js";
6
- import {
7
- isChromaDBEnabled,
8
- getChromaDBConfig
9
- } from "../core/config/storage-config.js";
10
- import * as fs from "fs";
11
- import * as path from "path";
12
- import * as crypto from "crypto";
13
- import { execSync } from "child_process";
14
- import ignore from "ignore";
15
- async function getChromaDBAdapter() {
16
- try {
17
- return await import("../core/storage/chromadb-adapter.js");
18
- } catch {
19
- throw new Error(
20
- "chromadb is not installed. Install it with: npm install chromadb"
21
- );
22
- }
23
- }
24
- class RepoIngestionSkill {
25
- constructor(config, userId, teamId) {
26
- this.config = config;
27
- this.userId = userId;
28
- this.teamId = teamId;
29
- this.logger = new Logger("RepoIngestionSkill");
30
- this.chromaEnabled = isChromaDBEnabled();
31
- if (this.chromaEnabled) {
32
- const chromaConfig = getChromaDBConfig();
33
- if (chromaConfig && chromaConfig.apiKey) {
34
- this.adapterConfig = {
35
- apiKey: config?.apiKey || chromaConfig.apiKey,
36
- tenant: config?.tenant || chromaConfig.tenant || "default_tenant",
37
- database: config?.database || chromaConfig.database || "default_database",
38
- collectionName: config?.collectionName || "stackmemory_repos"
39
- };
40
- }
41
- }
42
- }
43
- logger;
44
- adapter = null;
45
- metadataCache = /* @__PURE__ */ new Map();
46
- fileHashCache = /* @__PURE__ */ new Map();
47
- chromaEnabled = false;
48
- adapterConfig = null;
49
- /**
50
- * Check if ChromaDB is available for use
51
- */
52
- isAvailable() {
53
- return this.chromaEnabled && this.adapter !== null;
54
- }
55
- async initialize() {
56
- if (!this.chromaEnabled || !this.adapterConfig) {
57
- this.logger.warn(
58
- "ChromaDB not enabled. Repository ingestion features are unavailable."
59
- );
60
- this.logger.warn('Run "stackmemory init --chromadb" to enable ChromaDB.');
61
- return;
62
- }
63
- if (!this.adapter && this.adapterConfig) {
64
- try {
65
- const { ChromaDBAdapter } = await getChromaDBAdapter();
66
- this.adapter = await ChromaDBAdapter.create(
67
- this.adapterConfig,
68
- this.userId,
69
- this.teamId
70
- );
71
- } catch (error) {
72
- this.logger.warn(
73
- `Failed to initialize ChromaDB: ${error instanceof Error ? error.message : String(error)}`
74
- );
75
- this.logger.warn(
76
- "chromadb is optional. Install it with: npm install chromadb"
77
- );
78
- return;
79
- }
80
- }
81
- if (this.adapter) {
82
- await this.adapter.initialize();
83
- }
84
- await this.loadMetadataCache();
85
- }
86
- /**
87
- * Ingest a repository into ChromaDB
88
- */
89
- async ingestRepository(repoPath, repoName, options = {}) {
90
- if (!this.isAvailable()) {
91
- return {
92
- success: false,
93
- message: 'ChromaDB not enabled. Run "stackmemory init --chromadb" to enable semantic search features.'
94
- };
95
- }
96
- const startTime = Date.now();
97
- try {
98
- this.logger.info(`Starting repository ingestion for ${repoName}`);
99
- if (!fs.existsSync(repoPath)) {
100
- throw new Error(`Repository path not found: ${repoPath}`);
101
- }
102
- const metadata = await this.getRepoMetadata(repoPath, repoName);
103
- const existingMetadata = this.metadataCache.get(metadata.repoId);
104
- if (options.incremental && existingMetadata && !options.forceUpdate) {
105
- const changedFiles = await this.getChangedFiles(
106
- repoPath,
107
- existingMetadata.lastCommit,
108
- metadata.lastCommit
109
- );
110
- if (changedFiles.length === 0) {
111
- return {
112
- success: true,
113
- message: "No changes detected since last ingestion"
114
- };
115
- }
116
- this.logger.info(
117
- `Incremental update: ${changedFiles.length} files changed`
118
- );
119
- }
120
- const files = await this.getRepoFiles(repoPath, options);
121
- this.logger.info(`Found ${files.length} files to process`);
122
- let filesProcessed = 0;
123
- let chunksCreated = 0;
124
- let totalSize = 0;
125
- for (const file of files) {
126
- try {
127
- const chunks = await this.processFile(
128
- file,
129
- repoPath,
130
- repoName,
131
- metadata,
132
- options
133
- );
134
- for (const chunk of chunks) {
135
- await this.storeChunk(chunk, metadata);
136
- chunksCreated++;
137
- }
138
- filesProcessed++;
139
- totalSize += fs.statSync(file).size;
140
- if (filesProcessed % 100 === 0) {
141
- this.logger.info(
142
- `Processed ${filesProcessed}/${files.length} files`
143
- );
144
- }
145
- } catch (error) {
146
- this.logger.warn(`Failed to process file ${file}:`, error);
147
- }
148
- }
149
- metadata.filesCount = filesProcessed;
150
- metadata.totalSize = totalSize;
151
- metadata.lastIngested = Date.now();
152
- await this.saveMetadata(metadata);
153
- const timeElapsed = Date.now() - startTime;
154
- this.logger.info(
155
- `Repository ingestion complete: ${filesProcessed} files, ${chunksCreated} chunks in ${timeElapsed}ms`
156
- );
157
- return {
158
- success: true,
159
- message: `Successfully ingested ${repoName}`,
160
- stats: {
161
- filesProcessed,
162
- chunksCreated,
163
- timeElapsed,
164
- totalSize
165
- }
166
- };
167
- } catch (error) {
168
- this.logger.error("Repository ingestion failed:", error);
169
- return {
170
- success: false,
171
- message: `Failed to ingest repository: ${error instanceof Error ? error.message : "Unknown error"}`
172
- };
173
- }
174
- }
175
- /**
176
- * Update an existing repository in ChromaDB
177
- */
178
- async updateRepository(repoPath, repoName, options = {}) {
179
- const startTime = Date.now();
180
- try {
181
- const metadata = await this.getRepoMetadata(repoPath, repoName);
182
- const existingMetadata = this.metadataCache.get(metadata.repoId);
183
- if (!existingMetadata) {
184
- return this.ingestRepository(repoPath, repoName, options);
185
- }
186
- const changedFiles = await this.getChangedFiles(
187
- repoPath,
188
- existingMetadata.lastCommit,
189
- metadata.lastCommit
190
- );
191
- if (changedFiles.length === 0) {
192
- return {
193
- success: true,
194
- message: "No changes detected",
195
- stats: {
196
- filesUpdated: 0,
197
- filesAdded: 0,
198
- filesRemoved: 0,
199
- timeElapsed: Date.now() - startTime
200
- }
201
- };
202
- }
203
- let filesUpdated = 0;
204
- let filesAdded = 0;
205
- let filesRemoved = 0;
206
- for (const change of changedFiles) {
207
- const filePath = path.join(repoPath, change.path);
208
- if (change.status === "deleted") {
209
- await this.removeFileChunks(change.path, metadata.repoId);
210
- filesRemoved++;
211
- } else if (change.status === "added") {
212
- const chunks = await this.processFile(
213
- filePath,
214
- repoPath,
215
- repoName,
216
- metadata,
217
- options
218
- );
219
- for (const chunk of chunks) {
220
- await this.storeChunk(chunk, metadata);
221
- }
222
- filesAdded++;
223
- } else if (change.status === "modified") {
224
- await this.removeFileChunks(change.path, metadata.repoId);
225
- const chunks = await this.processFile(
226
- filePath,
227
- repoPath,
228
- repoName,
229
- metadata,
230
- options
231
- );
232
- for (const chunk of chunks) {
233
- await this.storeChunk(chunk, metadata);
234
- }
235
- filesUpdated++;
236
- }
237
- }
238
- metadata.lastIngested = Date.now();
239
- await this.saveMetadata(metadata);
240
- const timeElapsed = Date.now() - startTime;
241
- return {
242
- success: true,
243
- message: `Successfully updated ${repoName}`,
244
- stats: {
245
- filesUpdated,
246
- filesAdded,
247
- filesRemoved,
248
- timeElapsed
249
- }
250
- };
251
- } catch (error) {
252
- this.logger.error("Repository update failed:", error);
253
- return {
254
- success: false,
255
- message: `Failed to update repository: ${error instanceof Error ? error.message : "Unknown error"}`
256
- };
257
- }
258
- }
259
- /**
260
- * Search code in ingested repositories
261
- */
262
- async searchCode(query, options) {
263
- if (!this.isAvailable() || !this.adapter) {
264
- this.logger.warn("ChromaDB not enabled. Code search unavailable.");
265
- return [];
266
- }
267
- try {
268
- const filters = {
269
- type: ["code_chunk"]
270
- };
271
- if (options?.repoName) {
272
- filters.repo_name = options.repoName;
273
- }
274
- if (options?.language) {
275
- filters.language = options.language;
276
- }
277
- const results = await this.adapter.queryContexts(
278
- query,
279
- options?.limit || 20,
280
- filters
281
- );
282
- return results.map((result) => ({
283
- filePath: result.metadata.file_path,
284
- content: result.content,
285
- score: 1 - result.distance,
286
- // Convert distance to similarity score
287
- startLine: result.metadata.start_line,
288
- endLine: result.metadata.end_line,
289
- repoName: result.metadata.repo_name
290
- }));
291
- } catch (error) {
292
- this.logger.error("Code search failed:", error);
293
- return [];
294
- }
295
- }
296
- /**
297
- * Get repository metadata
298
- */
299
- async getRepoMetadata(repoPath, repoName) {
300
- const branch = this.getCurrentBranch(repoPath);
301
- const lastCommit = this.getLastCommit(repoPath);
302
- const repoId = `${repoName}_${branch}`.replace(/[^a-zA-Z0-9_-]/g, "_");
303
- const { language, framework } = await this.detectLanguageAndFramework(repoPath);
304
- return {
305
- repoId,
306
- repoName,
307
- branch,
308
- lastCommit,
309
- lastIngested: Date.now(),
310
- filesCount: 0,
311
- totalSize: 0,
312
- language,
313
- framework
314
- };
315
- }
316
- /**
317
- * Get current git branch
318
- */
319
- getCurrentBranch(repoPath) {
320
- try {
321
- return execSync("git rev-parse --abbrev-ref HEAD", {
322
- cwd: repoPath,
323
- encoding: "utf8"
324
- }).trim();
325
- } catch {
326
- return "main";
327
- }
328
- }
329
- /**
330
- * Get last commit hash
331
- */
332
- getLastCommit(repoPath) {
333
- try {
334
- return execSync("git rev-parse HEAD", {
335
- cwd: repoPath,
336
- encoding: "utf8"
337
- }).trim();
338
- } catch {
339
- return "unknown";
340
- }
341
- }
342
- /**
343
- * Get changed files between commits
344
- */
345
- async getChangedFiles(repoPath, fromCommit, toCommit) {
346
- try {
347
- const diff = execSync(
348
- `git diff --name-status ${fromCommit}..${toCommit}`,
349
- {
350
- cwd: repoPath,
351
- encoding: "utf8"
352
- }
353
- );
354
- return diff.split("\n").filter((line) => line.trim()).map((line) => {
355
- const [status, ...pathParts] = line.split(" ");
356
- return {
357
- path: pathParts.join(" "),
358
- status: status === "A" ? "added" : status === "D" ? "deleted" : "modified"
359
- };
360
- });
361
- } catch {
362
- return [];
363
- }
364
- }
365
- /**
366
- * Get repository files to process
367
- */
368
- async getRepoFiles(repoPath, options) {
369
- const files = [];
370
- const ig = ignore();
371
- const gitignorePath = path.join(repoPath, ".gitignore");
372
- if (fs.existsSync(gitignorePath)) {
373
- ig.add(fs.readFileSync(gitignorePath, "utf8"));
374
- }
375
- const defaultExcludes = [
376
- "node_modules",
377
- ".git",
378
- "dist",
379
- "build",
380
- "coverage",
381
- ".env",
382
- "*.log",
383
- ...options.excludePatterns || []
384
- ];
385
- ig.add(defaultExcludes);
386
- const extensions = options.extensions || [
387
- ".ts",
388
- ".tsx",
389
- ".js",
390
- ".jsx",
391
- ".py",
392
- ".java",
393
- ".go",
394
- ".rs",
395
- ".c",
396
- ".cpp",
397
- ".h",
398
- ".hpp",
399
- ".cs",
400
- ".rb",
401
- ".php",
402
- ".swift",
403
- ".kt",
404
- ".scala",
405
- ".r",
406
- ".m",
407
- ".sql",
408
- ".yaml",
409
- ".yml",
410
- ".json"
411
- ];
412
- if (options.includeDocs) {
413
- extensions.push(".md", ".rst", ".txt");
414
- }
415
- const maxFileSize = options.maxFileSize || 1024 * 1024;
416
- const walkDir = (dir, baseDir = repoPath) => {
417
- const entries = fs.readdirSync(dir, { withFileTypes: true });
418
- for (const entry of entries) {
419
- const fullPath = path.join(dir, entry.name);
420
- const relativePath = path.relative(baseDir, fullPath);
421
- if (ig.ignores(relativePath)) {
422
- continue;
423
- }
424
- if (entry.isDirectory()) {
425
- walkDir(fullPath, baseDir);
426
- } else if (entry.isFile()) {
427
- const ext = path.extname(entry.name);
428
- if (!extensions.includes(ext)) {
429
- continue;
430
- }
431
- if (!options.includeTests && (entry.name.includes(".test.") || entry.name.includes(".spec.") || relativePath.includes("__tests__") || relativePath.includes("test/") || relativePath.includes("tests/"))) {
432
- continue;
433
- }
434
- const stats = fs.statSync(fullPath);
435
- if (stats.size > maxFileSize) {
436
- this.logger.debug(`Skipping large file: ${relativePath}`);
437
- continue;
438
- }
439
- files.push(fullPath);
440
- }
441
- }
442
- };
443
- walkDir(repoPath);
444
- return files;
445
- }
446
- /**
447
- * Process a file into chunks
448
- */
449
- async processFile(filePath, repoPath, repoName, metadata, options) {
450
- const relativePath = path.relative(repoPath, filePath);
451
- const content = fs.readFileSync(filePath, "utf8");
452
- const lines = content.split("\n");
453
- const language = this.detectFileLanguage(filePath);
454
- const chunkSize = options.chunkSize || 100;
455
- const chunks = [];
456
- const fileHash = crypto.createHash("md5").update(content).digest("hex");
457
- const cachedHash = this.fileHashCache.get(relativePath);
458
- if (cachedHash === fileHash && !options.forceUpdate) {
459
- return [];
460
- }
461
- this.fileHashCache.set(relativePath, fileHash);
462
- for (let i = 0; i < lines.length; i += chunkSize) {
463
- const chunkLines = lines.slice(i, Math.min(i + chunkSize, lines.length));
464
- const chunkContent = chunkLines.join("\n");
465
- if (chunkContent.trim().length === 0) {
466
- continue;
467
- }
468
- const chunkId = `${metadata.repoId}_${relativePath}_${i}`;
469
- const chunkHash = crypto.createHash("md5").update(chunkContent).digest("hex");
470
- chunks.push({
471
- id: chunkId,
472
- filePath: relativePath,
473
- content: chunkContent,
474
- startLine: i + 1,
475
- endLine: Math.min(i + chunkSize, lines.length),
476
- hash: chunkHash,
477
- language
478
- });
479
- }
480
- return chunks;
481
- }
482
- /**
483
- * Store a chunk in ChromaDB
484
- */
485
- async storeChunk(chunk, metadata) {
486
- if (!this.adapter) {
487
- throw new Error("ChromaDB adapter not available");
488
- }
489
- const documentContent = `File: ${chunk.filePath} (Lines ${chunk.startLine}-${chunk.endLine})
490
- Language: ${chunk.language}
491
- Repository: ${metadata.repoName}/${metadata.branch}
492
-
493
- ${chunk.content}`;
494
- if (!this.adapter) {
495
- throw new Error("ChromaDB adapter not initialized");
496
- }
497
- await this.adapter.storeContext("observation", documentContent, {
498
- type: "code_chunk",
499
- repo_id: metadata.repoId,
500
- repo_name: metadata.repoName,
501
- branch: metadata.branch,
502
- file_path: chunk.filePath,
503
- start_line: chunk.startLine,
504
- end_line: chunk.endLine,
505
- language: chunk.language,
506
- framework: metadata.framework,
507
- chunk_hash: chunk.hash,
508
- last_commit: metadata.lastCommit
509
- });
510
- }
511
- /**
512
- * Remove file chunks from ChromaDB
513
- */
514
- async removeFileChunks(filePath, repoId) {
515
- this.logger.debug(
516
- `Would remove chunks for file: ${filePath} from repo: ${repoId}`
517
- );
518
- }
519
- /**
520
- * Detect file language
521
- */
522
- detectFileLanguage(filePath) {
523
- const ext = path.extname(filePath).toLowerCase();
524
- const languageMap = {
525
- ".ts": "typescript",
526
- ".tsx": "typescript",
527
- ".js": "javascript",
528
- ".jsx": "javascript",
529
- ".py": "python",
530
- ".java": "java",
531
- ".go": "go",
532
- ".rs": "rust",
533
- ".c": "c",
534
- ".cpp": "cpp",
535
- ".cs": "csharp",
536
- ".rb": "ruby",
537
- ".php": "php",
538
- ".swift": "swift",
539
- ".kt": "kotlin",
540
- ".scala": "scala",
541
- ".r": "r",
542
- ".sql": "sql",
543
- ".yaml": "yaml",
544
- ".yml": "yaml",
545
- ".json": "json",
546
- ".md": "markdown"
547
- };
548
- return languageMap[ext] || "unknown";
549
- }
550
- /**
551
- * Detect language and framework
552
- */
553
- async detectLanguageAndFramework(repoPath) {
554
- const packageJsonPath = path.join(repoPath, "package.json");
555
- if (fs.existsSync(packageJsonPath)) {
556
- try {
557
- const packageJson = JSON.parse(
558
- fs.readFileSync(packageJsonPath, "utf8")
559
- );
560
- const deps = {
561
- ...packageJson.dependencies,
562
- ...packageJson.devDependencies
563
- };
564
- let framework;
565
- if (deps.react) framework = "react";
566
- else if (deps.vue) framework = "vue";
567
- else if (deps.angular) framework = "angular";
568
- else if (deps.express) framework = "express";
569
- else if (deps.next) framework = "nextjs";
570
- else if (deps.svelte) framework = "svelte";
571
- return {
572
- language: deps.typescript ? "typescript" : "javascript",
573
- framework
574
- };
575
- } catch {
576
- }
577
- }
578
- if (fs.existsSync(path.join(repoPath, "requirements.txt")) || fs.existsSync(path.join(repoPath, "setup.py"))) {
579
- return { language: "python" };
580
- }
581
- if (fs.existsSync(path.join(repoPath, "go.mod"))) {
582
- return { language: "go" };
583
- }
584
- if (fs.existsSync(path.join(repoPath, "Cargo.toml"))) {
585
- return { language: "rust" };
586
- }
587
- if (fs.existsSync(path.join(repoPath, "pom.xml")) || fs.existsSync(path.join(repoPath, "build.gradle"))) {
588
- return { language: "java" };
589
- }
590
- return { language: "unknown" };
591
- }
592
- /**
593
- * Load metadata cache
594
- */
595
- async loadMetadataCache() {
596
- this.metadataCache.clear();
597
- }
598
- /**
599
- * Save metadata
600
- */
601
- async saveMetadata(metadata) {
602
- this.metadataCache.set(metadata.repoId, metadata);
603
- }
604
- /**
605
- * Get repository statistics
606
- */
607
- async getRepoStats(repoName) {
608
- const stats = {
609
- totalRepos: this.metadataCache.size,
610
- totalFiles: 0,
611
- totalChunks: 0,
612
- languages: {},
613
- frameworks: {}
614
- };
615
- for (const metadata of this.metadataCache.values()) {
616
- if (!repoName || metadata.repoName === repoName) {
617
- stats.totalFiles += metadata.filesCount;
618
- if (metadata.language) {
619
- stats.languages[metadata.language] = (stats.languages[metadata.language] || 0) + 1;
620
- }
621
- if (metadata.framework) {
622
- stats.frameworks[metadata.framework] = (stats.frameworks[metadata.framework] || 0) + 1;
623
- }
624
- }
625
- }
626
- return stats;
627
- }
628
- }
629
- export {
630
- RepoIngestionSkill
631
- };
@@ -1,21 +0,0 @@
1
- #!/bin/bash
2
- # ChromaDB Hook Wrapper - Routes Claude events to ChromaDB
3
-
4
- HOOK_TYPE="$1"
5
- HOOK_DATA="$2"
6
- PROJECT_DIR="$(pwd)"
7
-
8
- # Find StackMemory installation
9
- if [ -d "$PROJECT_DIR/scripts" ] && [ -f "$PROJECT_DIR/scripts/claude-chromadb-hook.js" ]; then
10
- HOOK_SCRIPT="$PROJECT_DIR/scripts/claude-chromadb-hook.js"
11
- elif [ -f "$HOME/.stackmemory/bin/chromadb-hook.js" ]; then
12
- HOOK_SCRIPT="$HOME/.stackmemory/bin/chromadb-hook.js"
13
- else
14
- # Skip if ChromaDB hook not found
15
- exit 0
16
- fi
17
-
18
- # Execute ChromaDB hook in background to not block Claude
19
- nohup node "$HOOK_SCRIPT" "$HOOK_TYPE" "$HOOK_DATA" >> "$HOME/.stackmemory/logs/chromadb-hook.log" 2>&1 &
20
-
21
- exit 0