@claudetools/tools 0.8.2 → 0.8.4

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 (74) hide show
  1. package/dist/cli.js +41 -0
  2. package/dist/context/deduplication.d.ts +72 -0
  3. package/dist/context/deduplication.js +77 -0
  4. package/dist/context/deduplication.test.d.ts +6 -0
  5. package/dist/context/deduplication.test.js +84 -0
  6. package/dist/context/emergency-eviction.d.ts +73 -0
  7. package/dist/context/emergency-eviction.example.d.ts +13 -0
  8. package/dist/context/emergency-eviction.example.js +94 -0
  9. package/dist/context/emergency-eviction.js +226 -0
  10. package/dist/context/eviction-engine.d.ts +76 -0
  11. package/dist/context/eviction-engine.example.d.ts +7 -0
  12. package/dist/context/eviction-engine.example.js +144 -0
  13. package/dist/context/eviction-engine.js +176 -0
  14. package/dist/context/example-usage.d.ts +1 -0
  15. package/dist/context/example-usage.js +128 -0
  16. package/dist/context/exchange-summariser.d.ts +80 -0
  17. package/dist/context/exchange-summariser.js +261 -0
  18. package/dist/context/health-monitor.d.ts +97 -0
  19. package/dist/context/health-monitor.example.d.ts +1 -0
  20. package/dist/context/health-monitor.example.js +164 -0
  21. package/dist/context/health-monitor.js +210 -0
  22. package/dist/context/importance-scorer.d.ts +94 -0
  23. package/dist/context/importance-scorer.example.d.ts +1 -0
  24. package/dist/context/importance-scorer.example.js +140 -0
  25. package/dist/context/importance-scorer.js +187 -0
  26. package/dist/context/index.d.ts +9 -0
  27. package/dist/context/index.js +16 -0
  28. package/dist/context/session-helper.d.ts +10 -0
  29. package/dist/context/session-helper.js +51 -0
  30. package/dist/context/session-store.d.ts +94 -0
  31. package/dist/context/session-store.js +286 -0
  32. package/dist/context/usage-estimator.d.ts +131 -0
  33. package/dist/context/usage-estimator.js +260 -0
  34. package/dist/context/usage-estimator.test.d.ts +1 -0
  35. package/dist/context/usage-estimator.test.js +208 -0
  36. package/dist/context-cli.d.ts +16 -0
  37. package/dist/context-cli.js +309 -0
  38. package/dist/evaluation/build-dataset.d.ts +1 -0
  39. package/dist/evaluation/build-dataset.js +135 -0
  40. package/dist/evaluation/threshold-eval.d.ts +63 -0
  41. package/dist/evaluation/threshold-eval.js +250 -0
  42. package/dist/handlers/codedna-handlers.d.ts +2 -2
  43. package/dist/handlers/tool-handlers.js +126 -165
  44. package/dist/helpers/api-client.d.ts +5 -1
  45. package/dist/helpers/api-client.js +3 -1
  46. package/dist/helpers/compact-formatter.d.ts +51 -0
  47. package/dist/helpers/compact-formatter.js +130 -0
  48. package/dist/helpers/engagement-tracker.d.ts +10 -0
  49. package/dist/helpers/engagement-tracker.js +61 -0
  50. package/dist/helpers/error-tracking.js +1 -1
  51. package/dist/helpers/session-validation.d.ts +76 -0
  52. package/dist/helpers/session-validation.js +221 -0
  53. package/dist/helpers/usage-analytics.js +1 -1
  54. package/dist/hooks/index.d.ts +4 -0
  55. package/dist/hooks/index.js +6 -0
  56. package/dist/hooks/post-tool-use-hook-cli.d.ts +2 -0
  57. package/dist/hooks/post-tool-use-hook-cli.js +34 -0
  58. package/dist/hooks/post-tool-use.d.ts +67 -0
  59. package/dist/hooks/post-tool-use.js +234 -0
  60. package/dist/hooks/stop-hook-cli.d.ts +2 -0
  61. package/dist/hooks/stop-hook-cli.js +34 -0
  62. package/dist/hooks/stop.d.ts +64 -0
  63. package/dist/hooks/stop.js +192 -0
  64. package/dist/index.d.ts +3 -0
  65. package/dist/index.js +2 -0
  66. package/dist/logger.d.ts +1 -1
  67. package/dist/logger.js +4 -0
  68. package/dist/resources.js +3 -0
  69. package/dist/setup.js +206 -2
  70. package/dist/templates/claude-md.d.ts +1 -1
  71. package/dist/templates/claude-md.js +23 -35
  72. package/dist/templates/worker-prompt.js +35 -202
  73. package/dist/tools.js +26 -20
  74. package/package.json +6 -2
package/dist/cli.js CHANGED
@@ -11,6 +11,7 @@ import { runSetup, runUninstall, runInit, runCleanup } from './setup.js';
11
11
  import { startServer } from './index.js';
12
12
  import { startWatcher, stopWatcher, watcherStatus } from './watcher.js';
13
13
  import { generateCodebaseMap, generateCodebaseMapLocal } from './helpers/codebase-mapper.js';
14
+ import { contextStatus, contextEvict, contextSummarise, contextReset, } from './context-cli.js';
14
15
  // Get version from package.json
15
16
  const __filename = fileURLToPath(import.meta.url);
16
17
  const __dirname = dirname(__filename);
@@ -56,6 +57,10 @@ Commands:
56
57
  watch --status Check watcher status
57
58
  map Generate codebase map for current project
58
59
  map --local Generate map locally without uploading
60
+ context status Show current session context usage
61
+ context evict Manually trigger eviction cycle
62
+ context summarise Summarise and compress exchanges
63
+ context reset Clear session state
59
64
 
60
65
  Running without options starts the MCP server.
61
66
 
@@ -165,6 +170,42 @@ else if (positionals[0] === 'map') {
165
170
  process.exit(1);
166
171
  });
167
172
  }
173
+ else if (positionals[0] === 'context') {
174
+ // Handle context command
175
+ const subcommand = positionals[1];
176
+ const contextArgs = process.argv.slice(4); // Get args after subcommand
177
+ switch (subcommand) {
178
+ case 'status':
179
+ contextStatus(contextArgs).catch((error) => {
180
+ console.error('Context status failed:', error);
181
+ process.exit(1);
182
+ });
183
+ break;
184
+ case 'evict':
185
+ contextEvict(contextArgs).catch((error) => {
186
+ console.error('Context evict failed:', error);
187
+ process.exit(1);
188
+ });
189
+ break;
190
+ case 'summarise':
191
+ case 'summarize': // Support both spellings
192
+ contextSummarise(contextArgs).catch((error) => {
193
+ console.error('Context summarise failed:', error);
194
+ process.exit(1);
195
+ });
196
+ break;
197
+ case 'reset':
198
+ contextReset(contextArgs).catch((error) => {
199
+ console.error('Context reset failed:', error);
200
+ process.exit(1);
201
+ });
202
+ break;
203
+ default:
204
+ console.error(`Unknown context subcommand: ${subcommand}`);
205
+ console.error('Available subcommands: status, evict, summarise, reset');
206
+ process.exit(1);
207
+ }
208
+ }
168
209
  else {
169
210
  // Start MCP server
170
211
  startServer();
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Deduplication Tracker for Context Injection
3
+ *
4
+ * Tracks which facts have been injected into context and when,
5
+ * preventing redundant re-injection unless facts are stale.
6
+ *
7
+ * @module context/deduplication
8
+ */
9
+ export interface DeduplicationTracker {
10
+ /**
11
+ * Record that a fact was injected at a specific turn
12
+ */
13
+ recordInjection(factId: string, turn: number): void;
14
+ /**
15
+ * Determine if a fact should be injected
16
+ * @param factId - The fact ID to check
17
+ * @param currentTurn - Current conversation turn number
18
+ * @param freshnessThreshold - Number of turns before fact is considered stale (default: 10)
19
+ * @returns true if fact should be injected, false if it's already fresh in context
20
+ */
21
+ shouldInject(factId: string, currentTurn: number, freshnessThreshold?: number): boolean;
22
+ /**
23
+ * Get all currently tracked facts and their injection turns
24
+ */
25
+ getInjectedFacts(): Map<string, number>;
26
+ /**
27
+ * Clear all tracked facts
28
+ */
29
+ clear(): void;
30
+ /**
31
+ * Get statistics about tracked facts
32
+ */
33
+ getStats(currentTurn: number): {
34
+ totalTracked: number;
35
+ fresh: number;
36
+ stale: number;
37
+ averageAge: number;
38
+ };
39
+ /**
40
+ * Remove facts older than a certain age to prevent unbounded growth
41
+ */
42
+ pruneOldFacts(currentTurn: number, maxAge?: number): number;
43
+ }
44
+ /**
45
+ * In-memory deduplication tracker implementation
46
+ */
47
+ export declare class InMemoryDeduplicationTracker implements DeduplicationTracker {
48
+ private injectedFacts;
49
+ private defaultFreshnessThreshold;
50
+ constructor(defaultFreshnessThreshold?: number);
51
+ recordInjection(factId: string, turn: number): void;
52
+ shouldInject(factId: string, currentTurn: number, freshnessThreshold?: number): boolean;
53
+ getInjectedFacts(): Map<string, number>;
54
+ clear(): void;
55
+ /**
56
+ * Get statistics about tracked facts
57
+ */
58
+ getStats(currentTurn: number): {
59
+ totalTracked: number;
60
+ fresh: number;
61
+ stale: number;
62
+ averageAge: number;
63
+ };
64
+ /**
65
+ * Remove facts older than a certain age to prevent unbounded growth
66
+ */
67
+ pruneOldFacts(currentTurn: number, maxAge?: number): number;
68
+ }
69
+ /**
70
+ * Create a new deduplication tracker
71
+ */
72
+ export declare function createDeduplicationTracker(freshnessThreshold?: number): DeduplicationTracker;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Deduplication Tracker for Context Injection
3
+ *
4
+ * Tracks which facts have been injected into context and when,
5
+ * preventing redundant re-injection unless facts are stale.
6
+ *
7
+ * @module context/deduplication
8
+ */
9
+ /**
10
+ * In-memory deduplication tracker implementation
11
+ */
12
+ export class InMemoryDeduplicationTracker {
13
+ injectedFacts;
14
+ defaultFreshnessThreshold;
15
+ constructor(defaultFreshnessThreshold = 10) {
16
+ this.injectedFacts = new Map();
17
+ this.defaultFreshnessThreshold = defaultFreshnessThreshold;
18
+ }
19
+ recordInjection(factId, turn) {
20
+ this.injectedFacts.set(factId, turn);
21
+ }
22
+ shouldInject(factId, currentTurn, freshnessThreshold = this.defaultFreshnessThreshold) {
23
+ const lastInjectedTurn = this.injectedFacts.get(factId);
24
+ // Never injected before - should inject
25
+ if (lastInjectedTurn === undefined) {
26
+ return true;
27
+ }
28
+ // Calculate how many turns ago it was injected
29
+ const turnsSinceInjection = currentTurn - lastInjectedTurn;
30
+ // Should inject if it's been more than threshold turns
31
+ return turnsSinceInjection > freshnessThreshold;
32
+ }
33
+ getInjectedFacts() {
34
+ return new Map(this.injectedFacts);
35
+ }
36
+ clear() {
37
+ this.injectedFacts.clear();
38
+ }
39
+ /**
40
+ * Get statistics about tracked facts
41
+ */
42
+ getStats(currentTurn) {
43
+ const facts = Array.from(this.injectedFacts.values());
44
+ const fresh = facts.filter(turn => currentTurn - turn <= this.defaultFreshnessThreshold);
45
+ const stale = facts.filter(turn => currentTurn - turn > this.defaultFreshnessThreshold);
46
+ const totalAge = facts.reduce((sum, turn) => sum + (currentTurn - turn), 0);
47
+ return {
48
+ totalTracked: facts.length,
49
+ fresh: fresh.length,
50
+ stale: stale.length,
51
+ averageAge: facts.length > 0 ? totalAge / facts.length : 0,
52
+ };
53
+ }
54
+ /**
55
+ * Remove facts older than a certain age to prevent unbounded growth
56
+ */
57
+ pruneOldFacts(currentTurn, maxAge = 100) {
58
+ let pruned = 0;
59
+ const toDelete = [];
60
+ this.injectedFacts.forEach((turn, factId) => {
61
+ if (currentTurn - turn > maxAge) {
62
+ toDelete.push(factId);
63
+ }
64
+ });
65
+ toDelete.forEach(factId => {
66
+ this.injectedFacts.delete(factId);
67
+ pruned++;
68
+ });
69
+ return pruned;
70
+ }
71
+ }
72
+ /**
73
+ * Create a new deduplication tracker
74
+ */
75
+ export function createDeduplicationTracker(freshnessThreshold = 10) {
76
+ return new InMemoryDeduplicationTracker(freshnessThreshold);
77
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tests for DeduplicationTracker
3
+ *
4
+ * These tests demonstrate the usage and verify the logic.
5
+ */
6
+ export declare function runTests(): void;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Tests for DeduplicationTracker
3
+ *
4
+ * These tests demonstrate the usage and verify the logic.
5
+ */
6
+ import { createDeduplicationTracker } from './deduplication.js';
7
+ // Example usage demonstration
8
+ function demonstrateUsage() {
9
+ const tracker = createDeduplicationTracker(10); // 10-turn freshness threshold
10
+ console.log('\n=== Deduplication Tracker Demo ===\n');
11
+ // Scenario 1: First injection
12
+ console.log('Turn 1: Check if fact_123 should be injected');
13
+ console.log('Result:', tracker.shouldInject('fact_123', 1)); // true - never injected
14
+ tracker.recordInjection('fact_123', 1);
15
+ // Scenario 2: Recent injection (within threshold)
16
+ console.log('\nTurn 5: Check if fact_123 should be injected again');
17
+ console.log('Result:', tracker.shouldInject('fact_123', 5)); // false - only 4 turns ago
18
+ console.log('Turns since injection:', 5 - 1);
19
+ // Scenario 3: Stale injection (beyond threshold)
20
+ console.log('\nTurn 15: Check if fact_123 should be injected again');
21
+ console.log('Result:', tracker.shouldInject('fact_123', 15)); // true - 14 turns ago (> 10)
22
+ console.log('Turns since injection:', 15 - 1);
23
+ // Scenario 4: Multiple facts
24
+ tracker.recordInjection('fact_456', 10);
25
+ tracker.recordInjection('fact_789', 12);
26
+ console.log('\nTurn 20: Check multiple facts');
27
+ console.log('fact_123 (injected turn 1):', tracker.shouldInject('fact_123', 20)); // true - 19 turns
28
+ console.log('fact_456 (injected turn 10):', tracker.shouldInject('fact_456', 20)); // true - 10 turns
29
+ console.log('fact_789 (injected turn 12):', tracker.shouldInject('fact_789', 20)); // false - 8 turns
30
+ // Scenario 5: Statistics
31
+ console.log('\nStatistics at turn 20:');
32
+ console.log(JSON.stringify(tracker.getStats(20), null, 2));
33
+ // Scenario 6: Pruning old facts
34
+ console.log('\nPruning facts older than 50 turns at turn 100:');
35
+ tracker.recordInjection('old_fact', 30);
36
+ const pruned = tracker.pruneOldFacts(100, 50);
37
+ console.log('Pruned:', pruned, 'facts');
38
+ console.log('Remaining facts:', tracker.getInjectedFacts().size);
39
+ }
40
+ // Run tests if this file is executed directly
41
+ if (import.meta.url === `file://${process.argv[1]}`) {
42
+ demonstrateUsage();
43
+ }
44
+ // Simple assertion-based tests
45
+ export function runTests() {
46
+ const tracker = createDeduplicationTracker(10);
47
+ // Test 1: Never injected should return true
48
+ if (!tracker.shouldInject('test_fact', 1)) {
49
+ throw new Error('Test 1 failed: Never injected fact should inject');
50
+ }
51
+ // Test 2: Recent injection should return false
52
+ tracker.recordInjection('test_fact', 1);
53
+ if (tracker.shouldInject('test_fact', 5)) {
54
+ throw new Error('Test 2 failed: Recent fact should not inject');
55
+ }
56
+ // Test 3: Stale injection should return true
57
+ if (!tracker.shouldInject('test_fact', 15)) {
58
+ throw new Error('Test 3 failed: Stale fact should inject');
59
+ }
60
+ // Test 4: Custom threshold
61
+ if (!tracker.shouldInject('test_fact', 6, 5)) {
62
+ throw new Error('Test 4 failed: Custom threshold should allow injection');
63
+ }
64
+ // Test 5: Clear should reset state
65
+ tracker.clear();
66
+ if (tracker.getInjectedFacts().size !== 0) {
67
+ throw new Error('Test 5 failed: Clear should remove all facts');
68
+ }
69
+ // Test 6: Statistics
70
+ tracker.recordInjection('fact1', 1);
71
+ tracker.recordInjection('fact2', 8);
72
+ tracker.recordInjection('fact3', 15);
73
+ const stats = tracker.getStats(20);
74
+ if (stats.totalTracked !== 3) {
75
+ throw new Error('Test 6 failed: Should track 3 facts');
76
+ }
77
+ if (stats.fresh !== 1) {
78
+ throw new Error('Test 6 failed: Should have 1 fresh fact');
79
+ }
80
+ if (stats.stale !== 2) {
81
+ throw new Error('Test 6 failed: Should have 2 stale facts');
82
+ }
83
+ console.log('āœ… All tests passed!');
84
+ }
@@ -0,0 +1,73 @@
1
+ import type { PersistedSessionState } from './session-store.js';
2
+ /**
3
+ * Result of emergency eviction operation
4
+ */
5
+ export interface EmergencyResult {
6
+ wasEmergency: boolean;
7
+ actionsToken: string[];
8
+ evictedCount: number;
9
+ summarisedExchanges: number;
10
+ compressedCritical: number;
11
+ newEstimatedFill: number;
12
+ userWarning: string;
13
+ }
14
+ /**
15
+ * Emergency eviction configuration
16
+ */
17
+ export interface EmergencyConfig {
18
+ emergencyThreshold: number;
19
+ targetFill: number;
20
+ criticalCompressionThreshold: number;
21
+ }
22
+ export declare class EmergencyEviction {
23
+ private config;
24
+ private scorer;
25
+ constructor(config?: Partial<EmergencyConfig>);
26
+ /**
27
+ * Check if session is in emergency state
28
+ */
29
+ isEmergency(session: PersistedSessionState): boolean;
30
+ /**
31
+ * Run emergency eviction protocol
32
+ *
33
+ * Steps:
34
+ * 1. Summarise recent exchanges
35
+ * 2. Evict normal importance facts
36
+ * 3. If still critical, compress high importance facts
37
+ * 4. If still critical, compress critical facts (last resort)
38
+ *
39
+ * @param session - Current session state
40
+ * @returns Emergency result with actions taken
41
+ */
42
+ runEmergencyEviction(session: PersistedSessionState): Promise<EmergencyResult>;
43
+ /**
44
+ * Get facts by importance level
45
+ */
46
+ private getFactsByImportance;
47
+ /**
48
+ * Get count of unsummarised exchanges
49
+ */
50
+ private getUnsummarisedExchangeCount;
51
+ /**
52
+ * Estimate tokens for a set of exchanges
53
+ */
54
+ private estimateExchangeTokens;
55
+ /**
56
+ * Estimate tokens for a set of facts
57
+ * More realistic estimate: ~500 tokens per fact average
58
+ * (includes context, entities, relationships, metadata)
59
+ */
60
+ private estimateFactTokens;
61
+ /**
62
+ * Recalculate fill percentage after token change
63
+ */
64
+ private recalculateFill;
65
+ /**
66
+ * Generate user-facing warning message
67
+ */
68
+ private generateUserWarning;
69
+ }
70
+ /**
71
+ * Create emergency eviction instance with optional config
72
+ */
73
+ export declare function createEmergencyEviction(config?: Partial<EmergencyConfig>): EmergencyEviction;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Example: Monitor session context and trigger emergency eviction
3
+ */
4
+ declare function monitorSessionContext(sessionId: string): Promise<void>;
5
+ /**
6
+ * Example: Custom emergency configuration for aggressive cleanup
7
+ */
8
+ declare function aggressiveEmergencyCleanup(sessionId: string): Promise<void>;
9
+ /**
10
+ * Example: Integration with post-tool-use hook
11
+ */
12
+ declare function postToolUseEmergencyCheck(sessionId: string): Promise<void>;
13
+ export { monitorSessionContext, aggressiveEmergencyCleanup, postToolUseEmergencyCheck };
@@ -0,0 +1,94 @@
1
+ // =============================================================================
2
+ // Emergency Eviction - Usage Example
3
+ // =============================================================================
4
+ import { createEmergencyEviction, getSessionStore, } from './index.js';
5
+ /**
6
+ * Example: Monitor session context and trigger emergency eviction
7
+ */
8
+ async function monitorSessionContext(sessionId) {
9
+ const sessionStore = getSessionStore();
10
+ const eviction = createEmergencyEviction({
11
+ emergencyThreshold: 0.70, // Trigger at 70% fill
12
+ targetFill: 0.50, // Aim for 50% after eviction
13
+ criticalCompressionThreshold: 0.65, // Compress critical if still > 65%
14
+ });
15
+ // Get current session state
16
+ const session = await sessionStore.getSession(sessionId);
17
+ if (!session) {
18
+ console.log('Session not found');
19
+ return;
20
+ }
21
+ console.log(`Session fill: ${(session.estimated_fill * 100).toFixed(1)}%`);
22
+ // Check if emergency eviction is needed
23
+ if (eviction.isEmergency(session)) {
24
+ console.log('🚨 EMERGENCY: Context at critical level, running eviction...');
25
+ const result = await eviction.runEmergencyEviction(session);
26
+ console.log('\nEmergency Eviction Results:');
27
+ console.log('─────────────────────────────────────');
28
+ console.log(`Actions taken: ${result.actionsToken.length}`);
29
+ result.actionsToken.forEach((action) => console.log(` • ${action}`));
30
+ console.log(`\nEvicted facts: ${result.evictedCount}`);
31
+ console.log(`Summarised exchanges: ${result.summarisedExchanges}`);
32
+ console.log(`Compressed critical facts: ${result.compressedCritical}`);
33
+ console.log(`\nFill: ${(session.estimated_fill * 100).toFixed(1)}% → ${(result.newEstimatedFill * 100).toFixed(1)}%`);
34
+ console.log(`\nāš ļø ${result.userWarning}`);
35
+ // Update session with new fill estimate
36
+ await sessionStore.updateSession(sessionId, {
37
+ estimated_fill: result.newEstimatedFill,
38
+ });
39
+ }
40
+ else {
41
+ console.log('āœ“ Context within safe limits');
42
+ }
43
+ }
44
+ /**
45
+ * Example: Custom emergency configuration for aggressive cleanup
46
+ */
47
+ async function aggressiveEmergencyCleanup(sessionId) {
48
+ const sessionStore = getSessionStore();
49
+ const eviction = createEmergencyEviction({
50
+ emergencyThreshold: 0.60, // Trigger earlier at 60%
51
+ targetFill: 0.30, // Aim for very low fill (30%)
52
+ criticalCompressionThreshold: 0.50, // More aggressive critical compression
53
+ });
54
+ const session = await sessionStore.getSession(sessionId);
55
+ if (!session)
56
+ return;
57
+ if (eviction.isEmergency(session)) {
58
+ const result = await eviction.runEmergencyEviction(session);
59
+ console.log('šŸ”„ Aggressive cleanup completed:');
60
+ console.log(` Evicted: ${result.evictedCount} facts`);
61
+ console.log(` Compressed: ${result.compressedCritical} critical facts`);
62
+ console.log(` New fill: ${(result.newEstimatedFill * 100).toFixed(1)}%`);
63
+ await sessionStore.updateSession(sessionId, {
64
+ estimated_fill: result.newEstimatedFill,
65
+ });
66
+ }
67
+ }
68
+ /**
69
+ * Example: Integration with post-tool-use hook
70
+ */
71
+ async function postToolUseEmergencyCheck(sessionId) {
72
+ const sessionStore = getSessionStore();
73
+ const eviction = createEmergencyEviction();
74
+ const session = await sessionStore.getSession(sessionId);
75
+ if (!session)
76
+ return;
77
+ // Check after every tool use
78
+ if (eviction.isEmergency(session)) {
79
+ console.log('Emergency eviction triggered by tool use');
80
+ const result = await eviction.runEmergencyEviction(session);
81
+ // Log to user
82
+ if (result.compressedCritical > 0) {
83
+ console.error('āš ļø CRITICAL: Context pressure forced compression of important facts');
84
+ }
85
+ else if (result.evictedCount > 0) {
86
+ console.warn(`Context cleanup: Evicted ${result.evictedCount} facts`);
87
+ }
88
+ await sessionStore.updateSession(sessionId, {
89
+ estimated_fill: result.newEstimatedFill,
90
+ });
91
+ }
92
+ }
93
+ // Export examples
94
+ export { monitorSessionContext, aggressiveEmergencyCleanup, postToolUseEmergencyCheck };