@stackmemoryai/stackmemory 1.10.5 → 1.14.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.
Files changed (225) hide show
  1. package/LICENSE +131 -64
  2. package/README.md +107 -24
  3. package/bin/claude-sm +16 -1
  4. package/bin/claude-smd +16 -1
  5. package/bin/codex-smd +16 -1
  6. package/bin/gemini-sm +16 -1
  7. package/bin/hermes-sm +21 -0
  8. package/bin/hermes-smd +21 -0
  9. package/bin/opencode-sm +16 -1
  10. package/dist/src/cli/claude-sm.js +266 -84
  11. package/dist/src/cli/codex-sm.js +225 -33
  12. package/dist/src/cli/commands/bench.js +209 -2
  13. package/dist/src/cli/commands/brain.js +206 -0
  14. package/dist/src/cli/commands/cache.js +126 -0
  15. package/dist/src/cli/commands/company-os.js +184 -0
  16. package/dist/src/cli/commands/context.js +5 -0
  17. package/dist/src/cli/commands/daemon.js +41 -0
  18. package/dist/src/cli/commands/handoff.js +40 -9
  19. package/dist/src/cli/commands/onboard.js +70 -3
  20. package/dist/src/cli/commands/operator.js +127 -0
  21. package/dist/src/cli/commands/optimize.js +117 -0
  22. package/dist/src/cli/commands/orchestrate.js +232 -5
  23. package/dist/src/cli/commands/orchestrator.js +315 -26
  24. package/dist/src/cli/commands/pack.js +322 -0
  25. package/dist/src/cli/commands/patterns.js +254 -0
  26. package/dist/src/cli/commands/portal.js +161 -0
  27. package/dist/src/cli/commands/scaffold.js +92 -0
  28. package/dist/src/cli/commands/search.js +40 -1
  29. package/dist/src/cli/commands/setup.js +178 -11
  30. package/dist/src/cli/commands/skills.js +10 -1
  31. package/dist/src/cli/commands/state.js +265 -0
  32. package/dist/src/cli/commands/sync.js +253 -0
  33. package/dist/src/cli/commands/tasks.js +130 -1
  34. package/dist/src/cli/commands/vision.js +221 -0
  35. package/dist/src/cli/gemini-sm.js +19 -29
  36. package/dist/src/cli/hermes-sm.js +224 -0
  37. package/dist/src/cli/index.js +105 -39
  38. package/dist/src/cli/opencode-sm.js +38 -21
  39. package/dist/src/cli/utils/determinism-watcher.js +66 -0
  40. package/dist/src/cli/utils/real-cli-bin.js +116 -0
  41. package/dist/src/core/brain/brain-store.js +187 -0
  42. package/dist/src/core/brain/brain-sync.js +193 -0
  43. package/dist/src/core/brain/index.js +78 -0
  44. package/dist/src/core/brain/types.js +10 -0
  45. package/dist/src/core/cache/content-cache.js +238 -0
  46. package/dist/src/{integrations/diffmem → core/cache}/index.js +5 -5
  47. package/dist/src/core/cache/token-estimator.js +39 -0
  48. package/dist/src/core/config/feature-flags.js +2 -6
  49. package/dist/src/core/context/frame-database.js +79 -27
  50. package/dist/src/core/context/recursive-context-manager.js +1 -1
  51. package/dist/src/core/context/rehydration.js +2 -1
  52. package/dist/src/core/cross-search/cross-project-search.js +269 -0
  53. package/dist/src/core/cross-search/index.js +10 -0
  54. package/dist/src/core/database/sqlite-adapter.js +14 -84
  55. package/dist/src/core/extensions/provider-adapter.js +5 -0
  56. package/dist/src/core/models/model-router.js +54 -2
  57. package/dist/src/core/models/provider-pricing.js +58 -4
  58. package/dist/src/core/monitoring/logger.js +2 -1
  59. package/dist/src/core/optimization/trace-optimizer.js +413 -0
  60. package/dist/src/core/patterns/index.js +22 -0
  61. package/dist/src/core/patterns/pattern-applier.js +39 -0
  62. package/dist/src/core/patterns/pattern-observer.js +157 -0
  63. package/dist/src/core/patterns/pattern-store.js +259 -0
  64. package/dist/src/core/patterns/types.js +19 -0
  65. package/dist/src/core/provenance/confidence-scorer.js +128 -0
  66. package/dist/src/core/provenance/index.js +40 -0
  67. package/dist/src/core/provenance/provenance-store.js +194 -0
  68. package/dist/src/core/provenance/types.js +82 -0
  69. package/dist/src/core/retrieval/llm-context-retrieval.js +5 -4
  70. package/dist/src/core/retrieval/unified-context-assembler.js +11 -66
  71. package/dist/src/core/session/project-handoff.js +64 -0
  72. package/dist/src/core/session/session-manager.js +28 -0
  73. package/dist/src/core/shared-state/canonical-store.js +564 -0
  74. package/dist/src/core/skill-packs/index.js +18 -0
  75. package/dist/src/core/skill-packs/parser.js +42 -0
  76. package/dist/src/core/skill-packs/registry.js +224 -0
  77. package/dist/src/core/skill-packs/types.js +79 -0
  78. package/dist/src/core/storage/cloud-sync-manager.js +116 -0
  79. package/dist/src/core/storage/cloud-sync.js +574 -0
  80. package/dist/src/core/storage/two-tier-storage.js +5 -1
  81. package/dist/src/core/tasks/master-tasks-template.js +43 -0
  82. package/dist/src/core/tasks/md-task-parser.js +138 -0
  83. package/dist/src/core/trace/trace-event-store.js +282 -0
  84. package/dist/src/core/vision/index.js +27 -0
  85. package/dist/src/core/vision/signals.js +79 -0
  86. package/dist/src/core/vision/types.js +22 -0
  87. package/dist/src/core/vision/vision-file.js +146 -0
  88. package/dist/src/core/vision/vision-loop.js +220 -0
  89. package/dist/src/core/wiki/wiki-compiler.js +103 -1
  90. package/dist/src/daemon/daemon-config.js +52 -0
  91. package/dist/src/daemon/services/desire-path-service.js +566 -0
  92. package/dist/src/daemon/services/github-service.js +126 -0
  93. package/dist/src/daemon/services/research-stream-service.js +320 -0
  94. package/dist/src/daemon/services/telemetry-service.js +192 -0
  95. package/dist/src/daemon/unified-daemon.js +58 -1
  96. package/dist/src/features/browser/cli-browser-agent.js +417 -0
  97. package/dist/src/features/browser/stagehand-workflows.js +578 -0
  98. package/dist/src/features/operator/adapter-factory.js +62 -0
  99. package/dist/src/features/operator/browser-adapter.js +109 -0
  100. package/dist/src/features/operator/desktop-adapter.js +125 -0
  101. package/dist/src/features/operator/index.js +39 -0
  102. package/dist/src/features/operator/llm-decision.js +137 -0
  103. package/dist/src/features/operator/operator-logger.js +92 -0
  104. package/dist/src/features/operator/overnight-runner.js +327 -0
  105. package/dist/src/features/operator/screen-adapter.js +91 -0
  106. package/dist/src/features/operator/session-manager.js +127 -0
  107. package/dist/src/features/operator/state-machine.js +227 -0
  108. package/dist/src/features/operator/task-queue.js +81 -0
  109. package/dist/src/features/portal/index.js +26 -0
  110. package/dist/src/features/portal/server.js +240 -0
  111. package/dist/src/features/portal/types.js +14 -0
  112. package/dist/src/features/portal/ui.js +195 -0
  113. package/dist/src/features/sweep/pty-wrapper.js +13 -5
  114. package/dist/src/features/tasks/task-aware-context.js +2 -1
  115. package/dist/src/features/tui/simple-monitor.js +0 -23
  116. package/dist/src/features/tui/swarm-monitor.js +8 -66
  117. package/dist/src/features/web/client/hooks/use-socket.js +12 -0
  118. package/dist/src/{core/merge/index.js → features/web/client/lib/utils.js} +8 -4
  119. package/dist/src/features/web/client/next-env.d.js +4 -0
  120. package/dist/src/features/web/client/stores/session-store.js +12 -0
  121. package/dist/src/features/web/server/gcp-billing.js +76 -0
  122. package/dist/src/features/web/server/index.js +10 -0
  123. package/dist/src/features/web/server/spend-calculator.js +228 -0
  124. package/dist/src/hooks/schemas.js +6 -1
  125. package/dist/src/integrations/anthropic/client.js +3 -2
  126. package/dist/src/integrations/claude-code/agent-bridge.js +0 -3
  127. package/dist/src/integrations/claude-code/subagent-client.js +307 -11
  128. package/dist/src/integrations/claude-code/task-coordinator.js +2 -1
  129. package/dist/src/integrations/github/pr-state.js +158 -0
  130. package/dist/src/integrations/linear/client.js +4 -1
  131. package/dist/src/integrations/linear/webhook-retry.js +196 -0
  132. package/dist/src/integrations/linear/webhook-server.js +18 -22
  133. package/dist/src/integrations/mcp/handlers/cloud-sync-handlers.js +101 -0
  134. package/dist/src/integrations/mcp/handlers/index.js +40 -84
  135. package/dist/src/integrations/mcp/server.js +542 -641
  136. package/dist/src/integrations/mcp/tool-alias-registry.js +297 -0
  137. package/dist/src/integrations/mcp/tool-definitions.js +152 -682
  138. package/dist/src/mcp/stackmemory-mcp-server.js +571 -231
  139. package/dist/src/orchestrators/multimodal/determinism.js +244 -0
  140. package/dist/src/orchestrators/multimodal/harness.js +149 -78
  141. package/dist/src/orchestrators/multimodal/providers.js +44 -3
  142. package/dist/src/skills/recursive-agent-orchestrator.js +2 -4
  143. package/dist/src/utils/hook-installer.js +0 -8
  144. package/dist/src/utils/process-cleanup.js +1 -7
  145. package/docs/README.md +42 -0
  146. package/docs/guides/README_INSTALL.md +208 -0
  147. package/package.json +27 -9
  148. package/packs/coding/python-fastapi/instructions.md +60 -0
  149. package/packs/coding/python-fastapi/pack.yaml +28 -0
  150. package/packs/coding/typescript-react/instructions.md +47 -0
  151. package/packs/coding/typescript-react/pack.yaml +28 -0
  152. package/packs/core/commands/capture.md +32 -0
  153. package/packs/core/commands/learn.md +73 -0
  154. package/packs/core/commands/next.md +36 -0
  155. package/packs/core/commands/restart.md +58 -0
  156. package/packs/core/commands/restore.md +29 -0
  157. package/packs/core/commands/start.md +57 -0
  158. package/packs/core/commands/stop.md +65 -0
  159. package/packs/core/commands/summary.md +40 -0
  160. package/packs/core/manifest.json +24 -0
  161. package/packs/ops/decision-recovery/instructions.md +65 -0
  162. package/packs/ops/decision-recovery/pack.yaml +89 -0
  163. package/scripts/claude-code-wrapper.sh +11 -0
  164. package/scripts/claude-sm-setup.sh +12 -1
  165. package/scripts/codex-wrapper.sh +11 -0
  166. package/scripts/git-hooks/branch-context-manager.sh +11 -0
  167. package/scripts/git-hooks/post-checkout-stackmemory.sh +11 -0
  168. package/scripts/git-hooks/post-commit-stackmemory.sh +11 -0
  169. package/scripts/git-hooks/pre-commit-stackmemory.sh +11 -0
  170. package/scripts/hooks/cleanup-shell.sh +12 -1
  171. package/scripts/hooks/task-complete.sh +12 -1
  172. package/scripts/install-code-execution-hooks.sh +12 -1
  173. package/scripts/install-sweep-hook.sh +12 -0
  174. package/scripts/install.sh +11 -0
  175. package/scripts/opencode-wrapper.sh +11 -0
  176. package/scripts/portal/cloud-init.yaml +69 -0
  177. package/scripts/portal/setup.sh +69 -0
  178. package/scripts/portal/stackmemory-portal.service +34 -0
  179. package/scripts/setup-claude-integration.sh +12 -1
  180. package/scripts/smoke-init-db.sh +23 -0
  181. package/scripts/stackmemory-daemon.sh +11 -0
  182. package/scripts/verify-dist.cjs +11 -4
  183. package/dist/src/cli/commands/ralph.js +0 -1053
  184. package/dist/src/cli/commands/team.js +0 -168
  185. package/dist/src/core/context/shared-context-layer.js +0 -620
  186. package/dist/src/core/context/stack-merge-resolver.js +0 -748
  187. package/dist/src/core/merge/conflict-detector.js +0 -430
  188. package/dist/src/core/merge/resolution-engine.js +0 -557
  189. package/dist/src/core/merge/stack-diff.js +0 -531
  190. package/dist/src/core/merge/unified-merge-resolver.js +0 -302
  191. package/dist/src/hooks/diffmem-hooks.js +0 -376
  192. package/dist/src/integrations/diffmem/client.js +0 -208
  193. package/dist/src/integrations/diffmem/config.js +0 -14
  194. package/dist/src/integrations/greptile/client.js +0 -101
  195. package/dist/src/integrations/greptile/config.js +0 -14
  196. package/dist/src/integrations/greptile/index.js +0 -11
  197. package/dist/src/integrations/mcp/handlers/cord-handlers.js +0 -397
  198. package/dist/src/integrations/mcp/handlers/diffmem-handlers.js +0 -455
  199. package/dist/src/integrations/mcp/handlers/greptile-handlers.js +0 -456
  200. package/dist/src/integrations/mcp/handlers/provider-handlers.js +0 -227
  201. package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
  202. package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +0 -863
  203. package/dist/src/integrations/ralph/context/context-budget-manager.js +0 -308
  204. package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +0 -391
  205. package/dist/src/integrations/ralph/index.js +0 -17
  206. package/dist/src/integrations/ralph/learning/pattern-learner.js +0 -435
  207. package/dist/src/integrations/ralph/lifecycle/iteration-lifecycle.js +0 -448
  208. package/dist/src/integrations/ralph/loopmax.js +0 -488
  209. package/dist/src/integrations/ralph/monitoring/swarm-dashboard.js +0 -293
  210. package/dist/src/integrations/ralph/monitoring/swarm-registry.js +0 -107
  211. package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +0 -508
  212. package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +0 -407
  213. package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +0 -495
  214. package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +0 -387
  215. package/dist/src/integrations/ralph/performance/performance-optimizer.js +0 -357
  216. package/dist/src/integrations/ralph/recovery/crash-recovery.js +0 -461
  217. package/dist/src/integrations/ralph/state/state-reconciler.js +0 -420
  218. package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +0 -444
  219. package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -1007
  220. package/dist/src/integrations/ralph/visualization/ralph-debugger.js +0 -635
  221. package/scripts/ralph-loop-implementation.js +0 -404
  222. /package/dist/src/core/{merge → cache}/types.js +0 -0
  223. /package/dist/src/{integrations/diffmem/types.js → core/storage/cloud-sync-types.js} +0 -0
  224. /package/dist/src/{integrations/greptile/types.js → core/trace/trace-event.js} +0 -0
  225. /package/dist/src/{integrations/ralph → features/operator}/types.js +0 -0
@@ -1,531 +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 { ConflictDetector } from "./conflict-detector.js";
6
- class StackDiffVisualizer {
7
- conflictDetector;
8
- constructor() {
9
- this.conflictDetector = new ConflictDetector();
10
- }
11
- /**
12
- * Visualize divergence between two frame stacks
13
- */
14
- visualizeDivergence(baseFrame, branch1, branch2) {
15
- const nodes = [];
16
- const edges = [];
17
- nodes.push({
18
- id: baseFrame.frame_id,
19
- type: "common",
20
- frame: baseFrame,
21
- position: { x: 0, y: 0 },
22
- metadata: { label: "Common Ancestor" }
23
- });
24
- const branch1Nodes = this.processBranch(
25
- branch1,
26
- baseFrame.frame_id,
27
- -100,
28
- // Left side
29
- 100
30
- );
31
- nodes.push(...branch1Nodes.nodes);
32
- edges.push(...branch1Nodes.edges);
33
- const branch2Nodes = this.processBranch(
34
- branch2,
35
- baseFrame.frame_id,
36
- 100,
37
- // Right side
38
- 100
39
- );
40
- nodes.push(...branch2Nodes.nodes);
41
- edges.push(...branch2Nodes.edges);
42
- const conflicts = this.conflictDetector.detectConflicts(branch1, branch2);
43
- this.markConflicts(nodes, edges, conflicts);
44
- return {
45
- nodes,
46
- edges,
47
- layout: "tree"
48
- };
49
- }
50
- /**
51
- * Render conflict markers for visualization
52
- */
53
- renderConflictMarkers(conflicts) {
54
- const markers = [];
55
- for (const conflict of conflicts) {
56
- markers.push({
57
- frameId: conflict.frameId1,
58
- type: "conflict",
59
- color: this.getSeverityColor(conflict.severity),
60
- symbol: this.getConflictSymbol(conflict.type),
61
- description: conflict.description
62
- });
63
- markers.push({
64
- frameId: conflict.frameId2,
65
- type: "conflict",
66
- color: this.getSeverityColor(conflict.severity),
67
- symbol: this.getConflictSymbol(conflict.type),
68
- description: conflict.description
69
- });
70
- }
71
- return markers;
72
- }
73
- /**
74
- * Generate a merge preview based on resolution strategy
75
- */
76
- generateMergePreview(stack1, stack2, strategy) {
77
- const mergedFrames = [];
78
- const keptFromStack1 = [];
79
- const keptFromStack2 = [];
80
- const conflicts = this.conflictDetector.detectConflicts(stack1, stack2);
81
- switch (strategy) {
82
- case "keep_both":
83
- return this.previewKeepBoth(stack1, stack2, conflicts);
84
- case "team_vote":
85
- return this.previewTeamVote(stack1, stack2, conflicts);
86
- case "senior_override":
87
- return this.previewSeniorOverride(stack1, stack2, conflicts);
88
- case "ai_suggest":
89
- return this.previewAISuggest(stack1, stack2, conflicts);
90
- case "hybrid":
91
- return this.previewHybrid(stack1, stack2, conflicts);
92
- default:
93
- return {
94
- mergedFrames,
95
- keptFromStack1,
96
- keptFromStack2,
97
- conflicts,
98
- estimatedSuccess: 0
99
- };
100
- }
101
- }
102
- /**
103
- * Create a stack diff comparison
104
- */
105
- createStackDiff(baseFrameId, stack1, stack2) {
106
- const conflicts = this.conflictDetector.detectConflicts(stack1, stack2);
107
- const divergencePoint = this.findDivergencePoint(stack1, stack2);
108
- const commonAncestor = this.findCommonAncestor(stack1, stack2);
109
- const baseFrame = stack1.frames.find((f) => f.frame_id === baseFrameId) || stack2.frames.find((f) => f.frame_id === baseFrameId);
110
- const visualRepresentation = baseFrame ? this.visualizeDivergence(baseFrame, stack1, stack2) : void 0;
111
- return {
112
- baseFrame: baseFrameId,
113
- branch1: stack1,
114
- branch2: stack2,
115
- divergencePoint,
116
- conflicts,
117
- commonAncestor,
118
- visualRepresentation
119
- };
120
- }
121
- /**
122
- * Process a branch for visualization
123
- */
124
- processBranch(stack, parentId, xOffset, yStart) {
125
- const nodes = [];
126
- const edges = [];
127
- let yPos = yStart;
128
- const children = stack.frames.filter((f) => f.parent_frame_id === parentId);
129
- for (const frame of children) {
130
- nodes.push({
131
- id: frame.frame_id,
132
- type: xOffset < 0 ? "branch1" : "branch2",
133
- frame,
134
- position: { x: xOffset, y: yPos },
135
- metadata: {
136
- branch: xOffset < 0 ? "left" : "right",
137
- depth: frame.depth
138
- }
139
- });
140
- edges.push({
141
- source: parentId,
142
- target: frame.frame_id,
143
- type: "parent",
144
- weight: 1
145
- });
146
- const childResults = this.processBranch(
147
- stack,
148
- frame.frame_id,
149
- xOffset + (xOffset < 0 ? -50 : 50),
150
- yPos + 100
151
- );
152
- nodes.push(...childResults.nodes);
153
- edges.push(...childResults.edges);
154
- yPos += 150;
155
- }
156
- return { nodes, edges };
157
- }
158
- /**
159
- * Mark conflicts in the visualization
160
- */
161
- markConflicts(nodes, edges, conflicts) {
162
- for (const conflict of conflicts) {
163
- const node1 = nodes.find((n) => n.id === conflict.frameId1);
164
- const node2 = nodes.find((n) => n.id === conflict.frameId2);
165
- if (node1) {
166
- node1.type = "conflict";
167
- node1.metadata = {
168
- ...node1.metadata,
169
- conflictType: conflict.type,
170
- severity: conflict.severity
171
- };
172
- }
173
- if (node2) {
174
- node2.type = "conflict";
175
- node2.metadata = {
176
- ...node2.metadata,
177
- conflictType: conflict.type,
178
- severity: conflict.severity
179
- };
180
- }
181
- if (node1 && node2) {
182
- edges.push({
183
- source: conflict.frameId1,
184
- target: conflict.frameId2,
185
- type: "conflict",
186
- weight: this.getSeverityWeight(conflict.severity)
187
- });
188
- }
189
- }
190
- }
191
- /**
192
- * Get color for severity level
193
- */
194
- getSeverityColor(severity) {
195
- switch (severity) {
196
- case "critical":
197
- return "#ff0000";
198
- case "high":
199
- return "#ff6600";
200
- case "medium":
201
- return "#ffaa00";
202
- case "low":
203
- return "#ffdd00";
204
- default:
205
- return "#888888";
206
- }
207
- }
208
- /**
209
- * Get symbol for conflict type
210
- */
211
- getConflictSymbol(type) {
212
- switch (type) {
213
- case "parallel_solution":
214
- return "\u26A1";
215
- case "conflicting_decision":
216
- return "\u26A0\uFE0F";
217
- case "structural_divergence":
218
- return "\u{1F500}";
219
- default:
220
- return "\u2753";
221
- }
222
- }
223
- /**
224
- * Get weight for severity level
225
- */
226
- getSeverityWeight(severity) {
227
- switch (severity) {
228
- case "critical":
229
- return 4;
230
- case "high":
231
- return 3;
232
- case "medium":
233
- return 2;
234
- case "low":
235
- return 1;
236
- default:
237
- return 0;
238
- }
239
- }
240
- /**
241
- * Preview keep both strategy
242
- */
243
- previewKeepBoth(stack1, stack2, conflicts) {
244
- const mergedFrames = [];
245
- const keptFromStack1 = [];
246
- const keptFromStack2 = [];
247
- for (const frame of stack1.frames) {
248
- mergedFrames.push(frame);
249
- keptFromStack1.push(frame.frame_id);
250
- }
251
- for (const frame of stack2.frames) {
252
- if (!mergedFrames.find((f) => f.frame_id === frame.frame_id)) {
253
- mergedFrames.push(frame);
254
- keptFromStack2.push(frame.frame_id);
255
- }
256
- }
257
- const criticalConflicts = conflicts.filter(
258
- (c) => c.severity === "critical"
259
- ).length;
260
- const estimatedSuccess = Math.max(0, 1 - criticalConflicts * 0.2);
261
- return {
262
- mergedFrames,
263
- keptFromStack1,
264
- keptFromStack2,
265
- conflicts,
266
- estimatedSuccess
267
- };
268
- }
269
- /**
270
- * Preview team vote strategy
271
- */
272
- previewTeamVote(stack1, stack2, conflicts) {
273
- const mergedFrames = [];
274
- const keptFromStack1 = [];
275
- const keptFromStack2 = [];
276
- const conflictingFrameIds = /* @__PURE__ */ new Set();
277
- for (const conflict of conflicts) {
278
- conflictingFrameIds.add(conflict.frameId1);
279
- conflictingFrameIds.add(conflict.frameId2);
280
- }
281
- for (const frame of stack1.frames) {
282
- if (!conflictingFrameIds.has(frame.frame_id)) {
283
- mergedFrames.push(frame);
284
- keptFromStack1.push(frame.frame_id);
285
- }
286
- }
287
- for (const frame of stack2.frames) {
288
- if (!conflictingFrameIds.has(frame.frame_id) && !mergedFrames.find((f) => f.frame_id === frame.frame_id)) {
289
- mergedFrames.push(frame);
290
- keptFromStack2.push(frame.frame_id);
291
- }
292
- }
293
- let useStack1 = true;
294
- for (const conflict of conflicts) {
295
- if (useStack1) {
296
- const frame = stack1.frames.find(
297
- (f) => f.frame_id === conflict.frameId1
298
- );
299
- if (frame) {
300
- mergedFrames.push(frame);
301
- keptFromStack1.push(frame.frame_id);
302
- }
303
- } else {
304
- const frame = stack2.frames.find(
305
- (f) => f.frame_id === conflict.frameId2
306
- );
307
- if (frame) {
308
- mergedFrames.push(frame);
309
- keptFromStack2.push(frame.frame_id);
310
- }
311
- }
312
- useStack1 = !useStack1;
313
- }
314
- return {
315
- mergedFrames,
316
- keptFromStack1,
317
- keptFromStack2,
318
- conflicts,
319
- estimatedSuccess: 0.75
320
- // Team consensus usually works well
321
- };
322
- }
323
- /**
324
- * Preview senior override strategy
325
- */
326
- previewSeniorOverride(stack1, stack2, conflicts) {
327
- const mergedFrames = [...stack1.frames];
328
- const keptFromStack1 = stack1.frames.map((f) => f.frame_id);
329
- const keptFromStack2 = [];
330
- const stack1Ids = new Set(keptFromStack1);
331
- for (const frame of stack2.frames) {
332
- const hasConflict = conflicts.some((c) => c.frameId2 === frame.frame_id);
333
- if (!hasConflict && !stack1Ids.has(frame.frame_id)) {
334
- mergedFrames.push(frame);
335
- keptFromStack2.push(frame.frame_id);
336
- }
337
- }
338
- return {
339
- mergedFrames,
340
- keptFromStack1,
341
- keptFromStack2,
342
- conflicts,
343
- estimatedSuccess: 0.85
344
- // Senior override is usually reliable
345
- };
346
- }
347
- /**
348
- * Preview AI suggest strategy
349
- */
350
- previewAISuggest(stack1, stack2, conflicts) {
351
- const mergedFrames = [];
352
- const keptFromStack1 = [];
353
- const keptFromStack2 = [];
354
- for (const conflict of conflicts) {
355
- const frame1 = stack1.frames.find(
356
- (f) => f.frame_id === conflict.frameId1
357
- );
358
- const frame2 = stack2.frames.find(
359
- (f) => f.frame_id === conflict.frameId2
360
- );
361
- if (frame1 && frame2) {
362
- const score1 = this.scoreFrame(frame1);
363
- const score2 = this.scoreFrame(frame2);
364
- if (score1 >= score2) {
365
- mergedFrames.push(frame1);
366
- keptFromStack1.push(frame1.frame_id);
367
- } else {
368
- mergedFrames.push(frame2);
369
- keptFromStack2.push(frame2.frame_id);
370
- }
371
- }
372
- }
373
- this.addNonConflictingFrames(
374
- stack1,
375
- stack2,
376
- conflicts,
377
- mergedFrames,
378
- keptFromStack1,
379
- keptFromStack2
380
- );
381
- return {
382
- mergedFrames,
383
- keptFromStack1,
384
- keptFromStack2,
385
- conflicts,
386
- estimatedSuccess: 0.9
387
- // AI suggestions are usually optimal
388
- };
389
- }
390
- /**
391
- * Preview hybrid strategy
392
- */
393
- previewHybrid(stack1, stack2, conflicts) {
394
- const mergedFrames = [];
395
- const keptFromStack1 = [];
396
- const keptFromStack2 = [];
397
- for (const conflict of conflicts) {
398
- if (conflict.type === "parallel_solution") {
399
- const frame1 = stack1.frames.find(
400
- (f) => f.frame_id === conflict.frameId1
401
- );
402
- const frame2 = stack2.frames.find(
403
- (f) => f.frame_id === conflict.frameId2
404
- );
405
- if (frame1) {
406
- mergedFrames.push(frame1);
407
- keptFromStack1.push(frame1.frame_id);
408
- }
409
- if (frame2) {
410
- mergedFrames.push(frame2);
411
- keptFromStack2.push(frame2.frame_id);
412
- }
413
- } else if (conflict.type === "conflicting_decision") {
414
- const frame1 = stack1.frames.find(
415
- (f) => f.frame_id === conflict.frameId1
416
- );
417
- const frame2 = stack2.frames.find(
418
- (f) => f.frame_id === conflict.frameId2
419
- );
420
- if (frame1 && frame2) {
421
- const score1 = this.scoreFrame(frame1);
422
- const score2 = this.scoreFrame(frame2);
423
- if (score1 >= score2) {
424
- mergedFrames.push(frame1);
425
- keptFromStack1.push(frame1.frame_id);
426
- } else {
427
- mergedFrames.push(frame2);
428
- keptFromStack2.push(frame2.frame_id);
429
- }
430
- }
431
- } else {
432
- const frame1 = stack1.frames.find(
433
- (f) => f.frame_id === conflict.frameId1
434
- );
435
- if (frame1) {
436
- mergedFrames.push(frame1);
437
- keptFromStack1.push(frame1.frame_id);
438
- }
439
- }
440
- }
441
- this.addNonConflictingFrames(
442
- stack1,
443
- stack2,
444
- conflicts,
445
- mergedFrames,
446
- keptFromStack1,
447
- keptFromStack2
448
- );
449
- return {
450
- mergedFrames,
451
- keptFromStack1,
452
- keptFromStack2,
453
- conflicts,
454
- estimatedSuccess: 0.88
455
- // Hybrid is very effective
456
- };
457
- }
458
- /**
459
- * Score a frame for quality
460
- */
461
- scoreFrame(frame) {
462
- let score = 0;
463
- if (frame.state === "closed") score += 0.3;
464
- if (frame.outputs && Object.keys(frame.outputs).length > 0) score += 0.2;
465
- if (frame.digest_text) score += 0.2;
466
- if (frame.closed_at && frame.created_at) {
467
- const duration = frame.closed_at - frame.created_at;
468
- if (duration < 6e5) score += 0.3;
469
- }
470
- return score;
471
- }
472
- /**
473
- * Add non-conflicting frames to merge
474
- */
475
- addNonConflictingFrames(stack1, stack2, conflicts, mergedFrames, keptFromStack1, keptFromStack2) {
476
- const conflictingIds = /* @__PURE__ */ new Set();
477
- const mergedIds = new Set(mergedFrames.map((f) => f.frame_id));
478
- for (const conflict of conflicts) {
479
- conflictingIds.add(conflict.frameId1);
480
- conflictingIds.add(conflict.frameId2);
481
- }
482
- for (const frame of stack1.frames) {
483
- if (!conflictingIds.has(frame.frame_id) && !mergedIds.has(frame.frame_id)) {
484
- mergedFrames.push(frame);
485
- keptFromStack1.push(frame.frame_id);
486
- mergedIds.add(frame.frame_id);
487
- }
488
- }
489
- for (const frame of stack2.frames) {
490
- if (!conflictingIds.has(frame.frame_id) && !mergedIds.has(frame.frame_id)) {
491
- mergedFrames.push(frame);
492
- keptFromStack2.push(frame.frame_id);
493
- mergedIds.add(frame.frame_id);
494
- }
495
- }
496
- }
497
- /**
498
- * Find divergence point between stacks
499
- */
500
- findDivergencePoint(stack1, stack2) {
501
- const events1 = stack1.events.sort((a, b) => a.ts - b.ts);
502
- const events2 = stack2.events.sort((a, b) => a.ts - b.ts);
503
- for (let i = 0; i < Math.min(events1.length, events2.length); i++) {
504
- if (events1[i].event_id !== events2[i].event_id) {
505
- return events1[i].ts;
506
- }
507
- }
508
- return Math.min(
509
- events1[events1.length - 1]?.ts || 0,
510
- events2[events2.length - 1]?.ts || 0
511
- );
512
- }
513
- /**
514
- * Find common ancestor frame
515
- */
516
- findCommonAncestor(stack1, stack2) {
517
- const frames1 = new Set(stack1.frames.map((f) => f.frame_id));
518
- let deepestCommon;
519
- let maxDepth = -1;
520
- for (const frame of stack2.frames) {
521
- if (frames1.has(frame.frame_id) && frame.depth > maxDepth) {
522
- deepestCommon = frame;
523
- maxDepth = frame.depth;
524
- }
525
- }
526
- return deepestCommon?.frame_id;
527
- }
528
- }
529
- export {
530
- StackDiffVisualizer
531
- };