Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
518f9ab
chore(release): open dev at 2.84.0 before releasing 2.83.0 (#6902)
github-actions[bot] Oct 10, 2026
7d058f2
fix(server): release eager relay listeners after producer teardown (#…
mashfromband Oct 10, 2026
19c71a5
fix(logs): refuse upstream diagnostics that repeat a sent credential …
lidge-jun Oct 10, 2026
289d528
test: make the drip-feed probe and plugin lifecycle tests independent…
lidge-jun Oct 10, 2026
77a260f
fix(codex): preserve prompt drafts and validate base imports (#6866)
luvs01 Oct 10, 2026
1c7c2fa
fix(ollama): bound generated late-tool attribution (#6654)
luvs01 Oct 10, 2026
09b3e76
fix(link): recover Home-initiated links after outages and make Retry …
lidge-jun Oct 10, 2026
bf09e1a
fix(desktop): explicitly unlock the CLI record lock before closing (#…
lidge-jun Oct 10, 2026
c9e6a72
fix(gui): keep combo capabilities for targets hidden from the picker …
lidge-jun Oct 10, 2026
433764e
fix(grok): keep coupon callers on an operation that may still be spen…
lidge-jun Oct 10, 2026
f189b33
test(usage): keep the credential-shape case off a same-size rewrite (…
lidge-jun Oct 11, 2026
9b6f4b2
fix(link): restore remote hub browser pairing on loopback-bound manag…
lidge-jun Oct 11, 2026
49e50cc
fix(claude): keep loopback MCP servers off the intercept proxy with N…
lidge-jun Oct 11, 2026
c3a4cdf
fix(kimi): omit explicit empty assistant history on native Responses …
lidge-jun Oct 11, 2026
b1f39cd
fix: verify configured credentials by content, route the tray to the …
lidge-jun Oct 11, 2026
7d78598
fix(claude): label alias tier slots in /model; count Anthropic cache …
lidge-jun Oct 11, 2026
e1a2684
fix(claude): keep the NO_PROXY receipt across a failed removal, and d…
lidge-jun Oct 11, 2026
b5f690b
fix: preserve shadow-call user turns, honor ZCode dataBaseDir, forwar…
lidge-jun Oct 11, 2026
862b8f1
fix(cli): harden hub disable, log filters and service startup diagnos…
lidge-jun Oct 11, 2026
777b377
fix(accounts): admit reset Anthropic accounts and report OAuth subscr…
lidge-jun Oct 11, 2026
34bf006
fix(link): verify Child runtime relay and add fingerprint-bound CLI e…
lidge-jun Oct 11, 2026
7af092c
fix(config): preserve remote topology across guarded live saves (#6956)
lidge-jun Oct 11, 2026
0024ac6
fix(claude): reject unverified picker metadata snapshots (#6965)
luvs01 Oct 12, 2026
7258420
feat(codex): pick, clear and auto-assign each LazyCodex role's reason…
lidge-jun Oct 12, 2026
4fa0967
fix(openai-chat): handle Flash-Next leading-system templates (#6966)
areslp Oct 12, 2026
8eb1fc3
feat(codex): release account pins from the dashboard (#6964)
luvs01 Oct 12, 2026
561c55b
docs(codex): carry the translated LazyCodex role effort sections (#6970)
lidge-jun Oct 12, 2026
a0191a1
fix(codex): save a model-inheriting LazyCodex role's effort without p…
lidge-jun Oct 12, 2026
8d12a3c
fix(kiro): keep same-organization users as separate accounts (#6981)
lidge-jun Oct 12, 2026
f341b78
fix(responses): read V1 collaboration tools rendered inside code-mode…
lidge-jun Oct 12, 2026
744678f
fix(startup): dashboard installer on compiled ocx and clearer Desktop…
lidge-jun Oct 12, 2026
49ae1f7
docs(integrations): describe effort-only role saves in the translated…
lidge-jun Oct 12, 2026
e4af84a
fix(logs): keep the Codex WebSocket error wrapper's 5xx status and re…
lidge-jun Oct 12, 2026
03a9d31
ci(macos): split the macOS suite into three shards under the same 20-…
lidge-jun Oct 12, 2026
dc45bb2
fix(service): opt-in health sentinel recovers a hung but listening se…
lidge-jun Oct 12, 2026
3e58c2c
fix(anthropic): recover API-key credit-balance refusals before output…
lidge-jun Oct 12, 2026
419860b
fix(codex): deduplicate unchanged effort clamp observations (#7005)
Ingwannu Oct 12, 2026
5f3481b
test(codex): drain quota fixture owners before home removal (#7001)
Ingwannu Oct 12, 2026
4abec7a
fix(responses): frame a decoded ocx1 checkpoint as continuation in th…
robin-bially Oct 12, 2026
b1832a3
fix(codex): retire stale short-window quota after plan changes (#7002)
NineDayCC Oct 12, 2026
88433c3
fix(gui): cut the LazyCodex role section copy to what a user acts on …
LilMGenius Oct 12, 2026
6a69e54
test(codex): pin cache retention for omitted tertiary and malformed o…
lidge-jun Oct 12, 2026
07a5cf2
fix(responses): scope the checkpoint continuation note to authorized …
lidge-jun Oct 12, 2026
e33a2ce
docs(devlog): record the L2 contributor carry plan, audit and review
lidge-jun Oct 12, 2026
a63267c
Merge #7008: carry five contributor fixes for the 2.84.0 train
lidge-jun Oct 12, 2026
95bee27
fix(ci): run the test runner on Bun 1.4.3 so spawnSync stops losing c…
lidge-jun Oct 12, 2026
c220eec
ci(test): refresh shard durations from a full dispatch and give Windo…
lidge-jun Oct 12, 2026
ed07f0f
test(web-search): run the pacing deadline cases on a virtual clock (#…
lidge-jun Oct 12, 2026
bbe1fc1
fix(anthropic-pool): answer spent quota as a usage limit and lift Ret…
lidge-jun Oct 12, 2026
a061e70
fix(responses): retry and fail over a pooled Codex turn the upstream …
lidge-jun Oct 12, 2026
ce97299
fix(desktop): tray Start at Login shows only what Startup safety veri…
lidge-jun Oct 12, 2026
b993e66
fix(link): read-only Home management, Home Codex settings and one CLI…
lidge-jun Oct 12, 2026
6c27087
feat(gui): opt in custom Responses plaintext reasoning replay (#6961)
lidge-jun Oct 12, 2026
fe6768c
docs(devlog): record the L1 owner bundle and the #6999 split
lidge-jun Oct 12, 2026
c9438df
fix(responses): read deferred V1 collaboration tools from the Codex <…
lidge-jun Oct 12, 2026
43232a4
fix(claude): bound the picker front's discard of an abandoned upload
lidge-jun Oct 12, 2026
ed2e435
docs(devlog): record the L3 lane outcome for #6844 and the #6984 drai…
lidge-jun Oct 12, 2026
72fedca
fix(service): prove OpenCodex Desktop supervision on Windows (#6853)
lidge-jun Oct 12, 2026
57d9e2a
feat(codex): discover the Codex app's bundled CLI on macOS (#6973)
lidge-jun Oct 12, 2026
d89f374
test(link): classify passive-read opens by write capability
lidge-jun Oct 12, 2026
fa11541
docs(devlog): record the L4 lane plan, reviews and outcome for #6853 …
lidge-jun Oct 12, 2026
d91ecf8
fix(codex): check plist text with the XML Char predicate instead of a…
lidge-jun Oct 12, 2026
8f10f23
Merge #7009: land eight owner fixes for 2.84.0
lidge-jun Oct 12, 2026
b71d1e1
Merge #7010: detect deferred V1 collaboration tools and bound the pic…
lidge-jun Oct 12, 2026
bf57900
Merge #7011: recognize Desktop supervision on Windows and discover th…
lidge-jun Oct 12, 2026
bed3b47
feat(meta): seed Muse Wonder on the Meta Model API and Muse Code prov…
lidge-jun Oct 12, 2026
1b53510
fix(codex): default native GPT-6.1 Sol to the 500k context Codex now …
lidge-jun Oct 12, 2026
0180a51
docs(devlog): record the L5 sources, plan and audits for Muse Wonder …
lidge-jun Oct 12, 2026
3bb7a56
Merge #7013: GPT-6.1 Sol 500k default context in Codex and Meta Muse …
lidge-jun Oct 12, 2026
6def866
release: promote dev 3bb7a5612c to main as 2.84.0
lidge-jun Oct 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 4 additions & 2 deletions .github/actions/setup-project-bun/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ description: >-
runtime (default), or testRunnerBun for test-runner.

# Runtime 1.4.2 fixes #6684's Windows Bun.fetch stream truncation. The test runner
# stays on 1.4.0: #4821 reverted #4064 after 1.4.2's multi-file --isolate preload
# segfault; #6713 run 37631558263 reproduces it on Linux 1/4, macOS 2/2, Windows 9/9.
# skipped 1.4.2: #4821 reverted #4064 after its multi-file --isolate preload segfault
# (#6713 run 37631558263: Linux 1/4, macOS 2/2, Windows 9/9). It moved from 1.4.0 to
# 1.4.3 for oven-sh/bun#44581: 1.4.0's Bun.spawnSync could lose a child's exit after
# finalizers ran inside an earlier call and spin past its own timeout (#4956).
# Rejoin only after the upstream runner crash is fixed and a green lane=all
# dispatch proves the unified version; then delete testRunnerBun and this role input.
inputs:
Expand Down
28 changes: 18 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -550,8 +550,9 @@ jobs:
printf 'scheduled run tests dev at %s (workflow %s)\n' "$sha" "$GITHUB_SHA"

# Bun roles (#6713): runtime 1.4.2 fixes #6684's Windows Bun.fetch streaming;
# test-runner 1.4.0 avoids 1.4.2's multi-file --isolate preload segfault (#4821
# reverted #4064; run 37631558263: Linux 1/4, macOS 2/2, Windows 9/9).
# the test runner skipped 1.4.2's multi-file --isolate preload segfault (#4821
# reverted #4064; run 37631558263: Linux 1/4, macOS 2/2, Windows 9/9) and runs
# 1.4.3, whose oven-sh/bun#44581 stops Bun.spawnSync losing a child's exit (#4956).
# Rejoin after the upstream runner crash is fixed and a green lane=all dispatch
# proves the unified version, then delete testRunnerBun and the action's role input.
# The suite, split by file across four Linux runners.
Expand Down Expand Up @@ -797,23 +798,30 @@ jobs:
run: bun run src/cli/index.ts help

platform-macos:
name: macos ${{ matrix.shard }}/2
name: macos ${{ matrix.shard }}/3
needs: changes
# Native-gated: these legs only run when the changes job's `native` filter
# says the macOS suite's inputs could have changed, so an ordinary source
# pull request stops paying for two macOS runners.
# pull request stops paying for three macOS runners.
if: github.event_name != 'pull_request' || (needs.changes.outputs.ci == 'true' && needs.changes.outputs.native == 'true')
runs-on: macos-latest
# Two shards. Unsharded, this job was the critical path on every green dev
# Three shards. Unsharded, this job was the critical path on every green dev
# push (mean 14.9 min against a 4.7 min Linux maximum; devlog
# 260905_test_modularization_and_windows/003). Two halves finish in ~7.7 and
# cost 0.6 extra macOS minutes of setup per run. The full-membership control
# runs the same bounded batches without sharding on explicit dispatch.
# 260905_test_modularization_and_windows/003), so it was split in two. The
# suite then outgrew two halves: across seventeen dev dispatches from
# 2026-10-04 to 10-12 the slower half's test step went from 867s to 1155s,
# and run 38214884055 cancelled macos 2/2 at this cap with 68 files left
# while every test it had run was passing (#6978). Replaying the duration
# assignment against those runs' measured per-file times puts the slowest of
# three shards at 635-796s of tests, about 14 minutes with setup. The cap
# stays 20: the suite needs another shard, not a longer wait, and a wedged
# shard (#4956) is still cut off as early as before. The full-membership
# control runs the same bounded batches without sharding on explicit dispatch.
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
shard: [1, 2]
shard: [1, 2, 3]
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
Expand Down Expand Up @@ -859,7 +867,7 @@ jobs:

- name: Test in fresh-process batches
env:
TEST_SHARD: ${{ matrix.shard }}/2
TEST_SHARD: ${{ matrix.shard }}/3
BUN_TEST_FILE_SCOPE: all
BUN_TEST_BATCH_SIZE: '12'
BUN_TEST_PARALLEL: '1'
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ A ready-for-review PR is the author's claim that the change is complete, underst

## Local validation and hooks

The suite uses Bun 1.4.0 (`testRunnerBun`) while the shipped runtime is 1.4.2.
`scripts/test.ts` finds a 1.4.0 binary on PATH or in `~/.bun/bin`, or uses
The suite uses Bun 1.4.3 (`testRunnerBun`) while the shipped runtime is 1.4.2.
`scripts/test.ts` finds a 1.4.3 binary on PATH or in `~/.bun/bin`, or uses
`OCX_TEST_RUNNER_BUN`; install that version locally if it is missing.

Run `bun run test` before review readiness. If the full local suite is too costly
Expand Down
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# syntax=docker/dockerfile:1

# Keep the runtime aligned with package.json and pin the multi-platform image index.
# Runtime 1.4.2 fixes #6684's Windows Bun.fetch streaming; CI tests stay on 1.4.0
# Runtime 1.4.2 fixes #6684's Windows Bun.fetch streaming; CI tests run on 1.4.3
# because 1.4.2 segfaults reloading preloads in multi-file --isolate (#4821;
# #6713 run 37631558263: Linux 1/4, macOS 2/2, Windows 9/9). Rejoin after the
# #6713 run 37631558263: Linux 1/4, macOS 2/2, Windows 9/9) and 1.4.0's spawnSync
# can lose a child's exit (#4956, oven-sh/bun#44581). Rejoin after the
# upstream crash fix passes a unified-version lane=all dispatch, then delete
# package.json's testRunnerBun pin and setup-project-bun's role input.
ARG BUN_IMAGE=oven/bun:1.4.2@sha256:9114c058aeae42162ee16dd5084b95fe9473970bb6bcb5b232ab1630f0546895
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "opencodex-desktop"
version = "2.83.0"
version = "2.84.0"
description = "OpenCodex desktop shell"
authors = ["OpenCodex contributors"]
license = "MIT"
Expand Down
218 changes: 188 additions & 30 deletions desktop/src-tauri/src/cli_command_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,75 @@ impl Record {
pub struct Store {
pub root: PathBuf,
pub rc_allowed: Vec<PathBuf>,
_lock: fs::File,
_lock: LockGuard,
}
struct LockGuard {
file: fs::File,
}
impl LockGuard {
fn unlock(&self) -> i32 {
#[cfg(unix)]
{
use std::os::fd::AsRawFd;
// LOCK_UN releases the shared file description even if a fork retains a duplicate.
unsafe { flock(self.file.as_raw_fd(), 8) }
}
#[cfg(windows)]
{
use std::os::windows::io::AsRawHandle;
let mut v = Overlapped::zero();
unsafe { UnlockFileEx(self.file.as_raw_handle(), 0, 1, 0, &mut v) }
}
}
#[cfg(test)]
fn release_for_test(&self) -> i32 {
self.unlock()
}
}
impl Drop for LockGuard {
fn drop(&mut self) {
let _ = self.unlock();
}
}
#[cfg(windows)]
#[repr(C)]
struct Overlapped {
internal: usize,
high: usize,
offset: u32,
offset_high: u32,
event: *mut std::ffi::c_void,
}
#[cfg(windows)]
impl Overlapped {
fn zero() -> Self {
Self {
internal: 0,
high: 0,
offset: 0,
offset_high: 0,
event: std::ptr::null_mut(),
}
}
}
#[cfg(windows)]
#[link(name = "kernel32")]
unsafe extern "system" {
fn LockFileEx(
h: *mut std::ffi::c_void,
flags: u32,
reserved: u32,
low: u32,
high: u32,
overlapped: *mut Overlapped,
) -> i32;
fn UnlockFileEx(
h: *mut std::ffi::c_void,
reserved: u32,
low: u32,
high: u32,
overlapped: *mut Overlapped,
) -> i32;
}
#[cfg(unix)]
unsafe extern "C" {
Expand Down Expand Up @@ -533,7 +601,7 @@ pub fn atomic(path: &Path, before: Option<&[u8]>, after: &[u8], mode: u32) -> Re
let _ = fs::remove_file(tmp);
result
}
fn lock(root: &Path) -> Result<fs::File> {
fn lock(root: &Path) -> Result<LockGuard> {
let p = root.join("cli.lock");
let existed = fs::symlink_metadata(&p).is_ok();
if fs::symlink_metadata(&p).is_ok() {
Expand Down Expand Up @@ -561,45 +629,21 @@ fn lock(root: &Path) -> Result<fs::File> {
#[cfg(unix)]
{
use std::os::fd::AsRawFd;
// LOCK_EX | LOCK_NB: OS releases the lock on close/process death; no stale PID deletion.
// LOCK_EX | LOCK_NB: immediate exclusion; the guard unlocks before closing.
if unsafe { flock(f.as_raw_fd(), 2 | 4) } != 0 {
return Err("lock-busy".into());
}
}
#[cfg(windows)]
{
use std::os::windows::io::AsRawHandle;
#[repr(C)]
struct Overlapped {
internal: usize,
high: usize,
offset: u32,
offset_high: u32,
event: *mut std::ffi::c_void,
}
#[link(name = "kernel32")]
unsafe extern "system" {
fn LockFileEx(
h: *mut std::ffi::c_void,
flags: u32,
reserved: u32,
low: u32,
high: u32,
overlapped: *mut Overlapped,
) -> i32;
}
let mut v = Overlapped {
internal: 0,
high: 0,
offset: 0,
offset_high: 0,
event: std::ptr::null_mut(),
};
let mut v = Overlapped::zero();
if unsafe { LockFileEx(f.as_raw_handle(), 1 | 2, 0, 1, 0, &mut v) } == 0 {
return Err("lock-busy".into());
}
}
Ok(f)
// A failed acquisition must only close its own file, never unlock another owner.
Ok(LockGuard { file: f })
}
impl Store {
pub fn open(root: PathBuf, rc_allowed: Vec<PathBuf>) -> Result<Self> {
Expand Down Expand Up @@ -1807,6 +1851,120 @@ pub(crate) mod tests {
assert!(s.validate(&r, false).is_err());
}
#[test]
fn lock_drop_releases_and_held_store_excludes_second_open() {
let t = Temp::new();
let s = t.store();
let root = s.root.clone();
assert_eq!(
Store::open(root.clone(), vec![]).err().as_deref(),
Some("lock-busy")
);
drop(s);
let reopened = Store::open(root.clone(), vec![]).unwrap();
assert_eq!(
Store::open(root, vec![]).err().as_deref(),
Some("lock-busy")
);
drop(reopened);
}
#[cfg(unix)]
#[test]
fn lock_drop_releases_even_with_duplicate_file_description() {
let t = Temp::new();
let s = t.store();
let root = s.root.clone();
let duplicate = s._lock.file.try_clone().unwrap();
drop(s);
let reopened = Store::open(root.clone(), vec![]).unwrap();
assert_eq!(
Store::open(root, vec![]).err().as_deref(),
Some("lock-busy")
);
assert_eq!(reopened._lock.release_for_test(), 0);
drop(duplicate);
}
#[cfg(unix)]
#[test]
fn lock_drop_releases_during_concurrent_process_spawns() {
use std::{
process::Command,
sync::{atomic::AtomicBool, atomic::Ordering, Barrier},
thread,
};
// Present on macOS and on Linux runners; macOS has no /bin/true.
const TRUE: &str = "/usr/bin/true";
let t = Temp::new();
let root = t.store().root.clone();
let stop = AtomicBool::new(false);
let ready = Barrier::new(5);
let mut busy = 0;
let mut errors = Vec::new();
let spawns = thread::scope(|scope| {
let workers: Vec<_> = (0..4)
.map(|_| {
scope.spawn(|| {
ready.wait();
let mut spawns = 0;
while !stop.load(Ordering::Relaxed) {
assert!(Command::new(TRUE).status().unwrap().success());
spawns += 1;
}
spawns
})
})
.collect();
ready.wait();
for _ in 0..2000 {
// Each cycle opens, drops and reopens, without waiting or retrying a busy lock.
for _ in 0..2 {
match Store::open(root.clone(), vec![]) {
Ok(store) => drop(store),
Err(e) if e == "lock-busy" => busy += 1,
Err(e) => errors.push(e),
}
}
}
stop.store(true, Ordering::Relaxed);
workers
.into_iter()
.map(|worker| worker.join().unwrap())
.sum::<usize>()
});
eprintln!("lock stress: cycles=2000, spawners=4, spawns={spawns}, lock-busy={busy}");
assert!(spawns >= 4, "process spawners did not run");
assert!(errors.is_empty(), "unexpected open errors: {errors:?}");
assert_eq!(busy, 0);
}
#[test]
fn failed_open_after_lock_acquisition_releases_lock() {
let t = Temp::new();
let s = t.store();
let root = s.root.clone();
atomic(&root.join("cli.json"), None, b"{", 0o600).unwrap();
drop(s);
assert_eq!(
Store::open(root.clone(), vec![]).err().as_deref(),
Some("record-invalid")
);
let guard = lock(&root).unwrap();
assert_eq!(lock(&root).err().as_deref(), Some("lock-busy"));
drop(guard);
let _guard = lock(&root).unwrap();
}
#[cfg(windows)]
#[test]
fn lock_guard_windows_explicit_release_allows_second_handle_to_relock() {
let t = Temp::new();
let s = t.store();
assert_ne!(s._lock.release_for_test(), 0);
let root = s.root.clone();
let second = lock(&root).unwrap();
drop(s);
assert_eq!(lock(&root).err().as_deref(), Some("lock-busy"));
assert_ne!(second.release_for_test(), 0);
let _third = lock(&root).unwrap();
}
#[test]
fn lock_and_atomic_write_preserve_concurrent_user_edits() {
let t = Temp::new();
let s = t.store();
Expand Down
Loading
Loading