@oneciel-ai/ciel-runtime 0.2.38 → 0.2.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ capability, followed by the complete commit ledger merged into each release.
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.2.39 — 2026-09-07
9
+
10
+ - Fix native Codex startup failing with `invalid transport` when DuckDuckGo or
11
+ web_fetch is not registered. Inspect the effective workspace configuration
12
+ before adding process-only disabling overrides; never modify global or
13
+ workspace TOML. Concurrent non-native sessions retain their MCP settings.
14
+
8
15
  ## 0.2.38 — 2026-09-07
9
16
 
10
17
  - Disable inherited DuckDuckGo and web_fetch MCP servers with per-launch
@@ -1,5 +1,10 @@
1
1
  """Launch-mode policy for Ciel-owned tools, never user MCP definitions."""
2
2
  from collections.abc import Mapping
3
+ import json
4
+ import logging
5
+ from pathlib import Path
6
+ import subprocess
7
+ from subprocess import run as run_codex_config_probe
3
8
  from typing import Any
4
9
 
5
10
 
@@ -9,14 +14,57 @@ def should_inject_tool(*, native: bool, mode: str = "always") -> bool:
9
14
  return mode == "always" or (mode == "native") == native
10
15
 
11
16
 
12
- def codex_native_web_tool_overrides(*, native: bool) -> list[str]:
17
+ def codex_native_web_tool_overrides(
18
+ *, native: bool, passthrough: list[str] | None = None,
19
+ env: dict[str, str] | None = None, cwd: Path | None = None,
20
+ codex: str = "codex",
21
+ ) -> list[str]:
13
22
  """Disable inherited replacement web MCPs for this launch, not on disk."""
14
23
  if not native:
15
24
  return []
16
- return [
17
- "-c", "mcp_servers.duckduckgo.enabled=false",
18
- "-c", "mcp_servers.web_fetch.enabled=false",
19
- ]
25
+ # An enabled-only table is NOT a valid Codex MCP transport, even when
26
+ # disabled. Never manufacture such a table on a fresh installation.
27
+ # Ask the same executable to resolve its effective configuration. Merely
28
+ # scanning project TOML is unsafe: Codex can ignore untrusted projects,
29
+ # which would turn our enabled override into another transport-less table.
30
+ # `mcp list` reads configuration; it does not connect to MCP servers.
31
+ arguments = passthrough or []
32
+ configuration_args = []
33
+ index = 0
34
+ while index < len(arguments):
35
+ argument = arguments[index]
36
+ if argument == "--":
37
+ break
38
+ if argument in ("-c", "--config", "-p", "--profile", "-C", "--cd") and index + 1 < len(arguments):
39
+ configuration_args.extend([argument, arguments[index + 1]])
40
+ index += 1
41
+ elif argument.startswith(("--config=", "--profile=", "--cd=")):
42
+ configuration_args.append(argument)
43
+ index += 1
44
+ try:
45
+ completed = run_codex_config_probe(
46
+ [codex, *configuration_args, "mcp", "list", "--json"],
47
+ env=env, cwd=cwd, capture_output=True, text=True, encoding="utf-8",
48
+ errors="replace", timeout=5, check=False,
49
+ )
50
+ if completed.returncode != 0:
51
+ raise ValueError("configuration probe failed")
52
+ entries = json.loads(completed.stdout)
53
+ if not isinstance(entries, list):
54
+ raise ValueError("unexpected MCP list shape")
55
+ except (OSError, subprocess.TimeoutExpired, ValueError):
56
+ # Never print probe output: MCP configuration can contain credentials.
57
+ logging.getLogger(__name__).warning(
58
+ "Could not inspect Codex MCP configuration; skipping native web MCP overrides"
59
+ )
60
+ return []
61
+ names = {entry.get("name") for entry in entries if isinstance(entry, dict)
62
+ and isinstance(entry.get("name"), str)}
63
+ result = []
64
+ for name in ("duckduckgo", "web_fetch"):
65
+ if name in names:
66
+ result.extend(["-c", f"mcp_servers.{name}.enabled=false"])
67
+ return result
20
68
 
21
69
 
22
70
  def select_managed_tools(
@@ -97,7 +97,7 @@ OPENCODE_ENDPOINT_ALIASES = {
97
97
  }
98
98
 
99
99
  APP_NAME = "Ciel Runtime"
100
- VERSION = "0.2.38"
100
+ VERSION = "0.2.39"
101
101
  CREDITS = "Credits: One Ciel LLC"
102
102
  PRELAUNCH_CANCEL = 10
103
103
  PRELAUNCH_LAUNCH_CODEX = 11
@@ -927,7 +927,11 @@ def run_codex(
927
927
  )
928
928
  if workspace_mcp_launch is not None:
929
929
  codex_mcp_compat_args.extend(workspace_mcp_launch.codex_args)
930
- codex_mcp_compat_args.extend(codex_native_web_tool_overrides(native=native_codex_enabled(provider)))
930
+ codex_mcp_compat_args.extend(codex_native_web_tool_overrides(
931
+ native=native_codex_enabled(provider),
932
+ codex=codex,
933
+ passthrough=[*codex_passthrough, *codex_mcp_compat_args], env=env, cwd=launch_cwd,
934
+ ))
931
935
  codex_yolo_args = codex_yolo_launch_args(codex_passthrough)
932
936
  if not use_native_codex and not use_codex_routed:
933
937
  env[CODEX_RUNTIME_API_KEY_ENV] = env.get(CODEX_RUNTIME_API_KEY_ENV) or "ciel-runtime-router-local-key"
@@ -1260,7 +1264,11 @@ def run_codex_app_server(
1260
1264
  try:
1261
1265
  if workspace_mcp_launch is not None:
1262
1266
  codex_mcp_compat_args.extend(workspace_mcp_launch.codex_args)
1263
- codex_mcp_compat_args.extend(codex_native_web_tool_overrides(native=native_codex_enabled(provider)))
1267
+ codex_mcp_compat_args.extend(codex_native_web_tool_overrides(
1268
+ native=native_codex_enabled(provider),
1269
+ codex=codex,
1270
+ passthrough=[*passthrough, *config_args, *codex_mcp_compat_args], env=env, cwd=launch_cwd,
1271
+ ))
1264
1272
  config_args = [*config_args, *codex_mcp_compat_args]
1265
1273
  listen_url = codex_app_server_default_listen_url()
1266
1274
  app_server_args = codex_app_server_launch_args(
@@ -0,0 +1,39 @@
1
+ title: Codex native web MCP overrides without cross-session configuration writes
2
+ date: 2026-09-07
3
+ status: source fixed and locally verified; not installed or published
4
+ request:
5
+ symptom: Codex 0.153.4 fails with invalid transport in mcp_servers.duckduckgo.
6
+ isolation: Do not change global TOML; isolate workspace/provider sessions.
7
+ evidence:
8
+ reproduction:
9
+ environment: Real Windows codex-cli 0.153.4 with temporary empty CODEX_HOME.
10
+ arguments: -c mcp_servers.duckduckgo.enabled=false mcp list --json
11
+ exit_code: 1
12
+ stderr: "Error: failed to load bootstrap configuration; invalid transport in mcp_servers.duckduckgo"
13
+ cause: The unconditional native override creates an enabled-only server table without command or URL when the server is absent.
14
+ official_documentation: https://learn.chatgpt.com/docs/extend/mcp?surface=cli
15
+ documented_constraints: STDIO requires command; HTTP requires url; project configuration applies only to trusted projects.
16
+ implementation:
17
+ discovery: Run the same Codex executable's mcp list --json with the launch environment, cwd, and configuration arguments.
18
+ isolation: Apply enabled=false only in this process's arguments, only for servers in the effective list; no TOML writes.
19
+ workspace: Codex resolves workspace trust/configuration itself; no independent TOML parser or global edits.
20
+ native: Disable existing duckduckgo and web_fetch entries for CLI and app-server launches.
21
+ nonnative: No discovery process and no disabling overrides.
22
+ failure_policy: Five-second bounded probe; if unavailable/invalid, log a credential-free warning and skip overrides.
23
+ limitation: If discovery fails, replacement MCPs may remain enabled; this must not be described as successful suppression.
24
+ verification:
25
+ real_cli_command: "$env:CIEL_TEST_CODEX_EXE='C:/Users/djlov/AppData/Local/Programs/OpenAI/Codex/bin/codex.exe'; python -m unittest discover -s tests -p test_codex_native_web_cli.py -v"
26
+ real_cli_output: "Ran 4 tests in 0.667s; OK"
27
+ real_cli_cases:
28
+ empty_home: No overrides; mcp list exits 0 instead of invalid transport.
29
+ concurrent_shared_home_different_workspaces: native false/false; nonnative true/true for duckduckgo/web_fetch.
30
+ concurrent_shared_home_same_workspace: native false/false; nonnative true/true for duckduckgo/web_fetch.
31
+ file_integrity: Shared test config SHA256 unchanged; no workspace config created by override logic.
32
+ project_configuration: Trusted and untrusted project cases match Codex's effective server list; project TOML bytes unchanged.
33
+ generated_transport: Native disabled; nonnative enabled; no MCP connection needed.
34
+ policy_tests: "python -m unittest discover -s tests -p test_managed_tool_injection.py -v: Ran 9 tests; OK"
35
+ runtime_group: "python scripts/run_test_group.py runtime: Ran 280 tests; OK (skipped=12), real CLI checks enabled"
36
+ static_checks: py_compile successful; ruff All checks passed; git diff --check clean.
37
+ boundaries:
38
+ unchanged: Real user global/project TOML, active sessions, installation, npm registry, git remotes.
39
+ tested: Configuration loading and launch argument policy, not a paid model inference or remote user's TUI.
@@ -0,0 +1,10 @@
1
+ title: Publish native Codex transport regression fix as stable 0.2.39
2
+ date: 2026-09-07
3
+ authorization: User requested continuing through main branch deployment.
4
+ version: 0.2.39
5
+ scope: Commit verified fix and version increment, push main, verify CI and npm latest package.
6
+ verification_plan:
7
+ local: Lint, isolated runtime tests, real Codex config-loader regression checks.
8
+ remote: Publish workflow runs all test groups before publishing.
9
+ artifact: Download published package and verify runtime version and fixed helper behavior.
10
+ exclusions: No user configuration edits or active session restart.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneciel-ai/ciel-runtime",
3
- "version": "0.2.38",
3
+ "version": "0.2.39",
4
4
  "description": "Universal AI coding-agent runtime and model-routing layer for Claude, Codex, AGY, ZCode, and compatible runtimes.",
5
5
  "license": "MIT",
6
6
  "author": "One Ciel LLC",