@stackmemoryai/stackmemory 1.10.5 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -23
- package/dist/src/cli/claude-sm.js +266 -84
- package/dist/src/cli/codex-sm.js +185 -33
- package/dist/src/cli/commands/bench.js +209 -2
- package/dist/src/cli/commands/cache.js +126 -0
- package/dist/src/cli/commands/daemon.js +41 -0
- package/dist/src/cli/commands/handoff.js +40 -9
- package/dist/src/cli/commands/onboard.js +70 -3
- package/dist/src/cli/commands/optimize.js +117 -0
- package/dist/src/cli/commands/orchestrate.js +230 -5
- package/dist/src/cli/commands/orchestrator.js +312 -24
- package/dist/src/cli/commands/pack.js +322 -0
- package/dist/src/cli/commands/search.js +40 -1
- package/dist/src/cli/commands/setup.js +177 -7
- package/dist/src/cli/commands/skills.js +10 -1
- package/dist/src/cli/commands/state.js +265 -0
- package/dist/src/cli/gemini-sm.js +19 -29
- package/dist/src/cli/index.js +90 -29
- package/dist/src/cli/opencode-sm.js +38 -21
- package/dist/src/cli/utils/determinism-watcher.js +66 -0
- package/dist/src/cli/utils/real-cli-bin.js +44 -0
- package/dist/src/core/cache/content-cache.js +238 -0
- package/dist/src/core/cache/index.js +11 -0
- package/dist/src/core/cache/token-estimator.js +16 -0
- package/dist/src/core/context/frame-database.js +38 -30
- package/dist/src/core/cross-search/cross-project-search.js +269 -0
- package/dist/src/core/{merge → cross-search}/index.js +6 -4
- package/dist/src/core/database/sqlite-adapter.js +0 -83
- package/dist/src/core/extensions/provider-adapter.js +5 -0
- package/dist/src/core/models/model-router.js +22 -2
- package/dist/src/core/monitoring/logger.js +2 -1
- package/dist/src/core/optimization/trace-optimizer.js +413 -0
- package/dist/src/core/provenance/confidence-scorer.js +128 -0
- package/dist/src/core/provenance/index.js +40 -0
- package/dist/src/core/provenance/provenance-store.js +194 -0
- package/dist/src/core/provenance/types.js +82 -0
- package/dist/src/core/session/project-handoff.js +64 -0
- package/dist/src/core/session/session-manager.js +28 -0
- package/dist/src/core/shared-state/canonical-store.js +564 -0
- package/dist/src/core/skill-packs/index.js +18 -0
- package/dist/src/core/skill-packs/parser.js +42 -0
- package/dist/src/core/skill-packs/registry.js +224 -0
- package/dist/src/core/skill-packs/types.js +66 -0
- package/dist/src/core/trace/trace-event-store.js +282 -0
- package/dist/src/core/trace/trace-event.js +4 -0
- package/dist/src/daemon/daemon-config.js +7 -0
- package/dist/src/daemon/services/github-service.js +126 -0
- package/dist/src/daemon/unified-daemon.js +30 -0
- package/dist/src/features/sweep/pty-wrapper.js +13 -5
- package/dist/src/hooks/schemas.js +2 -0
- package/dist/src/integrations/claude-code/subagent-client.js +89 -0
- package/dist/src/integrations/github/pr-state.js +158 -0
- package/dist/src/integrations/linear/client.js +4 -1
- package/dist/src/integrations/mcp/handlers/cross-search-handlers.js +188 -0
- package/dist/src/integrations/mcp/handlers/index.js +40 -59
- package/dist/src/integrations/mcp/server.js +425 -311
- package/dist/src/integrations/mcp/tool-alias-registry.js +370 -0
- package/dist/src/integrations/mcp/tool-definitions.js +98 -229
- package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +3 -40
- package/dist/src/integrations/ralph/learning/pattern-learner.js +1 -20
- package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -2
- package/dist/src/mcp/stackmemory-mcp-server.js +315 -0
- package/dist/src/orchestrators/multimodal/determinism.js +243 -0
- package/dist/src/orchestrators/multimodal/harness.js +147 -77
- package/dist/src/orchestrators/multimodal/providers.js +44 -3
- package/dist/src/utils/hook-installer.js +0 -8
- package/package.json +10 -1
- package/packs/coding/python-fastapi/instructions.md +60 -0
- package/packs/coding/python-fastapi/pack.yaml +28 -0
- package/packs/coding/typescript-react/instructions.md +47 -0
- package/packs/coding/typescript-react/pack.yaml +28 -0
- package/packs/core/commands/capture.md +32 -0
- package/packs/core/commands/learn.md +73 -0
- package/packs/core/commands/next.md +36 -0
- package/packs/core/commands/restart.md +58 -0
- package/packs/core/commands/restore.md +29 -0
- package/packs/core/commands/start.md +57 -0
- package/packs/core/commands/stop.md +65 -0
- package/packs/core/commands/summary.md +40 -0
- package/packs/core/manifest.json +24 -0
- package/packs/ops/decision-recovery/instructions.md +65 -0
- package/packs/ops/decision-recovery/pack.yaml +89 -0
- package/dist/src/cli/commands/team.js +0 -168
- package/dist/src/core/context/shared-context-layer.js +0 -620
- package/dist/src/core/context/stack-merge-resolver.js +0 -748
- package/dist/src/core/merge/conflict-detector.js +0 -430
- package/dist/src/core/merge/resolution-engine.js +0 -557
- package/dist/src/core/merge/stack-diff.js +0 -531
- package/dist/src/core/merge/unified-merge-resolver.js +0 -302
- package/dist/src/integrations/mcp/handlers/cord-handlers.js +0 -397
- package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
- /package/dist/src/core/{merge → cache}/types.js +0 -0
|
@@ -1,430 +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 { v4 as uuidv4 } from "uuid";
|
|
6
|
-
import { logger } from "../monitoring/logger.js";
|
|
7
|
-
class ConflictDetector {
|
|
8
|
-
SIMILARITY_THRESHOLD = 0.8;
|
|
9
|
-
/**
|
|
10
|
-
* Detect all types of conflicts between two frame stacks
|
|
11
|
-
*/
|
|
12
|
-
detectConflicts(stack1, stack2) {
|
|
13
|
-
const conflicts = [];
|
|
14
|
-
const parallelConflicts = this.detectParallelSolutions(stack1, stack2);
|
|
15
|
-
conflicts.push(...parallelConflicts);
|
|
16
|
-
const decisionConflicts = this.detectConflictingDecisions(
|
|
17
|
-
stack1.events,
|
|
18
|
-
stack2.events
|
|
19
|
-
);
|
|
20
|
-
conflicts.push(...decisionConflicts);
|
|
21
|
-
const structuralConflicts = this.detectStructuralDivergence(
|
|
22
|
-
stack1.frames,
|
|
23
|
-
stack2.frames
|
|
24
|
-
);
|
|
25
|
-
conflicts.push(...structuralConflicts);
|
|
26
|
-
logger.info(`Detected ${conflicts.length} conflicts between stacks`, {
|
|
27
|
-
stack1Id: stack1.id,
|
|
28
|
-
stack2Id: stack2.id,
|
|
29
|
-
conflictTypes: this.summarizeConflictTypes(conflicts)
|
|
30
|
-
});
|
|
31
|
-
return conflicts;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Analyze frames to find parallel solutions to the same problem
|
|
35
|
-
*/
|
|
36
|
-
analyzeParallelSolutions(frames) {
|
|
37
|
-
const solutions = [];
|
|
38
|
-
const groupedFrames = this.groupSimilarFrames(frames);
|
|
39
|
-
for (const group of groupedFrames) {
|
|
40
|
-
if (group.length > 1) {
|
|
41
|
-
group.forEach((frame) => {
|
|
42
|
-
solutions.push({
|
|
43
|
-
frameId: frame.frame_id,
|
|
44
|
-
solution: this.extractSolution(frame),
|
|
45
|
-
approach: this.analyzeApproach(frame),
|
|
46
|
-
author: frame.inputs?.author || "unknown",
|
|
47
|
-
timestamp: frame.created_at,
|
|
48
|
-
effectiveness: this.calculateEffectiveness(frame)
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return solutions;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Identify conflicting decisions in event streams
|
|
57
|
-
*/
|
|
58
|
-
identifyConflictingDecisions(events) {
|
|
59
|
-
const conflicts = [];
|
|
60
|
-
const decisions = this.extractDecisions(events);
|
|
61
|
-
for (let i = 0; i < decisions.length; i++) {
|
|
62
|
-
for (let j = i + 1; j < decisions.length; j++) {
|
|
63
|
-
if (this.decisionsConflict(decisions[i], decisions[j])) {
|
|
64
|
-
conflicts.push({
|
|
65
|
-
decision1: decisions[i].payload?.decision || "",
|
|
66
|
-
decision2: decisions[j].payload?.decision || "",
|
|
67
|
-
impact: this.assessImpact(decisions[i], decisions[j]),
|
|
68
|
-
canCoexist: this.canCoexist(decisions[i], decisions[j])
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return conflicts;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Detect parallel solutions between two stacks
|
|
77
|
-
*/
|
|
78
|
-
detectParallelSolutions(stack1, stack2) {
|
|
79
|
-
const conflicts = [];
|
|
80
|
-
for (const frame1 of stack1.frames) {
|
|
81
|
-
for (const frame2 of stack2.frames) {
|
|
82
|
-
if (this.framesAreSimilar(frame1, frame2) && !this.framesAreIdentical(frame1, frame2)) {
|
|
83
|
-
conflicts.push({
|
|
84
|
-
id: uuidv4(),
|
|
85
|
-
type: "parallel_solution",
|
|
86
|
-
frameId1: frame1.frame_id,
|
|
87
|
-
frameId2: frame2.frame_id,
|
|
88
|
-
severity: this.calculateParallelSeverity(frame1, frame2),
|
|
89
|
-
description: `Parallel solutions detected: "${frame1.name}" vs "${frame2.name}"`,
|
|
90
|
-
detectedAt: Date.now(),
|
|
91
|
-
conflictingPaths: this.extractPaths(frame1, frame2)
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return conflicts;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Detect conflicting decisions between event streams
|
|
100
|
-
*/
|
|
101
|
-
detectConflictingDecisions(events1, events2) {
|
|
102
|
-
const conflicts = [];
|
|
103
|
-
const decisions1 = this.extractDecisions(events1);
|
|
104
|
-
const decisions2 = this.extractDecisions(events2);
|
|
105
|
-
for (const d1 of decisions1) {
|
|
106
|
-
for (const d2 of decisions2) {
|
|
107
|
-
if (this.decisionsConflict(d1, d2)) {
|
|
108
|
-
conflicts.push({
|
|
109
|
-
id: uuidv4(),
|
|
110
|
-
type: "conflicting_decision",
|
|
111
|
-
frameId1: d1.frame_id,
|
|
112
|
-
frameId2: d2.frame_id,
|
|
113
|
-
severity: this.assessImpact(d1, d2),
|
|
114
|
-
description: `Conflicting decisions: "${d1.payload?.decision}" vs "${d2.payload?.decision}"`,
|
|
115
|
-
detectedAt: Date.now()
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return conflicts;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Detect structural divergence in frame hierarchies
|
|
124
|
-
*/
|
|
125
|
-
detectStructuralDivergence(frames1, frames2) {
|
|
126
|
-
const conflicts = [];
|
|
127
|
-
const tree1 = this.buildFrameTree(frames1);
|
|
128
|
-
const tree2 = this.buildFrameTree(frames2);
|
|
129
|
-
const divergences = this.findDivergences(tree1, tree2);
|
|
130
|
-
for (const divergence of divergences) {
|
|
131
|
-
conflicts.push({
|
|
132
|
-
id: uuidv4(),
|
|
133
|
-
type: "structural_divergence",
|
|
134
|
-
frameId1: divergence.node1,
|
|
135
|
-
frameId2: divergence.node2,
|
|
136
|
-
severity: this.calculateDivergenceSeverity(divergence),
|
|
137
|
-
description: `Structural divergence at depth ${divergence.depth}`,
|
|
138
|
-
detectedAt: Date.now()
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
return conflicts;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Helper: Check if two frames are similar (solving same problem)
|
|
145
|
-
*/
|
|
146
|
-
framesAreSimilar(frame1, frame2) {
|
|
147
|
-
const nameSimilarity = this.calculateSimilarity(frame1.name, frame2.name);
|
|
148
|
-
if (nameSimilarity > this.SIMILARITY_THRESHOLD) return true;
|
|
149
|
-
if (frame1.type === frame2.type && frame1.parent_frame_id === frame2.parent_frame_id) {
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
|
-
const inputSimilarity = this.compareInputs(frame1.inputs, frame2.inputs);
|
|
153
|
-
return inputSimilarity > this.SIMILARITY_THRESHOLD;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Helper: Check if frames are identical
|
|
157
|
-
*/
|
|
158
|
-
framesAreIdentical(frame1, frame2) {
|
|
159
|
-
return frame1.frame_id === frame2.frame_id;
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Helper: Calculate string similarity (Levenshtein-based)
|
|
163
|
-
*/
|
|
164
|
-
calculateSimilarity(str1, str2) {
|
|
165
|
-
const maxLen = Math.max(str1.length, str2.length);
|
|
166
|
-
if (maxLen === 0) return 1;
|
|
167
|
-
const distance = this.levenshteinDistance(str1, str2);
|
|
168
|
-
return 1 - distance / maxLen;
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Helper: Levenshtein distance implementation
|
|
172
|
-
*/
|
|
173
|
-
levenshteinDistance(str1, str2) {
|
|
174
|
-
const matrix = [];
|
|
175
|
-
for (let i = 0; i <= str2.length; i++) {
|
|
176
|
-
matrix[i] = [i];
|
|
177
|
-
}
|
|
178
|
-
for (let j = 0; j <= str1.length; j++) {
|
|
179
|
-
matrix[0][j] = j;
|
|
180
|
-
}
|
|
181
|
-
for (let i = 1; i <= str2.length; i++) {
|
|
182
|
-
for (let j = 1; j <= str1.length; j++) {
|
|
183
|
-
if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
|
|
184
|
-
matrix[i][j] = matrix[i - 1][j - 1];
|
|
185
|
-
} else {
|
|
186
|
-
matrix[i][j] = Math.min(
|
|
187
|
-
matrix[i - 1][j - 1] + 1,
|
|
188
|
-
matrix[i][j - 1] + 1,
|
|
189
|
-
matrix[i - 1][j] + 1
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return matrix[str2.length][str1.length];
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Helper: Compare frame inputs
|
|
198
|
-
*/
|
|
199
|
-
compareInputs(inputs1, inputs2) {
|
|
200
|
-
const keys1 = Object.keys(inputs1 || {});
|
|
201
|
-
const keys2 = Object.keys(inputs2 || {});
|
|
202
|
-
const allKeys = /* @__PURE__ */ new Set([...keys1, ...keys2]);
|
|
203
|
-
if (allKeys.size === 0) return 1;
|
|
204
|
-
let matches = 0;
|
|
205
|
-
for (const key of allKeys) {
|
|
206
|
-
if (JSON.stringify(inputs1[key]) === JSON.stringify(inputs2[key])) {
|
|
207
|
-
matches++;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return matches / allKeys.size;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Helper: Calculate severity for parallel solutions
|
|
214
|
-
*/
|
|
215
|
-
calculateParallelSeverity(frame1, frame2) {
|
|
216
|
-
if (frame1.state === "closed" && frame2.state === "closed") {
|
|
217
|
-
const outputSimilarity = this.compareInputs(
|
|
218
|
-
frame1.outputs,
|
|
219
|
-
frame2.outputs
|
|
220
|
-
);
|
|
221
|
-
if (outputSimilarity < 0.5) return "critical";
|
|
222
|
-
if (outputSimilarity < 0.7) return "high";
|
|
223
|
-
}
|
|
224
|
-
if (frame1.parent_frame_id === frame2.parent_frame_id) {
|
|
225
|
-
return "high";
|
|
226
|
-
}
|
|
227
|
-
return "medium";
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Helper: Extract decision events
|
|
231
|
-
*/
|
|
232
|
-
extractDecisions(events) {
|
|
233
|
-
return events.filter(
|
|
234
|
-
(e) => e.event_type === "decision" || e.payload?.type === "decision" || e.payload?.decision !== void 0
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Helper: Check if two decisions conflict
|
|
239
|
-
*/
|
|
240
|
-
decisionsConflict(d1, d2) {
|
|
241
|
-
const resource1 = d1.payload?.resource || d1.payload?.path;
|
|
242
|
-
const resource2 = d2.payload?.resource || d2.payload?.path;
|
|
243
|
-
if (resource1 && resource2 && resource1 === resource2) {
|
|
244
|
-
return d1.payload?.decision !== d2.payload?.decision;
|
|
245
|
-
}
|
|
246
|
-
return this.hasLogicalConflict(d1.payload, d2.payload);
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* Helper: Check for logical conflicts in payloads
|
|
250
|
-
*/
|
|
251
|
-
hasLogicalConflict(payload1, payload2) {
|
|
252
|
-
if (payload1?.architecture && payload2?.architecture) {
|
|
253
|
-
return payload1.architecture !== payload2.architecture;
|
|
254
|
-
}
|
|
255
|
-
if (payload1?.technology && payload2?.technology) {
|
|
256
|
-
return payload1.technology !== payload2.technology;
|
|
257
|
-
}
|
|
258
|
-
return false;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Helper: Assess impact of conflicting decisions
|
|
262
|
-
*/
|
|
263
|
-
assessImpact(d1, d2) {
|
|
264
|
-
if (d1.payload?.type === "architecture" || d2.payload?.type === "architecture") {
|
|
265
|
-
return "high";
|
|
266
|
-
}
|
|
267
|
-
if (d1.payload?.scope === "implementation" || d2.payload?.scope === "implementation") {
|
|
268
|
-
return "medium";
|
|
269
|
-
}
|
|
270
|
-
return "low";
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Helper: Check if decisions can coexist
|
|
274
|
-
*/
|
|
275
|
-
canCoexist(d1, d2) {
|
|
276
|
-
if (d1.payload?.scope !== d2.payload?.scope) {
|
|
277
|
-
return true;
|
|
278
|
-
}
|
|
279
|
-
const resource1 = d1.payload?.resource;
|
|
280
|
-
const resource2 = d2.payload?.resource;
|
|
281
|
-
return resource1 !== resource2;
|
|
282
|
-
}
|
|
283
|
-
/**
|
|
284
|
-
* Helper: Build frame tree structure
|
|
285
|
-
*/
|
|
286
|
-
buildFrameTree(frames) {
|
|
287
|
-
const tree = /* @__PURE__ */ new Map();
|
|
288
|
-
for (const frame of frames) {
|
|
289
|
-
if (frame.parent_frame_id) {
|
|
290
|
-
if (!tree.has(frame.parent_frame_id)) {
|
|
291
|
-
tree.set(frame.parent_frame_id, /* @__PURE__ */ new Set());
|
|
292
|
-
}
|
|
293
|
-
const parentSet = tree.get(frame.parent_frame_id);
|
|
294
|
-
if (parentSet) {
|
|
295
|
-
parentSet.add(frame.frame_id);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return tree;
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Helper: Find divergence points in trees
|
|
303
|
-
*/
|
|
304
|
-
findDivergences(tree1, tree2) {
|
|
305
|
-
const divergences = [];
|
|
306
|
-
for (const [node, children1] of tree1) {
|
|
307
|
-
if (tree2.has(node)) {
|
|
308
|
-
const children2 = tree2.get(node);
|
|
309
|
-
if (children2 && !this.setsEqual(children1, children2)) {
|
|
310
|
-
divergences.push({
|
|
311
|
-
node1: node,
|
|
312
|
-
node2: node,
|
|
313
|
-
depth: this.calculateDepth(node, tree1)
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
return divergences;
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Helper: Check if two sets are equal
|
|
322
|
-
*/
|
|
323
|
-
setsEqual(set1, set2) {
|
|
324
|
-
if (set1.size !== set2.size) return false;
|
|
325
|
-
for (const item of set1) {
|
|
326
|
-
if (!set2.has(item)) return false;
|
|
327
|
-
}
|
|
328
|
-
return true;
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Helper: Calculate node depth in tree
|
|
332
|
-
*/
|
|
333
|
-
calculateDepth(node, tree) {
|
|
334
|
-
let depth = 0;
|
|
335
|
-
let current = node;
|
|
336
|
-
for (const [parent, children] of tree) {
|
|
337
|
-
if (children.has(current)) {
|
|
338
|
-
depth++;
|
|
339
|
-
current = parent;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
return depth;
|
|
343
|
-
}
|
|
344
|
-
/**
|
|
345
|
-
* Helper: Calculate divergence severity
|
|
346
|
-
*/
|
|
347
|
-
calculateDivergenceSeverity(divergence) {
|
|
348
|
-
if (divergence.depth === 0) return "critical";
|
|
349
|
-
if (divergence.depth === 1) return "high";
|
|
350
|
-
if (divergence.depth === 2) return "medium";
|
|
351
|
-
return "low";
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* Helper: Extract paths from frames
|
|
355
|
-
*/
|
|
356
|
-
extractPaths(frame1, frame2) {
|
|
357
|
-
const paths = [];
|
|
358
|
-
if (frame1.inputs?.path) paths.push(frame1.inputs.path);
|
|
359
|
-
if (frame2.inputs?.path) paths.push(frame2.inputs.path);
|
|
360
|
-
if (frame1.outputs?.files) paths.push(...frame1.outputs.files);
|
|
361
|
-
if (frame2.outputs?.files) paths.push(...frame2.outputs.files);
|
|
362
|
-
return [...new Set(paths)];
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Helper: Extract solution from frame
|
|
366
|
-
*/
|
|
367
|
-
extractSolution(frame) {
|
|
368
|
-
return frame.outputs?.solution || frame.digest_text || "No solution description";
|
|
369
|
-
}
|
|
370
|
-
/**
|
|
371
|
-
* Helper: Analyze approach taken
|
|
372
|
-
*/
|
|
373
|
-
analyzeApproach(frame) {
|
|
374
|
-
if (frame.outputs?.approach) return frame.outputs.approach;
|
|
375
|
-
if (frame.type === "debug") return "Debug approach";
|
|
376
|
-
if (frame.type === "review") return "Review approach";
|
|
377
|
-
return "Standard approach";
|
|
378
|
-
}
|
|
379
|
-
/**
|
|
380
|
-
* Helper: Calculate solution effectiveness
|
|
381
|
-
*/
|
|
382
|
-
calculateEffectiveness(frame) {
|
|
383
|
-
let score = 0.5;
|
|
384
|
-
if (frame.state === "closed") score += 0.2;
|
|
385
|
-
if (frame.outputs && Object.keys(frame.outputs).length > 0) score += 0.1;
|
|
386
|
-
if (frame.digest_text) score += 0.1;
|
|
387
|
-
if (frame.closed_at && frame.created_at) {
|
|
388
|
-
const duration = frame.closed_at - frame.created_at;
|
|
389
|
-
if (duration < 3e5) score += 0.1;
|
|
390
|
-
}
|
|
391
|
-
return Math.min(score, 1);
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Helper: Group similar frames together
|
|
395
|
-
*/
|
|
396
|
-
groupSimilarFrames(frames) {
|
|
397
|
-
const groups = [];
|
|
398
|
-
const processed = /* @__PURE__ */ new Set();
|
|
399
|
-
for (const frame of frames) {
|
|
400
|
-
if (processed.has(frame.frame_id)) continue;
|
|
401
|
-
const group = [frame];
|
|
402
|
-
processed.add(frame.frame_id);
|
|
403
|
-
for (const other of frames) {
|
|
404
|
-
if (!processed.has(other.frame_id) && this.framesAreSimilar(frame, other)) {
|
|
405
|
-
group.push(other);
|
|
406
|
-
processed.add(other.frame_id);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
groups.push(group);
|
|
410
|
-
}
|
|
411
|
-
return groups;
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* Helper: Summarize conflict types
|
|
415
|
-
*/
|
|
416
|
-
summarizeConflictTypes(conflicts) {
|
|
417
|
-
const summary = {
|
|
418
|
-
parallel_solution: 0,
|
|
419
|
-
conflicting_decision: 0,
|
|
420
|
-
structural_divergence: 0
|
|
421
|
-
};
|
|
422
|
-
for (const conflict of conflicts) {
|
|
423
|
-
summary[conflict.type]++;
|
|
424
|
-
}
|
|
425
|
-
return summary;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
export {
|
|
429
|
-
ConflictDetector
|
|
430
|
-
};
|