@minhspark/codex-mcp-bridge 1.10.0

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 ADDED
@@ -0,0 +1,223 @@
1
+ # Changelog
2
+
3
+ Follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [SemVer](https://semver.org/).
4
+
5
+ ## [1.10.0] - 2026-08-20
6
+
7
+ ### Added
8
+
9
+ - The package can be installed instead of cloned: `npm install -g @minhspark/codex-mcp-bridge`, or straight from the repository with `npm install -g git+https://github.com/buidangminh23/codex-mcp-bridge.git` for anyone who would rather not involve a registry. Measured end to end on a clean directory before this was documented: 94 packages, both server bins resolve, and the server prints its ready line.
10
+ - Two installer bins, `codex-mcp-bridge-install` and `claude-mcp-bridge-install`, so a copy installed as a package can do the wiring without `node scripts/...` paths into `node_modules`. Both installer scripts gained the shebang this requires.
11
+ - `publish` workflow, tag-triggered, with provenance and a guard that fails when the tag and `package.json` version disagree.
12
+ - `.gitattributes` pinning `eol=lf`, so a Windows clone and a macOS clone stop producing different bytes for the same file.
13
+ - `windows-latest` in the CI matrix.
14
+ - The publish workflow authenticates with npm through OIDC trusted publishing, so the repository stores no access token at all. npm attaches provenance automatically in that mode, so the `provenance` flag came back out of `publishConfig` - it would also have broken the one publish that cannot use OIDC, which is the first one. Note the version pin: trusted publishing needs npm 11.5.1 or newer and Node 22 still bundles npm 10.9.x, so the publish job runs Node 24 and fails early with a clear message if npm is older.
15
+ - `npm version` now rewrites the `VERSION` constant in `src/index.mjs` and stages it, via a `version` lifecycle script. The repo-hygiene test has always required the two to match; keeping them in step by hand was an avoidable way to fail a release.
16
+ - Workflows pin `actions/checkout@v7` and `actions/setup-node@v7`. The v4 pair targets Node.js 20, which GitHub deprecated and now force-runs on Node 24 with a warning on every job. The platform layer has Windows-specific branches and this is where the bridge is most used, so leaving it untested was the wrong gap to carry.
17
+
18
+ ### Changed
19
+
20
+ - **Package renamed to `@minhspark/codex-mcp-bridge`.** The unscoped name on npm belongs to an unrelated project by another author, so a scoped name is the only one this package can honestly publish under. The scope is `@minhspark` because npm only accepts a scope matching the publishing account or an organisation it belongs to, and the account here is `minhspark` - the GitHub handle and the npm handle are not the same.
21
+ - `CODEX_BRIDGE_ALLOWED_ROOTS` no longer defaults to the install directory when the package is installed as a dependency — it defaults to the directory the installer was run from, and the installer warns when the roots it wrote point inside `node_modules`. The old default produced an entry that started fine and then refused every thread.
22
+
23
+ ### Fixed
24
+
25
+ - **The peer bridge ignored `HOME` on Windows.** `src/peer-protocol.mjs` resolved `~/.claude` through `os.homedir()`, which reads `HOME` on macOS and Linux but `USERPROFILE` on Windows. A Windows user whose `HOME` points somewhere else - the default for Git Bash and MSYS shells - had the bridge look for Claude Code sessions and transcripts in a directory that holds neither, and get an empty list with no error. It now resolves the home directory through the same `homeDir()` helper as the rest of the code, so all three platforms agree.
26
+ - `files` now limits the tarball to what a consumer runs. Before this, `npm pack` shipped 37 files including `.github/`, the whole test suite, and a stray tooling directory carrying a second, older copy of the source. It now ships 17 files, 45.6 kB packed.
27
+ - Two tests could never pass on Windows and had gone unnoticed because CI never ran there: the Claude Desktop config assertion assumed the path follows `HOME` when Windows correctly follows `APPDATA`, and the symlink containment test needs a privilege Windows withholds from an unelevated process. The first now points `APPDATA` into its sandbox; the second skips with a stated reason instead of reporting a containment failure that never happened.
28
+
29
+ ## [1.9.6] - 2026-08-19
30
+
31
+ ### Changed
32
+
33
+ - The M8ven badge now requests `?variant=verified`, which their listing page documents as the way to show the verified mark without the letter grade. **It has no effect today**: with cache-busting query strings, `?variant=verified`, `?variant=nonsense` and no variant at all return byte-identical 1017-byte SVGs still reading `C · Emerging`, and the edge cache advertises `netlify-vary: query=__nextDataReq|_rsc`, so the parameter never reaches the application. The URL is written the documented way regardless, so it starts behaving correctly the moment they fix it rather than needing another commit here. The listing itself is claimed and verified, which the badge does show.
34
+
35
+ ## [1.9.5] - 2026-08-19
36
+
37
+ ### Added
38
+
39
+ - M8ven Trust Index badge in the README, linking to the third-party audit of this server. Two of that audit's findings were real and are fixed in 1.6.0 (missing annotation hints, no test suite); a third - "11 of 14 tool handlers declare input schemas" - is a scanner artefact: all 14 declare `inputSchema`, and the three counted as missing are empty because those tools take no parameters. The publisher has been told.
40
+
41
+ ## [1.9.4] - 2026-08-19
42
+
43
+ ### Changed
44
+
45
+ - **`CLAUDE.md` removed; its contributor guidance now lives in `CONTRIBUTING.md`.** A file named for one vendor's agent reads as part of one person's toolchain rather than as this project's conventions, which is the wrong shape for a public repository. Nothing was dropped: how to tell which checkout you are in, the `npm test` gate, the annotation contract every tool must satisfy, the rule that nothing here may depend on one person's setup, and how to get the app-server schema instead of guessing at it - all of it moved, under the name a contributor already knows to look for.
46
+
47
+ ## [1.9.3] - 2026-08-19
48
+
49
+ ### Added
50
+
51
+ - `test/repo-hygiene.test.mjs` fails the build on an instruction that only works inside one person's setup: a link to a private repository, or a reference to a personal rule, memory or skills file kept outside this project. A public repository cannot lean on a private one - an instruction pointing somewhere the reader cannot open is a dead end wearing the clothes of a rule. Verified by adding such a reference and watching the suite go red at that line.
52
+
53
+ ## [1.9.2] - 2026-08-19
54
+
55
+ ### Added
56
+
57
+ - **`open_codex_thread` and `openInApp` warn when the bridge is still holding the thread's writer lock.** The app-server takes that lock when it loads a thread and keeps it until it exits, so opening the same thread in the Codex app produces a message with no cause attached to it - the app only says the thread is open somewhere else, and the bridge is the somewhere else. The warning names the thread and the way out (`stop_codex_app_server`) at the moment of opening, which is the moment the reader can still act on it.
58
+ - `stop_codex_app_server` now says it released the writer locks too, not only the `~/.codex` state.
59
+ - `CodexAppServerClient.holdsThread()` and coverage for it: attaching takes the claim, creating a thread takes it too, and a dropped connection drops it - because the lock died with the app-server and continuing to claim it would be a lie.
60
+
61
+ ## [1.9.1] - 2026-08-19
62
+
63
+ ### Changed
64
+
65
+ - **Nothing tracked here names a real home directory, volume or checkout any more.** `CLAUDE.md` documented one contributor's machines by absolute path and the changelog quoted the same drive letter and mount point. To anyone else cloning the repository that reads as an instruction rather than as one person's setup. The same guidance is now stated as the situation it actually is - a tree reachable at more than one path, read-only on the macOS side of a shared NTFS drive - together with the two commands that tell you which copy you are in.
66
+
67
+ ### Added
68
+
69
+ - `test/repo-hygiene.test.mjs` fails the build on a path naming a real home directory, and on a real volume name in prose. Fixtures may still use invented volume labels, because a test has to hand the code under test a concrete string. Verified by injecting a real path and watching the suite go red.
70
+
71
+ ## [1.9.0] - 2026-08-19
72
+
73
+ ### Security
74
+
75
+ - **Thread operations are deny-by-default.** Existing threads require an exact ID in `CODEX_BRIDGE_ALLOWED_THREADS`; newly created threads are authorized only for the lifetime of that bridge process. Reading, sending, interrupting and opening all enforce that capability check.
76
+ - **Listing is gated on the workspace root instead**, because gating it on the same allowlist left no path to a thread id at all: an id cannot be allowlisted before it is known, and the bridge is the only thing that can report it, so the only usable thread was one the bridge had created itself. Naming a root in `CODEX_BRIDGE_ALLOWED_ROOTS` is the operator declaring that project in scope, which is what makes the id safe to disclose - acting on it still needs the allowlist, and every listed row says so when it is missing. A cwd this machine cannot resolve stays out of the listing: containment is decided on the real path, and a directory that is not there cannot be shown to be inside the root.
77
+ - **Working directories are confined.** `CODEX_BRIDGE_ALLOWED_ROOTS` is required for thread creation and every authorized thread's cwd is checked against it, including symlink canonicalization and traversal attempts. Callers can no longer supply arbitrary approval or sandbox settings; new threads use the bridge's safe policy (`on-request` plus `workspace-write` by default).
78
+ - **Automatic approval is disabled by default.** `CODEX_BRIDGE_APPROVAL=approve` now requires the explicit `CODEX_BRIDGE_AUTO_APPROVE_ACK=1` acknowledgement.
79
+ - **App-server endpoints are loopback-only.** The bridge rejects non-loopback `CODEX_APP_SERVER_URL` values because its WebSocket transport does not implement remote authentication.
80
+
81
+ ### Added
82
+
83
+ - Security-policy regression coverage for thread capabilities, workspace containment, endpoint validation, approval defaults, and the split between listing a thread and acting on one.
84
+
85
+ ## [1.8.0] - 2026-08-19
86
+
87
+ ### Changed
88
+
89
+ - **No drive letter or volume label is blessed any more.** 1.7.0 still shipped one machine's mount point and drive letter as defaults, which is a storage layout wearing a configuration hat. A path now counts as coming from another machine by its *shape* — a drive letter (`D:\project`) or an attached volume (`/Volumes/<label>/`, `/mnt/<label>/`, `/media/<user>/<label>/`) — so every dual-boot and external-disk setup is handled without configuring anything.
90
+ - **The path as given is tried first.** Rewriting a directory this machine can already write to would be guessing over an explicit instruction. Rewriting now only happens for a path this machine cannot use, which is exactly the case it exists for: macOS mounts NTFS read-only (measured: `EROFS` on the mount this was built for), so the drive a Windows brief quotes is visible and useless at the same time. This is what makes recognising every volume safe rather than reckless.
91
+
92
+ ### Removed
93
+
94
+ - `CODEX_BRIDGE_SHARE_MOUNT` and `CODEX_BRIDGE_SHARE_DRIVE`, added in 1.7.0 earlier the same day. Generic detection makes them dead knobs, and a dead knob in the documentation costs more than it saves. `CODEX_BRIDGE_WORKSPACE_ROOTS` and `CODEX_BRIDGE_REMAP` still cover overriding and opting out.
95
+
96
+ ### Verified
97
+
98
+ - Every path that resolved under the hardcoded version resolves to the same directory: the mounted-drive and drive-letter forms of a repo both reach the checkout beside the bridge, another project reaches its `$HOME`-level checkout, and a nonexistent project still fails with the list of what was tried.
99
+
100
+ ## [1.7.0] - 2026-08-19
101
+
102
+ ### Changed
103
+
104
+ - **The cwd remapping no longer hardcodes one developer's directory layout.** `remapCandidates()` used to probe a literal `$HOME/<a developer's own folder>/<project>`, which is a fact about one machine sitting in the source of a public repository. The second candidate is now derived from where the bridge itself is checked out: a bridge at `~/code/codex-mcp-bridge` makes `~/code` the place to look for a sibling project. That is a measurement rather than a guess, and it needs no configuration to be right. Verified unchanged on the machine the hardcoded value came from — every path that resolved before resolves to the same directory now.
105
+
106
+ ### Added
107
+
108
+ - `CODEX_BRIDGE_SHARE_MOUNT` and `CODEX_BRIDGE_SHARE_DRIVE` — the two halves of the dual-boot pair the remapping bridges, previously fixed at one machine's mount point and drive letter. Those remain the defaults; a drive letter is normalised, so `d`, `D` and `D:` all mean the same thing.
109
+ - `CODEX_BRIDGE_WORKSPACE_ROOTS` — take over the search entirely with an explicit, ordered, `path.delimiter`-separated list. It replaces the derived roots rather than adding to them, so the order is exactly what was written.
110
+ - Candidate lists are deduplicated, so a bridge checked out directly in `$HOME` no longer probes the same directory twice.
111
+ - `CODEX_BRIDGE_REMAP`, `CODEX_BRIDGE_SHARE_MOUNT` and `CODEX_BRIDGE_SHARE_DRIVE` are read per call instead of at import, so a client that changes the environment does not have to restart the bridge to be believed — and so the behaviour is testable in-process.
112
+ - Five tests covering the derived root, the explicit override and its ordering, a reconfigured mount and drive letter, and the `CODEX_BRIDGE_REMAP=0` opt-out.
113
+
114
+ ## [1.6.0] - 2026-08-19
115
+
116
+ ### Fixed
117
+
118
+ - **A failed `turn/start` killed the whole MCP server.** `runTurn` rejected its internal completion promise from the catch block, but on that path nothing is awaiting it — `await done` sits after the `turn/start` call that just threw. Node treats an unhandled rejection as fatal by default, so the process exited while the tool handler was still formatting a tidy error message for a client that no longer had a server to talk to. Sending into a thread the Codex desktop app holds open (`thread <id> already has an active writer`) is the everyday way to trigger it. The promise is now resolve-only. **Measured: the same failure used to exit the process with code 1; it now returns an error and the server stays up.**
119
+ - `start_codex_thread` declared `approvalPolicy` and `sandbox` with no descriptions, leaving a caller to guess that anything other than `approvalPolicy: "never"` stalls an unattended turn on the first approval prompt.
120
+
121
+ ### Added
122
+
123
+ - **Annotation hints on all 14 tools** (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`). Clients decide whether a call needs a human in the loop from these, and a tool without them reads as an unknown quantity — the wrong default for tools that reach another agent with shell access. Two are worth naming: `read_claude_inbox` empties the inbox as it reads it, so it is not read-only despite the name, and `claude_bridge_status` registers the peer endpoint on first call, so it writes too.
124
+ - **A real test suite: `npm test`, 96 tests across 7 files, no Codex install or quota needed.** Connection behaviour runs against the fake app-server; anything touching `~/.claude` or `~/.codex` runs against a throwaway `HOME`. Covers the tool contract, all 10 server requests, connection recovery, the turn state machine, the peer protocol over a real unix socket, platform resolution, and repository hygiene.
125
+ - GitHub Actions runs `npm test` on every push and pull request, across Node 22 and 24 on Linux and macOS.
126
+ - `test/repo-hygiene.test.mjs` fails the build if an environment file or build output is ever committed, if the version in `src/index.mjs` drifts from `package.json`, or if documentation stops being English.
127
+
128
+ ### Changed
129
+
130
+ - The repository is English-only. `README.en.md` merged back into `README.md`; the changelog translated.
131
+ - `README.md` documents every install path end to end, including Claude Code (`claude mcp add`), which was previously undocumented, plus prerequisites, verification and uninstall commands for each platform.
132
+ - `scripts/check-approvals.mjs` and `scripts/check-reconnect.mjs` became `test/server-requests.test.mjs` and `test/reconnect.test.mjs`; `scripts/fake-app-server.mjs` moved to `test/helpers/`. The fake app-server now binds an ephemeral port, so test files running in parallel cannot collide.
133
+
134
+ ## [1.5.0] - 2026-08-18
135
+
136
+ ### Fixed
137
+
138
+ - **A turn that lost its connection sat idle until its timeout expired — four minutes by default.** `runTurn` waits for a `turn/completed` notification, which can only arrive over a live socket; a dead socket wakes nobody. This is the everyday case after a machine wakes up: the old app-server died with the previous login session while the bridge kept waiting. The client now signals the break through `subscribeDisconnect()` and the turn ends immediately with status `disconnected` plus a hint to re-read the thread. **Measured: 20,004 ms → 302 ms.**
139
+ - **The old socket's `onclose` wiped the new one.** The handler set `this.ws = null` unconditionally, so a late `close` event from the previous socket destroyed the healthy connection a reconnect had just established and rejected all of its pending requests. It now only cleans up when `this.ws === ws`.
140
+ - **No retry at boot.** A freshly started machine produces transient failures: the app-server is still opening its sqlite state, or an old one is shutting down but still answering `/readyz`. `connect()` now retries once (750 ms apart) instead of failing the tool call and making the user repeat it. A handshake that breaks mid-way counts as an error rather than hanging for the full 15s timeout.
141
+
142
+ ### Added
143
+
144
+ - `npm run check:reconnect` — 9 assertions against a fake app-server: reconnecting after a drop, no leaked pending requests or listeners, an interrupted turn exiting promptly, and a refused first handshake being retried. Run against 1.4.0 the first two fail.
145
+ - `scripts/fake-app-server.mjs` — a shared fake app-server for the connection tests (hand-rolled WebSocket, no extra dependency).
146
+
147
+ ## [1.4.0] - 2026-08-18
148
+
149
+ ### Fixed
150
+
151
+ - **A turn stopped mid-run as if Codex had paused itself.** The app-server waits for the client's reply to each server request before continuing, so an unanswered method does **not** surface as an error — the turn simply stops. `#handleServerRequest` now answers all **10** `ServerRequest` methods (taken from `codex app-server generate-json-schema`, identical in codex-cli 0.147 and 0.148). Three used to fall through to `default:` and get `-32601`:
152
+ - `item/permissions/requestApproval` — Codex asking to widen permissions (writes outside the workspace, network). By far the most common.
153
+ - `mcpServer/elicitation/request` — an MCP server asking for input.
154
+ - `item/tool/call` — a dynamic tool call back to the client.
155
+
156
+ Each method needs the response shape its own schema declares; they are **not** interchangeable: `commandExecution`/`fileChange` need `{decision}`, `permissions` needs `{permissions, scope}`, `elicitation` needs `{action}`, `tool/call` needs `{success, contentItems}`. `attestation/generate` and `account/chatgptAuthTokens/refresh` are refused deliberately — the bridge cannot mint real tokens and does not touch auth.
157
+ - **Threads opened against the wrong directory.** The same project sits at `D:\X` on Windows, `/Volumes/<label>/X` when that drive is mounted on macOS (read-only), and a separate checkout under `$HOME` on macOS. `resolveWorkspacePath()` picks the candidate that both exists and is writable on the current machine. If nothing usable exists it fails immediately instead of opening a thread somewhere wrong; if the only match is read-only it says so. Disable with `CODEX_BRIDGE_REMAP=0`.
158
+ - **The wrong codex build spawned the app-server.** On macOS the bridge probed `~/.local/bin/codex` first and started a 0.147 app-server while Codex Desktop ran 0.148 — two builds writing the same `~/.codex/state_5.sqlite`. When the desktop app is installed, its own binary now wins.
159
+
160
+ ### Added
161
+
162
+ - `npm run check:approvals` — stands up a fake app-server (hand-rolled WebSocket, no extra dependency), fires all 10 server requests and asserts each reply matches its schema. Run against the unpatched code, exactly the three methods above fail.
163
+
164
+ ## [1.3.0] - 2026-08-17
165
+
166
+ ### Added
167
+
168
+ - `CODEX_BRIDGE_MODEL` and `CODEX_BRIDGE_EFFORT` — default model and effort for threads and turns the bridge creates, because Codex Desktop ignores `model`/`model_reasoning_effort` in `~/.codex/config.toml` and runs its own configuration.
169
+ - `effort` accepts `ultra` (verified: `state_5.sqlite` and the rollout both record `ultra` rather than silently dropping it).
170
+ - `codex_bridge_status` prints the default model and effort in effect.
171
+ - `install-claude-desktop.mjs` writes both variables into the MCP server's `env` when they are passed.
172
+
173
+ ## [1.2.1] - 2026-08-17
174
+
175
+ ### Added
176
+
177
+ - `stop_codex_app_server` — stop the shared app-server after a hand-off so Codex Desktop owns `~/.codex` alone; the bridge starts a new one when it next needs it.
178
+
179
+ ### Fixed
180
+
181
+ - `codex_bridge_status` detects the desktop app's own app-server and warns when a LaunchAgent runs alongside it — two app-servers sharing the `~/.codex` sqlite state make the Codex app UI stutter (measured at ~11% CPU while idle).
182
+ - `isDesktopAppServerRunning()` was missing its `execFileSync` import and silently always returned `false`.
183
+
184
+ ### Documentation
185
+
186
+ - Spelled out: do not enable the LaunchAgent while using Codex Desktop; a thread open in the app holds a writer lock; threads created by the bridge have no entry in `session_index.jsonl`, so the app shows no title for them.
187
+
188
+ ## [1.2.0] - 2026-08-17
189
+
190
+ ### Added
191
+
192
+ - `claude-bridge` — an MCP server that runs inside Codex and talks to a live Claude Code session: `list_claude_sessions`, `send_to_claude_session`, `read_claude_inbox`, `read_claude_transcript`, `bind_codex_thread`, `claude_bridge_status`.
193
+ - `src/peer-protocol.mjs` — a client for the Claude Code peer protocol (NDJSON over `/tmp/cc-socks/<pid>.sock`) that registers a peer session so Claude can see it and reply to it.
194
+ - `scripts/install-codex-mcp.mjs` — register and remove the bridge in `~/.codex/config.toml` through `codex mcp`.
195
+ - `scripts/check-claude-bridge.mjs` — exercise the Codex → Claude direction, sending for real and waiting for the answer.
196
+
197
+ ### Fixed
198
+
199
+ - The MCP server died when spawned with an empty PATH: `/bin/ps` is now called by absolute path and a failed peer registration no longer takes the server down (the old symptom was Codex hanging for 60s on every `thread/start`).
200
+ - Claude transcripts are found by scanning `~/.claude/projects/` instead of rebuilding the directory slug (`/mnt/dev_disk` becomes `-mnt-dev-disk`, which does not preserve `_`).
201
+
202
+ ## [1.1.0] - 2026-08-17
203
+
204
+ ### Added
205
+
206
+ - macOS and Linux support: `src/platform.mjs` resolves `codex` per platform and rebuilds PATH for child processes.
207
+ - `scripts/install-launch-agent.mjs` — a LaunchAgent that keeps the app-server alive on macOS.
208
+ - `open_codex_thread` and the `openInApp` parameter — open a thread in the Codex desktop app through `codex://threads/<id>`.
209
+ - `codex_bridge_status` — report the resolved environment.
210
+ - `README.en.md` and the MIT license.
211
+
212
+ ### Fixed
213
+
214
+ - `install-claude-desktop.mjs` picks the right config path for macOS/Windows/Linux and creates the file when it is missing.
215
+ - Spawning the app-server on macOS/Linux no longer dies at the `#!/usr/bin/env node` shebang when PATH is trimmed.
216
+
217
+ ## [1.0.0] - 2026-08-15
218
+
219
+ ### Added
220
+
221
+ - An MCP server that sends prompts into a live Codex thread through a shared app-server: `send_to_codex_thread`, `list_codex_threads`, `start_codex_thread`, `read_codex_thread`, `interrupt_codex_turn`.
222
+ - Autostart of the app-server when none is running, and automatic answers to approval requests according to `CODEX_BRIDGE_APPROVAL`.
223
+ - `scripts/install-claude-desktop.mjs`, `scripts/check.mjs`, `scripts/smoke.mjs`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bui Dang Minh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.