codex-copilot-dx 0.6.21 → 0.7.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.
Files changed (42) hide show
  1. package/README.md +142 -323
  2. package/bin/cli.mjs +26 -130
  3. package/package.json +2 -8
  4. package/scripts/benchmark.mjs +0 -114
  5. package/src/adapter.mjs +22 -107
  6. package/src/auth-profile.mjs +18 -130
  7. package/src/cli-animation.mjs +108 -0
  8. package/src/cli-auth.mjs +44 -398
  9. package/src/cli-models.mjs +21 -49
  10. package/src/cli-options.mjs +53 -75
  11. package/src/cli-status.mjs +6 -23
  12. package/src/config.mjs +2 -8
  13. package/src/copilot.mjs +2 -2
  14. package/src/doctor.mjs +44 -291
  15. package/src/model-cache.mjs +4 -11
  16. package/src/models.mjs +0 -184
  17. package/src/observability.mjs +1 -38
  18. package/src/profile-model-runtime.mjs +61 -189
  19. package/src/profile-routing.mjs +2 -102
  20. package/src/profile-runtime.mjs +15 -68
  21. package/src/responses-handler.mjs +1 -1
  22. package/src/responses-proxy.mjs +1 -1
  23. package/src/running-adapter.mjs +2 -4
  24. package/src/stream-errors.mjs +3 -6
  25. package/src/stream-performance.mjs +1 -1
  26. package/src/terminal-activity.mjs +40 -34
  27. package/src/terminal-animation.mjs +249 -0
  28. package/src/usage.mjs +0 -31
  29. package/src/user-settings.mjs +50 -0
  30. package/src/anthropic-handler.mjs +0 -195
  31. package/src/anthropic.mjs +0 -387
  32. package/src/claude-config.mjs +0 -57
  33. package/src/claude-desktop-config.mjs +0 -317
  34. package/src/cli-error.mjs +0 -50
  35. package/src/pm-studio-asar.mjs +0 -1244
  36. package/src/pm-studio-bundle-content.mjs +0 -165
  37. package/src/pm-studio-relay.mjs +0 -563
  38. package/src/pm-studio-setup-lock.mjs +0 -336
  39. package/src/pm-studio-setup.mjs +0 -1581
  40. package/src/pm-studio-status.mjs +0 -369
  41. package/src/token-counter-service.mjs +0 -211
  42. package/src/token-counter-worker.mjs +0 -16
package/README.md CHANGED
@@ -1,468 +1,283 @@
1
1
  # codex-copilot-dx
2
2
 
3
- Use [Codex Desktop](https://openai.com/codex), [Claude Code](https://claude.com/claude-code), and optionally Claude App or PM Studio with your **GitHub Copilot** subscription.
3
+ Use Codex Desktop or the ChatGPT app with GPT models provided by your **GitHub Copilot** subscription.
4
+
5
+ CCDX is a local compatibility adapter. It configures Codex-compatible desktop clients to use an OpenAI Responses API on loopback while GitHub authentication, model discovery, and inference stay backed by GitHub Copilot.
4
6
 
5
7
  ## How it works
6
8
 
7
- A single in-process adapter (port `2026`) exposes both APIs over one Copilot
8
- account by default, or over isolated Codex and Claude accounts when configured:
9
+ One in-process adapter listens on `127.0.0.1:2026` by default and exposes:
10
+
11
+ - `POST /v1/responses`
12
+ - `POST /v1/responses/compact`
13
+ - `GET /v1/models`
14
+
15
+ Responses-only models and compaction use Copilot's Responses transport directly. For GPT models that advertise only Chat Completions, CCDX converts the supported text, image, and function-tool subset and rejects incompatible request shapes explicitly. Both streaming SSE and non-streaming responses are supported.
16
+
17
+ The adapter preserves Codex and ChatGPT app behavior around response history, encrypted reasoning state, function/custom tools, images, compaction, cancellation, retries, and usage metadata. Model routing follows the live Copilot catalog instead of a hard-coded GPT model list.
9
18
 
10
- - **Codex** -> OpenAI Responses API (`/v1/responses`, `/v1/responses/compact`); Responses-only models and compaction proxy directly, while chat models convert the text, image, and function-tool subset and explicitly reject incompatible top-level items, tools, and tool choices.
11
- - **Claude Code** -> Anthropic Messages API (`/v1/messages`, `/v1/messages/count_tokens`), translated to/from Chat Completions.
12
- - **Claude App** -> optional Claude Desktop App gateway profile using the same local Messages API plus local model discovery for the configured gateway key.
13
- - **PM Studio** -> optional macOS app patch that keeps the active PM profile for GPT models while routing enabled Claude models through an isolated CCDX Claude account.
19
+ ### Fast and Standard modes
14
20
 
15
- Supports both HTTP SSE streaming and non-streaming.
21
+ Codex can select Standard or Fast without changing CCDX configuration. When the client requests `gpt-5.6-sol` with `service_tier: "priority"`, CCDX uses `gpt-5.6-sol-fast` only when the live Copilot catalog advertises that exact model as enabled, selectable, OpenAI-owned, and Responses-only. Standard mode continues to use `gpt-5.6-sol`; CCDX does not invent Fast availability when the upstream catalog does not provide it.
16
22
 
17
- Codex Auto-review requests use the hidden `codex-auto-review` model ID. The adapter maps it to Copilot's `gpt-5.5` Responses model by default and logs both model IDs when the mapping is used. The target can be changed interactively without reinstalling the package.
23
+ Codex Auto-review uses the hidden `codex-auto-review` model ID. CCDX maps it to Copilot's `gpt-5.5` Responses model by default, independently of the interactive Fast/Standard selection, and logs both model IDs when the mapping is used. The review target can be changed interactively without reinstalling or restarting CCDX.
18
24
 
19
25
  ## Prerequisites
20
26
 
21
27
  - GitHub Copilot subscription (Individual, Business, or Enterprise)
22
- - Node.js 22.15+ (required for built-in Zstandard request decompression)
23
- - [Codex Desktop](https://openai.com/codex), [Claude Code](https://claude.com/claude-code), Claude App, and/or a supported PM Studio installation
28
+ - Node.js 22.15 or newer, for built-in Zstandard request decompression
29
+ - Codex Desktop or the ChatGPT app on macOS
24
30
 
25
- ## Usage
31
+ ## Install and start
26
32
 
27
33
  ```bash
28
34
  npm install -g codex-copilot-dx@latest
29
35
  ccdx
30
36
  ```
31
37
 
32
- `ccdx` is the only documented command and primary launcher. The old
33
- `codex-copilot-dx` executable remains temporarily as a compatibility shim: it
34
- prints a deprecation warning at most once every 7 days in interactive terminals,
35
- runs `ccdx`, and remains silent in scripts. It will be removed in a future
36
- breaking release. For a one-off run without a global install, use
37
- `npm exec --yes --package=codex-copilot-dx@latest -- ccdx`.
38
- Run `ccdx <command> --help` (including `auth login claude --help` and
39
- `pms status --help`) for command-specific behavior and side-effect details.
40
- The read-only `usage`, `models`, `auth status`, and `pms status` commands use
41
- aligned tables in interactive terminals. Redirected or piped output keeps the
42
- legacy plain-text layout for script compatibility; use `--format table` or
43
- `--format plain` to choose explicitly.
44
-
45
- To query the models currently advertised as selectable for the saved Codex
46
- Copilot account, run:
38
+ `ccdx` is the primary launcher. The old `codex-copilot-dx` executable remains temporarily as a compatibility shim: it prints a deprecation warning at most once every seven days in interactive terminals, runs `ccdx`, and remains silent in scripts. It will be removed in a future breaking release.
39
+
40
+ For a one-off run without a global install:
47
41
 
48
42
  ```bash
49
- ccdx models
43
+ npm exec --yes --package=codex-copilot-dx@latest -- ccdx
50
44
  ```
51
45
 
52
- This performs a fresh, read-only GitHub Copilot model-directory lookup without
53
- starting the adapter, opening device login, reading the local model cache, or
54
- consuming an inference request. It lists model IDs in a provider, API, and
55
- preview-status table with their
56
- advertised API capabilities and reports the live Claude/Anthropic count. A model
57
- being advertised does not guarantee that a later inference request will avoid
58
- quota, rate-limit, or policy enforcement.
46
+ On a normal launch, CCDX:
59
47
 
60
- ### Separate GitHub account for Claude
48
+ 1. Prints the installed package version and checks for a newer npm release in the background.
49
+ 2. Reuses a compatible running adapter when available; otherwise it reuses a compatible local Copilot credential or starts GitHub Device Flow when authentication is required.
50
+ 3. Refreshes Copilot model metadata and listens on the configured loopback address.
51
+ 4. Updates `~/.codex/config.toml` to use the local `/v1` endpoint while preserving unrelated Codex settings.
52
+ 5. Attempts to open Codex Desktop or the ChatGPT app on macOS unless `CCDX_AUTO_LAUNCH` disables it.
61
53
 
62
- The default remains fully backward compatible: Codex and Claude requests share
63
- the existing GitHub authentication. To keep an enterprise account for Codex
64
- while using a different personal account that has Claude models enabled, run:
54
+ The `OPENAI_API_KEY=dummy` value written into the Codex shell environment is only a client-side placeholder. It is not a GitHub credential. CCDX exchanges the saved GitHub OAuth credential for short-lived Copilot service tokens internally.
65
55
 
66
- ```bash
67
- ccdx auth login claude --github-login <personal-github-login>
68
- ```
56
+ If a compatible adapter is already running, a later launch reuses it and refreshes the local Codex configuration. After updating the package, stop the old adapter before starting the new version; the CLI refuses to silently reuse an incompatible protocol version.
69
57
 
70
- This is the only command that may start the additional Device Flow. Before
71
- opening a browser, it checks compatible local Copilot credentials, excludes the
72
- current Codex identity, and reuses an unambiguous valid account. It then verifies
73
- the selected GitHub identity, Copilot entitlement, and an enabled Claude model
74
- before saving anything. It refuses the current Codex account and never changes,
75
- migrates, or deletes the existing Codex credential. The optional login pin is
76
- recommended so a machine with multiple accounts selects only the requested
77
- identity. Use `--reauth` to bypass local discovery and force Device Flow.
78
-
79
- The existing Codex token remains at
80
- `~/.local/share/copilot-api/github_token`. The isolated Claude credential is
81
- stored with mode `0600` under
82
- `~/.local/share/copilot-api/profiles/claude/github_token`, with matching account
83
- metadata committed last. Restart a running adapter after authentication.
84
-
85
- Once enabled, routing is fixed by API surface rather than by model name:
86
-
87
- - `/v1/responses`, `/v1/responses/compact`, their Chat fallback, and normal
88
- `/v1/models` use the Codex account.
89
- - `/v1/messages` and Claude App model discovery use the isolated Claude account.
90
- - `/v1/messages/count_tokens` remains local and uses neither account.
91
-
92
- The two profiles keep separate service tokens, API bases, refresh/backoff state,
93
- model endpoint metadata, and credential-bound model caches. Switching either
94
- GitHub account invalidates that profile's old cache instead of borrowing it.
95
- Cached catalogs are fresh for two hours; older catalogs remain immediately
96
- available for up to seven days while CCDX refreshes them in the background.
97
- If the isolated Claude profile later
98
- becomes invalid, Claude requests fail with a reauthentication instruction while
99
- Codex remains available; CCDX never silently falls back to the enterprise
100
- account. Reauthorize it explicitly with:
58
+ ## Version 0.7.0 migration
101
59
 
102
- ```bash
103
- ccdx auth login claude --reauth --github-login <personal-github-login>
104
- ```
60
+ CCDX 0.7.0 retires the former Claude App, Claude Code, Anthropic Messages API, isolated Claude account, and PM Studio patch integrations. Their setup, status, restore, profile, and routing commands are no longer supported.
105
61
 
106
- These commands are read-only and never start Device Flow:
62
+ If PM Studio is still patched by an older CCDX release, update or reinstall PM Studio to restore its official application bundle. CCDX 0.7.0 does not patch PM Studio and does not provide a restore workflow.
107
63
 
108
- ```bash
109
- ccdx auth status
110
- ccdx auth status --online
111
- ccdx models --profile claude
112
- ccdx doctor --online --profile all
113
- ```
64
+ The upgrade intentionally does not delete or rewrite retired Claude or PM Studio configuration, historical patch backups, or isolated credentials created by older versions. Normal Codex configuration updates continue as documented above. Review and remove obsolete retired-integration state yourself only if you no longer need it.
114
65
 
115
- ### PM Studio opt-in patch
116
-
117
- CCDX can add the isolated Claude catalog to PM Studio without switching its
118
- active account or profile. GPT requests keep PM Studio's native official GitHub
119
- Copilot transport and the bearer supplied by the current PM profile. Model
120
- discovery tries the compatible local CCDX merge first, and only exact enabled
121
- Anthropic model IDs use the isolated CCDX Claude profile. Neither credential is
122
- copied into the other application.
123
-
124
- CCDX treats the local PM Studio App selected for setup as the source of truth.
125
- Its version and build label backup and recovery records; neither they nor the
126
- installation source or original signature are compatibility admission gates.
127
- Setup derives a source-bound recipe whenever the local ASAR integrity metadata
128
- and exactly one compatible Copilot configuration module can be verified. A
129
- missing or ambiguous module, changed request transport, or unsupported
130
- integrity policy is rejected without modifying the App. Authorize the isolated
131
- Claude profile first, quit PM Studio and its updater, then run the one-time
132
- setup command:
66
+ ## Commands
133
67
 
134
- ```bash
135
- ccdx auth login claude --reauth --github-login <personal-github-login>
136
- ccdx pms setup
137
- ```
68
+ Run `ccdx <command> --help` for command-specific behavior and side-effect details.
138
69
 
139
- Inspect the installed version, exact patch manifest plus executable/signing
140
- integrity, isolated Claude profile, and live relay routing without changing files:
70
+ ### Live models
141
71
 
142
72
  ```bash
143
- ccdx pms status
73
+ ccdx models
144
74
  ```
145
75
 
146
- `ccdx pm-studio status`, `ccdx pm-studio setup`, and `ccdx pm-studio restore`
147
- are equivalent long-form aliases.
148
-
149
- `ccdx pms setup` performs local preflight, structural verification, backup,
150
- staging, integrity, signing, and replacement work. It does not access a PM
151
- Studio repository, release asset, PAT, or source-signing service. It never
152
- starts Device Flow, the adapter, Codex, or PM Studio, and it does not modify PM
153
- profiles, cached model lists, or saved PM tokens. Local fingerprints bind the
154
- recipe, backup, staged App, and installed App without deciding whether the
155
- original package is trusted. Structure, partial-patch, running-process, space,
156
- and every other pre-replacement failure leave the installed App unchanged. If final
157
- read-only verification after an atomic replacement detects exceptional
158
- filesystem drift, setup does not attempt a second automatic write: it preserves
159
- the verified backup, retains any diagnostic stage still present, and prints
160
- recovery paths. Repeating setup reuses the version/source-bound verified backup
161
- and is idempotent. The staged and installed CCDX patch must still pass strict
162
- ad-hoc signature verification, use the App's bundle identifier, and match the
163
- complete patched-tree record in the backup manifest.
164
-
165
- The patch uses split origins, not an App-wide proxy. GPT and other non-Claude
166
- inference requests remain on PM Studio's native official GitHub Copilot origin;
167
- they do not enter CCDX or depend on port 2026. Model discovery first tries the
168
- loopback-only `GET /pm-ccdx/models` merge and accepts it only when the relay
169
- returns the `X-CCDX-PM-Relay: split-origin-v1` compatibility marker. If the
170
- relay is unavailable or incompatible, model discovery safely falls back to the
171
- official directory and GPT remains available. Exact enabled Claude chat uses
172
- `POST /pm-ccdx/chat/completions` and fails closed if CCDX is unavailable; it
173
- never falls back to the PM enterprise account. The relay does not expose
174
- `/responses` or `/embeddings` and is not a general-purpose proxy.
175
-
176
- The loopback relay trusts local callers that present a valid Copilot bearer.
177
- CCDX uses the PM bearer only to fetch or validate official model access; it is
178
- never used as the credential for the isolated Claude upstream request. Keep
179
- port 2026 local to the machine.
180
-
181
- Patching applies an ad-hoc signature to the staged App. PM Studio's
182
- updater is not disabled; an official update may overwrite the patch or may
183
- require reinstalling PM Studio. Setup prints the verified backup and
184
- manifest paths plus the version-matched restore procedure. Never restore a
185
- backup over a different PM Studio version or build.
186
-
187
- To restore the original local bundle, first quit PM Studio and its updater,
188
- then run:
76
+ This performs a fresh, read-only GitHub Copilot model-directory lookup without starting the adapter, opening Device Flow, reading the local model cache, or consuming an inference request. It lists selectable GPT model IDs, providers, advertised APIs, and preview status. Catalog availability does not guarantee that a later inference request will avoid quota, rate-limit, or policy enforcement.
189
77
 
190
- ```bash
191
- ccdx pms restore
192
- ```
78
+ Interactive terminals use aligned tables for `models`, `auth status`, and `usage`. Redirected or piped output retains the plain-text layout for scripts; use `--format table` or `--format plain` when a command offers an explicit format override.
193
79
 
194
- The explicit command authorizes the local App replacement and does not show an
195
- additional confirmation prompt. Restore neither needs the Claude profile nor
196
- starts the adapter, Device Flow, Codex, or PM Studio. It selects the unique
197
- source-bound backup itself, verifies the installed patch record and the exact
198
- clean backup, stages and verifies the complete bundle, confirms that the
199
- installed App did not change during staging, and then performs an atomic
200
- replacement. It never restores a missing, ambiguous, drifted, or
201
- version/build-mismatched record. The original local signature is inspected and
202
- reported, but is not an admission gate: the exact source-bound content recorded
203
- when setup created the backup is authoritative. The verified backup and manifest
204
- remain available after a successful restore. Repeating restore on the same
205
- recorded clean App is safe and does not replace it again.
206
-
207
- If automatic restore reports that the replacement state cannot be verified, do
208
- not launch PM Studio. Keep the recovery path printed by the command and reinstall
209
- PM Studio. The following manual procedure is only an exceptional recovery path;
210
- use the exact backup and manifest paths printed by setup or restore, and first
211
- confirm that the installed App and backup still match the manifest version/build:
80
+ ### Auto-review model
212
81
 
213
82
  ```bash
214
- BACKUP_APP="<exact-verified-backup-path>"
215
- RECOVERY_DIR="$(/usr/bin/mktemp -d '/Applications/CCDX-PM-Studio-recovery.XXXXXX')"
216
- PATCHED_APP="$RECOVERY_DIR/PM Studio.app"
217
- mv "/Applications/PM Studio.app" "$PATCHED_APP"
218
- /usr/bin/ditto --rsrc --extattr --acl "$BACKUP_APP" "/Applications/PM Studio.app"
219
- ccdx pms status
83
+ ccdx auto-review-model
220
84
  ```
221
85
 
222
- The App-patch row from `ccdx pms status` must classify the restored bundle as
223
- the recorded clean local content rather than integrity drift. If the version
224
- check, copy, or content verification fails,
225
- do not launch the restored App. Keep the moved patched bundle at `$PATCHED_APP`
226
- and reinstall PM Studio instead of applying a version-mismatched
227
- backup. CCDX never uses `sudo` automatically.
86
+ The selector first queries the running adapter, including its last-known-good model list when live refresh is unavailable, then falls back to the non-expired local model cache. It offers only enabled models that advertise a Responses endpoint.
228
87
 
229
- To change the model used by Codex Auto-review, run:
88
+ The selection is saved in `~/.config/codex-copilot-dx/config.json`, or under `XDG_CONFIG_HOME` when set. Choosing `gpt-5.5` clears the override and restores the package default. A running adapter reads the setting on the next Auto-review request.
89
+
90
+ ### Terminal animation
91
+
92
+ Choose the terminal activity animation interactively:
230
93
 
231
94
  ```bash
232
- ccdx auto-review-model
95
+ ccdx animation
233
96
  ```
234
97
 
235
- The selector first queries the running adapter, including its last-known-good
236
- model list when live refresh is unavailable, then falls back to the non-expired
237
- local model cache. It offers only enabled models that advertise a Responses endpoint.
238
- It saves the selection in `~/.config/codex-copilot-dx/config.json` (or under
239
- `XDG_CONFIG_HOME` when set); choosing `gpt-5.5` clears the override and restores
240
- the package default. A running adapter reads the setting on the next Auto-review
241
- request, so it does not need to be restarted.
98
+ The selector is ordered numerically:
242
99
 
243
- To update the globally installed package, choose a source interactively:
100
+ 1. Comet (default)
101
+ 2. Twin
102
+ 3. Shuttle
103
+ 4. Chase
104
+ 5. Mirror
105
+ 6. Pulse
106
+ 7. Braille
107
+
108
+ Enter the corresponding number to select an animation. The Comet row includes a static preview, and after a selection CCDX plays one cycle of the chosen animation as confirmation when terminal animation is enabled. The setting is saved in `~/.config/codex-copilot-dx/config.json`, or under `XDG_CONFIG_HOME` when set.
109
+
110
+ The selected theme is loaded once when a new adapter starts, so changing it does not restart or alter an adapter that is already running. Stop and start CCDX to apply the new theme. `CCDX_TERMINAL_ANIMATION=0` (also `false`, `no`, or `off`) remains the boolean gate that disables terminal animation regardless of the selected theme.
111
+
112
+ ### Update
113
+
114
+ Choose a source interactively:
244
115
 
245
116
  ```bash
246
117
  ccdx update
247
118
  ```
248
119
 
249
- For scripts or a direct choice, pass the source explicitly:
120
+ Or choose directly:
250
121
 
251
122
  ```bash
252
123
  ccdx update npm
253
124
  ccdx update github
254
125
  ```
255
126
 
256
- `ccdx update gh` is accepted as a shorthand for the GitHub source.
257
-
258
- The npm source installs `codex-copilot-dx@latest` through the registry already
259
- configured for npm, including a company mirror. The GitHub source installs the
260
- latest commit from `DaleXiao/codex-copilot-dx` `main` and opts in to Git fetching
261
- for that command. It does not change npm's persistent `allow-git` setting. Both
262
- paths use npm's global installer without shell
263
- interpolation. A currently running adapter keeps its loaded version until it is
264
- stopped and started again.
265
- If a configured npm mirror has not synchronized the current release yet, use
266
- the GitHub source to install the current `main` revision.
267
-
268
- On a normal launch, it will:
269
- 1. Print the local package version and check for a newer npm release in the background
270
- 2. Reuse a compatible running adapter when available; otherwise authenticate with GitHub if needed, after first trying compatible local Copilot token sources
271
- 3. When starting a new adapter, refresh Copilot model metadata and listen on loopback (`127.0.0.1:2026`)
272
- 4. Configure Codex (`~/.codex/config.toml`) to use the adapter, including stale shell env base URLs if present
273
- 5. Configure Claude Code (`~/.claude/settings.json`) to use the adapter; it creates the file when missing, otherwise backs up `settings.json.bak` before updating the local API env keys
274
- 6. On macOS, attempt to launch Codex or ChatGPT unless `CCDX_AUTO_LAUNCH` disables it
127
+ `ccdx update gh` is accepted as shorthand for the GitHub source. The npm source installs `codex-copilot-dx@latest` through the registry already configured for npm, including a company mirror. The GitHub source installs the latest commit from `DaleXiao/codex-copilot-dx` `main` and opts in to Git fetching only for that command. It does not change npm's persistent `allow-git` setting.
275
128
 
276
- Claude Code picks up the new `ANTHROPIC_BASE_URL` on its next launch.
129
+ If a configured npm mirror has not synchronized the current release yet, use the GitHub source. A running adapter keeps its loaded version until it is stopped and restarted.
277
130
 
278
- If a compatible CCDX adapter is already running on the configured host and port, a second launch reuses it instead of starting another proxy. The second launch still refreshes Codex and Claude Code config, then exits.
131
+ ## Diagnostics
279
132
 
280
- The running adapter reports its package and protocol versions. After upgrading the package, stop the old process before starting the new version; the new CLI refuses to silently reuse an incompatible adapter.
281
-
282
- Do not set Claude Code by manually exporting `ANTHROPIC_BASE_URL` or `ANTHROPIC_AUTH_TOKEN` in your shell. Let `ccdx` write the local config files instead. If you previously exported those variables, remove them from shell startup files and restart the terminal before launching Claude Code.
283
-
284
- ### Diagnostics
285
-
286
- Run a read-only config check without starting the adapter or changing files:
133
+ Run a read-only local configuration check:
287
134
 
288
135
  ```bash
289
136
  ccdx doctor
290
137
  ```
291
138
 
292
- The command exits with status `1` when it finds an invalid configuration and `0` when checks contain only OK or warning results.
293
-
294
- The doctor checks the GitHub token, Codex config, Claude Code settings, Claude
295
- App gateway profile, adapter availability, and an installed PM Studio bundle.
296
- It ends with passed/warning/error totals and deduplicated next-step commands.
297
- An absent PM Studio installation is ignored; versions whose compatibility
298
- cannot be safely verified are reported without modification, while integrity
299
- drift remains an error.
139
+ The doctor checks the saved GitHub credential, Codex configuration, and adapter availability without starting the adapter or changing files. It exits with status `1` for an invalid configuration and `0` when results contain only OK or warning rows.
300
140
 
301
- For a read-only live check of the saved GitHub token, Copilot entitlement, and models endpoint, run:
141
+ To verify the saved GitHub token, Copilot entitlement, and live models endpoint without starting Device Flow or changing the credential:
302
142
 
303
143
  ```bash
304
144
  ccdx doctor --online
305
145
  ```
306
146
 
307
- The online doctor never starts device flow, scans for replacement tokens, or changes the saved token.
308
- Use `--profile codex`, `--profile claude`, or `--profile all` to choose which
309
- account entitlement is checked. Without `--profile`, the legacy Codex check is
310
- preserved.
311
-
312
- To actively verify the protocol path through an already-running adapter, run:
147
+ To exercise the protocol through an already-running adapter:
313
148
 
314
149
  ```bash
315
150
  ccdx doctor --compat
316
151
  ```
317
152
 
318
- The compatibility doctor sends a few minimal Copilot requests to check Codex Auto-review, native Responses, streaming history, compaction, and Anthropic streaming. It consumes a small amount of Copilot usage, never starts the adapter or device flow, and does not change client configuration. Combine it with `--online` when both the saved-token entitlement check and the adapter protocol checks are needed.
153
+ The compatibility doctor sends a few minimal Copilot requests covering Auto-review, native Responses, streaming history, and compaction. It consumes a small amount of Copilot usage, never starts the adapter or Device Flow, and does not change client configuration. Combine it with `--online` when both checks are needed.
319
154
 
320
- For a read-only summary of the running adapter, use:
155
+ For a concise summary of the running adapter:
321
156
 
322
157
  ```bash
323
158
  ccdx status
324
159
  ```
325
160
 
326
- For the complete machine-readable payload, query the loopback endpoint directly:
161
+ For the complete machine-readable status payload:
327
162
 
328
163
  ```bash
329
164
  curl -s http://127.0.0.1:2026/_ccdx/status | jq
330
165
  ```
331
166
 
332
- The status endpoint is restricted to the socket's real loopback address, even when LAN binding is explicitly enabled. It reports fixed-size request counters, bounded TTFT/TPOT histograms for streaming routes, admission pressure, memory use, response-history size, image queue/cache and adaptive-history state, profile model cache counts, PM relay route totals, and token expiry state. It never retains metric samples or includes prompts, completions, tool arguments, image content, account names, or token values. API responses always include a safe `X-Request-Id` for correlation. If the adapter is not running, the CLI prints the exact start-and-retry command. To include the same ID as `request_id` in related terminal and file log lines, start the adapter with:
167
+ The status endpoint is restricted to the socket's real loopback address even when LAN binding is explicitly enabled. It reports fixed-size request counters, bounded TTFT/TPOT histograms, admission pressure, memory use, response-history size, image queue/cache and adaptive-history state, model-cache counts, and token expiry state. It never retains metric samples or includes prompts, completions, tool arguments, image content, account names, or token values.
168
+
169
+ Every API response includes a safe `X-Request-Id` for correlation. To include the same ID in related terminal and file log lines, start with:
333
170
 
334
171
  ```bash
335
172
  ccdx --show-request-id
336
173
  ```
337
174
 
338
- When the saved token is missing, `ccdx` first looks for compatible local Copilot GitHub tokens, validates them with GitHub and Copilot, and imports a valid one before starting device login. It checks explicit token sources (`CCDX_GITHUB_TOKEN`, `CCDX_GITHUB_TOKEN_PATH`, `CCDX_GITHUB_TOKEN_PATHS`) plus common local `auth.json` layouts under application config directories. It does not rely on a specific app name. Generic discovery refuses to choose silently when valid tokens for multiple GitHub accounts are found. After an account is selected, automatic `401`/`403` recovery and in-process token rotation accept only the same GitHub account. Concurrent callers share token refresh work without sharing cancellation, and a still-valid Copilot token may be used briefly after a transient refresh failure. Explicit token variables remain the intentional way to switch accounts.
339
-
340
- If Copilot token refresh still fails with `401` or `403`, the saved GitHub token may be expired, revoked, or missing Copilot access. Delete the saved token and start the tool again to trigger GitHub device login:
175
+ ### Authentication recovery
341
176
 
342
- ```bash
343
- rm ~/.local/share/copilot-api/github_token
344
- ccdx
345
- ```
177
+ When the saved token is missing, `ccdx` looks for compatible local Copilot GitHub tokens, validates them with GitHub and Copilot, and imports a valid one before starting Device Flow. It checks explicit token sources (`CCDX_GITHUB_TOKEN`, `CCDX_GITHUB_TOKEN_PATH`, and `CCDX_GITHUB_TOKEN_PATHS`) plus common local `auth.json` layouts. Generic discovery refuses to choose silently when valid credentials for multiple GitHub accounts are found.
346
178
 
347
- ### Claude App opt-in
179
+ After an account is selected, automatic `401`/`403` recovery and in-process token rotation accept only that same GitHub account. Concurrent callers share token refresh work without sharing cancellation, and a still-valid Copilot token may be used briefly after a transient refresh failure. Explicit token variables remain the intentional way to select another account.
348
180
 
349
- Claude App support is opt-in so the default Codex Desktop and Claude Code setup stays unchanged:
181
+ If refresh still fails with `401` or `403`, the saved GitHub OAuth credential may be expired, revoked, or missing Copilot access. Remove that exact saved token and start again to trigger Device Flow:
350
182
 
351
183
  ```bash
352
- npm exec --yes --package=codex-copilot-dx@latest -- ccdx start --configure-claude-app
353
- ```
354
-
355
- The previous `--configure-claude-desktop` spelling remains a compatibility
356
- alias. Startup reports Claude App as ready only when a matching managed gateway
357
- key is restored or the profile is configured in that run.
358
-
359
- Or set:
360
-
361
- ```bash
362
- CCDX_CONFIGURE_CLAUDE_DESKTOP=1 npm exec --yes --package=codex-copilot-dx@latest -- ccdx
184
+ rm ~/.local/share/copilot-api/github_token
185
+ ccdx
363
186
  ```
364
187
 
365
- This writes a local Claude App 3P gateway profile that points to the adapter root URL, such as `http://127.0.0.1:2026`. The profile uses a generated local bearer key unless `CCDX_CLAUDE_DESKTOP_API_KEY` is set. Later starts restore that key only from the active managed profile when its gateway URL matches the adapter. Once that managed profile is active, successful Copilot model refreshes automatically keep its `inferenceModels` list current without changing the gateway key or other profile settings. Restart Claude App after the initial setup. Later model changes require no profile reconfiguration, although a running Claude App may need to be reopened if it has not reloaded the updated profile yet.
188
+ ## Security
366
189
 
367
- When reusing an already-running adapter, Claude App profile updates require `CCDX_CLAUDE_DESKTOP_API_KEY` or `CCDX_PROXY_API_KEY` so the profile key matches the running process. Otherwise the existing adapter is left untouched.
190
+ - CCDX binds to loopback by default. Non-loopback hosts are rejected unless `CCDX_ALLOW_LAN=1` is set explicitly.
191
+ - Enabling LAN binding exposes a Copilot-backed API to other reachable machines. Provide your own host firewall and network isolation; do not expose the listener to an untrusted network.
192
+ - The GitHub OAuth credential is stored locally at `~/.local/share/copilot-api/github_token`. Short-lived Copilot service tokens remain in process memory and are refreshed as needed.
193
+ - Runtime status, usage, and debug logs exclude authorization headers, prompts, completions, tool arguments, and image content.
194
+ - Request and response bodies are bounded. Queues, history, image work, SSE parsing, retries, and shutdown all have explicit resource or time limits.
368
195
 
369
196
  ## Configuration
370
197
 
371
- Environment variables:
372
-
373
198
  | Variable | Default | Description |
374
199
  |----------|---------|-------------|
375
- | `ADAPTER_HOST` | `127.0.0.1` | Host for the adapter; only loopback hosts are allowed by default |
376
- | `ADAPTER_PORT` | `2026` | Port for the adapter |
377
- | `CCDX_ALLOW_LAN` | unset | Set to `1` to allow non-loopback `ADAPTER_HOST` values such as `0.0.0.0`; exposes your Copilot-backed adapter beyond this machine |
378
- | `CCDX_MAX_BODY_BYTES` | `67108864` | Maximum compressed/raw request body size |
379
- | `CCDX_MAX_DECODED_BODY_BYTES` | `134217728` | Maximum decoded request body size after decompression |
200
+ | `ADAPTER_HOST` | `127.0.0.1` | Adapter host; only loopback hosts are allowed by default |
201
+ | `ADAPTER_PORT` | `2026` | Adapter port |
202
+ | `CCDX_ALLOW_LAN` | unset | Set to `1` to permit a non-loopback host such as `0.0.0.0`; this exposes the Copilot-backed adapter beyond this machine |
203
+ | `CCDX_MAX_BODY_BYTES` | `67108864` | Maximum compressed or raw request-body size |
204
+ | `CCDX_MAX_DECODED_BODY_BYTES` | `134217728` | Maximum decoded request-body size after decompression |
380
205
  | `CCDX_MAX_INFLIGHT_BODY_BYTES` | `33554432` | Per-pool byte budget for raw bodies, decoded bodies, and materialized response history; a larger item runs exclusively in its pool |
381
- | `CCDX_MAX_UPSTREAM_CHAT_RESPONSE_BYTES` | `67108864` | Maximum buffered successful Chat Completions response used by Responses, Anthropic, and PM Studio conversion paths |
382
- | `CCDX_MAX_UPSTREAM_RESPONSES_RESPONSE_BYTES` | `268435456` | Maximum buffered successful native Responses or compact response; streaming Responses are forwarded with bounded backpressure instead |
383
- | `CCDX_MAX_QUEUED_REQUESTS` | `16` | Maximum body requests waiting for the shared byte budget |
206
+ | `CCDX_MAX_UPSTREAM_CHAT_RESPONSE_BYTES` | `67108864` | Maximum buffered successful Chat Completions response used by the internal Responses compatibility path |
207
+ | `CCDX_MAX_UPSTREAM_RESPONSES_RESPONSE_BYTES` | `268435456` | Maximum buffered successful native Responses or compact response; streaming Responses use bounded backpressure |
208
+ | `CCDX_MAX_QUEUED_REQUESTS` | `16` | Maximum body requests waiting for shared byte admission |
384
209
  | `CCDX_REQUEST_QUEUE_TIMEOUT_MS` | `120000` | Maximum wait for request-body admission before returning `503` |
385
- | `CCDX_REQUEST_BODY_TIMEOUT_MS` | `120000` | Maximum time to receive and decode one request body before returning `408` |
210
+ | `CCDX_REQUEST_BODY_TIMEOUT_MS` | `120000` | Maximum time to receive and decode a request body before returning `408` |
386
211
  | `CCDX_MAX_UPSTREAM_BODY_BYTES` | `31457280` | Strict maximum forwarded Responses body size; larger payloads are adapted locally or rejected with `413` |
387
- | `CCDX_MAX_SSE_BUFFER_BYTES` | `8388608` | Maximum buffered bytes for one unterminated upstream SSE line/event |
388
- | `CCDX_UPSTREAM_TIMEOUT_MS` | `120000` | Per-phase timeout for Responses preparation and non-streaming upstream Copilot requests |
212
+ | `CCDX_MAX_SSE_BUFFER_BYTES` | `8388608` | Maximum buffered bytes for one unterminated upstream SSE line or event |
213
+ | `CCDX_UPSTREAM_TIMEOUT_MS` | `120000` | Per-phase timeout for Responses preparation and non-streaming upstream requests |
389
214
  | `CCDX_STREAM_HANDSHAKE_TIMEOUT_MS` | `120000` | Timeout while waiting for upstream streaming response headers |
390
215
  | `CCDX_STREAM_IDLE_TIMEOUT_MS` | `120000` | Maximum idle time between upstream streaming body chunks |
391
216
  | `CCDX_UPSTREAM_RETRIES` | `2` | Retries for safe requests and clearly pre-connect POST failures; capped at `5` |
392
217
  | `CCDX_UPSTREAM_RETRY_DELAY_MS` | `300` | Initial upstream retry backoff in milliseconds; capped at `5000` |
393
- | `CCDX_AUTO_REVIEW_MODEL` | saved selection or `gpt-5.5` | Copilot Responses model used for Codex Auto-review requests; overrides the interactive selection |
218
+ | `CCDX_AUTO_REVIEW_MODEL` | saved selection or `gpt-5.5` | Copilot Responses model used for Codex Auto-review; overrides the interactive selection |
394
219
  | `CCDX_LOG_PATH` | unset | Mirror terminal logs to a file; set to `1` for `~/.local/share/codex-copilot-dx/debug.log` |
395
- | `CCDX_LOG_LEVEL` | `info` | Set to `debug` to include upstream request attempts, status codes, retry causes, and timings |
396
- | `CCDX_LOG_MAX_BYTES` | `16777216` | Rotate the debug log at this size, retaining one `.1` backup; set to `0` to disable rotation |
397
- | `CCDX_TERMINAL_ANIMATION` | auto | Show a transient comet while an interactive terminal has active requests and no new output for 800ms; set to `0` to disable |
398
- | `CCDX_IMG_MAX_DIM` | `2048` | Max long edge in pixels for image downscaling |
399
- | `CCDX_IMG_QUALITY` | `82` | Initial WebP quality used when re-encoding images |
400
- | `CCDX_IMG_MIN_BYTES` | `100000` | In-bounds images smaller than this are left untouched; oversized images are still downscaled |
401
- | `CCDX_IMG_CONCURRENCY` | `2` | Global concurrent image optimization tasks; values above `12` are capped at `12` |
402
- | `CCDX_IMG_MAX_INPUT_PIXELS` | `40000000` | Maximum decoded pixels accepted by `sharp` for one image |
403
- | `CCDX_IMG_CACHE_MAX_BYTES` | `67108864` | Process-local byte ceiling for cached image optimization results; set to `0` to disable result caching |
220
+ | `CCDX_LOG_LEVEL` | `info` | Set to `debug` for upstream attempts, status codes, retry causes, and timings |
221
+ | `CCDX_LOG_MAX_BYTES` | `16777216` | Rotate the debug log at this size and retain one `.1` backup; set to `0` to disable rotation |
222
+ | `CCDX_TERMINAL_ANIMATION` | auto | Show the selected transient animation while an interactive terminal has active requests and no output for 800 ms; set to `0`, `false`, `no`, or `off` to disable |
223
+ | `CCDX_IMG_MAX_DIM` | `2048` | Maximum long edge in pixels for image downscaling |
224
+ | `CCDX_IMG_QUALITY` | `82` | Initial WebP quality for image re-encoding |
225
+ | `CCDX_IMG_MIN_BYTES` | `100000` | In-bounds images smaller than this remain unchanged; oversized images are still downscaled |
226
+ | `CCDX_IMG_CONCURRENCY` | `2` | Global concurrent image-optimization tasks; values above `12` are capped |
227
+ | `CCDX_IMG_MAX_INPUT_PIXELS` | `40000000` | Maximum decoded pixels accepted for one image |
228
+ | `CCDX_IMG_CACHE_MAX_BYTES` | `67108864` | Process-local byte ceiling for cached image transforms; set to `0` to disable the cache |
404
229
  | `CCDX_DISABLE_IMG_OPT` | unset | Set to `1` to disable image optimization |
405
- | `CCDX_CONFIGURE_CLAUDE_DESKTOP` | unset | Set to `1` to write the Claude App 3P gateway profile during startup |
406
- | `CCDX_AUTO_LAUNCH` | enabled | Set to `0`, `false`, `no`, or `off` to start the adapter without opening Codex or ChatGPT |
407
- | `CCDX_CLAUDE_DESKTOP_API_KEY` | managed profile or generated for opt-in setup | Explicit bearer key written into the Claude App profile and recognized by the adapter for model discovery |
408
- | `CCDX_PROXY_API_KEY` | unset | Backward-compatible alias for `CCDX_CLAUDE_DESKTOP_API_KEY`; the Claude-specific variable takes precedence |
409
- | `CCDX_CLAUDE_MODEL_ALIASES` | built-in Claude aliases | Comma-separated Desktop-to-upstream aliases, for example `claude-sonnet-4-6=claude-sonnet-4.6` |
410
- | `CCDX_GITHUB_TOKEN` | unset | Explicit GitHub Copilot OAuth token to validate and import before device login |
411
- | `CCDX_GITHUB_TOKEN_PATH` | unset | Explicit file containing a GitHub Copilot OAuth token to validate and import before device login |
230
+ | `CCDX_AUTO_LAUNCH` | enabled | Set to `0`, `false`, `no`, or `off` to start without opening Codex or ChatGPT |
231
+ | `CCDX_GITHUB_TOKEN` | unset | Explicit GitHub Copilot OAuth token to validate and import before Device Flow |
232
+ | `CCDX_GITHUB_TOKEN_PATH` | unset | Explicit file containing a GitHub Copilot OAuth token |
412
233
  | `CCDX_GITHUB_TOKEN_PATHS` | unset | Multiple token files separated by the platform path delimiter (`:` on macOS/Linux, `;` on Windows) |
413
234
  | `CCDX_GITHUB_LOGIN` | saved account | Require automatic discovery and recovery to use this GitHub login |
414
- | `CCDX_DISABLE_TOKEN_DISCOVERY` | unset | Set to `1` to skip local token discovery and go straight to the saved token or device flow |
415
- | `CCDX_TOKEN_LOCK_TIMEOUT_MS` | `600000` | Maximum time to wait for another local process to finish GitHub token login/import |
416
- | `CCDX_TOKEN_LOCK_STALE_MS` | `900000` | Age after which a stale GitHub token lock file can be removed |
235
+ | `CCDX_DISABLE_TOKEN_DISCOVERY` | unset | Set to `1` to skip local token discovery and use the saved token or Device Flow |
236
+ | `CCDX_TOKEN_LOCK_TIMEOUT_MS` | `600000` | Maximum time to wait for another process to finish GitHub token login or import |
237
+ | `CCDX_TOKEN_LOCK_STALE_MS` | `900000` | Age after which a stale GitHub-token lock can be removed |
417
238
  | `CCDX_EXISTING_ADAPTER_TIMEOUT_MS` | `500` | Timeout for detecting an already-running local adapter during startup |
418
- | `CCDX_MODEL_REFRESH_TIMEOUT_MS` | `5000` | Timeout for a Copilot model metadata refresh or live Auto-review model lookup |
419
- | `CCDX_MODEL_REFRESH_INTERVAL_MS` | `7200000` | Interval for refreshing Copilot model metadata; successful lists are cached locally as last-known-good data |
239
+ | `CCDX_MODEL_REFRESH_TIMEOUT_MS` | `5000` | Timeout for Copilot model refresh or live Auto-review model lookup |
240
+ | `CCDX_MODEL_REFRESH_INTERVAL_MS` | `7200000` | Model refresh interval; successful lists are cached as last-known-good data |
420
241
  | `CCDX_RESPONSE_HISTORY_MAX_BYTES` | `67108864` | Total in-memory byte budget for locally expanded Responses history |
421
242
  | `CCDX_RESPONSE_HISTORY_MAX_ENTRIES` | `4096` | Maximum stored incremental Responses history nodes |
422
- | `CCDX_USAGE_PATH` | `~/.local/share/codex-copilot-dx/usage.jsonl` | Local JSONL token usage log |
423
- | `CCDX_USAGE_MAX_BYTES` | `33554432` | Rotate the usage log at this size, retaining one `.1` backup; set to `0` to disable rotation |
243
+ | `CCDX_USAGE_PATH` | `~/.local/share/codex-copilot-dx/usage.jsonl` | Local JSONL token-usage log |
244
+ | `CCDX_USAGE_MAX_BYTES` | `33554432` | Rotate the usage log at this size and retain one `.1` backup; set to `0` to disable rotation |
424
245
  | `CCDX_DISABLE_USAGE` | unset | Set to `1` to disable usage logging |
425
246
  | `CCDX_SHUTDOWN_TIMEOUT_MS` | `5000` | Time to drain active HTTP connections before forcing shutdown |
426
247
 
427
- ### Usage logging
248
+ ## Usage logging
428
249
 
429
- The adapter records token usage metadata to `~/.local/share/codex-copilot-dx/usage.jsonl` when upstream responses include usage fields. It logs counts, model names, API surface, and response IDs only; it does not log prompts, completions, tool arguments, or image content.
250
+ When upstream responses contain usage fields, CCDX records token counts, model names, API surface, and response IDs in `~/.local/share/codex-copilot-dx/usage.jsonl`. It does not record prompts, completions, tool arguments, or image content.
430
251
 
431
252
  ```bash
432
253
  ccdx usage
433
254
  ```
434
255
 
435
- The summary covers the retained current usage log and its single rotated
436
- backup, not an unbounded lifetime history. Its table reports recorded usage
437
- responses and per-model input, cache-read, output, and total token metadata.
438
-
439
- ### Debug logging
256
+ The summary covers the current log and its single rotated backup, not an unbounded lifetime history. It reports recorded responses and per-model input, cache-read, output, and total token metadata.
440
257
 
441
- Set `CCDX_LOG_PATH=1` to mirror terminal logs to `~/.local/share/codex-copilot-dx/debug.log`, or set `CCDX_LOG_PATH` to a custom file. Add `CCDX_LOG_LEVEL=debug` to include upstream request attempts, retry causes, status codes, and timings. Debug logs do not include prompts, completions, request bodies, or authorization tokens.
258
+ ## Debug logging
442
259
 
443
- ### Image optimization
260
+ Set `CCDX_LOG_PATH=1` to mirror terminal logs to `~/.local/share/codex-copilot-dx/debug.log`, or provide a custom path. Add `CCDX_LOG_LEVEL=debug` for upstream attempts, retry causes, status codes, and timings. Debug logs do not include prompts, completions, request bodies, or authorization tokens.
444
261
 
445
- Long computer-use sessions can accumulate screenshots inside the conversation history. Each screenshot is shipped on later turns, which can increase local preparation time, upstream handshake latency, and the chance of a `413 Payload Too Large` response.
262
+ ## Large histories and images
446
263
 
447
- The adapter automatically downsamples embedded screenshots to model-appropriate pixel bounds (with a conservative 2048 px long-edge fallback) and initially re-encodes them as WebP quality 82 before forwarding `/v1/responses`. It never replaces an image with a larger encoding and applies one global concurrency limit across direct, function-tool, and custom-tool output images.
264
+ Long computer-use sessions can accumulate screenshots that are sent again on later turns. This can increase local preparation time, upstream handshake latency, and the chance of a `413 Payload Too Large` response.
448
265
 
449
- The final serialized UTF-8 request body is measured before forwarding. Above the configured byte limit, unique source images are processed largest-first from their originals at quality 75 / 1600 px and then quality 65 / 1280 px, stopping as soon as the body fits. If necessary, the forwarded view omits older duplicate images, historical tool images, other historical images, and finally old tool outputs while preserving current input and tool-call skeletons. A request that still cannot fit is rejected locally with a structured `413` instead of sending an oversized body upstream.
266
+ CCDX automatically downsamples embedded screenshots to model-appropriate pixel bounds, with a conservative 2048 px fallback, and initially encodes them as WebP quality 82. It never replaces an image with a larger encoding and uses one global concurrency limit across direct images and function/custom-tool outputs.
450
267
 
451
- Completed image transforms are reused from a byte-bounded process-local LRU cache, and concurrent requests for the same transform share one encode. The cache key includes source content, MIME type, model-aware dimensions, WebP quality, and encoder settings; failures are not cached and request cancellation remains isolated.
268
+ The final serialized UTF-8 body is measured before forwarding. Above the configured limit, unique source images are processed largest-first from their originals at quality 75 / 1600 px and then quality 65 / 1280 px, stopping when the body fits. If necessary, the forwarded view omits older duplicate images, historical tool images, other historical images, and finally old tool outputs while preserving current input and tool-call skeletons. Requests that still do not fit receive a structured local `413`.
452
269
 
453
- Before image encoding, CCDX leaves ordinary visual history byte-for-byte unchanged while it has at most 24 historical images and the expanded body is at most 18 MiB. Above either threshold, the temporary upstream view keeps every current-turn image and at most 16 recent historical images, targeting 16 MiB. If that history tree then times out during local preparation, a streaming handshake, or a non-streaming upstream request, or if the upstream returns HTTP 408, the next retry automatically uses an 8-image, 10 MiB recovery window for ten minutes. Two successful requests or a successful compaction clear recovery mode. CCDX never transparently repeats the ambiguous timed-out POST, and no local history is deleted; retrying does not require restarting the service.
270
+ Completed image transforms are reused from a byte-bounded process-local LRU cache, and concurrent requests for the same transform share one encode. Failures are not cached and request cancellation remains isolated.
454
271
 
455
- When expanded Responses history exceeds Copilot's 50-image request limit, the adapter removes older duplicate image occurrences first, then keeps the 50 most recent images. This applies only to the forwarded request: local history remains complete, current images are preferred over older history, and requests at or below the limit are unchanged.
272
+ Ordinary visual history stays byte-for-byte unchanged while it has at most 24 historical images and the expanded body is at most 18 MiB. Above either threshold, the temporary upstream view keeps every current-turn image and up to 16 recent historical images, targeting 16 MiB. After a preparation, handshake, upstream timeout, or HTTP `408`, the next retry uses an 8-image, 10 MiB recovery window for ten minutes. Two successful requests or a successful compaction clear recovery mode. CCDX never transparently repeats an ambiguous timed-out POST, and it does not delete local history.
456
273
 
457
- For `/v1/responses/compact`, the adapter sends one terminal `compaction_trigger` in unary mode, validates that Copilot returned completed compaction state, and preserves the complete upstream compacted window as the canonical next context. Only a validated window becomes a new local history root. Later turns continue from it without re-expanding pre-compaction history; existing older response branches remain available until normal history eviction.
274
+ When expanded history exceeds Copilot's 50-image request limit, CCDX removes older duplicate occurrences first and then keeps the 50 most recent images. This affects only the forwarded request; local history remains complete and current images are preferred.
458
275
 
459
- Successful streaming responses are accepted only when the upstream body is SSE and reaches its protocol terminal event; bytes after that terminal are not forwarded. Unexpected EOF becomes a protocol-native stream error, and repeated blank tool-argument deltas are stopped per tool call. Inference responses forward safe quota, retry, model, trace, and upstream request-ID metadata; cookies, authorization, body-length, and encoding headers are not forwarded.
276
+ For `/v1/responses/compact`, CCDX sends one terminal `compaction_trigger`, validates completed compaction state, and preserves the complete returned window as the canonical next context. Only a validated window becomes a new local history root. Existing older branches remain available until normal history eviction.
460
277
 
461
- Newer ChatGPT/Codex clients can advertise an `image_gen` namespace that already exists upstream. The adapter removes that exact conflicting client tool before forwarding and retries once only when Copilot explicitly reports an image namespace collision. Image inputs and screenshot optimization remain enabled.
278
+ Successful streaming responses are accepted only when the upstream body is SSE and reaches its protocol terminal event. Unexpected EOF becomes a protocol-native stream error, and repeated blank tool-argument deltas are stopped per tool call. Safe quota, retry, model, trace, and upstream request-ID metadata are forwarded; cookies, authorization, body-length, and encoding headers are not.
462
279
 
463
- ## License
464
-
465
- MIT
280
+ Newer Codex and ChatGPT clients can advertise an `image_gen` namespace that already exists upstream. CCDX removes that exact conflicting client tool before forwarding and retries once only when Copilot explicitly reports an image namespace collision. Image input and screenshot optimization remain enabled.
466
281
 
467
282
  ## Development
468
283
 
@@ -472,4 +287,8 @@ npm run verify
472
287
  npm run bench:payload
473
288
  ```
474
289
 
475
- `npm test` runs the unit and handler-level suite. `npm run test:smoke` starts a real local HTTP adapter with fully injected offline upstreams. `npm run bench:check` enforces relative token-counting performance, linear SSE scanning, and request-admission resource limits. `npm run pack:check` verifies the npm tarball contents without publishing. `npm run bench:payload` remains a report-only, isolated-process benchmark for 5-60 MiB image payloads and does not contact Copilot. The CI workflow runs the verification checks on supported Node.js release lines.
290
+ `npm test` runs unit and handler-level tests. `npm run test:smoke` starts a real local adapter with fully injected offline upstreams. `npm run bench:check` enforces linear SSE scanning, image/tool processing, and request-admission resource limits. `npm run pack:check` verifies npm tarball contents without publishing. `npm run bench:payload` is a report-only isolated-process benchmark for 5–60 MiB image payloads and does not contact Copilot. CI runs verification on the supported Node.js release lines.
291
+
292
+ ## License
293
+
294
+ MIT