@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
package/README.md CHANGED
@@ -10,14 +10,17 @@ Lossless, project-scoped memory for AI coding tools.
10
10
  StackMemory is a **production-ready memory runtime** for AI coding tools that preserves full project context across sessions:
11
11
 
12
12
  - **Zero-config setup** — `stackmemory init` just works
13
- - **25 MCP tools** for Claude Code integration
14
- - **Full Linear integration** with bidirectional sync
13
+ - **32 MCP tools** for Claude Code integration (context, tasks, Linear, traces, discovery, cord, team)
14
+ - **FTS5 full-text search** with BM25 scoring and hybrid retrieval
15
+ - **Full Linear integration** with bidirectional sync and OAuth/API key support
15
16
  - **Context persistence** that survives `/clear` operations
16
17
  - **Hierarchical frame organization** (nested call stack model)
18
+ - **Multi-wrapper support** — `claude-sm`, `codex-sm`, `opencode-sm` with auto context loading
17
19
  - **Skills system** with `/spec` and `/linear-run` for Claude Code
18
20
  - **Automatic hooks** for task tracking, Linear sync, and spec progress
19
21
  - **Memory monitor daemon** with automatic capture/clear on RAM pressure
20
- - **652 tests passing** with comprehensive coverage
22
+ - **Auto-save service** for periodic context persistence
23
+ - **Comprehensive test coverage** across all core modules
21
24
 
22
25
  Instead of a linear chat log, StackMemory organizes memory as a **call stack** of scoped work (frames), with intelligent LLM-driven retrieval and team collaboration features.
23
26
 
@@ -50,13 +53,14 @@ Tools forget decisions and constraints between sessions. StackMemory makes conte
50
53
 
51
54
  ## Features
52
55
 
53
- - **MCP tools** for Claude Code: 25 tools across context, tasks, Linear, traces, and discovery
56
+ - **MCP tools** for Claude Code: 36 tools across context, tasks, Linear, traces, discovery, cord, and team
57
+ - **FTS5 search**: full-text search with BM25 scoring, hybrid retrieval, and smart thresholds
54
58
  - **Skills**: `/spec` (iterative spec generation), `/linear-run` (task execution via RLM)
55
- - **Hooks**: automatic context save, task tracking, Linear sync, PROMPT_PLAN updates
59
+ - **Hooks**: automatic context save, task tracking, Linear sync, PROMPT_PLAN updates, cord tracing
56
60
  - **Prompt Forge**: watches CLAUDE.md and AGENTS.md for prompt optimization (GEPA)
57
61
  - **Safe branches**: worktree isolation with `--worktree` or `-w`
58
62
  - **Persistent context**: frames, anchors, decisions, retrieval
59
- - **Integrations**: Linear, DiffMem, Browser MCP
63
+ - **Integrations**: Linear (API key + OAuth), DiffMem, Browser MCP, log-mcp (log analysis)
60
64
 
61
65
  ---
62
66
 
@@ -322,6 +322,28 @@ class ClaudeSM {
322
322
  } catch {
323
323
  }
324
324
  }
325
+ getTheoryContent() {
326
+ try {
327
+ let root;
328
+ try {
329
+ root = execSync("git rev-parse --show-toplevel", {
330
+ encoding: "utf-8",
331
+ timeout: 5e3
332
+ }).trim();
333
+ } catch {
334
+ root = process.cwd();
335
+ }
336
+ const theoryPath = path.join(root, "THEORY.MD");
337
+ if (fs.existsSync(theoryPath)) {
338
+ const content = fs.readFileSync(theoryPath, "utf8").trim();
339
+ if (content.length > 0) {
340
+ return content.length > 4e3 ? content.substring(0, 4e3) + "\n\n[...truncated]" : content;
341
+ }
342
+ }
343
+ } catch {
344
+ }
345
+ return null;
346
+ }
325
347
  getHandoffContent() {
326
348
  if (!this.config.contextEnabled) return null;
327
349
  try {
@@ -684,13 +706,20 @@ Session ended (exit ${exitCode ?? 0})`));
684
706
  this.startGEPAWatcher();
685
707
  }
686
708
  let initialInput = "";
687
- const handoffContent = this.getHandoffContent();
688
- if (handoffContent) {
689
- const hasResume = claudeArgs.includes("--continue") || claudeArgs.some((a) => a === "--resume");
690
- if (!hasResume) {
709
+ const hasResume = claudeArgs.includes("--continue") || claudeArgs.some((a) => a === "--resume");
710
+ if (!hasResume) {
711
+ const handoffContent = this.getHandoffContent();
712
+ if (handoffContent) {
691
713
  initialInput = handoffContent;
692
714
  console.log(chalk.gray(" Handoff context ready"));
693
715
  }
716
+ const theoryContent = this.getTheoryContent();
717
+ if (theoryContent) {
718
+ initialInput += (initialInput ? "\n\n---\n\n" : "") + `## Operating Theory (THEORY.MD)
719
+
720
+ ${theoryContent}`;
721
+ console.log(chalk.gray(" Theory context loaded"));
722
+ }
694
723
  }
695
724
  console.log();
696
725
  if (this.config.useSweep) {
@@ -6,7 +6,10 @@ const __dirname = __pathDirname(__filename);
6
6
  import { spawn } from "child_process";
7
7
  import * as path from "path";
8
8
  const codexSmPath = path.join(__dirname, "codex-sm.js");
9
- const args = ["--dangerously-skip-permissions", ...process.argv.slice(2)];
9
+ const args = [
10
+ "--dangerously-bypass-approvals-and-sandbox",
11
+ ...process.argv.slice(2)
12
+ ];
10
13
  const child = spawn("node", [codexSmPath, ...args], {
11
14
  stdio: "inherit",
12
15
  env: process.env
@@ -339,14 +339,12 @@ class CodexSM {
339
339
  action: "session_end",
340
340
  exitCode: code
341
341
  });
342
- if (process.env["LINEAR_API_KEY"]) {
343
- try {
344
- execSync("stackmemory linear sync", {
345
- stdio: "ignore",
346
- timeout: 1e4
347
- });
348
- } catch {
349
- }
342
+ try {
343
+ execSync("stackmemory linear sync", {
344
+ stdio: "ignore",
345
+ timeout: 1e4
346
+ });
347
+ } catch {
350
348
  }
351
349
  if (this.config.tracingEnabled) {
352
350
  const summary = trace.getExecutionSummary();
@@ -13,13 +13,6 @@ import {
13
13
  DEFAULT_WEIGHTS,
14
14
  DEFAULT_TOOL_SCORES
15
15
  } from "../../core/config/types.js";
16
- import {
17
- loadStorageConfig,
18
- enableChromaDB,
19
- disableChromaDB,
20
- getStorageModeDescription
21
- } from "../../core/config/storage-config.js";
22
- import inquirer from "inquirer";
23
16
  function createConfigCommand() {
24
17
  const config = new Command("config").description(
25
18
  "Manage StackMemory configuration"
@@ -363,80 +356,6 @@ Profile: ${profile}`));
363
356
  console.log(" \u2022 Profile usage frequency");
364
357
  console.log(" \u2022 Score trends over time");
365
358
  });
366
- const storageCmd = config.command("storage").description(
367
- `Manage storage configuration
368
-
369
- Storage Modes:
370
- sqlite (default): Local storage only, fast, no external dependencies
371
- hybrid: SQLite + ChromaDB for semantic search and cloud backup`
372
- );
373
- storageCmd.command("show").description("Show current storage configuration").action(async () => {
374
- const storageConfig = loadStorageConfig();
375
- console.log(chalk.blue("\nStorage Configuration:"));
376
- console.log(` Mode: ${chalk.cyan(storageConfig.mode)}`);
377
- console.log(` Description: ${chalk.gray(getStorageModeDescription())}`);
378
- if (storageConfig.chromadb.enabled) {
379
- console.log(chalk.blue("\nChromaDB Settings:"));
380
- console.log(` Enabled: ${chalk.green("Yes")}`);
381
- console.log(
382
- ` API URL: ${chalk.gray(storageConfig.chromadb.apiUrl || "https://api.trychroma.com")}`
383
- );
384
- console.log(
385
- ` Tenant: ${chalk.gray(storageConfig.chromadb.tenant || "default_tenant")}`
386
- );
387
- console.log(
388
- ` Database: ${chalk.gray(storageConfig.chromadb.database || "default_database")}`
389
- );
390
- console.log(
391
- ` API Key: ${chalk.gray(storageConfig.chromadb.apiKey ? "[configured]" : "[not set]")}`
392
- );
393
- } else {
394
- console.log(chalk.blue("\nChromaDB Settings:"));
395
- console.log(` Enabled: ${chalk.yellow("No")}`);
396
- console.log(
397
- chalk.gray(
398
- " Enable with: stackmemory config storage enable-chromadb"
399
- )
400
- );
401
- }
402
- });
403
- storageCmd.command("enable-chromadb").description("Enable ChromaDB for semantic search and cloud backup").option("--api-key <key>", "ChromaDB API key").option("--api-url <url>", "ChromaDB API URL", "https://api.trychroma.com").action(async (options) => {
404
- let apiKey = options.apiKey;
405
- if (!apiKey && process.stdin.isTTY) {
406
- const answers = await inquirer.prompt([
407
- {
408
- type: "password",
409
- name: "apiKey",
410
- message: "Enter your ChromaDB API key:",
411
- validate: (input) => {
412
- if (!input || input.trim().length === 0) {
413
- return "API key is required for ChromaDB";
414
- }
415
- return true;
416
- }
417
- }
418
- ]);
419
- apiKey = answers.apiKey;
420
- }
421
- if (!apiKey) {
422
- console.log(chalk.red("[ERROR] ChromaDB API key is required."));
423
- console.log(
424
- chalk.gray("Provide via --api-key flag or run interactively.")
425
- );
426
- process.exit(1);
427
- }
428
- enableChromaDB({
429
- apiKey,
430
- apiUrl: options.apiUrl
431
- });
432
- console.log(chalk.green("[OK] ChromaDB enabled successfully."));
433
- console.log(chalk.gray(`Storage mode: ${getStorageModeDescription()}`));
434
- });
435
- storageCmd.command("disable-chromadb").description("Disable ChromaDB and use SQLite-only storage").action(async () => {
436
- disableChromaDB();
437
- console.log(chalk.green("[OK] ChromaDB disabled."));
438
- console.log(chalk.gray(`Storage mode: ${getStorageModeDescription()}`));
439
- });
440
359
  return config;
441
360
  }
442
361
  export {
@@ -17,12 +17,16 @@ async function handleContextRehydrate(options) {
17
17
  const projectRoot = process.cwd();
18
18
  const dbPath = join(projectRoot, ".stackmemory", "context.db");
19
19
  if (!existsSync(dbPath)) {
20
- console.log('\u274C StackMemory not initialized. Run "stackmemory init" first.');
20
+ console.log(
21
+ '\u274C StackMemory not initialized. Run "stackmemory init" first.'
22
+ );
21
23
  return;
22
24
  }
23
25
  try {
24
26
  console.log("\u{1F504} Enhanced Context Rehydration System");
25
- console.log("\u{1F4DA} This system preserves rich context across Claude compactions\n");
27
+ console.log(
28
+ "\u{1F4DA} This system preserves rich context across Claude compactions\n"
29
+ );
26
30
  if (options.list) {
27
31
  await listCheckpoints();
28
32
  return;
@@ -66,7 +70,10 @@ async function handleContextRehydrate(options) {
66
70
  }
67
71
  } catch (error) {
68
72
  logger.error("Context rehydration error:", error);
69
- console.error("\u274C Failed to rehydrate context:", error instanceof Error ? error.message : error);
73
+ console.error(
74
+ "\u274C Failed to rehydrate context:",
75
+ error instanceof Error ? error.message : error
76
+ );
70
77
  process.exit(1);
71
78
  }
72
79
  }
@@ -101,7 +108,10 @@ async function createRehydrationCheckpoint(withTraces = false) {
101
108
  const checkpointPath = join(checkpointDir, `${checkpointId}.json`);
102
109
  await fs.writeFile(checkpointPath, JSON.stringify(checkpoint, null, 2));
103
110
  checkpoint.verification.files_captured = checkpoint.recent_files.length;
104
- checkpoint.verification.total_size = checkpoint.recent_files.reduce((sum, file) => sum + file.size, 0);
111
+ checkpoint.verification.total_size = checkpoint.recent_files.reduce(
112
+ (sum, file) => sum + file.size,
113
+ 0
114
+ );
105
115
  checkpoint.verification.integrity_hash = await calculateCheckpointHash(checkpoint);
106
116
  await fs.writeFile(checkpointPath, JSON.stringify(checkpoint, null, 2));
107
117
  console.log(`\u2705 Created checkpoint: ${checkpointId}`);
@@ -109,7 +119,9 @@ async function createRehydrationCheckpoint(withTraces = false) {
109
119
  console.log(`\u{1F4CA} Captured ${checkpoint.recent_files.length} recent files`);
110
120
  if (withTraces) {
111
121
  console.log(`\u{1F41B} Captured ${checkpoint.stack_traces.length} stack traces`);
112
- console.log(`\u{1F50D} Detected ${checkpoint.error_patterns.length} error patterns`);
122
+ console.log(
123
+ `\u{1F50D} Detected ${checkpoint.error_patterns.length} error patterns`
124
+ );
113
125
  }
114
126
  } catch (error) {
115
127
  console.error("\u274C Failed to create checkpoint:", error);
@@ -134,7 +146,10 @@ async function performRehydration(checkpointId) {
134
146
  }
135
147
  checkpointFiles.sort((a, b) => b.localeCompare(a));
136
148
  const latestFile = checkpointFiles[0];
137
- const content = await fs.readFile(join(checkpointDir, latestFile), "utf8");
149
+ const content = await fs.readFile(
150
+ join(checkpointDir, latestFile),
151
+ "utf8"
152
+ );
138
153
  checkpoint = JSON.parse(content);
139
154
  }
140
155
  console.log(`\u{1F504} Rehydrating from checkpoint: ${checkpoint.id}`);
@@ -143,11 +158,15 @@ async function performRehydration(checkpointId) {
143
158
  console.log(`\u{1F4CB} Recent files: ${checkpoint.recent_files.length}`);
144
159
  console.log("\n\u{1F4CA} Context Summary:");
145
160
  checkpoint.recent_files.slice(0, 5).forEach((file, i) => {
146
- console.log(` ${i + 1}. ${file.path} (${file.size} bytes, modified ${new Date(file.mtime).toLocaleString()})`);
161
+ console.log(
162
+ ` ${i + 1}. ${file.path} (${file.size} bytes, modified ${new Date(file.mtime).toLocaleString()})`
163
+ );
147
164
  });
148
165
  if (checkpoint.project_context.key_files.length > 0) {
149
- console.log(`
150
- \u{1F511} Key project files: ${checkpoint.project_context.key_files.join(", ")}`);
166
+ console.log(
167
+ `
168
+ \u{1F511} Key project files: ${checkpoint.project_context.key_files.join(", ")}`
169
+ );
151
170
  }
152
171
  return true;
153
172
  } catch (error) {
@@ -187,7 +206,12 @@ async function analyzeProjectContext() {
187
206
  framework: "unknown"
188
207
  };
189
208
  try {
190
- const projectFiles = ["package.json", "tsconfig.json", "README.md", "docker-compose.yml"];
209
+ const projectFiles = [
210
+ "package.json",
211
+ "tsconfig.json",
212
+ "README.md",
213
+ "docker-compose.yml"
214
+ ];
191
215
  for (const file of projectFiles) {
192
216
  try {
193
217
  await fs.access(file);
@@ -224,11 +248,15 @@ async function listCheckpoints() {
224
248
  const checkpoints = files.filter((f) => f.endsWith(".json"));
225
249
  if (checkpoints.length === 0) {
226
250
  console.log("\u{1F4ED} No rehydration checkpoints found");
227
- console.log("\u{1F4A1} Create one with: stackmemory context rehydrate --create");
251
+ console.log(
252
+ "\u{1F4A1} Create one with: stackmemory context rehydrate --create"
253
+ );
228
254
  return;
229
255
  }
230
- console.log(`\u{1F4CB} Found ${checkpoints.length} rehydration checkpoint(s):
231
- `);
256
+ console.log(
257
+ `\u{1F4CB} Found ${checkpoints.length} rehydration checkpoint(s):
258
+ `
259
+ );
232
260
  for (const file of checkpoints) {
233
261
  const id = file.replace(".json", "");
234
262
  const stats = await fs.stat(`${checkpointDir}/${file}`);
@@ -238,12 +266,16 @@ async function listCheckpoints() {
238
266
  console.log(`\u{1F516} ${id}`);
239
267
  console.log(` Created: ${stats.birthtime.toISOString()}`);
240
268
  console.log(` Size: ${(stats.size / 1024).toFixed(1)} KB`);
241
- console.log(` Files: ${checkpoint.verification?.files_captured || checkpoint.recent_files?.length || 0}`);
269
+ console.log(
270
+ ` Files: ${checkpoint.verification?.files_captured || checkpoint.recent_files?.length || 0}`
271
+ );
242
272
  if (checkpoint.stack_traces?.length > 0) {
243
273
  console.log(` Stack traces: ${checkpoint.stack_traces.length}`);
244
274
  }
245
275
  if (checkpoint.error_patterns?.length > 0) {
246
- console.log(` Error patterns: ${checkpoint.error_patterns.length}`);
276
+ console.log(
277
+ ` Error patterns: ${checkpoint.error_patterns.length}`
278
+ );
247
279
  }
248
280
  console.log("");
249
281
  } catch {
@@ -254,10 +286,14 @@ async function listCheckpoints() {
254
286
  }
255
287
  }
256
288
  console.log("\u{1F4A1} Use: stackmemory context rehydrate -c <checkpoint-id>");
257
- console.log("\u{1F4A1} Verify: stackmemory context rehydrate --verify -c <checkpoint-id>");
289
+ console.log(
290
+ "\u{1F4A1} Verify: stackmemory context rehydrate --verify -c <checkpoint-id>"
291
+ );
258
292
  } catch (err) {
259
293
  console.log("\u{1F4ED} No rehydration checkpoints directory found");
260
- console.log("\u{1F4A1} Create first checkpoint with: stackmemory context rehydrate --create");
294
+ console.log(
295
+ "\u{1F4A1} Create first checkpoint with: stackmemory context rehydrate --create"
296
+ );
261
297
  }
262
298
  } catch (error) {
263
299
  console.error("\u274C Failed to list checkpoints:", error);
@@ -291,7 +327,12 @@ async function verifyCheckpoint(checkpointPath) {
291
327
  const checkpoint = JSON.parse(content);
292
328
  const fileName = checkpointPath.split("/").pop()?.replace(".json", "") || "unknown";
293
329
  console.log(`\u{1F50D} Verifying checkpoint: ${fileName}`);
294
- const requiredFields = ["id", "timestamp", "working_directory", "recent_files"];
330
+ const requiredFields = [
331
+ "id",
332
+ "timestamp",
333
+ "working_directory",
334
+ "recent_files"
335
+ ];
295
336
  const missingFields = requiredFields.filter((field) => !checkpoint[field]);
296
337
  if (missingFields.length > 0) {
297
338
  console.log(`\u274C Missing required fields: ${missingFields.join(", ")}`);
@@ -299,8 +340,12 @@ async function verifyCheckpoint(checkpointPath) {
299
340
  }
300
341
  console.log(`\u{1F4C1} Files captured: ${checkpoint.recent_files?.length || 0}`);
301
342
  if (checkpoint.verification) {
302
- console.log(`\u{1F4CA} Total size: ${(checkpoint.verification.total_size / 1024).toFixed(1)} KB`);
303
- console.log(`\u{1F512} Integrity hash: ${checkpoint.verification.integrity_hash.slice(0, 12)}...`);
343
+ console.log(
344
+ `\u{1F4CA} Total size: ${(checkpoint.verification.total_size / 1024).toFixed(1)} KB`
345
+ );
346
+ console.log(
347
+ `\u{1F512} Integrity hash: ${checkpoint.verification.integrity_hash.slice(0, 12)}...`
348
+ );
304
349
  const recalculatedHash = await calculateCheckpointHash(checkpoint);
305
350
  if (recalculatedHash === checkpoint.verification.integrity_hash) {
306
351
  console.log(`\u2705 Integrity check: PASSED`);
@@ -310,8 +355,12 @@ async function verifyCheckpoint(checkpointPath) {
310
355
  }
311
356
  if (checkpoint.stack_traces) {
312
357
  console.log(`\u{1F41B} Stack traces: ${checkpoint.stack_traces.length}`);
313
- const pendingTraces = checkpoint.stack_traces.filter((t) => t.resolution_status === "pending");
314
- const resolvedTraces = checkpoint.stack_traces.filter((t) => t.resolution_status === "resolved");
358
+ const pendingTraces = checkpoint.stack_traces.filter(
359
+ (t) => t.resolution_status === "pending"
360
+ );
361
+ const resolvedTraces = checkpoint.stack_traces.filter(
362
+ (t) => t.resolution_status === "resolved"
363
+ );
315
364
  if (pendingTraces.length > 0) {
316
365
  console.log(` \u23F3 Pending resolution: ${pendingTraces.length}`);
317
366
  }
@@ -320,7 +369,9 @@ async function verifyCheckpoint(checkpointPath) {
320
369
  }
321
370
  }
322
371
  if (checkpoint.error_patterns?.length > 0) {
323
- console.log(`\u{1F50D} Error patterns detected: ${checkpoint.error_patterns.join(", ")}`);
372
+ console.log(
373
+ `\u{1F50D} Error patterns detected: ${checkpoint.error_patterns.join(", ")}`
374
+ );
324
375
  }
325
376
  console.log(`\u2705 Checkpoint verification complete`);
326
377
  } catch (error) {
@@ -357,7 +408,12 @@ async function captureStackTraces() {
357
408
  "logs/error.log",
358
409
  "tmp/cache/error.log"
359
410
  ];
360
- const allLogFiles = [...stackMemoryLogs, ...nodeLogs, ...buildLogs, ...frameworkLogs];
411
+ const allLogFiles = [
412
+ ...stackMemoryLogs,
413
+ ...nodeLogs,
414
+ ...buildLogs,
415
+ ...frameworkLogs
416
+ ];
361
417
  for (const logFile of allLogFiles) {
362
418
  await extractTracesFromLogFile(logFile, traces, fs);
363
419
  }
@@ -590,26 +646,34 @@ async function showStackTraces() {
590
646
  const projectRoot = process.cwd();
591
647
  const dbPath = join(projectRoot, ".stackmemory", "context.db");
592
648
  if (!existsSync(dbPath)) {
593
- console.log('\u274C StackMemory not initialized. Run "stackmemory init" first.');
649
+ console.log(
650
+ '\u274C StackMemory not initialized. Run "stackmemory init" first.'
651
+ );
594
652
  return;
595
653
  }
596
654
  const Database = (await import("better-sqlite3")).default;
597
655
  const db = new Database(dbPath);
598
656
  try {
599
- const tableExists = db.prepare(`
657
+ const tableExists = db.prepare(
658
+ `
600
659
  SELECT name FROM sqlite_master
601
660
  WHERE type='table' AND name='stack_traces'
602
- `).get();
661
+ `
662
+ ).get();
603
663
  if (!tableExists) {
604
664
  console.log("\u{1F4ED} No stack traces found in database");
605
- console.log("\u{1F4A1} Stack traces are stored when using enhanced rehydration features");
665
+ console.log(
666
+ "\u{1F4A1} Stack traces are stored when using enhanced rehydration features"
667
+ );
606
668
  return;
607
669
  }
608
- const traces = db.prepare(`
670
+ const traces = db.prepare(
671
+ `
609
672
  SELECT * FROM stack_traces
610
673
  ORDER BY created_at DESC
611
674
  LIMIT 20
612
- `).all();
675
+ `
676
+ ).all();
613
677
  if (traces.length === 0) {
614
678
  console.log("\u{1F4ED} No stack traces found in database");
615
679
  return;
@@ -620,9 +684,13 @@ async function showStackTraces() {
620
684
  const createdAt = new Date(trace.created_at * 1e3).toLocaleString();
621
685
  const severity = trace.error_severity || "medium";
622
686
  const severityIcon = severity === "high" ? "\u{1F534}" : severity === "low" ? "\u{1F7E1}" : "\u{1F7E0}";
623
- console.log(`${severityIcon} ${trace.error_type || "Error"} - ${severity.toUpperCase()}`);
687
+ console.log(
688
+ `${severityIcon} ${trace.error_type || "Error"} - ${severity.toUpperCase()}`
689
+ );
624
690
  console.log(` Message: ${trace.error_message}`);
625
- console.log(` File: ${trace.file_path || "unknown"}${trace.line_number ? `:${trace.line_number}` : ""}`);
691
+ console.log(
692
+ ` File: ${trace.file_path || "unknown"}${trace.line_number ? `:${trace.line_number}` : ""}`
693
+ );
626
694
  console.log(` Function: ${trace.function_name || "unknown"}`);
627
695
  console.log(` Status: ${trace.resolution_status}`);
628
696
  console.log(` Created: ${createdAt}`);
@@ -649,16 +717,20 @@ async function showStackTraceStats() {
649
717
  const projectRoot = process.cwd();
650
718
  const dbPath = join(projectRoot, ".stackmemory", "context.db");
651
719
  if (!existsSync(dbPath)) {
652
- console.log('\u274C StackMemory not initialized. Run "stackmemory init" first.');
720
+ console.log(
721
+ '\u274C StackMemory not initialized. Run "stackmemory init" first.'
722
+ );
653
723
  return;
654
724
  }
655
725
  const Database = (await import("better-sqlite3")).default;
656
726
  const db = new Database(dbPath);
657
727
  try {
658
- const tableExists = db.prepare(`
728
+ const tableExists = db.prepare(
729
+ `
659
730
  SELECT name FROM sqlite_master
660
731
  WHERE type='table' AND name='stack_traces'
661
- `).get();
732
+ `
733
+ ).get();
662
734
  if (!tableExists) {
663
735
  console.log("\u{1F4ED} No stack trace data available");
664
736
  return;
@@ -666,30 +738,37 @@ async function showStackTraceStats() {
666
738
  console.log("\u{1F4CA} Stack Trace Statistics\n");
667
739
  const totalTraces = db.prepare("SELECT COUNT(*) as count FROM stack_traces").get().count;
668
740
  console.log(`Total traces: ${totalTraces}`);
669
- const statusStats = db.prepare(`
741
+ const statusStats = db.prepare(
742
+ `
670
743
  SELECT resolution_status, COUNT(*) as count
671
744
  FROM stack_traces
672
745
  GROUP BY resolution_status
673
746
  ORDER BY count DESC
674
- `).all();
747
+ `
748
+ ).all();
675
749
  console.log("\n\u{1F4C8} By Resolution Status:");
676
750
  for (const stat of statusStats) {
677
751
  const percentage = (stat.count / totalTraces * 100).toFixed(1);
678
- console.log(` ${stat.resolution_status}: ${stat.count} (${percentage}%)`);
752
+ console.log(
753
+ ` ${stat.resolution_status}: ${stat.count} (${percentage}%)`
754
+ );
679
755
  }
680
- const typeStats = db.prepare(`
756
+ const typeStats = db.prepare(
757
+ `
681
758
  SELECT error_type, COUNT(*) as count
682
759
  FROM stack_traces
683
760
  GROUP BY error_type
684
761
  ORDER BY count DESC
685
762
  LIMIT 10
686
- `).all();
763
+ `
764
+ ).all();
687
765
  console.log("\n\u{1F50D} Top Error Types:");
688
766
  for (const stat of typeStats) {
689
767
  const percentage = (stat.count / totalTraces * 100).toFixed(1);
690
768
  console.log(` ${stat.error_type}: ${stat.count} (${percentage}%)`);
691
769
  }
692
- const severityStats = db.prepare(`
770
+ const severityStats = db.prepare(
771
+ `
693
772
  SELECT error_severity, COUNT(*) as count
694
773
  FROM stack_traces
695
774
  GROUP BY error_severity
@@ -699,28 +778,35 @@ async function showStackTraceStats() {
699
778
  WHEN 'medium' THEN 2
700
779
  WHEN 'low' THEN 3
701
780
  END
702
- `).all();
781
+ `
782
+ ).all();
703
783
  console.log("\n\u26A0\uFE0F By Severity:");
704
784
  for (const stat of severityStats) {
705
785
  const percentage = (stat.count / totalTraces * 100).toFixed(1);
706
786
  const icon = stat.error_severity === "high" ? "\u{1F534}" : stat.error_severity === "low" ? "\u{1F7E1}" : "\u{1F7E0}";
707
- console.log(` ${icon} ${stat.error_severity}: ${stat.count} (${percentage}%)`);
787
+ console.log(
788
+ ` ${icon} ${stat.error_severity}: ${stat.count} (${percentage}%)`
789
+ );
708
790
  }
709
- const recentTraces = db.prepare(`
791
+ const recentTraces = db.prepare(
792
+ `
710
793
  SELECT COUNT(*) as count
711
794
  FROM stack_traces
712
795
  WHERE created_at > (unixepoch() - 86400)
713
- `).get().count;
796
+ `
797
+ ).get().count;
714
798
  console.log(`
715
799
  \u{1F4C5} Recent Activity (24 hours): ${recentTraces} traces`);
716
- const fileStats = db.prepare(`
800
+ const fileStats = db.prepare(
801
+ `
717
802
  SELECT file_path, COUNT(*) as count
718
803
  FROM stack_traces
719
804
  WHERE file_path IS NOT NULL
720
805
  GROUP BY file_path
721
806
  ORDER BY count DESC
722
807
  LIMIT 5
723
- `).all();
808
+ `
809
+ ).all();
724
810
  if (fileStats.length > 0) {
725
811
  console.log("\n\u{1F5C2}\uFE0F Most Problematic Files:");
726
812
  for (const stat of fileStats) {