codeburn/tests/cli-progress-keepalive-entry.test.ts
Resham Joshi bd88b89988
Some checks failed
CI / semgrep (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (24) (push) Waiting to run
Tests / test (26) (push) Waiting to run
Tests / test-platforms (macos-latest) (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (push) Waiting to run
macOS Menubar CI / test (push) Has been cancelled
Windows Menubar CI / check (ubuntu-latest) (push) Has been cancelled
Windows Menubar CI / check (windows-latest) (push) Has been cancelled
fix: stop the desktop status-timeout loop (#1644)
The desktop serve client counted every death, watchdog kills included,
against a 3-death budget that never reset, so three sporadic kills over an
app run disabled serve for good. The budget now resets on any healthy
answer: three generations in a row that never answer still disable it.

One-shot CLI runs only heartbeated inside a parse, so a run waiting on
another process's cold hydration lock (up to 10 min) went silent and was
killed at 45s on every poll. Start the keepalive at command entry.
2026-10-05 23:51:04 +02:00

45 lines
1.8 KiB
TypeScript

import { spawn } from 'node:child_process'
import { mkdtemp, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'
// A one-shot read that waits on another process's cold hydration lock does no
// parsing yet, and the app watchdogs kill on silence. It must beat anyway.
describe('one-shot CLI keepalive', () => {
it('beats while waiting on a foreign hydration lock', async () => {
const home = await mkdtemp(join(tmpdir(), 'cb-entry-keepalive-home-'))
const cacheDir = await mkdtemp(join(tmpdir(), 'cb-entry-keepalive-cache-'))
// This test process is alive and is not the child, so the child waits.
await writeFile(join(cacheDir, 'hydrating.lock'), JSON.stringify({ pid: process.pid, at: Date.now() }))
const child = spawn(process.execPath, ['--import', 'tsx', 'src/cli.ts', 'status', '--format', 'menubar-json', '--provider', 'claude'], {
cwd: process.cwd(),
env: {
...process.env,
HOME: home,
USERPROFILE: home,
CLAUDE_CONFIG_DIR: join(home, '.claude'),
CODEBURN_CACHE_DIR: cacheDir,
CODEBURN_PROGRESS: '1',
},
stdio: ['ignore', 'ignore', 'pipe'],
})
try {
const sawKeepalive = await new Promise<boolean>(resolve => {
let stderr = ''
const timer = setTimeout(() => resolve(false), 20_000)
child.stderr.on('data', chunk => {
stderr += chunk
if (stderr.includes('"kind":"keepalive"')) { clearTimeout(timer); resolve(true) }
})
child.on('exit', () => { clearTimeout(timer); resolve(false) })
})
expect(sawKeepalive).toBe(true)
} finally {
child.kill('SIGKILL')
await rm(home, { recursive: true, force: true })
await rm(cacheDir, { recursive: true, force: true })
}
}, 30_000)
})