@stackmemoryai/stackmemory 0.5.52 → 0.5.53
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/dist/cli/commands/handoff.js +191 -50
- package/dist/cli/commands/handoff.js.map +2 -2
- package/package.json +1 -1
- package/dist/core/context/compaction-handler.js +0 -330
- package/dist/core/context/compaction-handler.js.map +0 -7
- package/dist/core/context/context-bridge.js +0 -238
- package/dist/core/context/context-bridge.js.map +0 -7
- package/scripts/testing/scripts/testing/ab-test-runner.js +0 -363
- package/scripts/testing/scripts/testing/collect-metrics.js +0 -292
- package/scripts/testing/src/core/context/context-bridge.js +0 -253
- package/scripts/testing/src/core/context/frame-manager.js +0 -746
- package/scripts/testing/src/core/context/shared-context-layer.js +0 -437
- package/scripts/testing/src/core/database/database-adapter.js +0 -54
- package/scripts/testing/src/core/errors/index.js +0 -291
- package/scripts/testing/src/core/errors/recovery.js +0 -268
- package/scripts/testing/src/core/monitoring/logger.js +0 -145
- package/scripts/testing/src/core/retrieval/context-retriever.js +0 -516
- package/scripts/testing/src/core/session/index.js +0 -1
- package/scripts/testing/src/core/session/session-manager.js +0 -323
- package/scripts/testing/src/core/trace/cli-trace-wrapper.js +0 -140
- package/scripts/testing/src/core/trace/db-trace-wrapper.js +0 -251
- package/scripts/testing/src/core/trace/debug-trace.js +0 -398
- package/scripts/testing/src/core/trace/index.js +0 -120
- package/scripts/testing/src/core/trace/linear-api-wrapper.js +0 -204
|
@@ -1,330 +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 { logger } from "../monitoring/logger.js";
|
|
6
|
-
class CompactionHandler {
|
|
7
|
-
frameManager;
|
|
8
|
-
metrics;
|
|
9
|
-
tokenAccumulator = 0;
|
|
10
|
-
preservedAnchors = /* @__PURE__ */ new Map();
|
|
11
|
-
constructor(frameManager) {
|
|
12
|
-
this.frameManager = frameManager;
|
|
13
|
-
this.metrics = {
|
|
14
|
-
estimatedTokens: 0,
|
|
15
|
-
warningThreshold: 15e4,
|
|
16
|
-
// 150K tokens
|
|
17
|
-
criticalThreshold: 17e4,
|
|
18
|
-
// 170K tokens
|
|
19
|
-
anchorsPreserved: 0
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Track token usage from a message
|
|
24
|
-
*/
|
|
25
|
-
trackTokens(content) {
|
|
26
|
-
const estimatedTokens = Math.ceil(content.length / 4);
|
|
27
|
-
this.tokenAccumulator += estimatedTokens;
|
|
28
|
-
this.metrics.estimatedTokens += estimatedTokens;
|
|
29
|
-
if (this.isApproachingCompaction()) {
|
|
30
|
-
this.preserveCriticalContext();
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Check if approaching compaction threshold
|
|
35
|
-
*/
|
|
36
|
-
isApproachingCompaction() {
|
|
37
|
-
return this.metrics.estimatedTokens >= this.metrics.warningThreshold;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Check if past critical threshold
|
|
41
|
-
*/
|
|
42
|
-
isPastCriticalThreshold() {
|
|
43
|
-
return this.metrics.estimatedTokens >= this.metrics.criticalThreshold;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Detect if compaction likely occurred
|
|
47
|
-
*/
|
|
48
|
-
detectCompactionEvent(content) {
|
|
49
|
-
const compactionIndicators = [
|
|
50
|
-
"earlier in this conversation",
|
|
51
|
-
"previously discussed",
|
|
52
|
-
"as mentioned before",
|
|
53
|
-
"summarized for brevity",
|
|
54
|
-
"[conversation compressed]",
|
|
55
|
-
"[context truncated]"
|
|
56
|
-
];
|
|
57
|
-
const lowerContent = content.toLowerCase();
|
|
58
|
-
return compactionIndicators.some(
|
|
59
|
-
(indicator) => lowerContent.includes(indicator)
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Preserve critical context before compaction
|
|
64
|
-
*/
|
|
65
|
-
async preserveCriticalContext() {
|
|
66
|
-
try {
|
|
67
|
-
const currentFrameId = this.frameManager.getCurrentFrameId();
|
|
68
|
-
if (!currentFrameId) {
|
|
69
|
-
logger.warn("No active frame to preserve context from");
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const events = this.frameManager.getFrameEvents(currentFrameId);
|
|
73
|
-
const toolCalls = this.extractToolCalls(events);
|
|
74
|
-
const fileOps = this.extractFileOperations(events);
|
|
75
|
-
const decisions = this.extractDecisions(events);
|
|
76
|
-
const errorPatterns = this.extractErrorPatterns(events);
|
|
77
|
-
const anchor = {
|
|
78
|
-
anchor_id: `compact_${Date.now()}`,
|
|
79
|
-
type: "COMPACTION_PRESERVE",
|
|
80
|
-
priority: 10,
|
|
81
|
-
content: {
|
|
82
|
-
tool_calls: toolCalls,
|
|
83
|
-
file_operations: fileOps,
|
|
84
|
-
decisions,
|
|
85
|
-
error_resolutions: errorPatterns
|
|
86
|
-
},
|
|
87
|
-
created_at: Date.now(),
|
|
88
|
-
token_estimate: this.metrics.estimatedTokens
|
|
89
|
-
};
|
|
90
|
-
this.frameManager.addAnchor(
|
|
91
|
-
"CONSTRAINT",
|
|
92
|
-
// Using CONSTRAINT type for now
|
|
93
|
-
JSON.stringify(anchor),
|
|
94
|
-
10,
|
|
95
|
-
{
|
|
96
|
-
compaction_preserve: true,
|
|
97
|
-
token_count: this.metrics.estimatedTokens
|
|
98
|
-
},
|
|
99
|
-
currentFrameId
|
|
100
|
-
);
|
|
101
|
-
this.preservedAnchors.set(anchor.anchor_id, anchor);
|
|
102
|
-
this.metrics.anchorsPreserved++;
|
|
103
|
-
logger.info(
|
|
104
|
-
`Preserved critical context at ${this.metrics.estimatedTokens} tokens`
|
|
105
|
-
);
|
|
106
|
-
} catch (error) {
|
|
107
|
-
logger.error(
|
|
108
|
-
"Failed to preserve critical context:",
|
|
109
|
-
error instanceof Error ? error : void 0
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Extract tool calls from events
|
|
115
|
-
*/
|
|
116
|
-
extractToolCalls(events) {
|
|
117
|
-
const toolCalls = [];
|
|
118
|
-
const toolEvents = events.filter((e) => e.event_type === "tool_call");
|
|
119
|
-
for (const event of toolEvents) {
|
|
120
|
-
const resultEvent = events.find(
|
|
121
|
-
(e) => e.event_type === "tool_result" && e.seq > event.seq && e.payload.tool_name === event.payload.tool_name
|
|
122
|
-
);
|
|
123
|
-
toolCalls.push({
|
|
124
|
-
tool: event.payload.tool_name || "unknown",
|
|
125
|
-
timestamp: event.ts,
|
|
126
|
-
key_inputs: this.extractKeyInputs(event.payload),
|
|
127
|
-
key_outputs: resultEvent ? this.extractKeyOutputs(resultEvent.payload) : {},
|
|
128
|
-
files_affected: this.extractAffectedFiles(
|
|
129
|
-
event.payload,
|
|
130
|
-
resultEvent?.payload
|
|
131
|
-
),
|
|
132
|
-
success: resultEvent ? !resultEvent.payload.error : false,
|
|
133
|
-
error: resultEvent?.payload.error
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
return toolCalls;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Extract key inputs from tool call
|
|
140
|
-
*/
|
|
141
|
-
extractKeyInputs(payload) {
|
|
142
|
-
const keys = [
|
|
143
|
-
"file_path",
|
|
144
|
-
"command",
|
|
145
|
-
"query",
|
|
146
|
-
"path",
|
|
147
|
-
"pattern",
|
|
148
|
-
"content"
|
|
149
|
-
];
|
|
150
|
-
const result = {};
|
|
151
|
-
for (const key of keys) {
|
|
152
|
-
if (payload.arguments?.[key]) {
|
|
153
|
-
result[key] = payload.arguments[key];
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return result;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Extract key outputs from tool result
|
|
160
|
-
*/
|
|
161
|
-
extractKeyOutputs(payload) {
|
|
162
|
-
return {
|
|
163
|
-
success: !payload.error,
|
|
164
|
-
error: payload.error,
|
|
165
|
-
result_type: payload.result_type,
|
|
166
|
-
files_created: payload.files_created,
|
|
167
|
-
files_modified: payload.files_modified
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Extract affected files from tool events
|
|
172
|
-
*/
|
|
173
|
-
extractAffectedFiles(callPayload, resultPayload) {
|
|
174
|
-
const files = /* @__PURE__ */ new Set();
|
|
175
|
-
if (callPayload?.arguments?.file_path) {
|
|
176
|
-
files.add(callPayload.arguments.file_path);
|
|
177
|
-
}
|
|
178
|
-
if (callPayload?.arguments?.path) {
|
|
179
|
-
files.add(callPayload.arguments.path);
|
|
180
|
-
}
|
|
181
|
-
if (resultPayload?.files_created) {
|
|
182
|
-
resultPayload.files_created.forEach((f) => files.add(f));
|
|
183
|
-
}
|
|
184
|
-
if (resultPayload?.files_modified) {
|
|
185
|
-
resultPayload.files_modified.forEach((f) => files.add(f));
|
|
186
|
-
}
|
|
187
|
-
return Array.from(files);
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Extract file operations from events
|
|
191
|
-
*/
|
|
192
|
-
extractFileOperations(events) {
|
|
193
|
-
const fileOps = [];
|
|
194
|
-
const fileTools = ["Read", "Write", "Edit", "MultiEdit", "Delete"];
|
|
195
|
-
const toolEvents = events.filter(
|
|
196
|
-
(e) => e.event_type === "tool_call" && fileTools.includes(e.payload.tool_name)
|
|
197
|
-
);
|
|
198
|
-
for (const event of toolEvents) {
|
|
199
|
-
const operation = this.mapToolToOperation(event.payload.tool_name);
|
|
200
|
-
const path = event.payload.arguments?.file_path || event.payload.arguments?.path || "unknown";
|
|
201
|
-
fileOps.push({
|
|
202
|
-
type: operation,
|
|
203
|
-
path,
|
|
204
|
-
timestamp: event.ts,
|
|
205
|
-
success: true,
|
|
206
|
-
// Will be updated from result
|
|
207
|
-
error: void 0
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
return fileOps;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Map tool name to file operation type
|
|
214
|
-
*/
|
|
215
|
-
mapToolToOperation(toolName) {
|
|
216
|
-
const mapping = {
|
|
217
|
-
Read: "read",
|
|
218
|
-
Write: "write",
|
|
219
|
-
Edit: "edit",
|
|
220
|
-
MultiEdit: "edit",
|
|
221
|
-
Delete: "delete"
|
|
222
|
-
};
|
|
223
|
-
return mapping[toolName] || "read";
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Extract decisions from events
|
|
227
|
-
*/
|
|
228
|
-
extractDecisions(events) {
|
|
229
|
-
const decisions = [];
|
|
230
|
-
const decisionEvents = events.filter((e) => e.event_type === "decision");
|
|
231
|
-
for (const event of decisionEvents) {
|
|
232
|
-
if (event.payload.text) {
|
|
233
|
-
decisions.push(event.payload.text);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return decisions;
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Extract error patterns and resolutions
|
|
240
|
-
*/
|
|
241
|
-
extractErrorPatterns(events) {
|
|
242
|
-
const patterns = [];
|
|
243
|
-
const errorEvents = events.filter(
|
|
244
|
-
(e) => e.event_type === "tool_result" && e.payload.error
|
|
245
|
-
);
|
|
246
|
-
for (const errorEvent of errorEvents) {
|
|
247
|
-
const subsequentTools = events.filter((e) => e.event_type === "tool_call" && e.seq > errorEvent.seq).slice(0, 3);
|
|
248
|
-
if (subsequentTools.length > 0) {
|
|
249
|
-
patterns.push({
|
|
250
|
-
error: errorEvent.payload.error,
|
|
251
|
-
resolution: `Attempted resolution with ${subsequentTools.map((t) => t.payload.tool_name).join(", ")}`,
|
|
252
|
-
tool_sequence: subsequentTools.map((t) => t.payload.tool_name),
|
|
253
|
-
timestamp: errorEvent.ts
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return patterns;
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Restore context after compaction detected
|
|
261
|
-
*/
|
|
262
|
-
async restoreContext() {
|
|
263
|
-
if (this.preservedAnchors.size === 0) {
|
|
264
|
-
logger.warn("No preserved anchors to restore from");
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
const anchors = Array.from(this.preservedAnchors.values());
|
|
268
|
-
anchors.sort((a, b) => b.created_at - a.created_at);
|
|
269
|
-
const latestAnchor = anchors[0];
|
|
270
|
-
const restorationFrame = this.frameManager.createFrame({
|
|
271
|
-
type: "review",
|
|
272
|
-
name: "Context Restoration After Compaction",
|
|
273
|
-
inputs: { reason: "autocompaction_detected" }
|
|
274
|
-
});
|
|
275
|
-
this.frameManager.addAnchor(
|
|
276
|
-
"FACT",
|
|
277
|
-
`Context restored from token position ${latestAnchor.token_estimate}`,
|
|
278
|
-
10,
|
|
279
|
-
{ restoration: true },
|
|
280
|
-
restorationFrame
|
|
281
|
-
);
|
|
282
|
-
const toolSequence = latestAnchor.content.tool_calls.map((t) => t.tool).join(" \u2192 ");
|
|
283
|
-
this.frameManager.addAnchor(
|
|
284
|
-
"FACT",
|
|
285
|
-
`Tool sequence: ${toolSequence}`,
|
|
286
|
-
9,
|
|
287
|
-
{},
|
|
288
|
-
restorationFrame
|
|
289
|
-
);
|
|
290
|
-
const files = /* @__PURE__ */ new Set();
|
|
291
|
-
latestAnchor.content.file_operations.forEach((op) => files.add(op.path));
|
|
292
|
-
if (files.size > 0) {
|
|
293
|
-
this.frameManager.addAnchor(
|
|
294
|
-
"FACT",
|
|
295
|
-
`Files touched: ${Array.from(files).join(", ")}`,
|
|
296
|
-
8,
|
|
297
|
-
{},
|
|
298
|
-
restorationFrame
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
for (const decision of latestAnchor.content.decisions) {
|
|
302
|
-
this.frameManager.addAnchor(
|
|
303
|
-
"DECISION",
|
|
304
|
-
decision,
|
|
305
|
-
7,
|
|
306
|
-
{},
|
|
307
|
-
restorationFrame
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
logger.info("Context restored after compaction detection");
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* Get current metrics
|
|
314
|
-
*/
|
|
315
|
-
getMetrics() {
|
|
316
|
-
return { ...this.metrics };
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Reset token counter (e.g., at session start)
|
|
320
|
-
*/
|
|
321
|
-
resetTokenCount() {
|
|
322
|
-
this.metrics.estimatedTokens = 0;
|
|
323
|
-
this.tokenAccumulator = 0;
|
|
324
|
-
this.metrics.lastCompactionAt = void 0;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
export {
|
|
328
|
-
CompactionHandler
|
|
329
|
-
};
|
|
330
|
-
//# sourceMappingURL=compaction-handler.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/core/context/compaction-handler.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Compaction Handler for Claude Code Autocompaction\n * Preserves critical context across token limit boundaries\n */\n\nimport { FrameManager } from './index.js';\nimport type { Anchor, Event } from './index.js';\nimport { logger } from '../monitoring/logger.js';\n\nexport interface CompactionMetrics {\n estimatedTokens: number;\n warningThreshold: number;\n criticalThreshold: number;\n lastCompactionAt?: number;\n anchorsPreserved: number;\n}\n\nexport interface ToolCallSummary {\n tool: string;\n timestamp: number;\n key_inputs: Record<string, any>;\n key_outputs: Record<string, any>;\n files_affected: string[];\n success: boolean;\n error?: string;\n}\n\nexport interface CriticalContextAnchor {\n anchor_id: string;\n type: 'COMPACTION_PRESERVE';\n priority: 10; // Highest priority\n content: {\n tool_calls: ToolCallSummary[];\n decisions: string[];\n file_operations: FileOperation[];\n error_resolutions: ErrorPattern[];\n };\n created_at: number;\n token_estimate: number;\n}\n\nexport interface FileOperation {\n type: 'read' | 'write' | 'edit' | 'delete' | 'create';\n path: string;\n timestamp: number;\n success: boolean;\n error?: string;\n}\n\nexport interface ErrorPattern {\n error: string;\n resolution: string;\n tool_sequence: string[];\n timestamp: number;\n}\n\nexport class CompactionHandler {\n private frameManager: FrameManager;\n private metrics: CompactionMetrics;\n private tokenAccumulator: number = 0;\n private preservedAnchors: Map<string, CriticalContextAnchor> = new Map();\n\n constructor(frameManager: FrameManager) {\n this.frameManager = frameManager;\n this.metrics = {\n estimatedTokens: 0,\n warningThreshold: 150000, // 150K tokens\n criticalThreshold: 170000, // 170K tokens\n anchorsPreserved: 0,\n };\n }\n\n /**\n * Track token usage from a message\n */\n trackTokens(content: string): void {\n // Rough estimation: 1 token \u2248 4 characters\n const estimatedTokens = Math.ceil(content.length / 4);\n this.tokenAccumulator += estimatedTokens;\n this.metrics.estimatedTokens += estimatedTokens;\n\n // Check thresholds\n if (this.isApproachingCompaction()) {\n this.preserveCriticalContext();\n }\n }\n\n /**\n * Check if approaching compaction threshold\n */\n isApproachingCompaction(): boolean {\n return this.metrics.estimatedTokens >= this.metrics.warningThreshold;\n }\n\n /**\n * Check if past critical threshold\n */\n isPastCriticalThreshold(): boolean {\n return this.metrics.estimatedTokens >= this.metrics.criticalThreshold;\n }\n\n /**\n * Detect if compaction likely occurred\n */\n detectCompactionEvent(content: string): boolean {\n const compactionIndicators = [\n 'earlier in this conversation',\n 'previously discussed',\n 'as mentioned before',\n 'summarized for brevity',\n '[conversation compressed]',\n '[context truncated]',\n ];\n\n const lowerContent = content.toLowerCase();\n return compactionIndicators.some((indicator) =>\n lowerContent.includes(indicator)\n );\n }\n\n /**\n * Preserve critical context before compaction\n */\n async preserveCriticalContext(): Promise<void> {\n try {\n const currentFrameId = this.frameManager.getCurrentFrameId();\n if (!currentFrameId) {\n logger.warn('No active frame to preserve context from');\n return;\n }\n\n // Get events from current frame\n const events = this.frameManager.getFrameEvents(currentFrameId);\n\n // Extract critical information\n const toolCalls = this.extractToolCalls(events);\n const fileOps = this.extractFileOperations(events);\n const decisions = this.extractDecisions(events);\n const errorPatterns = this.extractErrorPatterns(events);\n\n // Create preservation anchor\n const anchor: CriticalContextAnchor = {\n anchor_id: `compact_${Date.now()}`,\n type: 'COMPACTION_PRESERVE',\n priority: 10,\n content: {\n tool_calls: toolCalls,\n file_operations: fileOps,\n decisions: decisions,\n error_resolutions: errorPatterns,\n },\n created_at: Date.now(),\n token_estimate: this.metrics.estimatedTokens,\n };\n\n // Store in frame manager as high-priority anchor\n this.frameManager.addAnchor(\n 'CONSTRAINT' as any, // Using CONSTRAINT type for now\n JSON.stringify(anchor),\n 10,\n {\n compaction_preserve: true,\n token_count: this.metrics.estimatedTokens,\n },\n currentFrameId\n );\n\n // Store locally for quick access\n this.preservedAnchors.set(anchor.anchor_id, anchor);\n this.metrics.anchorsPreserved++;\n\n logger.info(\n `Preserved critical context at ${this.metrics.estimatedTokens} tokens`\n );\n } catch (error: unknown) {\n logger.error(\n 'Failed to preserve critical context:',\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Extract tool calls from events\n */\n private extractToolCalls(events: Event[]): ToolCallSummary[] {\n const toolCalls: ToolCallSummary[] = [];\n const toolEvents = events.filter((e) => e.event_type === 'tool_call');\n\n for (const event of toolEvents) {\n const resultEvent = events.find(\n (e) =>\n e.event_type === 'tool_result' &&\n e.seq > event.seq &&\n e.payload.tool_name === event.payload.tool_name\n );\n\n toolCalls.push({\n tool: event.payload.tool_name || 'unknown',\n timestamp: event.ts,\n key_inputs: this.extractKeyInputs(event.payload),\n key_outputs: resultEvent\n ? this.extractKeyOutputs(resultEvent.payload)\n : {},\n files_affected: this.extractAffectedFiles(\n event.payload,\n resultEvent?.payload\n ),\n success: resultEvent ? !resultEvent.payload.error : false,\n error: resultEvent?.payload.error,\n });\n }\n\n return toolCalls;\n }\n\n /**\n * Extract key inputs from tool call\n */\n private extractKeyInputs(payload: any): Record<string, any> {\n const keys = [\n 'file_path',\n 'command',\n 'query',\n 'path',\n 'pattern',\n 'content',\n ];\n const result: Record<string, any> = {};\n\n for (const key of keys) {\n if (payload.arguments?.[key]) {\n result[key] = payload.arguments[key];\n }\n }\n\n return result;\n }\n\n /**\n * Extract key outputs from tool result\n */\n private extractKeyOutputs(payload: any): Record<string, any> {\n return {\n success: !payload.error,\n error: payload.error,\n result_type: payload.result_type,\n files_created: payload.files_created,\n files_modified: payload.files_modified,\n };\n }\n\n /**\n * Extract affected files from tool events\n */\n private extractAffectedFiles(callPayload: any, resultPayload: any): string[] {\n const files = new Set<string>();\n\n // From tool call\n if (callPayload?.arguments?.file_path) {\n files.add(callPayload.arguments.file_path);\n }\n if (callPayload?.arguments?.path) {\n files.add(callPayload.arguments.path);\n }\n\n // From tool result\n if (resultPayload?.files_created) {\n resultPayload.files_created.forEach((f: string) => files.add(f));\n }\n if (resultPayload?.files_modified) {\n resultPayload.files_modified.forEach((f: string) => files.add(f));\n }\n\n return Array.from(files);\n }\n\n /**\n * Extract file operations from events\n */\n private extractFileOperations(events: Event[]): FileOperation[] {\n const fileOps: FileOperation[] = [];\n const fileTools = ['Read', 'Write', 'Edit', 'MultiEdit', 'Delete'];\n\n const toolEvents = events.filter(\n (e) =>\n e.event_type === 'tool_call' && fileTools.includes(e.payload.tool_name)\n );\n\n for (const event of toolEvents) {\n const operation = this.mapToolToOperation(event.payload.tool_name);\n const path =\n event.payload.arguments?.file_path ||\n event.payload.arguments?.path ||\n 'unknown';\n\n fileOps.push({\n type: operation,\n path: path,\n timestamp: event.ts,\n success: true, // Will be updated from result\n error: undefined,\n });\n }\n\n return fileOps;\n }\n\n /**\n * Map tool name to file operation type\n */\n private mapToolToOperation(toolName: string): FileOperation['type'] {\n const mapping: Record<string, FileOperation['type']> = {\n Read: 'read',\n Write: 'write',\n Edit: 'edit',\n MultiEdit: 'edit',\n Delete: 'delete',\n };\n\n return mapping[toolName] || 'read';\n }\n\n /**\n * Extract decisions from events\n */\n private extractDecisions(events: Event[]): string[] {\n const decisions: string[] = [];\n\n const decisionEvents = events.filter((e) => e.event_type === 'decision');\n for (const event of decisionEvents) {\n if (event.payload.text) {\n decisions.push(event.payload.text);\n }\n }\n\n return decisions;\n }\n\n /**\n * Extract error patterns and resolutions\n */\n private extractErrorPatterns(events: Event[]): ErrorPattern[] {\n const patterns: ErrorPattern[] = [];\n\n // Find tool results with errors\n const errorEvents = events.filter(\n (e) => e.event_type === 'tool_result' && e.payload.error\n );\n\n for (const errorEvent of errorEvents) {\n // Look for subsequent successful tool calls that might be resolutions\n const subsequentTools = events\n .filter((e) => e.event_type === 'tool_call' && e.seq > errorEvent.seq)\n .slice(0, 3); // Next 3 tools might be resolution attempts\n\n if (subsequentTools.length > 0) {\n patterns.push({\n error: errorEvent.payload.error,\n resolution: `Attempted resolution with ${subsequentTools.map((t) => t.payload.tool_name).join(', ')}`,\n tool_sequence: subsequentTools.map((t) => t.payload.tool_name),\n timestamp: errorEvent.ts,\n });\n }\n }\n\n return patterns;\n }\n\n /**\n * Restore context after compaction detected\n */\n async restoreContext(): Promise<void> {\n if (this.preservedAnchors.size === 0) {\n logger.warn('No preserved anchors to restore from');\n return;\n }\n\n // Get the most recent anchor\n const anchors = Array.from(this.preservedAnchors.values());\n anchors.sort((a, b) => b.created_at - a.created_at);\n const latestAnchor = anchors[0];\n\n // Create restoration frame\n const restorationFrame = this.frameManager.createFrame({\n type: 'review',\n name: 'Context Restoration After Compaction',\n inputs: { reason: 'autocompaction_detected' },\n });\n\n // Add restoration anchor\n this.frameManager.addAnchor(\n 'FACT',\n `Context restored from token position ${latestAnchor.token_estimate}`,\n 10,\n { restoration: true },\n restorationFrame\n );\n\n // Add tool sequence summary\n const toolSequence = latestAnchor.content.tool_calls\n .map((t) => t.tool)\n .join(' \u2192 ');\n this.frameManager.addAnchor(\n 'FACT',\n `Tool sequence: ${toolSequence}`,\n 9,\n {},\n restorationFrame\n );\n\n // Add file operations summary\n const files = new Set<string>();\n latestAnchor.content.file_operations.forEach((op) => files.add(op.path));\n if (files.size > 0) {\n this.frameManager.addAnchor(\n 'FACT',\n `Files touched: ${Array.from(files).join(', ')}`,\n 8,\n {},\n restorationFrame\n );\n }\n\n // Add decisions\n for (const decision of latestAnchor.content.decisions) {\n this.frameManager.addAnchor(\n 'DECISION',\n decision,\n 7,\n {},\n restorationFrame\n );\n }\n\n logger.info('Context restored after compaction detection');\n }\n\n /**\n * Get current metrics\n */\n getMetrics(): CompactionMetrics {\n return { ...this.metrics };\n }\n\n /**\n * Reset token counter (e.g., at session start)\n */\n resetTokenCount(): void {\n this.metrics.estimatedTokens = 0;\n this.tokenAccumulator = 0;\n this.metrics.lastCompactionAt = undefined;\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,238 +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 { sharedContextLayer } from "./shared-context-layer.js";
|
|
6
|
-
import { sessionManager } from "../session/session-manager.js";
|
|
7
|
-
import { logger } from "../monitoring/logger.js";
|
|
8
|
-
class ContextBridge {
|
|
9
|
-
static instance;
|
|
10
|
-
frameManager = null;
|
|
11
|
-
syncTimer = null;
|
|
12
|
-
lastSyncTime = 0;
|
|
13
|
-
options = {
|
|
14
|
-
autoSync: true,
|
|
15
|
-
syncInterval: 6e4,
|
|
16
|
-
// 1 minute
|
|
17
|
-
minFrameScore: 0.5,
|
|
18
|
-
// Include frames with score above 0.5
|
|
19
|
-
importantTags: ["decision", "error", "milestone", "learning"]
|
|
20
|
-
};
|
|
21
|
-
constructor() {
|
|
22
|
-
}
|
|
23
|
-
static getInstance() {
|
|
24
|
-
if (!ContextBridge.instance) {
|
|
25
|
-
ContextBridge.instance = new ContextBridge();
|
|
26
|
-
}
|
|
27
|
-
return ContextBridge.instance;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Initialize the bridge with a frame manager
|
|
31
|
-
*/
|
|
32
|
-
async initialize(frameManager, options) {
|
|
33
|
-
this.frameManager = frameManager;
|
|
34
|
-
this.options = { ...this.options, ...options };
|
|
35
|
-
await this.loadSharedContext();
|
|
36
|
-
if (this.options.autoSync) {
|
|
37
|
-
this.startAutoSync();
|
|
38
|
-
}
|
|
39
|
-
logger.info("Context bridge initialized", {
|
|
40
|
-
autoSync: this.options.autoSync,
|
|
41
|
-
syncInterval: this.options.syncInterval
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Load relevant shared context into current session
|
|
46
|
-
*/
|
|
47
|
-
async loadSharedContext() {
|
|
48
|
-
try {
|
|
49
|
-
const session = sessionManager.getCurrentSession();
|
|
50
|
-
if (!session) return;
|
|
51
|
-
const discovery = await sharedContextLayer.autoDiscoverContext();
|
|
52
|
-
if (!discovery.hasSharedContext) {
|
|
53
|
-
logger.info("No shared context available to load");
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
if (discovery.recentPatterns.length > 0) {
|
|
57
|
-
logger.info("Loaded recent patterns from shared context", {
|
|
58
|
-
patternCount: discovery.recentPatterns.length
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
if (discovery.lastDecisions.length > 0) {
|
|
62
|
-
logger.info("Loaded recent decisions from shared context", {
|
|
63
|
-
decisionCount: discovery.lastDecisions.length
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
if (discovery.suggestedFrames.length > 0) {
|
|
67
|
-
const metadata = {
|
|
68
|
-
suggestedFrames: discovery.suggestedFrames,
|
|
69
|
-
loadedAt: Date.now()
|
|
70
|
-
};
|
|
71
|
-
if (this.frameManager) {
|
|
72
|
-
await this.frameManager.addContext(
|
|
73
|
-
"shared-context-suggestions",
|
|
74
|
-
metadata
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
logger.info("Loaded suggested frames from shared context", {
|
|
78
|
-
frameCount: discovery.suggestedFrames.length
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
} catch (error) {
|
|
82
|
-
logger.error("Failed to load shared context", error);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Sync current session's important frames to shared context
|
|
87
|
-
*/
|
|
88
|
-
async syncToSharedContext() {
|
|
89
|
-
try {
|
|
90
|
-
if (!this.frameManager) return;
|
|
91
|
-
const session = sessionManager.getCurrentSession();
|
|
92
|
-
if (!session) return;
|
|
93
|
-
const activeFrames = this.frameManager.getActiveFramePath().filter(Boolean);
|
|
94
|
-
const recentFrames = await this.frameManager.getRecentFrames(100);
|
|
95
|
-
const allFrames = [...activeFrames, ...recentFrames].filter(Boolean);
|
|
96
|
-
const importantFrames = this.filterImportantFrames(allFrames);
|
|
97
|
-
if (importantFrames.length === 0) {
|
|
98
|
-
logger.debug("No important frames to sync");
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
await sharedContextLayer.addToSharedContext(importantFrames, {
|
|
102
|
-
minScore: this.options.minFrameScore,
|
|
103
|
-
tags: this.options.importantTags
|
|
104
|
-
});
|
|
105
|
-
this.lastSyncTime = Date.now();
|
|
106
|
-
logger.info("Synced frames to shared context", {
|
|
107
|
-
frameCount: importantFrames.length,
|
|
108
|
-
sessionId: session.sessionId
|
|
109
|
-
});
|
|
110
|
-
} catch (error) {
|
|
111
|
-
logger.error("Failed to sync to shared context", error);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Query shared context for relevant frames
|
|
116
|
-
*/
|
|
117
|
-
async querySharedFrames(query) {
|
|
118
|
-
try {
|
|
119
|
-
const results = await sharedContextLayer.querySharedContext({
|
|
120
|
-
...query,
|
|
121
|
-
minScore: this.options.minFrameScore
|
|
122
|
-
});
|
|
123
|
-
logger.info("Queried shared context", {
|
|
124
|
-
query,
|
|
125
|
-
resultCount: results.length
|
|
126
|
-
});
|
|
127
|
-
return results;
|
|
128
|
-
} catch (error) {
|
|
129
|
-
logger.error("Failed to query shared context", error);
|
|
130
|
-
return [];
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Add a decision to shared context
|
|
135
|
-
*/
|
|
136
|
-
async addDecision(decision, reasoning) {
|
|
137
|
-
try {
|
|
138
|
-
await sharedContextLayer.addDecision({
|
|
139
|
-
decision,
|
|
140
|
-
reasoning,
|
|
141
|
-
outcome: "pending"
|
|
142
|
-
});
|
|
143
|
-
logger.info("Added decision to shared context", { decision });
|
|
144
|
-
} catch (error) {
|
|
145
|
-
logger.error("Failed to add decision", error);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Start automatic synchronization
|
|
150
|
-
*/
|
|
151
|
-
startAutoSync() {
|
|
152
|
-
if (this.syncTimer) {
|
|
153
|
-
clearInterval(this.syncTimer);
|
|
154
|
-
}
|
|
155
|
-
this.syncTimer = setInterval(() => {
|
|
156
|
-
this.syncToSharedContext().catch((error) => {
|
|
157
|
-
logger.error("Auto-sync failed", error);
|
|
158
|
-
});
|
|
159
|
-
}, this.options.syncInterval);
|
|
160
|
-
this.setupEventListeners();
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Stop automatic synchronization
|
|
164
|
-
*/
|
|
165
|
-
stopAutoSync() {
|
|
166
|
-
if (this.syncTimer) {
|
|
167
|
-
clearInterval(this.syncTimer);
|
|
168
|
-
this.syncTimer = null;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Filter frames that are important enough to share
|
|
173
|
-
*/
|
|
174
|
-
filterImportantFrames(frames) {
|
|
175
|
-
return frames.filter((frame) => {
|
|
176
|
-
const hasImportantTag = this.options.importantTags.some(
|
|
177
|
-
(tag) => frame.metadata?.tags?.includes(tag)
|
|
178
|
-
);
|
|
179
|
-
const isImportantType = [
|
|
180
|
-
"task",
|
|
181
|
-
"milestone",
|
|
182
|
-
"error",
|
|
183
|
-
"resolution",
|
|
184
|
-
"decision"
|
|
185
|
-
].includes(frame.type);
|
|
186
|
-
const markedImportant = frame.metadata?.importance === "high";
|
|
187
|
-
return hasImportantTag || isImportantType || markedImportant;
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Setup event listeners for automatic syncing
|
|
192
|
-
*/
|
|
193
|
-
setupEventListeners() {
|
|
194
|
-
if (!this.frameManager) return;
|
|
195
|
-
const originalClose = this.frameManager.closeFrame.bind(this.frameManager);
|
|
196
|
-
this.frameManager.closeFrame = async (frameId, metadata) => {
|
|
197
|
-
const result = await originalClose(frameId, metadata);
|
|
198
|
-
const frame = await this.frameManager.getFrame(frameId);
|
|
199
|
-
if (frame && this.filterImportantFrames([frame]).length > 0) {
|
|
200
|
-
await this.syncToSharedContext();
|
|
201
|
-
}
|
|
202
|
-
return result;
|
|
203
|
-
};
|
|
204
|
-
const originalMilestone = this.frameManager.createFrame.bind(
|
|
205
|
-
this.frameManager
|
|
206
|
-
);
|
|
207
|
-
this.frameManager.createFrame = async (params) => {
|
|
208
|
-
const result = await originalMilestone(params);
|
|
209
|
-
if (params.type === "milestone") {
|
|
210
|
-
await this.syncToSharedContext();
|
|
211
|
-
}
|
|
212
|
-
return result;
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Get sync statistics
|
|
217
|
-
*/
|
|
218
|
-
getSyncStats() {
|
|
219
|
-
return {
|
|
220
|
-
lastSyncTime: this.lastSyncTime,
|
|
221
|
-
autoSyncEnabled: this.options.autoSync,
|
|
222
|
-
syncInterval: this.options.syncInterval
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Manual trigger for immediate sync
|
|
227
|
-
*/
|
|
228
|
-
async forceSyncNow() {
|
|
229
|
-
logger.info("Force sync triggered");
|
|
230
|
-
await this.syncToSharedContext();
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
const contextBridge = ContextBridge.getInstance();
|
|
234
|
-
export {
|
|
235
|
-
ContextBridge,
|
|
236
|
-
contextBridge
|
|
237
|
-
};
|
|
238
|
-
//# sourceMappingURL=context-bridge.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/core/context/context-bridge.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Context Bridge - Automatic synchronization between sessions and shared context\n *\n * This bridge automatically:\n * - Syncs important frames to shared context\n * - Loads relevant context on session start\n * - Maintains consistency across sessions\n */\n\nimport { FrameManager, type Frame } from './index.js';\nimport { sharedContextLayer } from './shared-context-layer.js';\nimport { sessionManager } from '../session/session-manager.js';\nimport { logger } from '../monitoring/logger.js';\n\nexport interface BridgeOptions {\n autoSync: boolean;\n syncInterval: number;\n minFrameScore: number;\n importantTags: string[];\n}\n\nexport class ContextBridge {\n private static instance: ContextBridge;\n private frameManager: FrameManager | null = null;\n private syncTimer: NodeJS.Timeout | null = null;\n private lastSyncTime: number = 0;\n private options: BridgeOptions = {\n autoSync: true,\n syncInterval: 60000, // 1 minute\n minFrameScore: 0.5, // Include frames with score above 0.5\n importantTags: ['decision', 'error', 'milestone', 'learning'],\n };\n\n private constructor() {}\n\n static getInstance(): ContextBridge {\n if (!ContextBridge.instance) {\n ContextBridge.instance = new ContextBridge();\n }\n return ContextBridge.instance;\n }\n\n /**\n * Initialize the bridge with a frame manager\n */\n async initialize(\n frameManager: FrameManager,\n options?: Partial<BridgeOptions>\n ): Promise<void> {\n this.frameManager = frameManager;\n this.options = { ...this.options, ...options };\n\n // Load shared context on initialization\n await this.loadSharedContext();\n\n // Start auto-sync if enabled\n if (this.options.autoSync) {\n this.startAutoSync();\n }\n\n logger.info('Context bridge initialized', {\n autoSync: this.options.autoSync,\n syncInterval: this.options.syncInterval,\n });\n }\n\n /**\n * Load relevant shared context into current session\n */\n async loadSharedContext(): Promise<void> {\n try {\n const session = sessionManager.getCurrentSession();\n if (!session) return;\n\n // Get context discovery\n const discovery = await sharedContextLayer.autoDiscoverContext();\n\n if (!discovery.hasSharedContext) {\n logger.info('No shared context available to load');\n return;\n }\n\n // Load recent patterns as metadata\n if (discovery.recentPatterns.length > 0) {\n logger.info('Loaded recent patterns from shared context', {\n patternCount: discovery.recentPatterns.length,\n });\n }\n\n // Load last decisions for reference\n if (discovery.lastDecisions.length > 0) {\n logger.info('Loaded recent decisions from shared context', {\n decisionCount: discovery.lastDecisions.length,\n });\n }\n\n // Store suggested frames in metadata for quick reference\n if (discovery.suggestedFrames.length > 0) {\n const metadata = {\n suggestedFrames: discovery.suggestedFrames,\n loadedAt: Date.now(),\n };\n\n // Store in frame manager's context\n if (this.frameManager) {\n await this.frameManager.addContext(\n 'shared-context-suggestions',\n metadata\n );\n }\n\n logger.info('Loaded suggested frames from shared context', {\n frameCount: discovery.suggestedFrames.length,\n });\n }\n } catch (error: unknown) {\n logger.error('Failed to load shared context', error as Error);\n }\n }\n\n /**\n * Sync current session's important frames to shared context\n */\n async syncToSharedContext(): Promise<void> {\n try {\n if (!this.frameManager) return;\n\n const session = sessionManager.getCurrentSession();\n if (!session) return;\n\n // Get all active frames (filter out any nulls from missing frames)\n const activeFrames = this.frameManager\n .getActiveFramePath()\n .filter(Boolean);\n\n // Get recent closed frames (last 100)\n const recentFrames = await this.frameManager.getRecentFrames(100);\n\n // Combine and filter important frames\n const allFrames = [...activeFrames, ...recentFrames].filter(Boolean);\n const importantFrames = this.filterImportantFrames(allFrames);\n\n if (importantFrames.length === 0) {\n logger.debug('No important frames to sync');\n return;\n }\n\n // Add to shared context\n await sharedContextLayer.addToSharedContext(importantFrames, {\n minScore: this.options.minFrameScore,\n tags: this.options.importantTags,\n });\n\n this.lastSyncTime = Date.now();\n\n logger.info('Synced frames to shared context', {\n frameCount: importantFrames.length,\n sessionId: session.sessionId,\n });\n } catch (error: unknown) {\n logger.error('Failed to sync to shared context', error as Error);\n }\n }\n\n /**\n * Query shared context for relevant frames\n */\n async querySharedFrames(query: {\n tags?: string[];\n type?: string;\n limit?: number;\n }): Promise<any[]> {\n try {\n const results = await sharedContextLayer.querySharedContext({\n ...query,\n minScore: this.options.minFrameScore,\n });\n\n logger.info('Queried shared context', {\n query,\n resultCount: results.length,\n });\n\n return results;\n } catch (error: unknown) {\n logger.error('Failed to query shared context', error as Error);\n return [];\n }\n }\n\n /**\n * Add a decision to shared context\n */\n async addDecision(decision: string, reasoning: string): Promise<void> {\n try {\n await sharedContextLayer.addDecision({\n decision,\n reasoning,\n outcome: 'pending',\n });\n\n logger.info('Added decision to shared context', { decision });\n } catch (error: unknown) {\n logger.error('Failed to add decision', error as Error);\n }\n }\n\n /**\n * Start automatic synchronization\n */\n private startAutoSync(): void {\n if (this.syncTimer) {\n clearInterval(this.syncTimer);\n }\n\n this.syncTimer = setInterval(() => {\n this.syncToSharedContext().catch((error) => {\n logger.error('Auto-sync failed', error as Error);\n });\n }, this.options.syncInterval);\n\n // Also sync on important events\n this.setupEventListeners();\n }\n\n /**\n * Stop automatic synchronization\n */\n stopAutoSync(): void {\n if (this.syncTimer) {\n clearInterval(this.syncTimer);\n this.syncTimer = null;\n }\n }\n\n /**\n * Filter frames that are important enough to share\n */\n private filterImportantFrames(frames: Frame[]): Frame[] {\n return frames.filter((frame) => {\n // Check if frame has important tags\n const hasImportantTag = this.options.importantTags.some((tag) =>\n frame.metadata?.tags?.includes(tag)\n );\n\n // Check frame type importance\n const isImportantType = [\n 'task',\n 'milestone',\n 'error',\n 'resolution',\n 'decision',\n ].includes(frame.type);\n\n // Check metadata importance flag\n const markedImportant = frame.metadata?.importance === 'high';\n\n return hasImportantTag || isImportantType || markedImportant;\n });\n }\n\n /**\n * Setup event listeners for automatic syncing\n */\n private setupEventListeners(): void {\n if (!this.frameManager) return;\n\n // Sync when a frame is closed\n const originalClose = this.frameManager.closeFrame.bind(this.frameManager);\n this.frameManager.closeFrame = async (frameId: string, metadata?: any) => {\n const result = await originalClose(frameId, metadata);\n\n // Sync if it was an important frame\n const frame = await this.frameManager!.getFrame(frameId);\n if (frame && this.filterImportantFrames([frame]).length > 0) {\n await this.syncToSharedContext();\n }\n\n return result;\n };\n\n // Sync when a milestone is reached\n const originalMilestone = this.frameManager.createFrame.bind(\n this.frameManager\n );\n this.frameManager.createFrame = async (params: any) => {\n const result = await originalMilestone(params);\n\n if (params.type === 'milestone') {\n await this.syncToSharedContext();\n }\n\n return result;\n };\n }\n\n /**\n * Get sync statistics\n */\n getSyncStats(): {\n lastSyncTime: number;\n autoSyncEnabled: boolean;\n syncInterval: number;\n } {\n return {\n lastSyncTime: this.lastSyncTime,\n autoSyncEnabled: this.options.autoSync,\n syncInterval: this.options.syncInterval,\n };\n }\n\n /**\n * Manual trigger for immediate sync\n */\n async forceSyncNow(): Promise<void> {\n logger.info('Force sync triggered');\n await this.syncToSharedContext();\n }\n}\n\nexport const contextBridge = ContextBridge.getInstance();\n\n// Export for testing\nexport { BridgeOptions };\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|