@stackmemoryai/stackmemory 1.2.1 → 1.2.4

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 (100) hide show
  1. package/dist/src/cli/codex-sm.js +6 -8
  2. package/dist/src/cli/commands/config.js +0 -81
  3. package/dist/src/cli/commands/context-rehydrate.js +133 -47
  4. package/dist/src/cli/commands/db.js +35 -8
  5. package/dist/src/cli/commands/handoff.js +1 -1
  6. package/dist/src/cli/commands/linear.js +9 -0
  7. package/dist/src/cli/commands/ralph.js +2 -2
  8. package/dist/src/cli/commands/setup.js +2 -2
  9. package/dist/src/cli/commands/signup.js +3 -1
  10. package/dist/src/cli/commands/skills.js +123 -1
  11. package/dist/src/cli/commands/storage-tier.js +26 -8
  12. package/dist/src/cli/index.js +1 -57
  13. package/dist/src/core/config/feature-flags.js +0 -4
  14. package/dist/src/core/context/dual-stack-manager.js +10 -3
  15. package/dist/src/core/context/frame-database.js +32 -0
  16. package/dist/src/core/context/frame-handoff-manager.js +2 -2
  17. package/dist/src/core/context/{refactored-frame-manager.js → frame-manager.js} +3 -3
  18. package/dist/src/core/context/index.js +2 -2
  19. package/dist/src/core/database/sqlite-adapter.js +161 -1
  20. package/dist/src/core/digest/frame-digest-integration.js +1 -1
  21. package/dist/src/core/digest/index.js +1 -1
  22. package/dist/src/core/execution/parallel-executor.js +5 -1
  23. package/dist/src/core/projects/project-isolation.js +18 -4
  24. package/dist/src/core/security/index.js +2 -0
  25. package/dist/src/core/security/input-sanitizer.js +23 -0
  26. package/dist/src/core/utils/update-checker.js +10 -6
  27. package/dist/src/daemon/daemon-config.js +2 -1
  28. package/dist/src/daemon/services/auto-save-service.js +121 -0
  29. package/dist/src/daemon/services/maintenance-service.js +76 -1
  30. package/dist/src/features/sweep/prompt-builder.js +2 -2
  31. package/dist/src/hooks/graphiti-hooks.js +149 -0
  32. package/dist/src/hooks/session-summary.js +30 -0
  33. package/dist/src/integrations/graphiti/linear-graphiti-bridge.js +115 -0
  34. package/dist/src/integrations/greptile/client.js +101 -0
  35. package/dist/src/integrations/greptile/config.js +14 -0
  36. package/dist/src/integrations/greptile/index.js +11 -0
  37. package/dist/src/integrations/greptile/types.js +4 -0
  38. package/dist/src/integrations/linear/config.js +3 -1
  39. package/dist/src/integrations/linear/sync.js +18 -5
  40. package/dist/src/integrations/linear/webhook.js +16 -0
  41. package/dist/src/integrations/mcp/handlers/code-execution-handlers.js +33 -7
  42. package/dist/src/integrations/mcp/handlers/cord-handlers.js +397 -0
  43. package/dist/src/integrations/mcp/handlers/greptile-handlers.js +456 -0
  44. package/dist/src/integrations/mcp/handlers/index.js +55 -1
  45. package/dist/src/integrations/mcp/handlers/task-handlers.js +55 -12
  46. package/dist/src/integrations/mcp/handlers/team-handlers.js +211 -0
  47. package/dist/src/integrations/mcp/handlers/trace-handlers.js +25 -9
  48. package/dist/src/integrations/mcp/index.js +2 -2
  49. package/dist/src/integrations/mcp/refactored-server.js +31 -10
  50. package/dist/src/integrations/mcp/server.js +27 -0
  51. package/dist/src/integrations/mcp/tool-definitions.js +215 -1
  52. package/dist/src/integrations/ralph/context/context-budget-manager.js +10 -2
  53. package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +54 -22
  54. package/dist/src/integrations/ralph/learning/pattern-learner.js +59 -24
  55. package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +81 -35
  56. package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +12 -4
  57. package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +32 -9
  58. package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +25 -8
  59. package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +17 -5
  60. package/dist/src/integrations/ralph/visualization/ralph-debugger.js +73 -22
  61. package/dist/src/skills/claude-skills.js +46 -103
  62. package/dist/src/skills/parallel-agent-skill.js +514 -0
  63. package/dist/src/utils/hook-installer.js +8 -0
  64. package/package.json +5 -5
  65. package/scripts/gepa/.before-optimize.md +140 -159
  66. package/scripts/gepa/config.json +7 -1
  67. package/scripts/gepa/evals/fixtures/api-endpoint.ts +31 -0
  68. package/scripts/gepa/evals/fixtures/brittle-integration.ts +38 -0
  69. package/scripts/gepa/evals/fixtures/fts5-triggers.sql +23 -0
  70. package/scripts/gepa/evals/fixtures/leaky-service.ts +70 -0
  71. package/scripts/gepa/evals/fixtures/mcp-dispatch-stub.ts +39 -0
  72. package/scripts/gepa/evals/fixtures/pr-diff.txt +24 -0
  73. package/scripts/gepa/evals/fixtures/unsafe-webhook.ts +34 -0
  74. package/scripts/gepa/evals/fixtures/unwrapped-db-op.ts +42 -0
  75. package/scripts/gepa/evals/stackmemory-tasks.jsonl +8 -0
  76. package/scripts/gepa/generations/gen-000/baseline.md +172 -159
  77. package/scripts/gepa/generations/gen-001/baseline.md +172 -159
  78. package/scripts/gepa/generations/gen-001/variant-a.md +156 -146
  79. package/scripts/gepa/generations/gen-001/variant-b.md +199 -170
  80. package/scripts/gepa/generations/gen-001/variant-c.md +127 -46
  81. package/scripts/gepa/generations/gen-001/variant-d.md +160 -107
  82. package/scripts/gepa/hooks/reflect.js +44 -5
  83. package/scripts/gepa/optimize.js +281 -39
  84. package/scripts/gepa/results/eval-1-baseline.json +187 -10
  85. package/scripts/gepa/results/eval-1-variant-a.json +188 -11
  86. package/scripts/gepa/results/eval-1-variant-b.json +188 -11
  87. package/scripts/gepa/results/eval-1-variant-c.json +168 -11
  88. package/scripts/gepa/results/eval-1-variant-d.json +169 -12
  89. package/scripts/gepa/state.json +18 -18
  90. package/scripts/install-claude-hooks-auto.js +8 -0
  91. package/templates/claude-hooks/cord-trace.js +225 -0
  92. package/dist/src/core/config/storage-config.js +0 -114
  93. package/dist/src/core/storage/chromadb-adapter.js +0 -379
  94. package/dist/src/integrations/claude-code/enhanced-pre-clear-hooks.js +0 -458
  95. package/dist/src/integrations/ralph/coordination/enhanced-coordination.js +0 -409
  96. package/dist/src/skills/repo-ingestion-skill.js +0 -631
  97. package/templates/claude-hooks/chromadb-wrapper +0 -21
  98. /package/dist/src/core/context/{enhanced-rehydration.js → rehydration.js} +0 -0
  99. /package/dist/src/core/digest/{enhanced-hybrid-digest.js → hybrid-digest.js} +0 -0
  100. /package/dist/src/core/session/{enhanced-handoff.js → handoff.js} +0 -0
@@ -14,7 +14,9 @@ class MCPToolDefinitions {
14
14
  ...this.getTraceTools(),
15
15
  ...this.getDiscoveryTools(),
16
16
  ...this.getEditTools(),
17
- ...this.getGraphitiTools()
17
+ ...this.getGraphitiTools(),
18
+ ...this.getTeamTools(),
19
+ ...this.getCordTools()
18
20
  ];
19
21
  }
20
22
  /**
@@ -755,6 +757,214 @@ class MCPToolDefinitions {
755
757
  }
756
758
  ];
757
759
  }
760
+ /**
761
+ * Multi-agent team collaboration tools
762
+ */
763
+ getTeamTools() {
764
+ return [
765
+ {
766
+ name: "team_context_get",
767
+ description: "Get context from other agents working on the same project. Returns recent frames and shared anchors from other sessions.",
768
+ inputSchema: {
769
+ type: "object",
770
+ properties: {
771
+ limit: {
772
+ type: "number",
773
+ default: 10,
774
+ description: "Max frames to return"
775
+ },
776
+ types: {
777
+ type: "array",
778
+ items: { type: "string" },
779
+ description: "Filter by frame types"
780
+ },
781
+ since: {
782
+ type: "number",
783
+ description: "Only frames created after this timestamp (epoch ms)"
784
+ }
785
+ }
786
+ }
787
+ },
788
+ {
789
+ name: "team_context_share",
790
+ description: "Share a piece of context with other agents working on the same project. Creates a high-priority anchor visible to team_context_get.",
791
+ inputSchema: {
792
+ type: "object",
793
+ properties: {
794
+ content: {
795
+ type: "string",
796
+ description: "The context to share"
797
+ },
798
+ type: {
799
+ type: "string",
800
+ enum: [
801
+ "FACT",
802
+ "DECISION",
803
+ "CONSTRAINT",
804
+ "INTERFACE_CONTRACT",
805
+ "TODO",
806
+ "RISK"
807
+ ],
808
+ default: "FACT",
809
+ description: "Type of context"
810
+ },
811
+ priority: {
812
+ type: "number",
813
+ minimum: 1,
814
+ maximum: 10,
815
+ default: 8,
816
+ description: "Priority level (1-10)"
817
+ }
818
+ },
819
+ required: ["content"]
820
+ }
821
+ },
822
+ {
823
+ name: "team_search",
824
+ description: "Search across all agents' context in the project. Uses full-text search across all sessions.",
825
+ inputSchema: {
826
+ type: "object",
827
+ properties: {
828
+ query: {
829
+ type: "string",
830
+ description: "Search query"
831
+ },
832
+ limit: {
833
+ type: "number",
834
+ default: 20,
835
+ description: "Maximum results to return"
836
+ },
837
+ include_events: {
838
+ type: "boolean",
839
+ default: false,
840
+ description: "Include events in results"
841
+ }
842
+ },
843
+ required: ["query"]
844
+ }
845
+ }
846
+ ];
847
+ }
848
+ /**
849
+ * Cord task orchestration tools
850
+ */
851
+ getCordTools() {
852
+ return [
853
+ {
854
+ name: "cord_spawn",
855
+ description: "Create a subtask with clean context (spawn). Child sees only its prompt and completed blocker results.",
856
+ inputSchema: {
857
+ type: "object",
858
+ properties: {
859
+ goal: {
860
+ type: "string",
861
+ description: "What this task should accomplish"
862
+ },
863
+ prompt: {
864
+ type: "string",
865
+ description: "Detailed instructions for the task"
866
+ },
867
+ blocked_by: {
868
+ type: "array",
869
+ items: { type: "string" },
870
+ description: "Task IDs that must complete before this can start"
871
+ },
872
+ parent_id: {
873
+ type: "string",
874
+ description: "Parent task ID"
875
+ }
876
+ },
877
+ required: ["goal"]
878
+ }
879
+ },
880
+ {
881
+ name: "cord_fork",
882
+ description: "Create a subtask with full sibling context (fork). Child sees its prompt, blocker results, AND completed sibling results.",
883
+ inputSchema: {
884
+ type: "object",
885
+ properties: {
886
+ goal: {
887
+ type: "string",
888
+ description: "What this task should accomplish"
889
+ },
890
+ prompt: {
891
+ type: "string",
892
+ description: "Detailed instructions for the task"
893
+ },
894
+ blocked_by: {
895
+ type: "array",
896
+ items: { type: "string" },
897
+ description: "Task IDs that must complete before this can start"
898
+ },
899
+ parent_id: {
900
+ type: "string",
901
+ description: "Parent task ID"
902
+ }
903
+ },
904
+ required: ["goal"]
905
+ }
906
+ },
907
+ {
908
+ name: "cord_complete",
909
+ description: "Mark a cord task as completed with a result. Automatically unblocks dependent tasks.",
910
+ inputSchema: {
911
+ type: "object",
912
+ properties: {
913
+ task_id: {
914
+ type: "string",
915
+ description: "Task ID to complete"
916
+ },
917
+ result: {
918
+ type: "string",
919
+ description: "The result/output of this task"
920
+ }
921
+ },
922
+ required: ["task_id", "result"]
923
+ }
924
+ },
925
+ {
926
+ name: "cord_ask",
927
+ description: "Create an ask task \u2014 a question that needs an answer before dependent tasks can proceed.",
928
+ inputSchema: {
929
+ type: "object",
930
+ properties: {
931
+ question: {
932
+ type: "string",
933
+ description: "The question to ask"
934
+ },
935
+ options: {
936
+ type: "array",
937
+ items: { type: "string" },
938
+ description: "Optional list of answer choices"
939
+ },
940
+ parent_id: {
941
+ type: "string",
942
+ description: "Parent task ID"
943
+ }
944
+ },
945
+ required: ["question"]
946
+ }
947
+ },
948
+ {
949
+ name: "cord_tree",
950
+ description: "View the cord task tree with context scoping. Shows which tasks are active, blocked, or completed.",
951
+ inputSchema: {
952
+ type: "object",
953
+ properties: {
954
+ task_id: {
955
+ type: "string",
956
+ description: "Root task ID to show subtree (omit for full project tree)"
957
+ },
958
+ include_results: {
959
+ type: "boolean",
960
+ default: false,
961
+ description: "Include task results in output"
962
+ }
963
+ }
964
+ }
965
+ }
966
+ ];
967
+ }
758
968
  /**
759
969
  * Get tool definition by name
760
970
  */
@@ -780,6 +990,10 @@ class MCPToolDefinitions {
780
990
  return this.getEditTools();
781
991
  case "graphiti":
782
992
  return this.getGraphitiTools();
993
+ case "team":
994
+ return this.getTeamTools();
995
+ case "cord":
996
+ return this.getCordTools();
783
997
  default:
784
998
  return [];
785
999
  }
@@ -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
  /**
@@ -25,7 +25,10 @@ class PatternLearner {
25
25
  await sharedContextLayer.initialize();
26
26
  const session = await sessionManager.getOrCreateSession({});
27
27
  if (session.database) {
28
- this.frameManager = new FrameManager(session.database, session.projectId);
28
+ this.frameManager = new FrameManager(
29
+ session.database,
30
+ session.projectId
31
+ );
29
32
  }
30
33
  logger.info("Pattern learner initialized successfully");
31
34
  } catch (error) {
@@ -40,7 +43,9 @@ class PatternLearner {
40
43
  logger.info("Starting pattern learning from completed loops");
41
44
  try {
42
45
  const completedLoops = await this.getCompletedRalphLoops();
43
- logger.info(`Found ${completedLoops.length} completed loops for analysis`);
46
+ logger.info(
47
+ `Found ${completedLoops.length} completed loops for analysis`
48
+ );
44
49
  if (completedLoops.length < this.config.minLoopCountForPattern) {
45
50
  logger.info("Not enough loops for pattern extraction");
46
51
  return [];
@@ -55,7 +60,9 @@ class PatternLearner {
55
60
  const taskPatterns = await this.extractTaskPatterns(completedLoops);
56
61
  patterns.push(...taskPatterns);
57
62
  await this.saveLearnedPatterns(patterns);
58
- logger.info(`Learned ${patterns.length} patterns from ${completedLoops.length} loops`);
63
+ logger.info(
64
+ `Learned ${patterns.length} patterns from ${completedLoops.length} loops`
65
+ );
59
66
  return patterns;
60
67
  } catch (error) {
61
68
  logger.error("Failed to learn patterns", error);
@@ -97,7 +104,10 @@ class PatternLearner {
97
104
  analyses.push(analysis);
98
105
  }
99
106
  } catch (error) {
100
- logger.warn(`Failed to analyze loop ${frame.frame_id}`, error);
107
+ logger.warn(
108
+ `Failed to analyze loop ${frame.frame_id}`,
109
+ error
110
+ );
101
111
  }
102
112
  }
103
113
  return analyses;
@@ -159,15 +169,21 @@ class PatternLearner {
159
169
  examples: successfulLoops.slice(0, 3).map((l) => l.task),
160
170
  metadata: {
161
171
  avgIterations,
162
- minIterations: Math.min(...successfulLoops.map((l) => l.iterationCount)),
163
- maxIterations: Math.max(...successfulLoops.map((l) => l.iterationCount))
172
+ minIterations: Math.min(
173
+ ...successfulLoops.map((l) => l.iterationCount)
174
+ ),
175
+ maxIterations: Math.max(
176
+ ...successfulLoops.map((l) => l.iterationCount)
177
+ )
164
178
  }
165
179
  });
166
180
  const criteriaPatterns = this.extractCriteriaPatterns(successfulLoops);
167
181
  patterns.push(...criteriaPatterns);
168
182
  const successFactors = this.extractSuccessFactors(successfulLoops);
169
183
  patterns.push(...successFactors);
170
- return patterns.filter((p) => p.confidence >= this.config.confidenceThreshold);
184
+ return patterns.filter(
185
+ (p) => p.confidence >= this.config.confidenceThreshold
186
+ );
171
187
  }
172
188
  /**
173
189
  * Extract patterns from failed loops to avoid
@@ -191,7 +207,9 @@ class PatternLearner {
191
207
  metadata: { failureType: failure.type }
192
208
  });
193
209
  }
194
- return patterns.filter((p) => p.confidence >= this.config.confidenceThreshold);
210
+ return patterns.filter(
211
+ (p) => p.confidence >= this.config.confidenceThreshold
212
+ );
195
213
  }
196
214
  /**
197
215
  * Extract iteration-specific patterns
@@ -223,7 +241,10 @@ class PatternLearner {
223
241
  const patterns = [];
224
242
  for (const [taskType, taskLoops] of Object.entries(taskGroups)) {
225
243
  if (taskLoops.length >= this.config.minLoopCountForPattern) {
226
- const taskSpecificPatterns = await this.extractSpecializedPatterns(taskLoops, taskType);
244
+ const taskSpecificPatterns = await this.extractSpecializedPatterns(
245
+ taskLoops,
246
+ taskType
247
+ );
227
248
  patterns.push(...taskSpecificPatterns);
228
249
  }
229
250
  }
@@ -266,12 +287,15 @@ class PatternLearner {
266
287
  */
267
288
  classifyTaskType(task) {
268
289
  const taskLower = task.toLowerCase();
269
- if (taskLower.includes("test") || taskLower.includes("unit")) return "testing";
290
+ if (taskLower.includes("test") || taskLower.includes("unit"))
291
+ return "testing";
270
292
  if (taskLower.includes("fix") || taskLower.includes("bug")) return "bugfix";
271
293
  if (taskLower.includes("refactor")) return "refactoring";
272
- if (taskLower.includes("add") || taskLower.includes("implement")) return "feature";
294
+ if (taskLower.includes("add") || taskLower.includes("implement"))
295
+ return "feature";
273
296
  if (taskLower.includes("document")) return "documentation";
274
- if (taskLower.includes("optimize") || taskLower.includes("performance")) return "optimization";
297
+ if (taskLower.includes("optimize") || taskLower.includes("performance"))
298
+ return "optimization";
275
299
  return "general";
276
300
  }
277
301
  /**
@@ -331,7 +355,10 @@ class PatternLearner {
331
355
  // Additional helper methods for pattern analysis
332
356
  analyzeIterations(iterations) {
333
357
  return {
334
- avgDuration: iterations.length > 0 ? iterations.reduce((sum, i) => sum + (i.updated_at - i.created_at), 0) / iterations.length : 0,
358
+ avgDuration: iterations.length > 0 ? iterations.reduce(
359
+ (sum, i) => sum + (i.updated_at - i.created_at),
360
+ 0
361
+ ) / iterations.length : 0,
335
362
  progressPattern: this.extractProgressPattern(iterations),
336
363
  commonIssues: this.extractCommonIssues(iterations)
337
364
  };
@@ -347,11 +374,16 @@ class PatternLearner {
347
374
  return iterations.filter((i) => i.outputs?.errors?.length > 0).flatMap((i) => i.outputs.errors).slice(0, 3);
348
375
  }
349
376
  extractCriteriaPatterns(loops) {
350
- const criteriaWords = loops.flatMap((l) => l.criteria.toLowerCase().split(/\s+/));
351
- const wordCounts = criteriaWords.reduce((acc, word) => {
352
- acc[word] = (acc[word] || 0) + 1;
353
- return acc;
354
- }, {});
377
+ const criteriaWords = loops.flatMap(
378
+ (l) => l.criteria.toLowerCase().split(/\s+/)
379
+ );
380
+ const wordCounts = criteriaWords.reduce(
381
+ (acc, word) => {
382
+ acc[word] = (acc[word] || 0) + 1;
383
+ return acc;
384
+ },
385
+ {}
386
+ );
355
387
  const commonCriteria = Object.entries(wordCounts).filter(([_, count]) => count >= this.config.minLoopCountForPattern).sort((a, b) => b[1] - a[1]).slice(0, 3);
356
388
  return commonCriteria.map(([word, count]) => ({
357
389
  id: `criteria-${word}`,
@@ -374,12 +406,15 @@ class PatternLearner {
374
406
  return [];
375
407
  }
376
408
  groupByTaskType(loops) {
377
- return loops.reduce((acc, loop) => {
378
- const type = loop.taskType;
379
- if (!acc[type]) acc[type] = [];
380
- acc[type].push(loop);
381
- return acc;
382
- }, {});
409
+ return loops.reduce(
410
+ (acc, loop) => {
411
+ const type = loop.taskType;
412
+ if (!acc[type]) acc[type] = [];
413
+ acc[type].push(loop);
414
+ return acc;
415
+ },
416
+ {}
417
+ );
383
418
  }
384
419
  summarizeSuccessPattern(loops) {
385
420
  const avgIterations = loops.reduce((sum, l) => sum + l.iterationCount, 0) / loops.length;