@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,620 +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 * as fs from "fs/promises";
7
- import * as path from "path";
8
- import { sessionManager } from "../session/session-manager.js";
9
- import { logger } from "../monitoring/logger.js";
10
- class SharedContextLayer {
11
- static instance;
12
- contextDir;
13
- cache = /* @__PURE__ */ new Map();
14
- MAX_CACHE_SIZE = 100;
15
- CACHE_TTL = 5 * 60 * 1e3;
16
- // 5 minutes
17
- lastCacheClean = Date.now();
18
- constructor() {
19
- const homeDir = process.env["HOME"] || process.env["USERPROFILE"] || "";
20
- this.contextDir = path.join(homeDir, ".stackmemory", "shared-context");
21
- }
22
- static getInstance() {
23
- if (!SharedContextLayer.instance) {
24
- SharedContextLayer.instance = new SharedContextLayer();
25
- }
26
- return SharedContextLayer.instance;
27
- }
28
- async initialize() {
29
- await fs.mkdir(this.contextDir, { recursive: true });
30
- await fs.mkdir(path.join(this.contextDir, "projects"), { recursive: true });
31
- await fs.mkdir(path.join(this.contextDir, "patterns"), { recursive: true });
32
- await fs.mkdir(path.join(this.contextDir, "decisions"), {
33
- recursive: true
34
- });
35
- }
36
- /**
37
- * Get or create shared context for current project/branch
38
- */
39
- async getSharedContext(options) {
40
- const session = sessionManager.getCurrentSession();
41
- const projectId = options?.projectId || session?.projectId || "global";
42
- const branch = options?.branch || session?.branch;
43
- const cacheKey = `${projectId}:${branch || "main"}`;
44
- if (this.cache.has(cacheKey)) {
45
- const cached = this.cache.get(cacheKey);
46
- if (Date.now() - cached.lastUpdated < this.CACHE_TTL) {
47
- return cached;
48
- }
49
- }
50
- const context = await this.loadProjectContext(projectId, branch);
51
- if (options?.includeOtherBranches) {
52
- const otherBranches = await this.loadOtherBranchContexts(
53
- projectId,
54
- branch
55
- );
56
- context.sessions.push(...otherBranches);
57
- }
58
- this.cache.set(cacheKey, context);
59
- this.cleanCache();
60
- return context;
61
- }
62
- /**
63
- * Add current session's important frames to shared context
64
- */
65
- async addToSharedContext(frames, options) {
66
- const session = sessionManager.getCurrentSession();
67
- if (!session) return;
68
- const context = await this.getSharedContext();
69
- const minScore = options?.minScore || 0.7;
70
- const importantFrames = frames.filter((f) => {
71
- const score = this.calculateFrameScore(f);
72
- return score >= minScore;
73
- });
74
- const sessionContext = {
75
- sessionId: session.sessionId,
76
- runId: session.runId,
77
- summary: this.generateSessionSummary(importantFrames),
78
- keyFrames: importantFrames.map((f) => this.summarizeFrame(f)),
79
- createdAt: session.startedAt,
80
- lastActiveAt: Date.now(),
81
- metadata: session.metadata
82
- };
83
- const existingIndex = context.sessions.findIndex(
84
- (s) => s.sessionId === session.sessionId
85
- );
86
- if (existingIndex >= 0) {
87
- context.sessions[existingIndex] = sessionContext;
88
- } else {
89
- context.sessions.push(sessionContext);
90
- }
91
- this.updatePatterns(context, importantFrames);
92
- this.updateReferenceIndex(context, importantFrames);
93
- await this.saveProjectContext(context);
94
- }
95
- /**
96
- * Query shared context for relevant frames
97
- */
98
- async querySharedContext(query) {
99
- const context = await this.getSharedContext({ includeOtherBranches: true });
100
- let results = [];
101
- for (const session of context.sessions) {
102
- if (query.sessionId && session.sessionId !== query.sessionId) continue;
103
- if (!session.keyFrames || !Array.isArray(session.keyFrames)) continue;
104
- const filtered = session.keyFrames.filter((f) => {
105
- if (query.tags && !query.tags.some((tag) => f.tags.includes(tag)))
106
- return false;
107
- if (query.type && f.type !== query.type) return false;
108
- if (query.minScore && f.score < query.minScore) return false;
109
- return true;
110
- });
111
- results.push(...filtered);
112
- }
113
- results.sort((a, b) => {
114
- const scoreWeight = 0.7;
115
- const recencyWeight = 0.3;
116
- const aScore = a.score * scoreWeight + (1 - (Date.now() - a.createdAt) / (30 * 24 * 60 * 60 * 1e3)) * recencyWeight;
117
- const bScore = b.score * scoreWeight + (1 - (Date.now() - b.createdAt) / (30 * 24 * 60 * 60 * 1e3)) * recencyWeight;
118
- return bScore - aScore;
119
- });
120
- if (query.limit) {
121
- results = results.slice(0, query.limit);
122
- }
123
- const index = context.referenceIndex;
124
- if (!index.recentlyAccessed) {
125
- index.recentlyAccessed = [];
126
- }
127
- if (results.length > 0) {
128
- const frameIds = results.map((r) => r.frameId);
129
- index.recentlyAccessed = [
130
- ...frameIds,
131
- ...index.recentlyAccessed.filter((id) => !frameIds.includes(id))
132
- ].slice(0, 100);
133
- await this.saveProjectContext(context);
134
- }
135
- return results;
136
- }
137
- /**
138
- * Get relevant patterns from shared context
139
- */
140
- async getPatterns(type) {
141
- const context = await this.getSharedContext();
142
- if (type) {
143
- return context.globalPatterns.filter((p) => p.type === type);
144
- }
145
- return context.globalPatterns;
146
- }
147
- /**
148
- * Add a decision to the shared context
149
- */
150
- async addDecision(decision) {
151
- const session = sessionManager.getCurrentSession();
152
- if (!session) return;
153
- const context = await this.getSharedContext();
154
- const newDecision = {
155
- id: uuidv4(),
156
- timestamp: Date.now(),
157
- sessionId: session.sessionId,
158
- outcome: "pending",
159
- ...decision
160
- };
161
- context.decisionLog.push(newDecision);
162
- if (context.decisionLog.length > 100) {
163
- context.decisionLog = context.decisionLog.slice(-100);
164
- }
165
- await this.saveProjectContext(context);
166
- }
167
- /**
168
- * Get recent decisions from shared context
169
- */
170
- async getDecisions(limit = 10) {
171
- const context = await this.getSharedContext();
172
- return context.decisionLog.slice(-limit);
173
- }
174
- /**
175
- * Automatic context discovery on CLI startup
176
- */
177
- async autoDiscoverContext() {
178
- const context = await this.getSharedContext({
179
- includeOtherBranches: false
180
- });
181
- const recentPatterns = context.globalPatterns.filter((p) => Date.now() - p.lastSeen < 7 * 24 * 60 * 60 * 1e3).sort((a, b) => b.frequency - a.frequency).slice(0, 5);
182
- const lastDecisions = context.decisionLog.slice(-5);
183
- const suggestedFrames = await this.querySharedContext({
184
- minScore: 0.8,
185
- limit: 5
186
- });
187
- return {
188
- hasSharedContext: context.sessions.length > 0,
189
- sessionCount: context.sessions.length,
190
- recentPatterns,
191
- lastDecisions,
192
- suggestedFrames
193
- };
194
- }
195
- async loadProjectContext(projectId, branch) {
196
- const contextFile = path.join(
197
- this.contextDir,
198
- "projects",
199
- `${projectId}_${branch || "main"}.json`
200
- );
201
- try {
202
- const data = await fs.readFile(contextFile, "utf-8");
203
- const context = JSON.parse(data);
204
- context.referenceIndex.byTag = new Map(
205
- Object.entries(context.referenceIndex.byTag || {})
206
- );
207
- context.referenceIndex.byType = new Map(
208
- Object.entries(context.referenceIndex.byType || {})
209
- );
210
- return context;
211
- } catch {
212
- return {
213
- projectId,
214
- branch,
215
- lastUpdated: Date.now(),
216
- sessions: [],
217
- globalPatterns: [],
218
- decisionLog: [],
219
- referenceIndex: {
220
- byTag: /* @__PURE__ */ new Map(),
221
- byType: /* @__PURE__ */ new Map(),
222
- byScore: [],
223
- recentlyAccessed: []
224
- }
225
- };
226
- }
227
- }
228
- async saveProjectContext(context) {
229
- const contextFile = path.join(
230
- this.contextDir,
231
- "projects",
232
- `${context.projectId}_${context.branch || "main"}.json`
233
- );
234
- const serializable = {
235
- ...context,
236
- lastUpdated: Date.now(),
237
- referenceIndex: {
238
- ...context.referenceIndex,
239
- byTag: Object.fromEntries(context.referenceIndex.byTag),
240
- byType: Object.fromEntries(context.referenceIndex.byType)
241
- }
242
- };
243
- await fs.writeFile(contextFile, JSON.stringify(serializable, null, 2));
244
- }
245
- async loadOtherBranchContexts(projectId, currentBranch) {
246
- const projectsDir = path.join(this.contextDir, "projects");
247
- const files = await fs.readdir(projectsDir);
248
- const sessions = [];
249
- for (const file of files) {
250
- if (file.startsWith(`${projectId}_`) && !file.includes(currentBranch || "main")) {
251
- try {
252
- const data = await fs.readFile(path.join(projectsDir, file), "utf-8");
253
- const context = JSON.parse(data);
254
- sessions.push(...context.sessions);
255
- } catch {
256
- }
257
- }
258
- }
259
- return sessions;
260
- }
261
- calculateFrameScore(frame) {
262
- let score = 0.5;
263
- if (frame.type === "task" || frame.type === "review") score += 0.2;
264
- if (frame.type === "debug" || frame.type === "write") score += 0.15;
265
- if (frame.type === "error") score += 0.15;
266
- const frameWithData = frame;
267
- if (frameWithData.data) score += 0.2;
268
- if (frame.outputs && Object.keys(frame.outputs).length > 0) score += 0.2;
269
- if (frame.digest_text || frame.digest_json && Object.keys(frame.digest_json).length > 0)
270
- score += 0.1;
271
- if (frame.created_at) {
272
- const age = Date.now() - frame.created_at;
273
- const daysSinceCreation = age / (24 * 60 * 60 * 1e3);
274
- score *= Math.max(0.3, 1 - daysSinceCreation / 30);
275
- }
276
- return Math.min(1, score);
277
- }
278
- summarizeFrame(frame) {
279
- return {
280
- frameId: frame.frame_id,
281
- title: frame.name,
282
- type: frame.type,
283
- score: this.calculateFrameScore(frame),
284
- tags: [],
285
- summary: this.generateFrameSummary(frame),
286
- createdAt: frame.created_at
287
- };
288
- }
289
- generateFrameSummary(frame) {
290
- const parts = [];
291
- const frameWithData = frame;
292
- if (frame.type) parts.push(`[${frame.type}]`);
293
- if (frame.name) parts.push(frame.name);
294
- if (frameWithData.title) parts.push(frameWithData.title);
295
- if (frameWithData.data?.error)
296
- parts.push(`Error: ${frameWithData.data.error}`);
297
- if (frameWithData.data?.resolution)
298
- parts.push(`Resolution: ${frameWithData.data.resolution}`);
299
- return parts.join(" - ").slice(0, 200);
300
- }
301
- generateSessionSummary(frames) {
302
- const types = [...new Set(frames.map((f) => f.type))];
303
- return `Session with ${frames.length} key frames: ${types.join(", ")}`;
304
- }
305
- updatePatterns(context, frames) {
306
- for (const frame of frames) {
307
- const frameWithData = frame;
308
- if (frameWithData.data?.error) {
309
- this.addPattern(
310
- context,
311
- frameWithData.data.error,
312
- "error",
313
- frameWithData.data?.resolution
314
- );
315
- } else if (frame.type === "error" && frame.name) {
316
- const errorText = frame.outputs?.error || frame.name;
317
- const resolution = frame.outputs?.resolution;
318
- if (errorText) {
319
- this.addPattern(context, errorText, "error", resolution);
320
- }
321
- }
322
- if (frame.type === "decision" && frameWithData.data?.decision) {
323
- this.addPattern(context, frameWithData.data.decision, "decision");
324
- } else if (frame.digest_json?.decision) {
325
- this.addPattern(context, frame.digest_json.decision, "decision");
326
- }
327
- }
328
- }
329
- addPattern(context, pattern, type, resolution) {
330
- const existing = context.globalPatterns.find(
331
- (p) => p.pattern === pattern && p.type === type
332
- );
333
- if (existing) {
334
- existing.frequency++;
335
- existing.lastSeen = Date.now();
336
- if (resolution) existing.resolution = resolution;
337
- } else {
338
- context.globalPatterns.push({
339
- pattern,
340
- type,
341
- frequency: 1,
342
- lastSeen: Date.now(),
343
- resolution
344
- });
345
- }
346
- if (context.globalPatterns.length > 100) {
347
- context.globalPatterns.sort((a, b) => b.frequency - a.frequency);
348
- context.globalPatterns = context.globalPatterns.slice(0, 100);
349
- }
350
- }
351
- updateReferenceIndex(context, frames) {
352
- for (const frame of frames) {
353
- const summary = this.summarizeFrame(frame);
354
- for (const tag of summary.tags) {
355
- if (!context.referenceIndex.byTag.has(tag)) {
356
- context.referenceIndex.byTag.set(tag, []);
357
- }
358
- context.referenceIndex.byTag.get(tag).push(frame.frameId);
359
- }
360
- if (!context.referenceIndex.byType.has(frame.type)) {
361
- context.referenceIndex.byType.set(frame.type, []);
362
- }
363
- context.referenceIndex.byType.get(frame.type).push(frame.frameId);
364
- const scoreIndex = context.referenceIndex.byScore;
365
- const insertIndex = scoreIndex.findIndex((id) => {
366
- const otherFrame = context.sessions.flatMap((s) => s.keyFrames).find((f) => f.frameId === id);
367
- return otherFrame && otherFrame.score < summary.score;
368
- });
369
- if (insertIndex >= 0) {
370
- scoreIndex.splice(insertIndex, 0, frame.frameId);
371
- } else {
372
- scoreIndex.push(frame.frameId);
373
- }
374
- context.referenceIndex.byScore = scoreIndex.slice(0, 1e3);
375
- }
376
- }
377
- cleanCache() {
378
- if (Date.now() - this.lastCacheClean < 6e4) return;
379
- if (this.cache.size > this.MAX_CACHE_SIZE) {
380
- const entries = Array.from(this.cache.entries()).sort(
381
- (a, b) => b[1].lastUpdated - a[1].lastUpdated
382
- );
383
- this.cache = new Map(entries.slice(0, this.MAX_CACHE_SIZE / 2));
384
- }
385
- this.lastCacheClean = Date.now();
386
- }
387
- }
388
- const sharedContextLayer = SharedContextLayer.getInstance();
389
- class ContextBridge {
390
- static instance;
391
- frameManager = null;
392
- syncTimer = null;
393
- lastSyncTime = 0;
394
- options = {
395
- autoSync: true,
396
- syncInterval: 6e4,
397
- // 1 minute
398
- minFrameScore: 0.5,
399
- // Include frames with score above 0.5
400
- importantTags: ["decision", "error", "milestone", "learning"]
401
- };
402
- constructor() {
403
- }
404
- static getInstance() {
405
- if (!ContextBridge.instance) {
406
- ContextBridge.instance = new ContextBridge();
407
- }
408
- return ContextBridge.instance;
409
- }
410
- /**
411
- * Initialize the bridge with a frame manager
412
- */
413
- async initialize(frameManager, options) {
414
- this.frameManager = frameManager;
415
- this.options = { ...this.options, ...options };
416
- await this.loadSharedContext();
417
- if (this.options.autoSync) {
418
- this.startAutoSync();
419
- }
420
- logger.info("Context bridge initialized", {
421
- autoSync: this.options.autoSync,
422
- syncInterval: this.options.syncInterval
423
- });
424
- }
425
- /**
426
- * Load relevant shared context into current session
427
- */
428
- async loadSharedContext() {
429
- try {
430
- const session = sessionManager.getCurrentSession();
431
- if (!session) return;
432
- const discovery = await sharedContextLayer.autoDiscoverContext();
433
- if (!discovery.hasSharedContext) {
434
- logger.info("No shared context available to load");
435
- return;
436
- }
437
- if (discovery.recentPatterns.length > 0) {
438
- logger.info("Loaded recent patterns from shared context", {
439
- patternCount: discovery.recentPatterns.length
440
- });
441
- }
442
- if (discovery.lastDecisions.length > 0) {
443
- logger.info("Loaded recent decisions from shared context", {
444
- decisionCount: discovery.lastDecisions.length
445
- });
446
- }
447
- if (discovery.suggestedFrames.length > 0) {
448
- const metadata = {
449
- suggestedFrames: discovery.suggestedFrames,
450
- loadedAt: Date.now()
451
- };
452
- if (this.frameManager) {
453
- await this.frameManager.addContext(
454
- "shared-context-suggestions",
455
- metadata
456
- );
457
- }
458
- logger.info("Loaded suggested frames from shared context", {
459
- frameCount: discovery.suggestedFrames.length
460
- });
461
- }
462
- } catch (error) {
463
- logger.error("Failed to load shared context", error);
464
- }
465
- }
466
- /**
467
- * Sync current session's important frames to shared context
468
- */
469
- async syncToSharedContext() {
470
- try {
471
- if (!this.frameManager) return;
472
- const session = sessionManager.getCurrentSession();
473
- if (!session) return;
474
- const activeFrames = this.frameManager.getActiveFramePath().filter(Boolean);
475
- const recentFrames = await this.frameManager.getRecentFrames(100);
476
- const allFrames = [...activeFrames, ...recentFrames].filter(Boolean);
477
- const importantFrames = this.filterImportantFrames(allFrames);
478
- if (importantFrames.length === 0) {
479
- logger.debug("No important frames to sync");
480
- return;
481
- }
482
- await sharedContextLayer.addToSharedContext(importantFrames, {
483
- minScore: this.options.minFrameScore,
484
- tags: this.options.importantTags
485
- });
486
- this.lastSyncTime = Date.now();
487
- logger.info("Synced frames to shared context", {
488
- frameCount: importantFrames.length,
489
- sessionId: session.sessionId
490
- });
491
- } catch (error) {
492
- logger.error("Failed to sync to shared context", error);
493
- }
494
- }
495
- /**
496
- * Query shared context for relevant frames
497
- */
498
- async querySharedFrames(query) {
499
- try {
500
- const results = await sharedContextLayer.querySharedContext({
501
- ...query,
502
- minScore: this.options.minFrameScore
503
- });
504
- logger.info("Queried shared context", {
505
- query,
506
- resultCount: results.length
507
- });
508
- return results;
509
- } catch (error) {
510
- logger.error("Failed to query shared context", error);
511
- return [];
512
- }
513
- }
514
- /**
515
- * Add a decision to shared context
516
- */
517
- async addDecision(decision, reasoning) {
518
- try {
519
- await sharedContextLayer.addDecision({
520
- decision,
521
- reasoning,
522
- outcome: "pending"
523
- });
524
- logger.info("Added decision to shared context", { decision });
525
- } catch (error) {
526
- logger.error("Failed to add decision", error);
527
- }
528
- }
529
- /**
530
- * Start automatic synchronization
531
- */
532
- startAutoSync() {
533
- if (this.syncTimer) {
534
- clearInterval(this.syncTimer);
535
- }
536
- this.syncTimer = setInterval(() => {
537
- this.syncToSharedContext().catch((error) => {
538
- logger.error("Auto-sync failed", error);
539
- });
540
- }, this.options.syncInterval);
541
- this.setupEventListeners();
542
- }
543
- /**
544
- * Stop automatic synchronization
545
- */
546
- stopAutoSync() {
547
- if (this.syncTimer) {
548
- clearInterval(this.syncTimer);
549
- this.syncTimer = null;
550
- }
551
- }
552
- /**
553
- * Filter frames that are important enough to share
554
- */
555
- filterImportantFrames(frames) {
556
- return frames.filter((frame) => {
557
- const hasImportantTag = this.options.importantTags.some(
558
- (tag) => frame.metadata?.tags?.includes(tag)
559
- );
560
- const isImportantType = [
561
- "task",
562
- "milestone",
563
- "error",
564
- "resolution",
565
- "decision"
566
- ].includes(frame.type);
567
- const markedImportant = frame.metadata?.importance === "high";
568
- return hasImportantTag || isImportantType || markedImportant;
569
- });
570
- }
571
- /**
572
- * Setup event listeners for automatic syncing
573
- */
574
- setupEventListeners() {
575
- if (!this.frameManager) return;
576
- const originalClose = this.frameManager.closeFrame.bind(this.frameManager);
577
- this.frameManager.closeFrame = async (frameId, metadata) => {
578
- const result = await originalClose(frameId, metadata);
579
- const frame = await this.frameManager.getFrame(frameId);
580
- if (frame && this.filterImportantFrames([frame]).length > 0) {
581
- await this.syncToSharedContext();
582
- }
583
- return result;
584
- };
585
- const originalMilestone = this.frameManager.createFrame.bind(
586
- this.frameManager
587
- );
588
- this.frameManager.createFrame = async (params) => {
589
- const result = await originalMilestone(params);
590
- if (params.type === "milestone") {
591
- await this.syncToSharedContext();
592
- }
593
- return result;
594
- };
595
- }
596
- /**
597
- * Get sync statistics
598
- */
599
- getSyncStats() {
600
- return {
601
- lastSyncTime: this.lastSyncTime,
602
- autoSyncEnabled: this.options.autoSync,
603
- syncInterval: this.options.syncInterval
604
- };
605
- }
606
- /**
607
- * Manual trigger for immediate sync
608
- */
609
- async forceSyncNow() {
610
- logger.info("Force sync triggered");
611
- await this.syncToSharedContext();
612
- }
613
- }
614
- const contextBridge = ContextBridge.getInstance();
615
- export {
616
- ContextBridge,
617
- SharedContextLayer,
618
- contextBridge,
619
- sharedContextLayer
620
- };