Skip to content
Merged
Show file tree
Hide file tree
Changes from 134 commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
9c9eb57
wip(cli-bun): bun runner, preload parity, and shared vi.mock shim fixes
acoliver Aug 3, 2026
bd5300f
revert bun-written snapshot entries
acoliver Aug 3, 2026
67346c7
wip(cli-bun): batch remediation from parallel agents + snapshot key m…
acoliver Aug 4, 2026
ce9452a
wip(cli-bun): further batch remediation
acoliver Aug 4, 2026
16cda9f
fix(bun-shim): Vitest-compatible spyOn freshness, restoreAllMocks mod…
acoliver Aug 4, 2026
7914fa0
fix(bun-shim): automock default interop, vi.unmock restore, provider-…
acoliver Aug 4, 2026
292e5e6
fix(cli-bun): reset process.exitCode per test and stop yargs from exi…
acoliver Aug 4, 2026
3067113
fix(bun-shim): snapshot module exports through accessors for builtin …
acoliver Aug 4, 2026
78e19ef
fix(bun-shim): synthesize automock default export for CommonJS modules
acoliver Aug 4, 2026
bf86939
test(cli): load toolMapping after its telemetry mock is registered
acoliver Aug 4, 2026
ba14078
test(cli): rewrite resolves.not.toThrow assertions as direct awaits
acoliver Aug 4, 2026
3e2440c
test(cli): restore real stdio and remove drain/error timer races in c…
acoliver Aug 4, 2026
b617500
test(cli): load errorReporting after its core mock is registered
acoliver Aug 4, 2026
396c54b
test(cli): load dynamicSettings after its telemetry mock is registered
acoliver Aug 4, 2026
536d59c
test(cli): inject the MCP token store on the class diagnostics actual…
acoliver Aug 4, 2026
ad6a0b3
test(cli): await fs.access instead of asserting its runtime-specific …
acoliver Aug 4, 2026
723742b
fix(bun-shim): mockRestore returns a vi.fn to its constructor impleme…
acoliver Aug 4, 2026
2a4e6cb
test(cli): run the fd-forwarding harness under node explicitly
acoliver Aug 4, 2026
0bc7044
test(cli): restore the real provider aliases via vi.unmock and import…
acoliver Aug 4, 2026
894ef99
test(cli): use a real class for the mocked agent client constructor
acoliver Aug 4, 2026
6dc11e3
fix(bun-shim): tolerate dependencies that cannot be required when sna…
acoliver Aug 4, 2026
5eab2ca
fix(bun-shim): run due timers when advanceTimersByTimeAsync is called…
acoliver Aug 4, 2026
78b3f88
test: pin the CLI bun runner discovery contract and the Vitest-parity…
acoliver Aug 4, 2026
e763bb8
test(cli): use a real class for the shared mocked agent client constr…
acoliver Aug 4, 2026
b31995e
test(cli): drop mocks for hooks that no longer exist in the workspace
acoliver Aug 4, 2026
f01b324
test(cli): poll AuthDialog keystroke assertions instead of sleeping a…
acoliver Aug 4, 2026
6542416
test(cli): poll AuthDialog OAuth toggle assertions instead of sleeping
acoliver Aug 4, 2026
68cf0f1
fix(cli): type the mocked agent client instances passed to useAgentSt…
acoliver Aug 4, 2026
e87c7dc
fix(cli): clear the typecheck and lint errors introduced by the migra…
acoliver Aug 4, 2026
2b37a7d
chore: apply repository formatting
acoliver Aug 4, 2026
3abc1ae
fix(bun-shim): stop overriding vi.fn, which broke mock-as-constructor
acoliver Aug 4, 2026
86177a7
test: drop parity cases for the reverted vi.fn override and document …
acoliver Aug 4, 2026
6c8f620
docs: record the delivered bun migration architecture and its diverge…
acoliver Aug 4, 2026
1025829
fix(bun-shim): clear module-mock call history on restoreAllMocks, mat…
acoliver Aug 4, 2026
15882ee
feat(cli-bun): report aggregate test-case counts for vitest parity ve…
acoliver Aug 4, 2026
8da91cc
docs: record measured bun test-case totals and the vitest OOM that bl…
acoliver Aug 4, 2026
22bc0a2
refactor(cli): remove vitest from the workspace and run every test fi…
acoliver Aug 4, 2026
e879005
test(cli): delete tests asserting removed behaviour and record the co…
acoliver Aug 4, 2026
cf8c4c4
test(cli): port ContextIndicator and delete the theme prop-instrument…
acoliver Aug 4, 2026
0795e14
test(cli): delete the App test family, written against a superseded c…
acoliver Aug 4, 2026
e54f1db
test(cli): supply MouseProvider and the current TextBuffer fields to …
acoliver Aug 4, 2026
0574ba3
fix(cli-test-utils): route useStdin to the active render stdin so key…
acoliver Aug 4, 2026
f807663
test(cli): add a complete SessionMetrics fixture factory and refresh …
acoliver Aug 4, 2026
3723fac
test(cli): port TodoPanel.responsive and ProviderDialog.responsive to…
acoliver Aug 4, 2026
f6480e6
test(cli): update agent-stream call-signature expectations; drop canc…
acoliver Aug 4, 2026
c7e9f55
docs: record the cancellation coverage moved to the agent loop
acoliver Aug 4, 2026
f8ff193
test(cli): port finish-reason cases to canonical reasons; delete the …
acoliver Aug 4, 2026
80b88e2
test(cli): default renderMarkdown in the shared UI state and supply t…
acoliver Aug 4, 2026
426ffe1
test(cli): align line-number tests with the shipped showLineNumbers d…
acoliver Aug 4, 2026
5d58641
test(cli): follow the loading-phrases setting rename and inversion in…
acoliver Aug 4, 2026
2b0653a
test(cli): port tool confirmation assertions, refresh tool group snap…
acoliver Aug 4, 2026
0a81388
test(cli): supply the runtime bridge and extensions getter to Session…
acoliver Aug 4, 2026
a08195f
test(cli): render the responsive-testing helper fixture with ink prim…
acoliver Aug 4, 2026
1f78f58
fix(cli): satisfy the ink text-color lint rule in the responsive help…
acoliver Aug 4, 2026
57b1fe8
fix(settings): restore the lost retries/retrywait validators and port…
acoliver Aug 4, 2026
d58706e
test(cli): resolve profiles from the isolated storage root and read t…
acoliver Aug 4, 2026
9faa0d5
test(cli): point oauth-timing ProfileManager at its temp profiles dir…
acoliver Aug 4, 2026
a1f1f25
test(cli): align spawned-CLI profile tests with the isolated storage …
acoliver Aug 4, 2026
d71b4e4
test(cli): assert cleanup logging on the debug logger and correct a m…
acoliver Aug 4, 2026
bd660d6
test(cli): assert Config-level normalisation of streaming settings
acoliver Aug 4, 2026
3d04417
fix(cli-test): omit an empty LLXPRT_CONFIG_HOME when spawning the CLI
acoliver Aug 4, 2026
cd2e123
test(cli): correct git-stats diff arithmetic and cumulative filesChan…
acoliver Aug 4, 2026
f3e0d71
test(cli): attach agent factories and assert Config-level context-lim…
acoliver Aug 4, 2026
6272396
test(cli): resolve loadbalancer profiles from the isolated root; reco…
acoliver Aug 4, 2026
5ffd93d
test(cli): assert provider-switch clearing and supply the proactive-r…
acoliver Aug 4, 2026
5a0e56f
test(cli): delete auth-e2e integration suite that spawned a nonexiste…
acoliver Aug 4, 2026
346170d
test(cli): make the multi-provider logging fixture exercise what it a…
acoliver Aug 4, 2026
c354b99
test(cli): keep a yargs validation exit from killing the test process
acoliver Aug 4, 2026
aa4d1c0
test(cli): keep the yargs assertion in the test body for lint
acoliver Aug 4, 2026
1056db0
test(cli): restore the 30s test timeout that vitest.config.ts had set
acoliver Aug 4, 2026
4a9f0cb
test(cli): pass the per-test timeout explicitly to each bun test invo…
acoliver Aug 4, 2026
0b517df
test(cli): assert specified completion ranking and the debounce contr…
acoliver Aug 4, 2026
320b970
test(cli): drop the unused render result in the debounce test
acoliver Aug 4, 2026
fa2d63e
test(cli): assert large-paste placeholder behaviour and add threshold…
acoliver Aug 4, 2026
206a6b7
test(cli): record the ESC dispatch finding and back out an incorrect …
acoliver Aug 4, 2026
083d069
docs(issue2843): record what is ruled out for the InputPrompt keyboar…
acoliver Aug 4, 2026
8aad329
test(cli): assert elapsed-time retention rather than effect schedulin…
acoliver Aug 4, 2026
de1c71d
test(cli): emit the context-warning event the dispatcher consumes and…
acoliver Aug 4, 2026
bcdd12c
docs(issue2843): record the Bun extra-fd limitation blocking sandbox …
acoliver Aug 4, 2026
0035208
test(cli): redirect homedir via spy and assert the AggregateError dir…
acoliver Aug 4, 2026
efba341
test(cli): capture ink render through the documented injection seam
acoliver Aug 5, 2026
811c6f1
test(cli): delete InputPrompt queued-message cases for a prop nothing…
acoliver Aug 5, 2026
a17e0e2
test(cli): give the buffer double its render fields and snapshot once…
acoliver Aug 5, 2026
e43b5ea
test(cli): restore snapshots from main and record the fabricated-snap…
acoliver Aug 5, 2026
0f4dea4
test(cli): re-record snapshots for previously-excluded files after ve…
acoliver Aug 5, 2026
ba5abdb
test(cli): honour the mouseEventsEnabled option the paste tests alrea…
acoliver Aug 5, 2026
cffb298
test(cli): give the third InputPrompt buffer double its render fields
acoliver Aug 5, 2026
47fae09
test(cli): correct the useKeypress mock specifier and record the buff…
acoliver Aug 5, 2026
658b106
test(cli): drive SessionController identity and paid mode through the…
acoliver Aug 5, 2026
1379f42
docs(cli): record the useAgentStream.finished and SessionController f…
acoliver Aug 5, 2026
7514114
test(cli): delete placeholder tests and make the mouse assertion real
acoliver Aug 5, 2026
e2eac24
docs(cli): add the coverage-gap issue body filed as #3046
acoliver Aug 5, 2026
393e236
test(cli): extract the extension loadSettings seam to keep the file u…
acoliver Aug 5, 2026
d2a864d
fix(cli-bun): restore Ink teardown and credential env isolation, fail…
acoliver Aug 5, 2026
6882876
test(cli): assert SettingsDialog wraparound as a round trip instead o…
acoliver Aug 5, 2026
aeb0bd7
test(cli): restore the full branch-name assertion; reject the showLin…
acoliver Aug 5, 2026
82bf75a
test(cli): de-duplicate the debounce assertions and record why public…
acoliver Aug 5, 2026
6f72456
fix(cli-bun): clear nested module mocks and kill the whole process gr…
acoliver Aug 5, 2026
72dc924
Merge remote-tracking branch 'origin/main' into issue2843
acoliver Aug 5, 2026
dc86957
docs(cli): record the stale-dist masking and the spawned-CLI profile-…
acoliver Aug 5, 2026
3254044
docs(cli): correct the stale-bundle findings; profiles do honour LLXP…
acoliver Aug 5, 2026
7ffc853
docs(cli): add the PR body for the Bun test migration
acoliver Aug 5, 2026
7be5d1b
fix(cli): satisfy the CLI type-escape policy and re-own the bun manif…
acoliver Aug 5, 2026
d657e83
fix(cli): give spawned-CLI tests a budget that survives a cold CI runner
acoliver Aug 5, 2026
f9b0cf3
fix(cli): size the whole-file budget for CI-speed CLI spawns
acoliver Aug 5, 2026
2abcd55
fix(cli): stop a zero-length timer advance from splitting a paste seq…
acoliver Aug 5, 2026
9be95bb
fix(cli): keep the kitty debounce branch out of the test body
acoliver Aug 5, 2026
9776630
Merge remote-tracking branch 'origin/main' into issue2843
acoliver Aug 5, 2026
52261c1
fix(cli): repair four real defects the Bun migration exposed
acoliver Aug 5, 2026
191b877
fix(cli): restore click-to-position in the prompt and unbreak two hid…
acoliver Aug 5, 2026
fa7c2a0
fix(cli): give keypress tests human timing so they exercise the real …
acoliver Aug 5, 2026
d3a47e0
test(cli): exercise Ctrl+R command search in the mode that implements it
acoliver Aug 5, 2026
0725b19
test(cli): feed the raw server event through the agent event adapter
acoliver Aug 5, 2026
aa9960e
test(cli): stop reading an object that Bun's toMatchObject has corrupted
acoliver Aug 5, 2026
82d0a5f
test(cli): let the OAuth mock report the enablement state the tests d…
acoliver Aug 5, 2026
eb4d80d
test(cli): assert the behaviour these two suites actually govern
acoliver Aug 5, 2026
98a9e99
test(cli): stop spawned CLIs inheriting the host session's JSP bootstrap
acoliver Aug 5, 2026
89b3b88
fix(cli): scrub the host session's JSP bootstrap and unmask a hidden …
acoliver Aug 5, 2026
b94b500
test(cli): assert the suggestion rendering this fork actually has
acoliver Aug 5, 2026
42e0363
fix(cli): stop declaring a provider-neutral gemini identifier in the …
acoliver Aug 5, 2026
21ff260
test(cli): make the spawned-CLI integration suites survive a CI runner
acoliver Aug 5, 2026
1d3b52b
test(cli): stop spawned CLIs inheriting CI's real provider credentials
acoliver Aug 5, 2026
fbb4321
test(cli): stop settingsIntegration calling the real OS keychain
acoliver Aug 5, 2026
c62ab46
test(cli): keep PoliciesDialog state updates inside act()
acoliver Aug 5, 2026
22a0236
fix: keep the credential scrub clear of the provider-naming guard
acoliver Aug 5, 2026
205c979
ci: let the coverage comment report N/A for the migrated cli shard
acoliver Aug 5, 2026
79808d0
Merge remote-tracking branch 'origin/main' into issue2843
acoliver Aug 5, 2026
adafc32
review: fix the findings that hold, with evidence for those that do not
acoliver Aug 5, 2026
84d2112
fix(cli): stop the runner following a symlink cycle forever
acoliver Aug 6, 2026
bf87689
Merge origin/main into issue2843
acoliver Aug 6, 2026
8a94751
test(cli): close the remaining Bun migration review gaps
acoliver Aug 6, 2026
fc95298
Merge remote-tracking branch 'origin/main' into issue2843
acoliver Aug 6, 2026
578d390
Merge branch 'main' into issue2843
acoliver Aug 6, 2026
c1a2938
Merge remote-tracking branch 'origin/main' into issue2843
acoliver Aug 6, 2026
ad070ce
test: eliminate Bun migration lifecycle flakes
acoliver Aug 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1541,11 +1541,11 @@ jobs:
- name: 'Download CLI coverage (cli shard)'
# Issue #2707: coverage is now per-shard. The composite action consumes
# the cli + core coverage summaries, produced by their respective shards.
# continue-on-error is not needed here: post_coverage_comment already
# has continue-on-error: true at the job level, so a missing artifact
# will fail this step but not block PR merges. The job's own `if`
# condition gates on needs.test.result == 'success', which means the
# cli/core shards passed and their coverage artifacts exist.
# CLI tests migrated to Bun's native runner (issue #2843) and no longer
# upload a Vitest coverage artifact, exactly as core did in #2842.
# Continue-on-error lets the post-coverage-comment action report "N/A"
# for cli instead of failing the job on a missing artifact.
continue-on-error: true
uses: 'actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c' # ratchet:actions/download-artifact@v8
with:
name: 'coverage-cli-${{ matrix.node-version }}-${{ matrix.os }}'
Expand Down
121 changes: 113 additions & 8 deletions packages/cli/bun-test-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,17 @@
import { JSDOM } from 'jsdom';
import { join } from 'node:path';
import React from 'react';
import { mock, afterEach } from 'bun:test';
import {
afterEach,
afterAll,
beforeAll,
beforeEach,
describe,
expect,
it,
test,
vi,
} from 'bun:test';
import {
clearActiveProviderRuntimeContext,
DebugLogger,
Expand All @@ -45,10 +55,53 @@ Object.assign(globalThis, {
getComputedStyle: dom.window.getComputedStyle.bind(dom.window),
});

// ---------------------------------------------------------------------------
// Test globals
//
// The Vitest configuration for this workspace sets `globals: true`, so many
// test files reference `describe` / `it` / `expect` without importing them.
// Bun only injects those names into files that import from 'bun:test' or
// 'vitest', so expose the same globals here to preserve that contract.
// ---------------------------------------------------------------------------
const testGlobals: Record<string, unknown> = {
afterAll,
afterEach,
beforeAll,
beforeEach,
describe,
expect,
it,
test,
vi,
};
for (const [name, value] of Object.entries(testGlobals)) {
if (!(name in globalThis)) {
Object.defineProperty(globalThis, name, {
value,
writable: true,
enumerable: false,
configurable: true,
});
}
}

// ---------------------------------------------------------------------------
// Environment
// ---------------------------------------------------------------------------
process.env.NODE_ENV = process.env.NODE_ENV || 'test';

// Clear credential-proxy env vars so unit tests do not inherit the host
// process's proxy configuration, which would skip proactive renewal
// scheduling, alter token-store behaviour, and change sandbox paths. The
// runner passes the parent environment to every child, so without this a
// developer's live capability material reaches the tests.
delete process.env.LLXPRT_CREDENTIAL_SOCKET;
delete process.env.LLXPRT_CAPABILITY_TOKEN;
delete process.env.LLXPRT_CAPABILITY_FD;
// A developer running the suite from inside llxprt exports this, pointing at a
// session-scoped bootstrap file. Anything that boots the CLI in-process then
// dies with "JSP bootstrap file could not be read".
delete process.env.LLXPRT_JSP_BOOTSTRAP_FILE;
if (process.env.NO_COLOR !== undefined) {
delete process.env.NO_COLOR;
}
Expand Down Expand Up @@ -78,7 +131,11 @@ Bun.plugin({
// ---------------------------------------------------------------------------
// Provider aliases mock (prevents "Provider not found" in fs-mocked tests)
// ---------------------------------------------------------------------------
mock.module(
// Registered through `vi.mock` rather than `mock.module` so the compatibility
// shim snapshots the real module first; a test that needs the genuine aliases
// (test/providers/providerAliases.test.ts) can then restore them with
// `vi.unmock`.
vi.mock(
'@vybestack/llxprt-code-providers/composition/providerAliases.js',
() => ({
loadProviderAliasEntries: () => [
Expand Down Expand Up @@ -278,6 +335,14 @@ const { __resetCleanupStateForTesting } = await import(
'./src/utils/cleanup.js'
);

// Bun's mock.module patches a module namespace in place and shares it with
// this preload, so a test that mocks '@vybestack/llxprt-code-core' would
// otherwise replace the cleanup helpers this file relies on. Capture the real
// implementations now, before any test file can register a module mock.
const resetDebugLoggerForTesting =
DebugLogger.resetForTesting.bind(DebugLogger);
const clearProviderRuntimeContext = clearActiveProviderRuntimeContext;

const managedProcessEvents = [
'exit',
'SIGINT',
Expand Down Expand Up @@ -318,11 +383,51 @@ function restoreProcessListeners(eventName: ManagedProcessEvent): void {
}
}

afterEach(async () => {
for (const eventName of managedProcessEvents) {
restoreProcessListeners(eventName);
// Ink teardown must run before the shared process and runtime state below are
// reset, so it is invoked at the top of the same hook rather than registered
// separately. Without this, a component mounted in one test stays mounted for
// the rest of the file, leaking effects, timers and the global active stdin.
const { cleanup: cleanupInkRenders } = await import(
'./test-utils/ink-testing-library.js'
);

async function runCleanupPhases(
phases: ReadonlyArray<() => void | Promise<void>>,
): Promise<void> {
const errors: unknown[] = [];
for (const phase of phases) {
try {
await phase();
} catch (error) {
errors.push(error);
}
}
if (errors.length === 1) {
throw errors[0];
}
await DebugLogger.resetForTesting();
__resetCleanupStateForTesting();
clearActiveProviderRuntimeContext();
if (errors.length > 1) {
throw new AggregateError(errors, 'Multiple CLI test cleanup phases failed');
}
}

afterEach(async () => {
await runCleanupPhases([
() => cleanupInkRenders(),
() => {
// Code under test (for example the extension commands) signals failure
// with `process.exitCode = 1`. Under Vitest that happens inside a worker,
// but a Bun test file IS the process, so a leftover exit code would fail
// the file even when every test passed. Bun sets the real exit status
// from the test results after the hooks have run.
process.exitCode = 0;
},
() => {
for (const eventName of managedProcessEvents) {
restoreProcessListeners(eventName);
}
},
() => resetDebugLoggerForTesting(),
() => __resetCleanupStateForTesting(),
() => clearProviderRuntimeContext(),
]);
});
4 changes: 4 additions & 0 deletions packages/cli/bunfig.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ linker = "hoisted"

[test]
preload = ["../../test-setup/augment-bun-vi.ts", "./bun-test-setup.ts"]
# Matches the testTimeout/hookTimeout that the removed vitest.config.ts set.
# Bun defaults to 5s, which is not enough for the tests that spawn the real CLI
# as a subprocess when the suite runs with concurrency.
timeout = 30000
9 changes: 2 additions & 7 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,8 @@
"postinstall": "node scripts/install-native-launchers.cjs",
"lint": "eslint . --ext .ts,.tsx",
"format": "prettier --write .",
"test": "vitest run && bun ../../scripts/run_bun_tests.ts --workspace cli",
"test:bun": "bun ../../scripts/run_bun_tests.ts --workspace cli",
"test:integration": "vitest run -c vitest.integration.config.ts",
"test:ci:covered": "vitest run -c vitest.ci.covered.config.ts",
"test:ci:fast": "vitest run -c vitest.ci.fast.config.ts",
"test:ci": "vitest run && bun ../../scripts/run_bun_tests.ts --workspace cli",
"test:legacy": "OPENAI_RESPONSES_DISABLE=true vitest run -t \"legacy|gpt-3.5-turbo\"",
"test": "bun run-bun-tests.ts",
"test:ci": "bun run-bun-tests.ts",
"typecheck": "tsc --noEmit",
"prepack": "bun ../../scripts/bun-build.config.ts --cli-only"
},
Expand Down
Loading
Loading