@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
@@ -31,7 +31,6 @@ import { LLMContextRetrieval } from "../../core/retrieval/index.js";
31
31
  import { DiscoveryHandlers } from "./handlers/discovery-handlers.js";
32
32
  import { DiffMemHandlers } from "./handlers/diffmem-handlers.js";
33
33
  import { GreptileHandlers } from "./handlers/greptile-handlers.js";
34
- import { GraphitiClient } from "../graphiti/client.js";
35
34
  import { fuzzyEdit } from "../../utils/fuzzy-edit.js";
36
35
  import { v4 as uuidv4 } from "uuid";
37
36
  import {
@@ -67,7 +66,6 @@ class LocalStackMemoryMCP {
67
66
  diffMemHandlers;
68
67
  greptileHandlers;
69
68
  providerHandlers = null;
70
- graphitiClient = null;
71
69
  pendingPlans = /* @__PURE__ */ new Map();
72
70
  constructor() {
73
71
  this.projectRoot = this.findProjectRoot();
@@ -142,15 +140,6 @@ class LocalStackMemoryMCP {
142
140
  this.diffMemHandlers = new DiffMemHandlers();
143
141
  this.greptileHandlers = new GreptileHandlers();
144
142
  this.initProviderHandlers();
145
- if (process.env.GRAPHITI_ENDPOINT) {
146
- this.graphitiClient = new GraphitiClient({
147
- endpoint: process.env.GRAPHITI_ENDPOINT,
148
- projectNamespace: process.env.STACKMEMORY_PROJECT_ID || this.projectId
149
- });
150
- logger.info("Graphiti client initialized", {
151
- endpoint: process.env.GRAPHITI_ENDPOINT
152
- });
153
- }
154
143
  this.setupHandlers();
155
144
  this.loadInitialContext();
156
145
  this.loadPendingPlans();
@@ -711,24 +700,6 @@ ${summary}...`, 0.8);
711
700
  properties: {}
712
701
  }
713
702
  },
714
- {
715
- name: "add_task_dependency",
716
- description: "Add dependency relationship between tasks",
717
- inputSchema: {
718
- type: "object",
719
- properties: {
720
- taskId: {
721
- type: "string",
722
- description: "Task that depends on another"
723
- },
724
- dependsOnId: {
725
- type: "string",
726
- description: "Task ID that this depends on"
727
- }
728
- },
729
- required: ["taskId", "dependsOnId"]
730
- }
731
- },
732
703
  {
733
704
  name: "linear_sync",
734
705
  description: "Sync tasks with Linear",
@@ -1087,51 +1058,6 @@ ${summary}...`, 0.8);
1087
1058
  properties: {}
1088
1059
  }
1089
1060
  },
1090
- // Graphiti tools (only active when GRAPHITI_ENDPOINT is set)
1091
- ...this.graphitiClient ? [
1092
- {
1093
- name: "graphiti_status",
1094
- description: "Check Graphiti temporal knowledge graph connection status",
1095
- inputSchema: {
1096
- type: "object",
1097
- properties: {}
1098
- }
1099
- },
1100
- {
1101
- name: "graphiti_query",
1102
- description: "Query the Graphiti temporal knowledge graph for entities, relations, and episodes",
1103
- inputSchema: {
1104
- type: "object",
1105
- properties: {
1106
- query: {
1107
- type: "string",
1108
- description: "Semantic text query"
1109
- },
1110
- entityTypes: {
1111
- type: "array",
1112
- items: { type: "string" },
1113
- description: 'Entity types to filter (e.g., ["Person", "File", "Issue"])'
1114
- },
1115
- validFrom: {
1116
- type: "number",
1117
- description: "Start of time window (epoch ms)"
1118
- },
1119
- validTo: {
1120
- type: "number",
1121
- description: "End of time window (epoch ms)"
1122
- },
1123
- maxHops: {
1124
- type: "number",
1125
- description: "Graph traversal depth (default 2)"
1126
- },
1127
- k: {
1128
- type: "number",
1129
- description: "Top-k results (default 20)"
1130
- }
1131
- }
1132
- }
1133
- }
1134
- ] : [],
1135
1061
  // Greptile tools (only active when GREPTILE_API_KEY is set)
1136
1062
  ...process.env.GREPTILE_API_KEY ? this.greptileHandlers.getToolDefinitions() : [],
1137
1063
  // Provider tools (only active when STACKMEMORY_MULTI_PROVIDER=true)
@@ -1299,9 +1225,6 @@ ${summary}...`, 0.8);
1299
1225
  case "get_task_metrics":
1300
1226
  result = await this.handleGetTaskMetrics(args);
1301
1227
  break;
1302
- case "add_task_dependency":
1303
- result = await this.handleAddTaskDependency(args);
1304
- break;
1305
1228
  case "linear_sync":
1306
1229
  result = await this.handleLinearSync(args);
1307
1230
  break;
@@ -1456,59 +1379,6 @@ ${summary}...`, 0.8);
1456
1379
  );
1457
1380
  }
1458
1381
  break;
1459
- // Graphiti tools
1460
- case "graphiti_status":
1461
- if (!this.graphitiClient) {
1462
- result = {
1463
- content: [
1464
- {
1465
- type: "text",
1466
- text: JSON.stringify({
1467
- connected: false,
1468
- message: "Graphiti integration disabled (GRAPHITI_ENDPOINT not set)"
1469
- })
1470
- }
1471
- ]
1472
- };
1473
- } else {
1474
- const status = await this.graphitiClient.getStatus();
1475
- result = {
1476
- content: [
1477
- { type: "text", text: JSON.stringify(status, null, 2) }
1478
- ]
1479
- };
1480
- }
1481
- break;
1482
- case "graphiti_query":
1483
- if (!this.graphitiClient) {
1484
- result = {
1485
- content: [
1486
- {
1487
- type: "text",
1488
- text: "Graphiti integration disabled (GRAPHITI_ENDPOINT not set)"
1489
- }
1490
- ]
1491
- };
1492
- } else {
1493
- const gCtx = await this.graphitiClient.queryTemporal({
1494
- query: args.query,
1495
- entityTypes: args.entityTypes,
1496
- validFrom: args.validFrom,
1497
- validTo: args.validTo,
1498
- maxHops: args.maxHops,
1499
- k: args.k
1500
- });
1501
- const text = gCtx.chunks.map((c) => c.text).join("\n\n");
1502
- result = {
1503
- content: [
1504
- {
1505
- type: "text",
1506
- text: text || `No results found (${gCtx.totalTokens} tokens searched)`
1507
- }
1508
- ]
1509
- };
1510
- }
1511
- break;
1512
1382
  default:
1513
1383
  throw new Error(`Unknown tool: ${name}`);
1514
1384
  }
@@ -14,7 +14,8 @@ class MCPToolDefinitions {
14
14
  ...this.getTraceTools(),
15
15
  ...this.getDiscoveryTools(),
16
16
  ...this.getEditTools(),
17
- ...this.getGraphitiTools()
17
+ ...this.getTeamTools(),
18
+ ...this.getCordTools()
18
19
  ];
19
20
  }
20
21
  /**
@@ -281,30 +282,6 @@ class MCPToolDefinitions {
281
282
  type: "object",
282
283
  properties: {}
283
284
  }
284
- },
285
- {
286
- name: "add_task_dependency",
287
- description: "Add dependency between tasks",
288
- inputSchema: {
289
- type: "object",
290
- properties: {
291
- task_id: {
292
- type: "string",
293
- description: "Task that depends on another"
294
- },
295
- depends_on: {
296
- type: "string",
297
- description: "Task that must be completed first"
298
- },
299
- dependency_type: {
300
- type: "string",
301
- enum: ["blocks", "related", "subtask"],
302
- default: "blocks",
303
- description: "Type of dependency"
304
- }
305
- },
306
- required: ["task_id", "depends_on"]
307
- }
308
285
  }
309
286
  ];
310
287
  }
@@ -415,7 +392,7 @@ class MCPToolDefinitions {
415
392
  return [
416
393
  {
417
394
  name: "get_traces",
418
- description: "Get execution traces with optional filtering",
395
+ description: "Get execution traces with optional filtering. Set analyze=true to run pattern analysis instead of listing traces.",
419
396
  inputSchema: {
420
397
  type: "object",
421
398
  properties: {
@@ -442,30 +419,21 @@ class MCPToolDefinitions {
442
419
  type: "boolean",
443
420
  default: false,
444
421
  description: "Include full trace context"
445
- }
446
- }
447
- }
448
- },
449
- {
450
- name: "analyze_traces",
451
- description: "Analyze trace patterns for insights",
452
- inputSchema: {
453
- type: "object",
454
- properties: {
422
+ },
423
+ analyze: {
424
+ type: "boolean",
425
+ default: false,
426
+ description: "Run analysis on traces instead of listing them"
427
+ },
455
428
  trace_id: {
456
429
  type: "string",
457
- description: "Specific trace to analyze"
430
+ description: "Specific trace to analyze (requires analyze=true)"
458
431
  },
459
432
  analysis_type: {
460
433
  type: "string",
461
434
  enum: ["performance", "patterns", "errors"],
462
435
  default: "performance",
463
- description: "Type of analysis to perform"
464
- },
465
- include_recommendations: {
466
- type: "boolean",
467
- default: true,
468
- description: "Include optimization recommendations"
436
+ description: "Type of analysis (requires analyze=true)"
469
437
  }
470
438
  }
471
439
  }
@@ -707,48 +675,207 @@ class MCPToolDefinitions {
707
675
  ];
708
676
  }
709
677
  /**
710
- * Graphiti knowledge graph tools
678
+ * Multi-agent team collaboration tools
711
679
  */
712
- getGraphitiTools() {
680
+ getTeamTools() {
713
681
  return [
714
682
  {
715
- name: "graphiti_status",
716
- description: "Check Graphiti temporal knowledge graph connection status",
683
+ name: "team_context_get",
684
+ description: "Get context from other agents working on the same project. Returns recent frames and shared anchors from other sessions.",
717
685
  inputSchema: {
718
686
  type: "object",
719
- properties: {}
687
+ properties: {
688
+ limit: {
689
+ type: "number",
690
+ default: 10,
691
+ description: "Max frames to return"
692
+ },
693
+ types: {
694
+ type: "array",
695
+ items: { type: "string" },
696
+ description: "Filter by frame types"
697
+ },
698
+ since: {
699
+ type: "number",
700
+ description: "Only frames created after this timestamp (epoch ms)"
701
+ }
702
+ }
703
+ }
704
+ },
705
+ {
706
+ name: "team_context_share",
707
+ description: "Share a piece of context with other agents working on the same project. Creates a high-priority anchor visible to team_context_get.",
708
+ inputSchema: {
709
+ type: "object",
710
+ properties: {
711
+ content: {
712
+ type: "string",
713
+ description: "The context to share"
714
+ },
715
+ type: {
716
+ type: "string",
717
+ enum: [
718
+ "FACT",
719
+ "DECISION",
720
+ "CONSTRAINT",
721
+ "INTERFACE_CONTRACT",
722
+ "TODO",
723
+ "RISK"
724
+ ],
725
+ default: "FACT",
726
+ description: "Type of context"
727
+ },
728
+ priority: {
729
+ type: "number",
730
+ minimum: 1,
731
+ maximum: 10,
732
+ default: 8,
733
+ description: "Priority level (1-10)"
734
+ }
735
+ },
736
+ required: ["content"]
720
737
  }
721
738
  },
722
739
  {
723
- name: "graphiti_query",
724
- description: "Query the Graphiti temporal knowledge graph for entities, relations, and episodes",
740
+ name: "team_search",
741
+ description: "Search across all agents' context in the project. Uses full-text search across all sessions.",
725
742
  inputSchema: {
726
743
  type: "object",
727
744
  properties: {
728
745
  query: {
729
746
  type: "string",
730
- description: "Semantic text query"
747
+ description: "Search query"
731
748
  },
732
- entityTypes: {
749
+ limit: {
750
+ type: "number",
751
+ default: 20,
752
+ description: "Maximum results to return"
753
+ },
754
+ include_events: {
755
+ type: "boolean",
756
+ default: false,
757
+ description: "Include events in results"
758
+ }
759
+ },
760
+ required: ["query"]
761
+ }
762
+ }
763
+ ];
764
+ }
765
+ /**
766
+ * Cord task orchestration tools
767
+ */
768
+ getCordTools() {
769
+ return [
770
+ {
771
+ name: "cord_spawn",
772
+ description: "Create a subtask with clean context (spawn). Child sees only its prompt and completed blocker results.",
773
+ inputSchema: {
774
+ type: "object",
775
+ properties: {
776
+ goal: {
777
+ type: "string",
778
+ description: "What this task should accomplish"
779
+ },
780
+ prompt: {
781
+ type: "string",
782
+ description: "Detailed instructions for the task"
783
+ },
784
+ blocked_by: {
733
785
  type: "array",
734
786
  items: { type: "string" },
735
- description: 'Entity types to filter (e.g., ["Person", "File", "Issue"])'
787
+ description: "Task IDs that must complete before this can start"
736
788
  },
737
- validFrom: {
738
- type: "number",
739
- description: "Start of time window (epoch ms)"
789
+ parent_id: {
790
+ type: "string",
791
+ description: "Parent task ID"
792
+ }
793
+ },
794
+ required: ["goal"]
795
+ }
796
+ },
797
+ {
798
+ name: "cord_fork",
799
+ description: "Create a subtask with full sibling context (fork). Child sees its prompt, blocker results, AND completed sibling results.",
800
+ inputSchema: {
801
+ type: "object",
802
+ properties: {
803
+ goal: {
804
+ type: "string",
805
+ description: "What this task should accomplish"
740
806
  },
741
- validTo: {
742
- type: "number",
743
- description: "End of time window (epoch ms)"
807
+ prompt: {
808
+ type: "string",
809
+ description: "Detailed instructions for the task"
744
810
  },
745
- maxHops: {
746
- type: "number",
747
- description: "Graph traversal depth (default 2)"
811
+ blocked_by: {
812
+ type: "array",
813
+ items: { type: "string" },
814
+ description: "Task IDs that must complete before this can start"
748
815
  },
749
- k: {
750
- type: "number",
751
- description: "Top-k results (default 20)"
816
+ parent_id: {
817
+ type: "string",
818
+ description: "Parent task ID"
819
+ }
820
+ },
821
+ required: ["goal"]
822
+ }
823
+ },
824
+ {
825
+ name: "cord_complete",
826
+ description: "Mark a cord task as completed with a result. Automatically unblocks dependent tasks.",
827
+ inputSchema: {
828
+ type: "object",
829
+ properties: {
830
+ task_id: {
831
+ type: "string",
832
+ description: "Task ID to complete"
833
+ },
834
+ result: {
835
+ type: "string",
836
+ description: "The result/output of this task"
837
+ }
838
+ },
839
+ required: ["task_id", "result"]
840
+ }
841
+ },
842
+ {
843
+ name: "cord_ask",
844
+ description: "Create an ask task \u2014 a question that needs an answer before dependent tasks can proceed.",
845
+ inputSchema: {
846
+ type: "object",
847
+ properties: {
848
+ question: {
849
+ type: "string",
850
+ description: "The question to ask"
851
+ },
852
+ options: {
853
+ type: "array",
854
+ items: { type: "string" },
855
+ description: "Optional list of answer choices"
856
+ },
857
+ parent_id: {
858
+ type: "string",
859
+ description: "Parent task ID"
860
+ }
861
+ },
862
+ required: ["question"]
863
+ }
864
+ },
865
+ {
866
+ name: "cord_tree",
867
+ description: "View the cord task tree with context scoping. Shows which tasks are active, blocked, or completed.",
868
+ inputSchema: {
869
+ type: "object",
870
+ properties: {
871
+ task_id: {
872
+ type: "string",
873
+ description: "Root task ID to show subtree (omit for full project tree)"
874
+ },
875
+ include_results: {
876
+ type: "boolean",
877
+ default: false,
878
+ description: "Include task results in output"
752
879
  }
753
880
  }
754
881
  }
@@ -778,8 +905,10 @@ class MCPToolDefinitions {
778
905
  return this.getDiscoveryTools();
779
906
  case "edit":
780
907
  return this.getEditTools();
781
- case "graphiti":
782
- return this.getGraphitiTools();
908
+ case "team":
909
+ return this.getTeamTools();
910
+ case "cord":
911
+ return this.getCordTools();
783
912
  default:
784
913
  return [];
785
914
  }
@@ -115,14 +115,22 @@ class ContextBudgetManager {
115
115
  const reductionRatio = this.config.maxTokens / currentTokens;
116
116
  const phase = this.determinePhase(context.task.currentIteration);
117
117
  const adjustedWeights = this.getPhaseAdjustedWeights(phase);
118
- return this.applyWeightedReduction(context, reductionRatio, adjustedWeights);
118
+ return this.applyWeightedReduction(
119
+ context,
120
+ reductionRatio,
121
+ adjustedWeights
122
+ );
119
123
  }
120
124
  /**
121
125
  * Priority-based allocation using fixed weights
122
126
  */
123
127
  priorityBasedAllocation(context, currentTokens) {
124
128
  const reductionRatio = this.config.maxTokens / currentTokens;
125
- return this.applyWeightedReduction(context, reductionRatio, this.config.priorityWeights);
129
+ return this.applyWeightedReduction(
130
+ context,
131
+ reductionRatio,
132
+ this.config.priorityWeights
133
+ );
126
134
  }
127
135
  /**
128
136
  * Apply weighted reduction to context
@@ -46,7 +46,10 @@ class StackMemoryContextLoader {
46
46
  await sharedContextLayer.initialize();
47
47
  const session = await sessionManager.getOrCreateSession({});
48
48
  if (session.database) {
49
- this.frameManager = new FrameManager(session.database, session.projectId);
49
+ this.frameManager = new FrameManager(
50
+ session.database,
51
+ session.projectId
52
+ );
50
53
  this.contextRetriever = new ContextRetriever(session.database);
51
54
  }
52
55
  logger.info("Context loader initialized successfully");
@@ -115,17 +118,25 @@ class StackMemoryContextLoader {
115
118
  totalTokens += sources[sources.length - 1].tokens;
116
119
  }
117
120
  const budgetedSources = this.budgetManager.allocateBudget({ sources });
118
- const synthesizedContext = this.synthesizeContext(budgetedSources.sources);
121
+ const synthesizedContext = this.synthesizeContext(
122
+ budgetedSources.sources
123
+ );
119
124
  logger.info("Context loaded successfully", {
120
125
  totalSources: sources.length,
121
126
  totalTokens,
122
- budgetedTokens: budgetedSources.sources.reduce((sum, s) => sum + s.tokens, 0)
127
+ budgetedTokens: budgetedSources.sources.reduce(
128
+ (sum, s) => sum + s.tokens,
129
+ 0
130
+ )
123
131
  });
124
132
  return {
125
133
  context: synthesizedContext,
126
134
  sources: budgetedSources.sources,
127
135
  metadata: {
128
- totalTokens: budgetedSources.sources.reduce((sum, s) => sum + s.tokens, 0),
136
+ totalTokens: budgetedSources.sources.reduce(
137
+ (sum, s) => sum + s.tokens,
138
+ 0
139
+ ),
129
140
  sourcesCount: budgetedSources.sources.length,
130
141
  patterns: request.usePatterns ? patterns : [],
131
142
  similarTasks: request.useSimilarTasks ? similarTasks : []
@@ -144,16 +155,22 @@ class StackMemoryContextLoader {
144
155
  return [];
145
156
  }
146
157
  try {
147
- const searchResults = await this.contextRetriever.search(taskDescription, {
148
- maxResults: 10,
149
- types: ["task", "subtask"],
150
- timeFilter: {
151
- days: this.config.lookbackDays
158
+ const searchResults = await this.contextRetriever.search(
159
+ taskDescription,
160
+ {
161
+ maxResults: 10,
162
+ types: ["task", "subtask"],
163
+ timeFilter: {
164
+ days: this.config.lookbackDays
165
+ }
152
166
  }
153
- });
167
+ );
154
168
  const similarities = [];
155
169
  for (const result of searchResults) {
156
- const similarity = this.calculateTaskSimilarity(taskDescription, result.content);
170
+ const similarity = this.calculateTaskSimilarity(
171
+ taskDescription,
172
+ result.content
173
+ );
157
174
  if (similarity >= this.config.similarityThreshold) {
158
175
  similarities.push({
159
176
  frameId: result.frameId,
@@ -184,7 +201,10 @@ class StackMemoryContextLoader {
184
201
  if (!context) return [];
185
202
  const relevantPatterns = [];
186
203
  for (const pattern of context.globalPatterns) {
187
- const relevance = this.calculatePatternRelevance(taskDescription, pattern.pattern);
204
+ const relevance = this.calculatePatternRelevance(
205
+ taskDescription,
206
+ pattern.pattern
207
+ );
188
208
  if (relevance >= 0.5) {
189
209
  relevantPatterns.push({
190
210
  pattern: pattern.pattern,
@@ -197,7 +217,9 @@ class StackMemoryContextLoader {
197
217
  });
198
218
  }
199
219
  }
200
- return relevantPatterns.sort((a, b) => b.relevance * Math.log(b.frequency + 1) - a.relevance * Math.log(a.frequency + 1)).slice(0, 8);
220
+ return relevantPatterns.sort(
221
+ (a, b) => b.relevance * Math.log(b.frequency + 1) - a.relevance * Math.log(a.frequency + 1)
222
+ ).slice(0, 8);
201
223
  } catch (error) {
202
224
  logger.error("Failed to extract patterns", error);
203
225
  return [];
@@ -270,12 +292,14 @@ class StackMemoryContextLoader {
270
292
  const contextParts = [];
271
293
  contextParts.push("Similar tasks from history:");
272
294
  for (const sim of similarities) {
273
- contextParts.push(`
295
+ contextParts.push(
296
+ `
274
297
  Task: ${sim.task}
275
298
  Outcome: ${sim.outcome}
276
299
  Similarity: ${Math.round(sim.similarity * 100)}%
277
300
  ${sim.outcome === "success" ? "\u2705 Successfully completed" : "\u274C Had issues"}
278
- `.trim());
301
+ `.trim()
302
+ );
279
303
  }
280
304
  return contextParts.join("\n\n");
281
305
  }
@@ -286,13 +310,15 @@ ${sim.outcome === "success" ? "\u2705 Successfully completed" : "\u274C Had issu
286
310
  const contextParts = [];
287
311
  contextParts.push("Relevant patterns from experience:");
288
312
  for (const pattern of patterns2) {
289
- contextParts.push(`
313
+ contextParts.push(
314
+ `
290
315
  Pattern: ${pattern.pattern}
291
316
  Type: ${pattern.type}
292
317
  Frequency: ${pattern.frequency} occurrences
293
318
  ${pattern.resolution ? `Resolution: ${pattern.resolution}` : ""}
294
319
  Relevance: ${Math.round(pattern.relevance * 100)}%
295
- `.trim());
320
+ `.trim()
321
+ );
296
322
  }
297
323
  return contextParts.join("\n\n");
298
324
  }
@@ -303,11 +329,13 @@ Relevance: ${Math.round(pattern.relevance * 100)}%
303
329
  const contextParts = [];
304
330
  contextParts.push("Recent successful decisions:");
305
331
  for (const decision of decisions) {
306
- contextParts.push(`
332
+ contextParts.push(
333
+ `
307
334
  Decision: ${decision.decision}
308
335
  Reasoning: ${decision.reasoning}
309
336
  Date: ${new Date(decision.timestamp).toLocaleDateString()}
310
- `.trim());
337
+ `.trim()
338
+ );
311
339
  }
312
340
  return contextParts.join("\n\n");
313
341
  }
@@ -322,11 +350,15 @@ Date: ${new Date(decision.timestamp).toLocaleDateString()}
322
350
  contextParts.push("Context from StackMemory:");
323
351
  const sortedSources = sources.sort((a, b) => b.weight - a.weight);
324
352
  for (const source of sortedSources) {
325
- contextParts.push(`
326
- --- ${source.type.replace("_", " ").toUpperCase()} ---`);
353
+ contextParts.push(
354
+ `
355
+ --- ${source.type.replace("_", " ").toUpperCase()} ---`
356
+ );
327
357
  contextParts.push(source.content);
328
358
  }
329
- contextParts.push("\nUse this context to inform your approach to the current task.");
359
+ contextParts.push(
360
+ "\nUse this context to inform your approach to the current task."
361
+ );
330
362
  return contextParts.join("\n");
331
363
  }
332
364
  /**