@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.
Files changed (92) hide show
  1. package/README.md +104 -23
  2. package/dist/src/cli/claude-sm.js +266 -84
  3. package/dist/src/cli/codex-sm.js +185 -33
  4. package/dist/src/cli/commands/bench.js +209 -2
  5. package/dist/src/cli/commands/cache.js +126 -0
  6. package/dist/src/cli/commands/daemon.js +41 -0
  7. package/dist/src/cli/commands/handoff.js +40 -9
  8. package/dist/src/cli/commands/onboard.js +70 -3
  9. package/dist/src/cli/commands/optimize.js +117 -0
  10. package/dist/src/cli/commands/orchestrate.js +230 -5
  11. package/dist/src/cli/commands/orchestrator.js +312 -24
  12. package/dist/src/cli/commands/pack.js +322 -0
  13. package/dist/src/cli/commands/search.js +40 -1
  14. package/dist/src/cli/commands/setup.js +177 -7
  15. package/dist/src/cli/commands/skills.js +10 -1
  16. package/dist/src/cli/commands/state.js +265 -0
  17. package/dist/src/cli/gemini-sm.js +19 -29
  18. package/dist/src/cli/index.js +90 -29
  19. package/dist/src/cli/opencode-sm.js +38 -21
  20. package/dist/src/cli/utils/determinism-watcher.js +66 -0
  21. package/dist/src/cli/utils/real-cli-bin.js +44 -0
  22. package/dist/src/core/cache/content-cache.js +238 -0
  23. package/dist/src/core/cache/index.js +11 -0
  24. package/dist/src/core/cache/token-estimator.js +16 -0
  25. package/dist/src/core/context/frame-database.js +38 -30
  26. package/dist/src/core/cross-search/cross-project-search.js +269 -0
  27. package/dist/src/core/{merge → cross-search}/index.js +6 -4
  28. package/dist/src/core/database/sqlite-adapter.js +0 -83
  29. package/dist/src/core/extensions/provider-adapter.js +5 -0
  30. package/dist/src/core/models/model-router.js +22 -2
  31. package/dist/src/core/monitoring/logger.js +2 -1
  32. package/dist/src/core/optimization/trace-optimizer.js +413 -0
  33. package/dist/src/core/provenance/confidence-scorer.js +128 -0
  34. package/dist/src/core/provenance/index.js +40 -0
  35. package/dist/src/core/provenance/provenance-store.js +194 -0
  36. package/dist/src/core/provenance/types.js +82 -0
  37. package/dist/src/core/session/project-handoff.js +64 -0
  38. package/dist/src/core/session/session-manager.js +28 -0
  39. package/dist/src/core/shared-state/canonical-store.js +564 -0
  40. package/dist/src/core/skill-packs/index.js +18 -0
  41. package/dist/src/core/skill-packs/parser.js +42 -0
  42. package/dist/src/core/skill-packs/registry.js +224 -0
  43. package/dist/src/core/skill-packs/types.js +66 -0
  44. package/dist/src/core/trace/trace-event-store.js +282 -0
  45. package/dist/src/core/trace/trace-event.js +4 -0
  46. package/dist/src/daemon/daemon-config.js +7 -0
  47. package/dist/src/daemon/services/github-service.js +126 -0
  48. package/dist/src/daemon/unified-daemon.js +30 -0
  49. package/dist/src/features/sweep/pty-wrapper.js +13 -5
  50. package/dist/src/hooks/schemas.js +2 -0
  51. package/dist/src/integrations/claude-code/subagent-client.js +89 -0
  52. package/dist/src/integrations/github/pr-state.js +158 -0
  53. package/dist/src/integrations/linear/client.js +4 -1
  54. package/dist/src/integrations/mcp/handlers/cross-search-handlers.js +188 -0
  55. package/dist/src/integrations/mcp/handlers/index.js +40 -59
  56. package/dist/src/integrations/mcp/server.js +425 -311
  57. package/dist/src/integrations/mcp/tool-alias-registry.js +370 -0
  58. package/dist/src/integrations/mcp/tool-definitions.js +98 -229
  59. package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +3 -40
  60. package/dist/src/integrations/ralph/learning/pattern-learner.js +1 -20
  61. package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -2
  62. package/dist/src/mcp/stackmemory-mcp-server.js +315 -0
  63. package/dist/src/orchestrators/multimodal/determinism.js +243 -0
  64. package/dist/src/orchestrators/multimodal/harness.js +147 -77
  65. package/dist/src/orchestrators/multimodal/providers.js +44 -3
  66. package/dist/src/utils/hook-installer.js +0 -8
  67. package/package.json +10 -1
  68. package/packs/coding/python-fastapi/instructions.md +60 -0
  69. package/packs/coding/python-fastapi/pack.yaml +28 -0
  70. package/packs/coding/typescript-react/instructions.md +47 -0
  71. package/packs/coding/typescript-react/pack.yaml +28 -0
  72. package/packs/core/commands/capture.md +32 -0
  73. package/packs/core/commands/learn.md +73 -0
  74. package/packs/core/commands/next.md +36 -0
  75. package/packs/core/commands/restart.md +58 -0
  76. package/packs/core/commands/restore.md +29 -0
  77. package/packs/core/commands/start.md +57 -0
  78. package/packs/core/commands/stop.md +65 -0
  79. package/packs/core/commands/summary.md +40 -0
  80. package/packs/core/manifest.json +24 -0
  81. package/packs/ops/decision-recovery/instructions.md +65 -0
  82. package/packs/ops/decision-recovery/pack.yaml +89 -0
  83. package/dist/src/cli/commands/team.js +0 -168
  84. package/dist/src/core/context/shared-context-layer.js +0 -620
  85. package/dist/src/core/context/stack-merge-resolver.js +0 -748
  86. package/dist/src/core/merge/conflict-detector.js +0 -430
  87. package/dist/src/core/merge/resolution-engine.js +0 -557
  88. package/dist/src/core/merge/stack-diff.js +0 -531
  89. package/dist/src/core/merge/unified-merge-resolver.js +0 -302
  90. package/dist/src/integrations/mcp/handlers/cord-handlers.js +0 -397
  91. package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
  92. /package/dist/src/core/{merge → cache}/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
- };