feat: persistent token tracking with global stats aggregation

- Add restoreTokens() method to Session class for recovery after restart
- Add GlobalStats type for cumulative usage tracking across all sessions
- Accumulate tokens from deleted sessions into global stats
- Track lifetime session count with incrementSessionsCreated()
- Add /api/stats endpoint for global stats
- Include globalStats in /api/status response
- Frontend shows aggregate tokens + cost in header
- Fix respawn controller config to filter undefined values
- Add 7 new tests for global stats functionality (v0.1343)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
arkon
2026-01-25 07:26:49 +01:00
co-authored by Claude Opus 4.5
parent 0aca55b099
commit e56c8626e4
10 changed files with 322 additions and 19 deletions
+10 -2
View File
@@ -662,7 +662,11 @@ export class RespawnController extends EventEmitter {
constructor(session: Session, config: Partial<RespawnConfig> = {}) {
super();
this.session = session;
this.config = { ...DEFAULT_CONFIG, ...config };
// Filter out undefined values from config to prevent overwriting defaults
const filteredConfig = Object.fromEntries(
Object.entries(config).filter(([, v]) => v !== undefined)
) as Partial<RespawnConfig>;
this.config = { ...DEFAULT_CONFIG, ...filteredConfig };
this.aiChecker = new AiIdleChecker(session.id, {
enabled: this.config.aiIdleCheckEnabled,
model: this.config.aiIdleCheckModel,
@@ -2169,7 +2173,11 @@ export class RespawnController extends EventEmitter {
* @fires log - With updated config details
*/
updateConfig(config: Partial<RespawnConfig>): void {
this.config = { ...this.config, ...config };
// Filter out undefined values to prevent overwriting existing config with undefined
const filteredConfig = Object.fromEntries(
Object.entries(config).filter(([, v]) => v !== undefined)
) as Partial<RespawnConfig>;
this.config = { ...this.config, ...filteredConfig };
// Sync AI checker config if relevant fields changed
if (config.aiIdleCheckEnabled !== undefined || config.aiIdleCheckModel !== undefined ||