@lyupro/codex-bridge 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.5.1] - 2026-08-12
10
+
11
+ ### Fixed
12
+
13
+ - Installing or uninstalling no longer fails over a rules-registry lock that is busy for one more
14
+ millisecond. Windows answers a taken lock with three codes, and only one of them is `EEXIST`: a
15
+ lock file whose delete is still pending comes back `EPERM`, and a file another process still
16
+ holds comes back `EBUSY` — the acquisition loop treated both as fatal instead of waiting. All
17
+ three now mean "not yours yet", and the decision lives in one exported check, `isLockTaken()`.
18
+
19
+ ### Changed
20
+
21
+ - The README's first screen names the problem the package solves, keeps the install command inside
22
+ the first 30 lines, adds a second badge row, and shows `doctor` output from a healthy host in
23
+ place of a screenshot.
24
+ - The reference documentation under `docs/` is English-only now (`overview.ru.md` became
25
+ `overview.md`), and the working folders — plans, checklists and audits — left the repository and
26
+ its history: a fresh clone contains the five reference documents and nothing else.
27
+
9
28
  ## [0.5.0] - 2026-08-11
10
29
 
11
30
  ### Added
package/README.md CHANGED
@@ -6,29 +6,14 @@
6
6
  [![Node.js](https://img.shields.io/node/v/@lyupro/codex-bridge)](https://www.npmjs.com/package/@lyupro/codex-bridge)
7
7
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
8
 
9
- ## What it gives you
10
-
11
- - **Runs survive the caller.** A detached worker keeps the run and its artifacts alive after the dispatcher exits.
12
- - **Invalid work is rejected before quota is spent.** Scope, order, retry, branch, and continuation checks run before a run folder is created.
13
- - **Verdicts come from artifacts.** CLI events, git state, and the declared report decide the result, not model claims about itself.
14
- - **Identical retries attach safely.** Repeating the same command joins the active run instead of starting another one.
15
- - **5 host guards enforce the boundary.** `reply-guard`, `order-gate`, `worktree-lock`, `prune-guard`, and `stop-guard` cover replies, orders, edits, deletion, and stopping.
16
- - **Installation is identifiable and reversible.** Writes to `settings.json` are merged and backed up; uninstall removes recorded package files only.
17
- - **Every run leaves an audit folder.** The verbatim task, scope, before/after git state, events, report, verdict, and reason remain together.
18
- - **Zero runtime dependencies and zero build steps.** The package is plain `.mjs` on the Node.js standard library.
9
+ [![npm downloads](https://img.shields.io/npm/dm/@lyupro/codex-bridge)](https://www.npmjs.com/package/@lyupro/codex-bridge)
10
+ [![npm unpacked size](https://img.shields.io/npm/unpacked-size/@lyupro/codex-bridge)](https://www.npmjs.com/package/@lyupro/codex-bridge)
11
+ [![dependencies: zero](https://img.shields.io/badge/dependencies-zero-brightgreen)](package.json)
19
12
 
20
- The current suite contains **603 automated tests: 602 passing and 1 skipped**.
21
-
22
- ## Requirements
23
-
24
- - Node.js >= 24
25
- - An authenticated [Codex CLI](https://developers.openai.com/codex/cli): `codex --version` and `codex login`
26
- - Claude Code, which hosts the agents, commands, and guards
13
+ Agentic coding spends one model subscription on everything, and implementation is the expensive part. codex-bridge moves that work to a separate [Codex CLI](https://developers.openai.com/codex/cli) subscription: Claude Code plans, dispatches and accepts, Codex executes — and every delegated run is guarded, verified and audited on disk.
27
14
 
28
15
  ## Install
29
16
 
30
- For a one-off user installation, global access, or a clone entry point:
31
-
32
17
  ```bash
33
18
  npm i -g @lyupro/codex-bridge # puts both command names on PATH
34
19
  codex-bridge install # into ~/.claude and ~/.lyupro/.codex-bridge/
@@ -50,12 +35,52 @@ If a global install and a clone coexist, you have two package copies. `codex-bri
50
35
 
51
36
  `codex-runs/` contains operator data. Uninstall never removes it.
52
37
 
38
+ ## Requirements
39
+
40
+ - Node.js >= 24
41
+ - An authenticated [Codex CLI](https://developers.openai.com/codex/cli): `codex --version` and `codex login`
42
+ - Claude Code, which hosts the agents, commands, and guards
43
+
44
+ ## What it gives you
45
+
46
+ - **Runs survive the caller.** A detached worker keeps the run and its artifacts alive after the dispatcher exits.
47
+ - **Invalid work is rejected before quota is spent.** Scope, order, retry, branch, and continuation checks run before a run folder is created.
48
+ - **Verdicts come from artifacts.** CLI events, git state, and the declared report decide the result, not model claims about itself.
49
+ - **Identical retries attach safely.** Repeating the same command joins the active run instead of starting another one.
50
+ - **5 host guards enforce the boundary.** `reply-guard`, `order-gate`, `worktree-lock`, `prune-guard`, and `stop-guard` cover replies, orders, edits, deletion, and stopping.
51
+ - **Installation is identifiable and reversible.** Writes to `settings.json` are merged and backed up; uninstall removes recorded package files only.
52
+ - **Every run leaves an audit folder.** The verbatim task, scope, before/after git state, events, report, verdict, and reason remain together.
53
+ - **Zero runtime dependencies and zero build steps.** The package is plain `.mjs` on the Node.js standard library.
54
+
55
+ The current suite contains **604 automated tests: 603 passing and 1 skipped**.
56
+
53
57
  ## Verify
54
58
 
55
59
  ```bash
56
60
  codex-bridge doctor
57
61
  ```
58
62
 
63
+ Output on a healthy host (trimmed):
64
+
65
+ ```text
66
+ [ok] host: ~/.claude (user, exists)
67
+ [ok] installation: @lyupro/codex-bridge@0.5.1 (matches package)
68
+ [ok] files: 53 installed file(s) present
69
+ [ok] rules: ~/.codex/rules/codex-bridge.rules (matches record)
70
+ [ok] permissions: installed (24/24 own strings in allow/deny)
71
+ [ok] hook:SubagentStop: matcher * -> ~/.lyupro/.codex-bridge/hooks/reply-guard.mjs
72
+ [ok] hook:PreToolUse: matcher Agent|Task -> ~/.lyupro/.codex-bridge/hooks/order-gate.mjs
73
+ [ok] hook:PreToolUse: matcher Write|Edit|MultiEdit|NotebookEdit -> ~/.lyupro/.codex-bridge/hooks/worktree-lock.mjs
74
+ [ok] hook:PreToolUse: matcher Bash|PowerShell -> ~/.lyupro/.codex-bridge/hooks/prune-guard.mjs
75
+ [ok] hook:PreToolUse: matcher TaskStop -> ~/.lyupro/.codex-bridge/hooks/stop-guard.mjs
76
+ [warn] retention: Automatic cleanup is ON — run transport older than 30 days is removed to reclaim disk space.
77
+ [ok] conventions: ~/.lyupro/.codex-bridge/conventions.md (found)
78
+ [ok] codex: codex-cli 0.146.1
79
+ [ok] node: 24.18.0 (requires >=24)
80
+ [ok] runsRoot: ~/.claude/codex-runs
81
+ [ok] liveRuns: 0 runs working right now
82
+ ```
83
+
59
84
  `doctor` reports the selected host, package source, installed files and guards, Codex availability, retention policy, permissions, live runs, and the current repository's run folder.
60
85
 
61
86
  ## Update
@@ -99,19 +99,41 @@ async function dropStaleLock(lockPath) {
99
99
  }
100
100
  }
101
101
 
102
+ /**
103
+ * Windows answers a taken lock with three different codes, and only one of them is EEXIST. A file
104
+ * whose last handle closed while a delete was pending stays visible but refuses to be opened:
105
+ * `open(..., 'wx')` comes back EPERM, and a file another process still holds comes back EBUSY.
106
+ * Treating those as fatal is what made `tests/cli/rules-owners.test.mjs` fail twice on 2026-08-11
107
+ * with EPERM on the lock file — the suite went red over a lock that was simply busy for one more
108
+ * millisecond. All three mean the same thing to a caller waiting for a lock: not yours yet.
109
+ */
110
+ const LOCK_TAKEN_CODES = new Set(['EEXIST', 'EPERM', 'EBUSY']);
111
+
112
+ /** Exported so the retry contract is asserted directly; the race itself reproduces only by luck. */
113
+ export function isLockTaken(err) {
114
+ return LOCK_TAKEN_CODES.has(err?.code);
115
+ }
116
+
102
117
  async function acquireRegistryLock(host) {
103
118
  await fs.mkdir(host.codexRulesDir, { recursive: true });
104
119
  const lockPath = registryLockPath(host);
120
+ let lastTaken;
105
121
  for (let attempt = 0; attempt < REGISTRY_LOCK_RETRIES; attempt += 1) {
106
122
  try {
107
123
  const handle = await fs.open(lockPath, 'wx');
108
124
  return { handle, lockPath };
109
125
  } catch (err) {
110
- if (err.code !== 'EEXIST') throw err;
126
+ if (!isLockTaken(err)) throw err;
127
+ lastTaken = err;
111
128
  if (!(await dropStaleLock(lockPath))) await waitForRegistryLock();
112
129
  }
113
130
  }
114
- throw new Error(`timed out waiting for rules ownership registry lock: ${lockPath}`);
131
+ // The code is part of the message: a timeout on EPERM points at a delete that never completed,
132
+ // a timeout on EEXIST at an owner that never released.
133
+ throw new Error(
134
+ `timed out waiting for rules ownership registry lock: ${lockPath} (last attempt: ${lastTaken.code})`,
135
+ { cause: lastTaken },
136
+ );
115
137
  }
116
138
 
117
139
  async function withRegistryLock(host, action) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lyupro/codex-bridge",
3
- "version": "0.5.0",
4
- "description": "Claude Code-to-Codex delegation with 5 guards, 603 tests, zero runtime dependencies, and zero build steps.",
3
+ "version": "0.5.1",
4
+ "description": "Claude Code-to-Codex delegation with 5 guards, 604 tests, zero runtime dependencies, and zero build steps.",
5
5
  "keywords": [
6
6
  "claude-code",
7
7
  "codex",