mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-08-01 12:25:31 +00:00
Performance and coherence: - Settings > General 'Refresh every' (Manual/30s/1m/3m/5m/10m), live via RefreshCadenceContext; Manual polls only on demand - usePolled memoKey LRU: provider/period switches paint the last-good result instantly with a switching hairline while refreshing quietly - quota TTL 5min + honest rate-limited copy on 429 backoff - version-suffixed cache files (session-cache.v5.json, daily-cache.v12, auto-minted on future bumps); legacy files never written or deleted, adopted once when versions match: old and new binaries coexist without clobbering (field-observed menubar-vs-desktop ping-pong) - advisory hydration lock: concurrent cold starts share one scan (wait-then-read-warm), stale/dead locks self-heal, never a correctness gate Telemetry v1 + onboarding (desktop only, per owner decisions): - first-launch onboarding (3 feature screens + consent); region-split default (EU/EEA/UK/CH off, elsewhere on, unknown off); nothing sends before consent completion or while off; dev builds never send - anonymous install UUID, rotated on opt-out; day-granularity events, cost buckets only; whitelisted names; 200-event queue, 5min flush - Settings > Privacy live toggle replaces the static claim Zero computed-number changes. App 316/316, root 1805. Wire contract targets api.codeburn.app/v1/telemetry (Worker follows).
81 lines
3.1 KiB
TypeScript
81 lines
3.1 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
import { mkdtemp, mkdir, writeFile, readFile, rm } from 'fs/promises'
|
|
import { join } from 'path'
|
|
import { tmpdir } from 'os'
|
|
|
|
import { parseAllSessions, clearSessionCache } from '../src/parser.js'
|
|
import { CACHE_VERSION, sessionCachePath } from '../src/session-cache.js'
|
|
|
|
let tmpDir: string
|
|
let cacheDir: string
|
|
|
|
beforeEach(async () => {
|
|
clearSessionCache()
|
|
tmpDir = await mkdtemp(join(tmpdir(), 'coldstart-'))
|
|
cacheDir = join(tmpDir, 'cache')
|
|
process.env['CLAUDE_CONFIG_DIR'] = tmpDir
|
|
process.env['CODEBURN_CACHE_DIR'] = cacheDir
|
|
process.env['CODEBURN_DESKTOP_SESSIONS_DIR'] = join(tmpDir, 'desktop-sessions')
|
|
})
|
|
|
|
afterEach(async () => {
|
|
clearSessionCache()
|
|
delete process.env['CODEBURN_PROGRESS']
|
|
await rm(tmpDir, { recursive: true, force: true })
|
|
})
|
|
|
|
async function writeSession(): Promise<void> {
|
|
const dir = join(tmpDir, 'projects', 'proj')
|
|
await mkdir(dir, { recursive: true })
|
|
await writeFile(join(dir, 'sess.jsonl'), JSON.stringify({
|
|
type: 'assistant',
|
|
sessionId: 'sess',
|
|
timestamp: '2026-05-15T10:00:00Z',
|
|
cwd: '/tmp/proj',
|
|
message: {
|
|
id: 'msg-1', type: 'message', role: 'assistant', model: 'claude-sonnet-4-5',
|
|
content: [], usage: { input_tokens: 100, output_tokens: 50 },
|
|
},
|
|
}) + '\n')
|
|
}
|
|
|
|
describe('cold-start cache persistence', () => {
|
|
// The desktop cold-start bug is "the cache never persists". This pins the
|
|
// invariant the fix depends on: a run that reaches the end of parseAllSessions
|
|
// writes the current-version session cache to disk, so the next launch is warm.
|
|
it('a completed parseAllSessions persists the current-version cache to disk', async () => {
|
|
await writeSession()
|
|
const projects = await parseAllSessions()
|
|
expect(projects.length).toBeGreaterThan(0)
|
|
|
|
const raw = JSON.parse(await readFile(sessionCachePath(), 'utf-8'))
|
|
expect(raw.version).toBe(CACHE_VERSION)
|
|
const claudeFiles = Object.keys(raw.providers?.claude?.files ?? {})
|
|
expect(claudeFiles.length).toBeGreaterThan(0)
|
|
// The persisted entry carries the parsed turn, so a warm reload serves it
|
|
// without re-reading the source file.
|
|
expect(raw.providers.claude.files[claudeFiles[0]!].turns.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it('streams per-provider scan progress only when CODEBURN_PROGRESS=1', async () => {
|
|
await writeSession()
|
|
const lines: string[] = []
|
|
const spy = vi.spyOn(process.stderr, 'write').mockImplementation(((chunk: unknown) => {
|
|
lines.push(String(chunk)); return true
|
|
}) as typeof process.stderr.write)
|
|
try {
|
|
// Off by default: plain CLI/terminal output is untouched.
|
|
await parseAllSessions()
|
|
expect(lines.filter(l => l.startsWith('CODEBURN_PROGRESS ')).length).toBe(0)
|
|
|
|
clearSessionCache()
|
|
process.env['CODEBURN_PROGRESS'] = '1'
|
|
await parseAllSessions()
|
|
const progress = lines.filter(l => l.startsWith('CODEBURN_PROGRESS '))
|
|
expect(progress.some(l => l.includes('"providers"'))).toBe(true)
|
|
expect(progress.some(l => l.includes('"provider":"claude"') && l.includes('"start"'))).toBe(true)
|
|
} finally {
|
|
spy.mockRestore()
|
|
}
|
|
})
|
|
})
|