flashbacker
Version:
Claude Code state management with session continuity and AI personas
145 lines • 6.54 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AutoContextManager = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const os_1 = __importDefault(require("os"));
const session_token_parser_js_1 = require("../utils/session-token-parser.js");
const stderr_directive_js_1 = require("../utils/stderr-directive.js");
/**
* AutoContextManager handles token monitoring and compaction detection
* Based on Cline's context management patterns but adapted for Claude Code session logs
*/
class AutoContextManager {
constructor(projectDir) {
this.projectDir = projectDir;
}
/**
* Get current token usage from session logs
* Parses JSONL files for exact token counts from API responses
*/
async getCurrentTokenUsage() {
const sessionInfo = await (0, session_token_parser_js_1.parseCurrentSessionTokens)(this.projectDir);
return sessionInfo.currentContextTokens;
}
/**
* Get current session information
* Extracts session ID, message count, and token usage
*/
async getSessionInfo() {
const sessionTokenInfo = await (0, session_token_parser_js_1.parseCurrentSessionTokens)(this.projectDir);
return {
sessionId: sessionTokenInfo.sessionId,
messageCount: sessionTokenInfo.messageCount,
tokenUsage: sessionTokenInfo.currentContextTokens,
timestamp: sessionTokenInfo.timestamp,
};
}
/**
* Check if todo update should be triggered
* Based on 80% threshold or message count intervals
*/
async shouldTriggerTodoUpdate() {
try {
// Get current session info
const currentInfo = await this.getSessionInfo();
// Get model configuration for threshold calculation
const modelConfig = await this.getModelConfig();
// Progressive token thresholds (25%, 50%, 70%, 80%)
const tokenPercentage = currentInfo.tokenUsage / modelConfig.contextWindow;
const progressiveThresholds = tokenPercentage >= 0.25 || // 25% early reminder
tokenPercentage >= 0.5 || // 50% regular update
tokenPercentage >= 0.7 || // 70% warning
tokenPercentage >= 0.8; // 80% critical
// POST-COMPACTION DETECTION: 0-24% after activity suggests compaction occurred
const lowContextAfterActivity = tokenPercentage < 0.25 &&
currentInfo.messageCount > 20 &&
currentInfo.tokenUsage > 1000; // Has some tokens but very low percentage
// Message-based triggers (ranges that actually work)
const messageRangeUpdate = currentInfo.messageCount > 50 &&
(Math.floor(currentInfo.messageCount / 50) % 4 === 0); // Every 4th group of 50 (200, 400, 600, etc.)
// Simple periodic trigger (much less frequent)
const periodicUpdate = currentInfo.messageCount > 100 &&
Math.floor(currentInfo.messageCount / 100) % 3 === 0; // Every 300 messages (300, 600, 900, etc.)
return progressiveThresholds || lowContextAfterActivity || messageRangeUpdate || periodicUpdate;
}
catch (error) {
console.error('Error checking todo update triggers:', error);
return false;
}
}
/**
* Get model configuration from settings
* Helper method for threshold calculations
*/
async getModelConfig() {
try {
const settingsPath = path_1.default.join(os_1.default.homedir(), '.claude', 'settings.json');
if (await fs_extra_1.default.pathExists(settingsPath)) {
const settings = JSON.parse(await fs_extra_1.default.readFile(settingsPath, 'utf8'));
const model = settings.model || 'sonnet';
// Parse context window from model name
let contextWindow = 200000; // Default for standard models
if (model.includes('[1m]')) {
contextWindow = 1000000; // 1M context models
}
else if (model.includes('gpt-4')) {
contextWindow = 128000; // GPT-4 context
}
return {
model,
contextWindow,
warningThreshold: Math.floor(contextWindow * 0.8),
emergencyThreshold: Math.floor(contextWindow * 0.95),
};
}
// Fallback to conservative defaults
return {
model: 'unknown',
contextWindow: 200000,
warningThreshold: 160000,
emergencyThreshold: 190000,
};
}
catch (error) {
console.error('Error reading model config:', error);
return {
model: 'error',
contextWindow: 200000,
warningThreshold: 160000,
emergencyThreshold: 190000,
};
}
}
/**
* Direct Claude to appropriate template based on context state
* Detects post-compaction scenarios and triggers session restoration
*/
async directClaudeToMaintenanceTemplate() {
try {
const currentInfo = await this.getSessionInfo();
const modelConfig = await this.getModelConfig();
const tokenPercentage = currentInfo.tokenUsage / modelConfig.contextWindow;
// DETECT POST-COMPACTION: Low context after activity suggests compaction
const isPostCompaction = tokenPercentage < 0.25 &&
currentInfo.messageCount > 20 &&
currentInfo.tokenUsage > 1000;
if (isPostCompaction) {
// Context was compacted - trigger session restoration
(0, stderr_directive_js_1.emitCompactionDirective)(Math.round(tokenPercentage * 100));
}
else {
// Normal maintenance
(0, stderr_directive_js_1.emitMaintenanceDirective)(Math.round(tokenPercentage * 100));
}
}
catch (error) {
console.error('Auto-context directive failed:', error);
}
}
}
exports.AutoContextManager = AutoContextManager;
//# sourceMappingURL=auto-context-manager.js.map
;