codex-copilot-dx 0.9.23 → 0.9.25

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 (43) hide show
  1. package/README.md +20 -20
  2. package/bin/cli.mjs +51 -19
  3. package/docs/ARCHITECTURE.md +50 -0
  4. package/docs/README.md +4 -0
  5. package/docs/REFERENCE.md +124 -71
  6. package/package.json +3 -2
  7. package/src/adapter.mjs +5 -2
  8. package/src/cli-image.mjs +13 -10
  9. package/src/cli-options.mjs +13 -4
  10. package/src/cli-status.mjs +5 -0
  11. package/src/client-integration.mjs +41 -0
  12. package/src/codex-config-doctor.mjs +3 -3
  13. package/src/codex-paths.mjs +10 -0
  14. package/src/codex-thread-compression.mjs +11 -6
  15. package/src/config.mjs +10 -6
  16. package/src/copilot-responses-policy.mjs +4 -2
  17. package/src/dashboard/index.html +7 -6
  18. package/src/dashboard/language.js +13 -21
  19. package/src/dashboard/ui.js +10 -20
  20. package/src/dashboard-api.mjs +0 -12
  21. package/src/launcher.mjs +7 -2
  22. package/src/lock.mjs +29 -0
  23. package/src/native-prediction-overlay.mjs +92 -0
  24. package/src/native-prediction-profile.mjs +178 -0
  25. package/src/native-prediction-state.mjs +29 -0
  26. package/src/native-prediction-transport.mjs +255 -0
  27. package/src/native-prediction.mjs +170 -0
  28. package/src/network-route.mjs +102 -0
  29. package/src/observability.mjs +2 -0
  30. package/src/operation-error.mjs +37 -0
  31. package/src/package-update.mjs +2 -3
  32. package/src/prediction-retirement.mjs +86 -0
  33. package/src/proxy-tunnel.mjs +102 -0
  34. package/src/responses-request.mjs +5 -2
  35. package/src/suggestion-auto.mjs +3 -103
  36. package/src/suggestion-mcp.mjs +64 -132
  37. package/src/user-settings.mjs +17 -4
  38. package/src/version.mjs +23 -46
  39. package/src/cli-suggestion.mjs +0 -120
  40. package/src/suggestion-config.mjs +0 -98
  41. package/src/suggestion-context.mjs +0 -108
  42. package/src/suggestion-provider.mjs +0 -41
  43. package/src/suggestion-ui.html +0 -26
package/README.md CHANGED
@@ -5,6 +5,7 @@ Use Codex App with GitHub Copilot through a local adapter.
5
5
  CCDX targets Codex App. It discovers Copilot models, adapts the client's model
6
6
  catalog, and preserves Responses streaming, tool calls and conversation history.
7
7
  Default Auto-review: **GPT-6.1 Sol / low**. Image generation is **off by default**.
8
+ Native predictions are also **off by default**.
8
9
 
9
10
  ## Install and run
10
11
 
@@ -29,7 +30,7 @@ The dashboard does not poll in the background; refresh when needed.
29
30
  | Command | Purpose |
30
31
  | --- | --- |
31
32
  | `ccdx help` | Command help; use `ccdx help <command>` for details |
32
- | `ccdx start` | Start without launching the App |
33
+ | `ccdx start` | Start or reuse the adapter and open Codex when auto-launch is enabled |
33
34
  | `ccdx status` | Runtime, limits and bounded request diagnostics |
34
35
  | `ccdx doctor` | Configuration, adapter and read-only App/catalog diagnostics |
35
36
  | `ccdx doctor config` | Read-only configuration check |
@@ -38,14 +39,13 @@ The dashboard does not poll in the background; refresh when needed.
38
39
  | `ccdx models` | Fresh upstream model list |
39
40
  | `ccdx usage` | Recorded tokens and upstream prompt-cache hit rate |
40
41
  | `ccdx auto-review-model` | Select model, then reasoning effort; `0` follows client |
41
- | `ccdx suggestion on` / `ccdx suggestion off` | Enable or disable the optional next-message panel |
42
- | `ccdx suggestion model` / `ccdx suggestion status` | Choose its model by number, or check settings |
43
42
  | `ccdx animation` | Preview and select terminal animation |
44
43
  | `ccdx cache --limit 128` | Set the history-cache budget in MiB |
45
44
  | `ccdx cache --clean` | Clear the rebuildable image-transform cache |
46
45
  | `ccdx limits --decoded 256` | Set the decoded request-body budget; restart to apply |
47
46
  | `ccdx enable-image` | Opt in to image generation/editing with your own API |
48
47
  | `ccdx image-status` / `ccdx disable-image` | Check or disable optional images |
48
+ | `ccdx prediction on` / `off` / `status` | Opt in to native next-message predictions (macOS) |
49
49
  | `ccdx update` | Update the global package |
50
50
 
51
51
  ## Compatibility and safety
@@ -64,20 +64,17 @@ The dashboard does not poll in the background; refresh when needed.
64
64
  break continuations. Generated images and Codex transcripts are not deleted.
65
65
  - Optional image setup/maintenance never blocks the primary service. Disabled
66
66
  users get no CCDX image skill or MCP installation.
67
- - Next-message suggestions are **off by default**. Opt in with `ccdx suggestion on`,
68
- then open **Next message / 下一句** in a local conversation panel or ask Codex for
69
- a next-message suggestion. **Add to draft / 加入草稿** appends ordinary text; it
70
- never sends, replaces your draft, or patches the client. Default model:
71
- `gpt-6-luna`, with `low` reasoning when advertised. Requires a running local
72
- adapter and a recent Codex with paginated thread reads and MCP draft support.
73
- - Suggestions read only a bounded page from the host-identified current thread.
74
- Images, reasoning items and tool outputs are excluded. On supported runtimes,
75
- `suggestion on` configures an async Stop hook; review it in Codex before it runs.
76
- CCDX never grants trust. The panel reads saved suggestions; adding drafts is manual.
77
- The dashboard shows settings and generation status. Model selection alone stays off.
78
- Existing user-managed MCP/profile configuration is preserved. Native prediction
79
- settings are untouched; account/remote defaults in all future clients cannot be
80
- reliably detected. Use `ccdx suggestion off` when preferring an official feature.
67
+ - The manual prediction MCP, background hook and dashboard panel are retired.
68
+ Startup removes only unchanged CCDX registrations and disables saved prediction
69
+ settings. The optional image MCP remains unchanged. Modified old registrations
70
+ can use inert compatibility entrypoints; they no longer generate suggestions.
71
+ - Native predictions are a separate, opt-in compatibility feature. Quit Codex,
72
+ run `ccdx prediction on`, then restart CCDX. This adds App-profile certificate
73
+ trust and an App-only route for `chatgpt.com` and `ab.chatgpt.com`; HTTPS on those
74
+ hosts is decrypted locally, but only prediction configuration is changed.
75
+ Other domains and the CCDX model endpoint stay on their existing routes.
76
+ No program files or OS trust are changed. Static HTTP/HTTPS/SOCKS5 proxies and bypass rules are retained.
77
+ Dynamic PAC/WPAD routes are reported as unsupported; see the reference for routing, rollback and client-version limits.
81
78
  - CCDX adds experimental local history compression only when installed App
82
79
  runtimes support it and report it off. Existing choices are preserved; an
83
80
  already-enabled default, unavailable runtime or failed check is skipped.
@@ -87,11 +84,14 @@ The dashboard does not poll in the background; refresh when needed.
87
84
  expose it to the public internet. The dashboard is not an authentication wall
88
85
  for the API. Diagnostic errors may contain sensitive upstream text.
89
86
 
90
- Startup checks GitHub Releases, not npm, and suggests `ccdx update github` when a newer stable version is available. GitHub updates install the exact release tag; dependency downloads still use npm's configured registry.
87
+ Startup checks GitHub's latest-release web redirect, not npm or the anonymous REST quota, and suggests `ccdx update github`.
88
+ Updates install the exact stable tag; dependencies still use npm's configured registry. Lookup errors identify HTTP refusal, timeout, network failure or invalid redirects.
89
+
90
+ The dashboard and CLI separate prediction preference, bridge state and observed config traffic; candidate visibility stays unknown.
91
+ Inference, client integration, optional images and management have separate ownership. See [architecture boundaries](docs/ARCHITECTURE.md).
91
92
 
92
93
  See the [complete command/configuration reference](https://github.com/DaleXiao/codex-copilot-dx/blob/main/docs/REFERENCE.md)
93
- for authentication recovery, configuration-write boundaries, advanced limits,
94
- logging, image setup and client compatibility details.
94
+ for authentication recovery, configuration safety, limits, logging, images and client compatibility.
95
95
  The same reference is included as `docs/REFERENCE.md` in the installed npm package.
96
96
 
97
97
  ## Development
package/bin/cli.mjs CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { ensureAuth, openCodex } from "../src/launcher.mjs";
4
- import { ensureCodexConfig } from "../src/config.mjs";
5
4
  import { startAdapter } from "../src/adapter.mjs";
6
5
  import { defaultCopilotClient, refreshVSCodeVersion } from "../src/copilot.mjs";
7
6
  import { status } from "../src/status.mjs";
@@ -22,9 +21,7 @@ import { runAuthCommand } from "../src/cli-auth.mjs";
22
21
  import { createProfileRuntime } from "../src/profile-runtime.mjs";
23
22
  import { createProfileModelRuntime } from "../src/profile-model-runtime.mjs";
24
23
  import { createCodexModelCatalog } from "../src/codex-model-catalog.mjs";
25
- import { readImageProviderConfig } from "../src/image-provider-config.mjs";
26
24
  import { setResponseHistoryMaxBytes } from "../src/response-history.mjs";
27
- import { ensureCodexThreadCompression } from "../src/codex-thread-compression.mjs";
28
25
 
29
26
  const LOCAL_VERSION = localPackageVersion();
30
27
  const CLI_NAME = cliCommandName();
@@ -77,8 +74,24 @@ if (CLI.command === "image") {
77
74
  }
78
75
  if (CLI.command === "suggestion") {
79
76
  try {
80
- const { runSuggestionCommand } = await import("../src/cli-suggestion.mjs");
81
- await runSuggestionCommand({ action: CLI.action, model: CLI.model, commandName: CLI_NAME });
77
+ const { retirePredictionIntegration } = await import("../src/prediction-retirement.mjs");
78
+ const result = retirePredictionIntegration({ dryRun: CLI.action === "status" });
79
+ console.log("The CCDX prediction panel has been retired and cannot be enabled.");
80
+ if (CLI.action === "status" && result.changed) console.log(`Legacy settings remain; run ${CLI_NAME} suggestion off to clean them up.`);
81
+ if (result.preserved) console.warn("Modified prediction settings were preserved.");
82
+ process.exit(0);
83
+ } catch (error) {
84
+ console.error(status("err", error.message));
85
+ process.exit(1);
86
+ }
87
+ }
88
+ if (CLI.command === "prediction") {
89
+ try {
90
+ const { runPredictionCommand } = await import("../src/native-prediction.mjs");
91
+ await runPredictionCommand({ action: CLI.action, runtimeSnapshot: () => {
92
+ const probe = parseAdapterProbeOptions(process.env);
93
+ return readAdapterStatus({ host: probe.adapterHost, port: probe.adapterPort, timeoutMs: probe.existingAdapterTimeoutMs }).then(({ data }) => data);
94
+ } });
82
95
  process.exit(0);
83
96
  } catch (error) {
84
97
  console.error(status("err", error.message));
@@ -251,6 +264,17 @@ const LOGGING = configureLogging();
251
264
  let activeServer = null;
252
265
  let modelRefreshTimer = null;
253
266
  let shuttingDown = false;
267
+ let nativePrediction = null;
268
+ let clientIntegration = null;
269
+
270
+ async function clientIntegrations() {
271
+ if (!clientIntegration) {
272
+ const { createClientIntegration } = await import("../src/client-integration.mjs");
273
+ clientIntegration = createClientIntegration({ port: ADAPTER_PORT, host: ADAPTER_HOST,
274
+ info: (message) => console.log(status("info", message)), warning: (message) => console.warn(status("warn", message)) });
275
+ }
276
+ return clientIntegration;
277
+ }
254
278
 
255
279
  if (LOGGING.filePath) {
256
280
  console.log(status("info", `Debug log: ${LOGGING.filePath}`));
@@ -272,7 +296,18 @@ async function reuseRunningAdapterIfAvailable() {
272
296
  console.log(status("ok", `Using existing adapter at ${running.baseUrl}`));
273
297
  const { compressionSetup } = await configureCodexClient();
274
298
 
275
- await openCodex();
299
+ let predictionPacUrl = null;
300
+ let predictionApp = null;
301
+ try {
302
+ const { readPredictionSettings } = await import("../src/native-prediction-profile.mjs");
303
+ const preference = readPredictionSettings();
304
+ if (preference.enabled) {
305
+ predictionPacUrl = running.data?.native_prediction_pac || null;
306
+ predictionApp = preference.app?.app;
307
+ if (!predictionPacUrl) console.warn(status("warn", "Restart ccdx to activate the newly enabled prediction bridge"));
308
+ }
309
+ } catch (error) { console.warn(status("warn", error.message)); }
310
+ await openCodex({ predictionPacUrl, predictionApp });
276
311
  console.log(`
277
312
  ${status("ok", "Ready, using the existing ccdx adapter")}
278
313
 
@@ -285,17 +320,7 @@ async function reuseRunningAdapterIfAvailable() {
285
320
  }
286
321
 
287
322
  async function configureCodexClient() {
288
- const imageProviderEnabled = Boolean(readImageProviderConfig());
289
- const { imageMcpSkipped } = ensureCodexConfig(ADAPTER_PORT, { host: ADAPTER_HOST, imageProviderEnabled });
290
- if (imageProviderEnabled && !imageMcpSkipped) {
291
- try {
292
- const { syncEnabledImageSkill } = await import("../src/cli-image.mjs");
293
- syncEnabledImageSkill({ adapterPort: ADAPTER_PORT, adapterHost: ADAPTER_HOST });
294
- } catch (error) {
295
- console.warn(status("warn", `Image guidance could not be updated: ${error.message}`));
296
- }
297
- }
298
- return { compressionSetup: runInBackground(ensureCodexThreadCompression) };
323
+ return (await clientIntegrations()).configure();
299
324
  }
300
325
 
301
326
  if (CLI.command === "doctor") {
@@ -369,13 +394,18 @@ try {
369
394
  streamHandshakeTimeoutMs: RUNTIME.streamHandshakeTimeoutMs,
370
395
  streamIdleTimeoutMs: RUNTIME.streamIdleTimeoutMs,
371
396
  terminalAnimationTheme,
397
+ nativePredictionPac: () => nativePrediction?.pacUrl || null,
398
+ clientIntegrationSnapshot: () => clientIntegration?.snapshot() || null,
372
399
  });
373
400
 
374
401
  // Point Codex App at the adapter.
375
402
  const { compressionSetup } = await configureCodexClient();
376
403
 
377
- // Launch Codex when available.
378
- await openCodex();
404
+ // Optional native prediction setup must never prevent the core adapter from running.
405
+ nativePrediction = await (await clientIntegrations()).start();
406
+
407
+ // Launch Codex when available. A running App is never forcibly restarted.
408
+ await openCodex({ predictionPacUrl: nativePrediction?.pacUrl, predictionApp: nativePrediction?.app });
379
409
 
380
410
  // Periodically refresh the model list + endpoint cache so a long-running
381
411
  // adapter picks up newly released models without a restart.
@@ -404,6 +434,7 @@ try {
404
434
  let exitCode = 0;
405
435
  try {
406
436
  if (modelRefreshTimer) clearInterval(modelRefreshTimer);
437
+ await clientIntegration?.close();
407
438
  const result = await closeHttpServer(activeServer, { timeoutMs: RUNTIME.shutdownTimeoutMs });
408
439
  if (result.forced) console.warn(status("warn", "Forced remaining adapter connections closed"));
409
440
  await flushUsageWrites();
@@ -420,6 +451,7 @@ try {
420
451
  await compressionSetup;
421
452
  } catch (e) {
422
453
  console.error(status("err", e.message));
454
+ await clientIntegration?.close().catch(() => {});
423
455
  await closeHttpServer(activeServer, { timeoutMs: RUNTIME.shutdownTimeoutMs }).catch(() => {});
424
456
  await flushUsageWrites();
425
457
  await LOGGING.cleanup();
@@ -0,0 +1,50 @@
1
+ # Architecture boundaries
2
+
3
+ CCDX is one local Node service for Codex App. Client integration, image tools and
4
+ the dashboard are optional parts of that service, not a general plugin framework.
5
+
6
+ | Responsibility | Ownership | Boundary |
7
+ | --- | --- | --- |
8
+ | Core inference | `adapter.mjs`, Responses modules, model catalog, history | Copilot requests, streaming and recovery |
9
+ | Client integration | `client-integration.mjs`, Codex config, native prediction | Client setup, optional start/stop, diagnostic snapshots |
10
+ | Optional images | Image provider, CLI setup, image MCP and skill | Opt-in API access and image delivery; failures do not block core startup |
11
+ | Management | CLI, dashboard, observability, package updates | Bounded metadata and explicit user actions |
12
+ | Shared foundations | Codex paths, file locks, atomic files, network routes | No dependency on inference or dashboard rendering |
13
+
14
+ ## Composition and lifecycle
15
+
16
+ The CLI composes the service. Client integration owns its `configure`, `start`,
17
+ `snapshot` and `close` operations. It does not forward inference requests or
18
+ render the dashboard. The adapter exposes integration snapshots and keeps
19
+ management/MCP routes separate from the Responses path.
20
+
21
+ Native prediction has a separate loopback transport and an isolated HTTPS agent.
22
+ Only its two selected hosts use the App-specific route. Non-configuration requests
23
+ on those hosts are forwarded unchanged. The bridge does not replace Copilot or
24
+ image-provider networking, modify client program files, or install system trust.
25
+ Static upstream proxy routes and bypass rules are preserved. Dynamic PAC/WPAD
26
+ and CIDR bypass rules are reported as unsupported, not silently discarded.
27
+
28
+ ## Configuration ownership
29
+
30
+ `CODEX_HOME` selects Codex configuration. App profile/trust paths have their own
31
+ selection and are not inferred from that directory. CCDX writers use a shared
32
+ per-file lock, reread current contents and preserve unrelated values. Locks do
33
+ not coordinate editors or other applications that ignore them. Read-only status
34
+ and doctor commands do not write configuration.
35
+
36
+ Legacy public module exports remain available. This change adds a concrete
37
+ composition boundary; it does not relocate every file or add speculative APIs.
38
+
39
+ ## Evidence and verification
40
+
41
+ Prediction preference, bridge readiness and observed configuration responses are
42
+ different states. None proves that a candidate appeared in the App. The dashboard
43
+ keeps that result unknown. Integration diagnostics retain bounded, redacted
44
+ metadata, not conversation or image contents.
45
+
46
+ Tests cover module dependency direction, default-off behavior, concurrent writers,
47
+ proxy handshakes, TLS validation, streaming, history isolation and release lookup.
48
+ Performance measurements distinguish request preparation from model latency.
49
+ Release reports describe a specific environment, not an SLA or a guarantee of
50
+ compatibility with every future client or corporate network policy.
package/docs/README.md CHANGED
@@ -4,6 +4,8 @@ The [root README](../README.md) is the quick start; the [command/configuration
4
4
  reference](REFERENCE.md) preserves complete current behavior and limits. `ccdx --help` and
5
5
  `ccdx <command> --help` describe the installed package's CLI. Code and tests
6
6
  resolve any discrepancy; CLI version and running-adapter version can differ.
7
+ The [architecture boundaries](ARCHITECTURE.md) explain module ownership,
8
+ optional integration lifecycle and configuration safety.
7
9
 
8
10
  `ccdx doctor config` performs local, read-only configuration diagnostics and
9
11
  previews the current startup writer. It does not claim to resolve the complete
@@ -15,6 +17,8 @@ These reports record a specific release and test environment. Their version,
15
17
  test counts, timings, live-provider observations, and limitations remain
16
18
  historical facts rather than current guarantees.
17
19
 
20
+ - [0.9.25: static proxy compatibility, integration boundaries and release diagnostics](RELEASE_0.9.25.md)
21
+
18
22
  - [0.9.19: GitHub startup checks and stable-release updates](RELEASE_0.9.19.md)
19
23
  - [0.9.21: compatibility-gated local history compression](RELEASE_0.9.21.md)
20
24
  - [0.9.20: timing evidence, real-client checks and bounded analytics reuse](RELEASE_0.9.20.md)
package/docs/REFERENCE.md CHANGED
@@ -6,78 +6,124 @@ CCDX is a local compatibility adapter for Codex App. It configures Codex to use
6
6
 
7
7
  ## How it works
8
8
 
9
- ### Optional next-message suggestions
10
-
11
- Suggestions are disabled by default. No suggestion MCP or skill is installed at
12
- startup, and the primary adapter does not start a predictor.
9
+ ### Retired prediction integration
10
+
11
+ The manual prediction MCP, automatic Stop hook and dashboard panel are removed.
12
+ CCDX does not install a prediction skill or replacement predictor. Startup disables
13
+ the old `suggestion.json` preference and removes only unchanged CCDX declarations
14
+ from the active `CODEX_HOME/config.toml` (or `~/.codex/config.toml`).
15
+ `CCDX_SUGGESTION_CONFIG` still identifies the legacy settings path for cleanup.
16
+ For an immediate cleanup without starting the adapter, run `ccdx suggestion off`.
17
+ The old `suggestion on` and `suggestion model` commands cannot re-enable it.
18
+
19
+ Modified, inline and profile-specific declarations are preserved. Cleanup failures
20
+ do not block the core adapter. Saved model preferences and old candidate files are
21
+ not deleted; they are inactive. Native Codex preference settings, hook trust records,
22
+ other hooks and the optional image MCP are untouched. Two inert compatibility
23
+ entrypoints prevent user-modified registrations from invoking a removed module:
24
+ the old Hook exits with an empty result, and the old MCP exposes no tools or panel.
25
+
26
+ ### Optional native predictions
27
+
28
+ Native next-message predictions are **off by default** and use no MCP, Hook, skill,
29
+ panel, renderer injection, or client-program modification. This macOS-only
30
+ compatibility feature uses the App's existing composer UI and the conversation's
31
+ selected model through CCDX. Suggestions are not sent automatically. Native
32
+ eligibility rules still apply; availability is not promised for every thread type.
13
33
 
14
34
  ```bash
15
- ccdx suggestion on
16
- ccdx suggestion off
17
- ccdx suggestion model
18
- ccdx suggestion model gpt-6.1-sol
19
- ccdx suggestion status
35
+ # Fully quit Codex App first.
36
+ ccdx prediction on
37
+ # Restart the running CCDX process, then launch Codex through ccdx.
38
+ ccdx
39
+ ccdx prediction status
40
+
41
+ # To remove the optional setup, fully quit Codex first:
42
+ ccdx prediction off
20
43
  ```
21
44
 
22
- Start CCDX, enable suggestions, then open **Next message / 下一句** from a local
23
- conversation panel, or ask Codex for a next-message suggestion. **Add to draft /
24
- 加入草稿** appends ordinary text and never sends. The user still presses Send.
25
- If the MCP has not appeared in an open App, restart the App once. There is no
26
- client patch, grey ghost text, automatic draft insertion, or auto-approval.
27
- Model selection alone keeps the feature disabled. The initial model is
28
- `gpt-6-luna`; `low` reasoning is used when advertised. No service tier is forced.
29
-
30
- Settings are stored in `suggestion.json` beside CCDX's `config.json`.
31
- `CCDX_SUGGESTION_CONFIG` overrides this file path; the managed MCP sets it to
32
- the exact saved file, so normal users do not need to set it. The managed
33
- MCP is `mcp_servers.ccdx_suggestion` in the active `CODEX_HOME/config.toml` (or
34
- `~/.codex/config.toml`). Existing user-managed, inline or profile-specific entries
35
- are preserved rather than overwritten; identical enabled setup is a no-op.
36
- Native prediction settings are never changed. Official account/remote defaults
37
- currently have no reliable generic local signal, so CCDX does not promise to
38
- detect every future client default. Use `suggestion off` when preferring native
39
- predictions. An unavailable capability reports a local error, not a fallback
40
- that edits the client or sends a chat message.
41
-
42
- The MCP uses the host-supplied thread ID and the installed Codex's paginated
43
- `thread/items/list` API. It reads at most 24 recent items, retaining up to eight
44
- user/assistant text excerpts and 16,000 characters. Images, reasoning items and
45
- tool outputs are excluded; there is no transcript scan, fork or resumed turn.
46
- Recent text is sent through the local CCDX adapter to the selected Copilot model
47
- when requested manually, or after a reply through the separately reviewed optional
48
- hook described below. Provider data policies still apply.
49
- Context lookup is capped at 5 seconds/2 MiB, the operation at 30 seconds, output
50
- at 64 KiB/300 characters, concurrent work at two, and in-memory candidates at 16.
51
- Candidates expire for adoption after 10 minutes and are bound to their thread
52
- and selected model. Failure/HTTP 200 incomplete responses never become drafts.
53
- No additional retry is added by the suggestion feature. Existing adapter policies
54
- remain unchanged. App support requires MCP draft insertion; the executable can
55
- be selected explicitly with `CCDX_CODEX_BINARY` when automatic discovery fails.
56
-
57
- On supported macOS/Linux Codex runtimes, `suggestion on` also registers an
58
- asynchronous `Stop` hook. It generates after a finished reply only after the user
59
- reviews and trusts that exact `suggestion-auto.mjs` command through Codex's normal
60
- hook review screen (`/hooks` in Codex CLI). CCDX never writes hook trust or bypasses
61
- review. Existing handlers and native prediction settings are preserved. Windows,
62
- unsupported hook runtimes and conflicting hook declarations keep the manual panel.
63
- Existing 0.9.22 users can run `ccdx suggestion on` once to configure the hook.
64
-
65
- Automatic work has one local slot, a 30-second deadline, no added retries and one
66
- attempt per observed turn. It checks the latest turn before and after inference;
67
- newer turns or changed settings discard the result. The hook does not start a new
68
- turn, send a message, edit a draft or wait on the foreground reply. Enabled users
69
- incur additional selected-model usage after replies. `suggestion off` removes only
70
- the unchanged CCDX hook and disables both automatic and manual requests.
71
-
72
- Only the candidate and generation metadata are saved locally in `suggestion-state`
73
- beside settings, with at most 32 entries. Candidates expire for adoption after ten
74
- minutes; stale files are pruned on the next automatic operation. No context excerpts
75
- are saved there. The loopback dashboard reads settings and safe recent status only;
76
- it does not invoke a model or confirm hook trust. Refresh it after changing settings.
77
- Opening Next message reads a current cached candidate without a second model call.
78
- The user must still choose **Add to draft**, then Send. Closed panels cannot access
79
- the composer, and the host exposes no atomic empty-draft insertion; automatic
80
- draft filling is therefore intentionally unavailable.
45
+ Enabling explicitly adds a private certificate trust record to the selected App
46
+ profile and a process-scoped PAC route for `chatgpt.com` and `ab.chatgpt.com` only.
47
+ HTTPS traffic for **all paths on those two hosts** is decrypted and forwarded
48
+ locally; PAC cannot select HTTPS paths before TLS. Only the bootstrap prediction
49
+ flag, prediction configuration, and corresponding Statsig refresh values are
50
+ overlaid. Other paths preserve upstream status, cookies, streaming and WebSocket
51
+ traffic. Upstream TLS verification stays enabled; no OS trust, global proxy, login,
52
+ account identity or account-permission value is rewritten. Credentials are not
53
+ logged or persisted by the bridge. The local private key has owner-only permissions;
54
+ its signing key is discarded after certificate creation.
55
+
56
+ Static proxy settings are composed with the local bridge. For HTTPS targets,
57
+ `https_proxy` takes precedence over `HTTPS_PROXY`, then `all_proxy`/`ALL_PROXY`,
58
+ then the macOS HTTPS proxy or SOCKS proxy. HTTP targets follow their corresponding
59
+ HTTP setting. An HTTP-only environment proxy is not used for HTTPS. HTTP CONNECT,
60
+ TLS to an HTTPS proxy, SOCKS5 (including username/password), `NO_PROXY`/`no_proxy`,
61
+ system exceptions and simple-host exclusions are supported. Proxy credentials
62
+ remain in memory, are never included in PAC responses or diagnostics, and are
63
+ sent only to the proxy. TLS verification remains enabled for both proxy and target.
64
+ Other App domains keep the resolved original route; if a bridge fails, its PAC
65
+ fallback uses that route rather than adding an unrequested direct connection.
66
+ Route selection is a startup snapshot; restart CCDX and Codex after changing it.
67
+ Bypass lists support host/domain patterns and optional ports. Unsupported CIDR
68
+ notation is reported explicitly rather than silently changing the route.
69
+
70
+ Dynamic PAC/WPAD is not executed or overwritten. Setup identifies the exact
71
+ system setting and preserves its rules. A non-default `CODEX_API_BASE_URL` is
72
+ also preserved and reported as a custom-route conflict; setting it to the normal
73
+ `https://chatgpt.com/backend-api` does not cause a conflict. No automatic direct
74
+ fallback after upstream-proxy rejection is added. The default App profile
75
+ is `~/Library/Application Support/Codex`; an explicit
76
+ `CODEX_ELECTRON_USER_DATA_PATH` is respected. Quit the App before trust changes;
77
+ CCDX never kills it. The launcher uses the exact App that passed the compatibility
78
+ check. Updating the App invalidates that check: quit it and run `prediction on`
79
+ again. Unknown client/store/configuration formats are not forcibly rewritten.
80
+ These are checked compatibility boundaries, not a promise for every future App.
81
+
82
+ The bridge changes only its own prediction fields and preserves already-enabled
83
+ official prediction configuration. A missing prediction-config route can receive
84
+ CCDX's own short JSON-suggestion prompt using low reasoning effort. Authentication,
85
+ permission, rate-limit and server errors are returned unchanged. Full and live
86
+ refresh schemas are supported; delta requests ask for complete values to avoid
87
+ merging upstream checksums with locally changed fields. Configuration bodies are
88
+ bounded at 16 MiB; larger or unknown bodies pass through without an overlay.
89
+ No extra inference or bridge exists for users who leave the feature disabled.
90
+ When enabled, prediction requests consume Copilot usage; the setting does not
91
+ provide a separate prediction-model picker.
92
+
93
+ `prediction off` immediately disables new local overlays. Quit/reopen Codex to
94
+ clear its cached predictions and temporary route. If the App is still running,
95
+ trust removal is deferred; quit it and run `prediction off` again. Only the exact
96
+ owned certificate record is removed, never the whole store. Failed activation
97
+ rolls back newly added trust; certificate replacement keeps old trust until the
98
+ new preference is committed. If the bridge stops, new connections can fall back
99
+ to the original route; already-interrupted requests are not replayed. Run `ccdx`
100
+ after quitting Codex to attach a newly started bridge. `CCDX_AUTO_LAUNCH=0` keeps
101
+ automatic launch disabled and does not attach the route to a manually opened App.
102
+ Optional prediction failures never prevent the core adapter or image service from
103
+ starting. `prediction status` reports the saved preference and, when a compatible
104
+ running adapter responds, its bridge state, configuration-response observations
105
+ and bounded TLS/upstream errors. The dashboard uses the same snapshot and manual
106
+ refresh. Configuration traffic is evidence of a request reaching the bridge, not
107
+ proof of a generated/displayed candidate. Candidate visibility remains unknown;
108
+ no prompt matching, UI injection, transcript scanning or extra inference is used
109
+ to invent that status. Prediction settings are stored separately in
110
+ `~/.config/codex-copilot-dx/native-prediction/` (or under `XDG_CONFIG_HOME`).
111
+
112
+ ### Configuration ownership
113
+
114
+ Core setup, image setup/guidance, config doctor, optional history compression and
115
+ legacy prediction cleanup resolve the same `CODEX_HOME/config.toml`; absent
116
+ `CODEX_HOME`, they use `~/.codex/config.toml`. An explicit function-level file path
117
+ still takes precedence for embedders. App-profile trust is a separate location
118
+ selected by `CODEX_ELECTRON_USER_DATA_PATH`, not by `CODEX_HOME`.
119
+
120
+ CCDX-owned config mutations share an owner-recorded cross-process lock, reread
121
+ under the lock, and retain existing atomic replacement/rollback checks. User
122
+ settings updates use a separate lock for their shared JSON file; prediction
123
+ on/off uses its own settings lock. Readers take no lock and write no lock file.
124
+ Contention fails with a retry message instead of stealing a live lock. Other
125
+ applications do not participate in these locks, so snapshot conflict checks still
126
+ apply; the locks do not claim a global filesystem transaction.
81
127
 
82
128
  ### Core adapter
83
129
 
@@ -133,7 +179,7 @@ On a normal launch, CCDX:
133
179
  1. Prints the installed package version and checks for a newer npm release in the background.
134
180
  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.
135
181
  3. Loads a usable model cache or attempts a live refresh, then starts listening. A cache older than two hours refreshes in the background; a fresh cache can be used immediately. A failed refresh retains the last-known-good list when one is available.
136
- 4. Checks the startup-managed settings in `~/.codex/config.toml`, including the local `/v1` endpoint.
182
+ 4. Checks the startup-managed settings in `CODEX_HOME/config.toml` (default `~/.codex/config.toml`), including the local `/v1` endpoint.
137
183
  5. Attempts to open Codex App on macOS unless `CCDX_AUTO_LAUNCH` disables it.
138
184
 
139
185
  The `OPENAI_API_KEY=dummy` value used in 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.
@@ -148,7 +194,7 @@ If a compatible adapter is already running, a later launch reuses it and checks
148
194
 
149
195
  ### Codex configuration writes
150
196
 
151
- Normal startup and reuse of an existing adapter check `~/.codex/config.toml` once, after startup prerequisites succeed. There is no file watcher or periodic configuration rewrite. The path is based on the OS home directory; CCDX does not redirect it through `CODEX_HOME` or edit project-level Codex files.
197
+ Normal startup and reuse of an existing adapter check `CODEX_HOME/config.toml` (default `~/.codex/config.toml`) once, after startup prerequisites succeed. There is no file watcher or periodic configuration rewrite. Startup, image setup, config doctor, compression and legacy prediction cleanup share this path. CCDX does not edit project-level Codex files.
152
198
 
153
199
  | Setting | Existing file | New file |
154
200
  | --- | --- | --- |
@@ -310,7 +356,14 @@ ccdx update npm
310
356
  ccdx update github
311
357
  ```
312
358
 
313
- Normal startup checks the latest stable GitHub Release once in the background, without accessing the npm registry. The anonymous check requires no PAT or Copilot credentials, has a two-second deadline and a bounded response body, and silently skips network errors, rate limits and invalid metadata. It never falls back to npm, retries, polls, installs an update or restarts the service. When a newer release is found, it prints the versions and `ccdx update github`. On adapter reuse, Ready is displayed before waiting for any remaining check budget so the short-lived command does not lose its notification.
359
+ Normal startup checks the official GitHub `releases/latest` web endpoint once in
360
+ the background, without accessing the npm registry or REST API. The anonymous
361
+ check requires no PAT or Copilot credentials, has a two-second deadline, validates
362
+ only the redirect header, cancels the response body without reading HTML, and
363
+ silently skips errors. Redirects must use HTTPS, the exact GitHub repository and
364
+ a stable version tag with no credentials, query or fragment. It never follows
365
+ the redirect, retries, polls, installs or restarts. On adapter reuse, Ready is
366
+ displayed before waiting for any remaining check budget.
314
367
 
315
368
  `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 queries the latest stable published Release (ten-second deadline), validates its version tag, and installs that exact tag from `DaleXiao/codex-copilot-dx`, not `main`. Lookup failure stops before installation, without an npm fallback. It opts in to Git fetching only for that command and does not change npm's persistent `allow-git` setting.
316
369
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-copilot-dx",
3
- "version": "0.9.23",
3
+ "version": "0.9.25",
4
4
  "description": "Use Codex App with GitHub Copilot",
5
5
  "author": "Dale Xiao",
6
6
  "type": "module",
@@ -15,7 +15,8 @@
15
15
  "scripts/benchmark-probes.mjs",
16
16
  "scripts/fixtures/",
17
17
  "README.md",
18
- "docs/REFERENCE.md"
18
+ "docs/REFERENCE.md",
19
+ "docs/ARCHITECTURE.md"
19
20
  ],
20
21
  "keywords": [
21
22
  "codex",
package/src/adapter.mjs CHANGED
@@ -64,7 +64,7 @@ export {
64
64
 
65
65
  const ADAPTER_RUNTIME_CONFIG = loadRuntimeConfig();
66
66
  const DASHBOARD_PATHS = new Set(["/", "/ui.css", "/theme.js", "/language.js", "/ui.js"]);
67
- const DASHBOARD_API_PATHS = new Set(["/_ccdx/ui/animation", "/_ccdx/ui/models/live", "/_ccdx/ui/usage", "/_ccdx/ui/auth", "/_ccdx/ui/suggestion"]);
67
+ const DASHBOARD_API_PATHS = new Set(["/_ccdx/ui/animation", "/_ccdx/ui/models/live", "/_ccdx/ui/usage", "/_ccdx/ui/auth"]);
68
68
 
69
69
  export function requestPath(reqUrl) {
70
70
  return new URL(reqUrl || "/", "http://localhost").pathname;
@@ -236,13 +236,16 @@ export function createAdapterHandler(options = {}) {
236
236
  codexClient,
237
237
  codexModelRegistry,
238
238
  codexModelCatalog,
239
+ clientIntegrations: options.clientIntegrationSnapshot?.(),
239
240
  })));
240
241
  return;
241
242
  }
242
243
 
243
244
  if (req.method === "GET" && pathname === ADAPTER_HEALTH_PATH) {
244
245
  res.writeHead(200, { "Content-Type": "application/json" });
245
- res.end(JSON.stringify(adapterHealthPayload()));
246
+ const predictionPac = isLoopbackAddress(req.socket?.remoteAddress) && isLoopbackHostHeader(req.headers?.host)
247
+ ? options.nativePredictionPac?.() : null;
248
+ res.end(JSON.stringify({ ...adapterHealthPayload(), ...(predictionPac ? { native_prediction_pac: predictionPac } : {}) }));
246
249
  return;
247
250
  }
248
251