@oneciel-ai/ciel-runtime 0.2.27 → 0.2.28

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
@@ -3,6 +3,17 @@
3
3
  This file records stable Ciel Runtime releases. Changes are grouped by user-visible
4
4
  capability, followed by the complete commit ledger merged into each release.
5
5
 
6
+ ## 0.2.28 — 2026-08-24
7
+
8
+ - Replaced manual `zcode://` callback pasting in the Z.AI authorization-code
9
+ fallback with a one-shot, state-bound listener at
10
+ `http://localhost:9899/callback`.
11
+ - Validate the exact callback host, port, path, and state before token exchange;
12
+ reject occupied ports, unrelated paths, oversized request targets, and stale
13
+ callbacks without changing the stored credential.
14
+ - Use the same localhost redirect URI for authorization and token exchange, and
15
+ return a secret-free browser completion page.
16
+
6
17
  ## 0.2.27 — 2026-08-24
7
18
 
8
19
  - Repair Codex startup only when an invalid TOML file contains equivalent MCP
@@ -87,7 +87,7 @@ OPENCODE_ENDPOINT_ALIASES = {
87
87
  }
88
88
 
89
89
  APP_NAME = "Ciel Runtime"
90
- VERSION = "0.2.27"
90
+ VERSION = "0.2.28"
91
91
  CREDITS = "Credits: One Ciel LLC"
92
92
  PRELAUNCH_CANCEL = 10
93
93
  PRELAUNCH_LAUNCH_CODEX = 11
@@ -19,11 +19,16 @@ from dataclasses import dataclass
19
19
  from datetime import datetime, timezone
20
20
  from typing import Any, Callable, Mapping
21
21
 
22
+ from .zai_oauth_callback import (
23
+ ZAI_OAUTH_CALLBACK_REDIRECT_URI,
24
+ ZaiOAuthLocalCallbackReceiver,
25
+ )
26
+
22
27
 
23
28
  ZCODE_OAUTH_BASE_URL = "https://zcode.z.ai/api/v1"
24
29
  ZAI_AUTHORIZE_ENDPOINT = "https://chat.z.ai/api/oauth/authorize"
25
30
  ZAI_OAUTH_CLIENT_ID = "client_P8X5CMWmlaRO9gyO-KSqtg"
26
- ZAI_OAUTH_REDIRECT_URI = "zcode://zai-auth/callback"
31
+ ZAI_OAUTH_REDIRECT_URI = ZAI_OAUTH_CALLBACK_REDIRECT_URI
27
32
  ZAI_BUSINESS_BASE_URL = "https://api.z.ai"
28
33
  ZAI_OAUTH_PROVIDER = "zai"
29
34
  ZAI_CODING_PLAN_KEY_NAME = "zcode-api-key"
@@ -129,24 +134,42 @@ class ZaiOAuthClient:
129
134
  return data
130
135
 
131
136
  @staticmethod
132
- def authorize_url(state: str) -> str:
137
+ def authorize_url(state: str, redirect_uri: str = ZAI_OAUTH_REDIRECT_URI) -> str:
133
138
  query = urllib.parse.urlencode(
134
139
  {
135
140
  "client_id": ZAI_OAUTH_CLIENT_ID,
136
- "redirect_uri": ZAI_OAUTH_REDIRECT_URI,
141
+ "redirect_uri": redirect_uri,
137
142
  "response_type": "code",
138
143
  "state": state,
139
144
  }
140
145
  )
141
146
  return f"{ZAI_AUTHORIZE_ENDPOINT}?{query}"
142
147
 
143
- def exchange_callback(self, callback_url: str, expected_state: str) -> Mapping[str, Any]:
148
+ def exchange_callback(
149
+ self,
150
+ callback_url: str,
151
+ expected_state: str,
152
+ redirect_uri: str = ZAI_OAUTH_REDIRECT_URI,
153
+ ) -> Mapping[str, Any]:
144
154
  try:
145
155
  parsed = urllib.parse.urlparse(callback_url.strip())
146
156
  except ValueError as exc:
147
157
  raise ZaiOAuthError("Z.AI returned an invalid OAuth callback URL.") from exc
148
158
  path = f"/{parsed.path.strip('/')}"
149
- if parsed.scheme != "zcode" or parsed.netloc != "zai-auth" or path != "/callback":
159
+ try:
160
+ expected = urllib.parse.urlparse(redirect_uri)
161
+ callback_target_matches = (
162
+ parsed.scheme.lower() == expected.scheme.lower()
163
+ and (parsed.hostname or "").lower() == (expected.hostname or "").lower()
164
+ and parsed.port == expected.port
165
+ and path == f"/{expected.path.strip('/')}"
166
+ and not parsed.username
167
+ and not parsed.password
168
+ and not parsed.fragment
169
+ )
170
+ except ValueError:
171
+ callback_target_matches = False
172
+ if not callback_target_matches:
150
173
  if (
151
174
  parsed.scheme == "https"
152
175
  and parsed.hostname == "chat.z.ai"
@@ -154,7 +177,7 @@ class ZaiOAuthClient:
154
177
  ):
155
178
  raise ZaiOAuthError(
156
179
  "The pasted URL is the authorization page, not the completed callback. "
157
- "Finish authorization and paste the complete zcode://zai-auth/callback URL."
180
+ "Finish authorization in the browser and wait for the localhost callback."
158
181
  )
159
182
  raise ZaiOAuthError("Z.AI returned an unexpected OAuth callback target.")
160
183
  query = urllib.parse.parse_qs(parsed.query)
@@ -175,7 +198,7 @@ class ZaiOAuthClient:
175
198
  body={
176
199
  "provider": ZAI_OAUTH_PROVIDER,
177
200
  "code": code,
178
- "redirect_uri": ZAI_OAUTH_REDIRECT_URI,
201
+ "redirect_uri": redirect_uri,
179
202
  "state": state,
180
203
  },
181
204
  )
@@ -310,7 +333,7 @@ class ZaiOAuthService:
310
333
  now: Callable[[], float] = time.time
311
334
  sleep: Callable[[float], None] = time.sleep
312
335
  open_url: Callable[[str], bool] = webbrowser.open
313
- read_callback: Callable[[str], str] = input
336
+ callback_receiver_factory: Callable[[str, float], Any] = ZaiOAuthLocalCallbackReceiver
314
337
  random_token: Callable[[], str] = lambda: secrets.token_hex(32)
315
338
  timeout_seconds: float = ZAI_OAUTH_TIMEOUT_SECONDS
316
339
 
@@ -347,23 +370,23 @@ class ZaiOAuthService:
347
370
  no_browser: bool,
348
371
  on_authorize_url: Callable[[str], None],
349
372
  ) -> ZaiOAuthResult:
350
- authorize_url = self.client.authorize_url(state)
351
- on_authorize_url(authorize_url)
352
- if not no_browser:
353
- self.open_url(authorize_url)
354
373
  try:
355
- callback_url = self.read_callback(
356
- "Paste the complete zcode://zai-auth/callback URL here: "
357
- ).strip()
358
- except (EOFError, KeyboardInterrupt) as exc:
359
- raise ZaiOAuthError(
360
- "Z.AI OAuth callback URL was not provided; login was not changed."
361
- ) from exc
362
- if not callback_url:
363
- raise ZaiOAuthError(
364
- "Z.AI OAuth callback URL was not provided; login was not changed."
374
+ with self.callback_receiver_factory(state, self.timeout_seconds) as receiver:
375
+ redirect_uri = receiver.redirect_uri
376
+ authorize_url = self.client.authorize_url(state, redirect_uri)
377
+ on_authorize_url(authorize_url)
378
+ if not no_browser:
379
+ self.open_url(authorize_url)
380
+ callback_url = receiver.wait()
381
+ except RuntimeError as exc:
382
+ raise ZaiOAuthError(str(exc)) from exc
383
+ return self._resolve_result(
384
+ self.client.exchange_callback(
385
+ callback_url,
386
+ state,
387
+ redirect_uri=redirect_uri,
365
388
  )
366
- return self._resolve_result(self.client.exchange_callback(callback_url, state))
389
+ )
367
390
 
368
391
  def _resolve_result(self, result: Mapping[str, Any]) -> ZaiOAuthResult:
369
392
  zai = result.get("zai")
@@ -0,0 +1,157 @@
1
+ """Loopback callback receiver for the Z.AI authorization-code flow."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hmac
6
+ import socket
7
+ import threading
8
+ import urllib.parse
9
+ from dataclasses import dataclass, field
10
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
11
+
12
+
13
+ ZAI_OAUTH_CALLBACK_HOST = "127.0.0.1"
14
+ ZAI_OAUTH_CALLBACK_PUBLIC_HOST = "localhost"
15
+ ZAI_OAUTH_CALLBACK_PORT = 9899
16
+ ZAI_OAUTH_CALLBACK_PATH = "/callback"
17
+ ZAI_OAUTH_CALLBACK_REDIRECT_URI = "http://localhost:9899/callback"
18
+ _MAX_REQUEST_TARGET_BYTES = 8_192
19
+
20
+
21
+ class _ExclusiveThreadingHTTPServer(ThreadingHTTPServer):
22
+ allow_reuse_address = False
23
+ daemon_threads = True
24
+
25
+ def server_bind(self) -> None:
26
+ if hasattr(socket, "SO_EXCLUSIVEADDRUSE"):
27
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
28
+ super().server_bind()
29
+
30
+
31
+ @dataclass(slots=True)
32
+ class ZaiOAuthLocalCallbackReceiver:
33
+ """Receive one state-bound OAuth callback on a loopback-only HTTP server."""
34
+
35
+ expected_state: str
36
+ timeout_seconds: float
37
+ host: str = ZAI_OAUTH_CALLBACK_HOST
38
+ port: int = ZAI_OAUTH_CALLBACK_PORT
39
+ public_host: str = ZAI_OAUTH_CALLBACK_PUBLIC_HOST
40
+ path: str = ZAI_OAUTH_CALLBACK_PATH
41
+ _server: _ExclusiveThreadingHTTPServer | None = field(default=None, init=False)
42
+ _thread: threading.Thread | None = field(default=None, init=False)
43
+ _callback_url: str = field(default="", init=False)
44
+ _callback_ready: threading.Event = field(default_factory=threading.Event, init=False)
45
+ _callback_lock: threading.Lock = field(default_factory=threading.Lock, init=False)
46
+
47
+ @property
48
+ def redirect_uri(self) -> str:
49
+ port = self._server.server_port if self._server is not None else self.port
50
+ return f"http://{self.public_host}:{port}{self.path}"
51
+
52
+ def __enter__(self) -> ZaiOAuthLocalCallbackReceiver:
53
+ receiver = self
54
+
55
+ class CallbackHandler(BaseHTTPRequestHandler):
56
+ def do_GET(self) -> None: # noqa: N802 - BaseHTTPRequestHandler contract
57
+ receiver._handle_get(self)
58
+
59
+ def log_message(self, _format: str, *_args: object) -> None:
60
+ return
61
+
62
+ try:
63
+ self._server = _ExclusiveThreadingHTTPServer((self.host, self.port), CallbackHandler)
64
+ except OSError as exc:
65
+ raise RuntimeError(
66
+ f"Z.AI OAuth callback listener could not bind to {self.host}:{self.port}."
67
+ ) from exc
68
+ self._thread = threading.Thread(
69
+ target=self._server.serve_forever,
70
+ kwargs={"poll_interval": 0.05},
71
+ name="ciel-zai-oauth-callback",
72
+ daemon=True,
73
+ )
74
+ self._thread.start()
75
+ return self
76
+
77
+ def __exit__(self, _exc_type: object, _exc: object, _traceback: object) -> None:
78
+ server, thread = self._server, self._thread
79
+ if server is not None:
80
+ server.shutdown()
81
+ server.server_close()
82
+ if thread is not None:
83
+ thread.join(timeout=2.0)
84
+ self._server = None
85
+ self._thread = None
86
+
87
+ def wait(self) -> str:
88
+ if self._server is None:
89
+ raise RuntimeError("Z.AI OAuth callback listener was not started.")
90
+ if not self._callback_ready.wait(max(0.0, self.timeout_seconds)):
91
+ raise RuntimeError(
92
+ f"Z.AI OAuth localhost callback timed out after {int(self.timeout_seconds)} seconds."
93
+ )
94
+ with self._callback_lock:
95
+ callback_url = self._callback_url
96
+ if not callback_url:
97
+ raise RuntimeError("Z.AI OAuth localhost callback was empty.")
98
+ return callback_url
99
+
100
+ def _handle_get(self, handler: BaseHTTPRequestHandler) -> None:
101
+ if len(handler.path.encode("utf-8", errors="ignore")) > _MAX_REQUEST_TARGET_BYTES:
102
+ self._respond(handler, 414, "OAuth callback request was too large.")
103
+ return
104
+ try:
105
+ parsed = urllib.parse.urlsplit(handler.path)
106
+ query = urllib.parse.parse_qs(parsed.query, keep_blank_values=True)
107
+ except ValueError:
108
+ self._respond(handler, 400, "Invalid OAuth callback request.")
109
+ return
110
+ if parsed.path != self.path:
111
+ self._respond(handler, 404, "OAuth callback path was not found.")
112
+ return
113
+ state = str((query.get("state") or [""])[0])
114
+ if not state or not hmac.compare_digest(state, self.expected_state):
115
+ self._respond(handler, 400, "OAuth callback state did not match.")
116
+ return
117
+ with self._callback_lock:
118
+ if self._callback_url:
119
+ self._respond(handler, 409, "OAuth callback was already received.")
120
+ return
121
+ self._callback_url = (
122
+ f"{self.redirect_uri}?{parsed.query}" if parsed.query else self.redirect_uri
123
+ )
124
+ self._respond(
125
+ handler,
126
+ 200,
127
+ "Z.AI authorization received. You may close this tab and return to Ciel Runtime.",
128
+ )
129
+ self._callback_ready.set()
130
+
131
+ @staticmethod
132
+ def _respond(handler: BaseHTTPRequestHandler, status: int, message: str) -> None:
133
+ body = (
134
+ "<!doctype html><meta charset=\"utf-8\"><title>Ciel Runtime OAuth</title>"
135
+ f"<p>{message}</p>"
136
+ ).encode("utf-8")
137
+ handler.send_response(status)
138
+ handler.send_header("Content-Type", "text/html; charset=utf-8")
139
+ handler.send_header("Content-Length", str(len(body)))
140
+ handler.send_header("Cache-Control", "no-store")
141
+ handler.send_header("Connection", "close")
142
+ handler.end_headers()
143
+ handler.close_connection = True
144
+ try:
145
+ handler.wfile.write(body)
146
+ except (BrokenPipeError, ConnectionResetError):
147
+ pass
148
+
149
+
150
+ __all__ = [
151
+ "ZAI_OAUTH_CALLBACK_HOST",
152
+ "ZAI_OAUTH_CALLBACK_PATH",
153
+ "ZAI_OAUTH_CALLBACK_PORT",
154
+ "ZAI_OAUTH_CALLBACK_PUBLIC_HOST",
155
+ "ZAI_OAUTH_CALLBACK_REDIRECT_URI",
156
+ "ZaiOAuthLocalCallbackReceiver",
157
+ ]
@@ -120,10 +120,13 @@ ciel-runtimectl zai-oauth logout
120
120
 
121
121
  ZCode CLI의 Z.AI init/poll OAuth 흐름으로 로그인하고 Coding Plan API key를
122
122
  발급한다. init endpoint가 404이면 공개 ZCode 래퍼와 동일한 authorization-code
123
- 계약으로 전환하며, 터미널에 완전한 `zcode://zai-auth/callback` URL을 붙여 넣어
124
- 완료한다. `--no-browser`는 브라우저를 자동으로 열지 않는다. Ciel은 OAuth access
125
- token이나 ZCode JWT를 디스크에 저장하지 않는다. `logout`은 OAuth로 만든 로컬
126
- API key만 지우며 원격 승인을 철회하지 않는다.
123
+ 계약으로 전환하며, `http://localhost:9899/callback`의 일회성 loopback listener가
124
+ 브라우저 콜백을 자동으로 수신한다. `--no-browser`는 브라우저를 자동으로 열지
125
+ 않지만 동일한 listener에서 기다린다. 브라우저와 Ciel Runtime이 서로 다른
126
+ 머신이면 먼저 `ssh -L 9899:127.0.0.1:9899 user@runtime-host`처럼 callback port를
127
+ 전달해야 한다. Ciel은 OAuth access token이나 ZCode JWT를 디스크에 저장하지
128
+ 않는다. `logout`은 OAuth로 만든 로컬 API key만 지우며 원격 승인을 철회하지
129
+ 않는다.
127
130
 
128
131
  #### `api-key`
129
132
  ```bash
package/docs/Providers.md CHANGED
@@ -183,7 +183,7 @@ Anthropic thinking 객체나 문서로 확인되지 않은 GLM-5.2 effort 문자
183
183
 
184
184
  - GLM 시리즈 모델 제공.
185
185
  - 기본 모델: `glm-5.3[1m]`
186
- - ZCode CLI의 init/poll 및 authorization-code fallback OAuth 흐름: `ciel-runtimectl zai-oauth login`
186
+ - ZCode CLI의 init/poll 및 localhost:9899 authorization-code fallback OAuth 흐름: `ciel-runtimectl zai-oauth login`
187
187
  - OAuth access token과 ZCode JWT는 메모리에만 유지하고, 최종 Coding Plan API key만 기존 Ciel credential 규칙으로 저장한다.
188
188
  - GLM-5.3은 reasoning을 끌 수 없으며 `low`, `high`, `max` effort만 사용한다.
189
189
  - Managed MCP 서버 포함: `web-search-prime`, `web-reader`, `zread`
@@ -6,7 +6,7 @@ knowledge:
6
6
  objective: >-
7
7
  Restore Kevin's Codex startup and prevent Mia's Z.AI OAuth callback input
8
8
  error from terminating the Ciel prelaunch interface.
9
- status: validation-in-progress
9
+ status: complete
10
10
 
11
11
  evidence:
12
12
  kevin:
@@ -23,6 +23,11 @@ knowledge:
23
23
  toml_valid: true
24
24
  codex_mcp_list_exit: 0
25
25
  ciel_runtime_codex_version_exit: 0
26
+ nightly_installed: 0.2.27-nightly.20260824-061806.8e24b2e
27
+ post_install_observation: >-
28
+ The first Ciel-routed Codex version probe encountered a transient router
29
+ port claim failure on 8802. The listener was absent immediately after the
30
+ failure, and the identical probe then exited 0 with codex-cli 0.149.1.
26
31
  backup: /home/kevin-codex/.codex/config.toml.ciel-repair-20260824T0555Z.bak
27
32
  attribution: >-
28
33
  The config and AI-Net managed artifacts were written in the same second,
@@ -33,6 +38,10 @@ knowledge:
33
38
  source_behavior: >-
34
39
  ZaiOAuthClient rejected the target with ZaiOAuthError and the prelaunch
35
40
  API-key panel invoked the action without a RuntimeError boundary.
41
+ nightly_installed: 0.2.27-nightly.20260824-061806.8e24b2e
42
+ installed_guard_probe:
43
+ exit: 0
44
+ result: authorize page rejected with completed callback guidance
36
45
 
37
46
  implementation:
38
47
  codex_preflight:
@@ -64,6 +73,10 @@ knowledge:
64
73
  - npm package dry run for version 0.2.27
65
74
  - local install reports ciel-runtime 0.2.27
66
75
  - local Ciel-routed Codex version exit 0
67
- pending:
68
- - main and nightly publication
69
- - Kevin and Mia nightly installation verification
76
+ - npm latest reports 0.2.27
77
+ - npm nightly reports 0.2.27-nightly.20260824-061806.8e24b2e
78
+ - registry-installed nightly execution reports ciel-runtime 0.2.27
79
+ - main CI and npm publication workflows succeeded
80
+ - nightly CI and npm publication workflows succeeded
81
+ - Kevin nightly installation and Ciel-routed Codex version probe exited 0
82
+ - Mia nightly installation and installed OAuth guard probe exited 0
@@ -0,0 +1,74 @@
1
+ okf_version: "1.0"
2
+ knowledge:
3
+ task:
4
+ id: mia-zai-oauth-state-mismatch-20260824
5
+ date: "2026-08-24"
6
+ objective: >-
7
+ Diagnose Mia's Z.AI OAuth state mismatch without weakening the OAuth
8
+ request-to-callback binding.
9
+ status: diagnosis-complete
10
+
11
+ evidence:
12
+ supplied_values:
13
+ authorization_state_length: 64
14
+ callback_state_length: 64
15
+ states_equal: false
16
+ secrets_recorded: false
17
+ installed_runtime:
18
+ host: mia@100.95.132.58
19
+ version: 0.2.27-nightly.20260824-061806.8e24b2e
20
+ ciel_source:
21
+ comparison: hmac.compare_digest(callback_state, expected_state)
22
+ token_exchange_before_mismatch: false
23
+ zcode_source:
24
+ repository: https://github.com/kingsword09/zcode-cli.git
25
+ revision: ce2dcfbdeee3e5cca54095fbe1191fb2d03c10db
26
+ behavior: rejects callbacks whose state differs from the active login state
27
+ live_provider_probe:
28
+ initial_endpoint_status: 307
29
+ redirect_target: /auth
30
+ state_preserved: true
31
+ browser_authorization_page_state_preserved: true
32
+ mia_recovery_flow:
33
+ oauth_status: connected
34
+ stale_waiting_process: terminated
35
+ expected_callback: complete callback URL from the same authorization flow
36
+ localhost_callback_test:
37
+ redirect_uri: http://localhost:9899/callback
38
+ provider_accepted_redirect_uri: true
39
+ callback_received: true
40
+ authorization_code_present: true
41
+ state_match: true
42
+ authorization_code_recorded: false
43
+ post_login_provider_test:
44
+ ciel_route:
45
+ endpoint: https://api.z.ai/api/anthropic
46
+ model: glm-5.3
47
+ status: 429
48
+ provider_code: "1113"
49
+ provider_message: Insufficient balance or no resource package
50
+ official_zcode_direct:
51
+ client: zcode-app-cli 3.8.1-15
52
+ runtime: 0.16.3
53
+ endpoint: https://api.z.ai/api/anthropic
54
+ model: glm-5.3
55
+ same_oauth_resolved_key: true
56
+ status: 429
57
+ provider_code: "1113"
58
+ provider_message: Insufficient balance or no resource package
59
+
60
+ conclusion:
61
+ confirmed: >-
62
+ The callback supplied by the user was not bound to the active authorization
63
+ request. Accepting it would bypass the OAuth CSRF state check and is not a
64
+ valid fix.
65
+ code_change_required: false
66
+ provider_model: >-
67
+ Z.AI Direct API and Z.AI Coding Plan are distinct credential and
68
+ entitlement profiles. ZCode remains a client, not the upstream provider.
69
+ retry_cause_excluded:
70
+ - Ciel Runtime User-Agent difference
71
+ - Ciel Runtime request-shape difference
72
+ unresolved_external_state: >-
73
+ The OAuth-resolved Coding Plan key has no usable resource package on the
74
+ upstream account according to provider code 1113.
@@ -0,0 +1,70 @@
1
+ okf_version: "1.0"
2
+ knowledge:
3
+ task:
4
+ id: zai-localhost-oauth-callback-20260824
5
+ date: "2026-08-24"
6
+ objective: >-
7
+ Replace manual Z.AI custom-scheme callback entry with an automatic,
8
+ state-bound localhost OAuth callback receiver.
9
+ status: verified
10
+
11
+ requirements:
12
+ redirect_uri: http://localhost:9899/callback
13
+ bind_address: 127.0.0.1
14
+ automatic_browser_callback: true
15
+ preserve_state_validation: true
16
+ token_exchange_redirect_must_match: true
17
+
18
+ implementation:
19
+ receiver: ciel_runtime_support/zai_oauth_callback.py
20
+ integration: ciel_runtime_support/zai_oauth.py
21
+ lifecycle:
22
+ - bind listener before presenting the authorization URL
23
+ - accept only the configured path and matching state
24
+ - return a secret-free browser completion page
25
+ - exchange the callback using the same redirect URI
26
+ - close the one-shot listener after success or timeout
27
+ remote_runtime: >-
28
+ Forward local port 9899 to runtime-host 127.0.0.1:9899 when the browser
29
+ and Ciel Runtime run on different machines.
30
+
31
+ evidence:
32
+ provider_browser_probe:
33
+ redirect_uri: http://localhost:9899/callback
34
+ provider_accepted_redirect_uri: true
35
+ callback_received: true
36
+ state_match: true
37
+ authorization_code_recorded: false
38
+ authorization_plan_screen:
39
+ observed_options:
40
+ - Start Plan
41
+ - Individual Plan
42
+ - API key
43
+ endpoint_urls_verified: false
44
+ conclusion: >-
45
+ The screen proves that three authorization choices are exposed. It does
46
+ not by itself prove that three different API endpoint URLs are used.
47
+ focused_tests:
48
+ status: passed
49
+ count: 18
50
+ final_verification:
51
+ status: passed
52
+ local_install_version: 0.2.28
53
+ callback_uri: http://localhost:9899/callback
54
+ callback_http_status: 200
55
+ callback_url_exact_match: true
56
+ browser_response_contains_authorization_code: false
57
+ listener_port_released_after_completion: true
58
+ full_test_groups:
59
+ unit:
60
+ tests: 1172
61
+ skipped: 44
62
+ router:
63
+ tests: 942
64
+ channel:
65
+ tests: 381
66
+ skipped: 80
67
+ runtime:
68
+ tests: 255
69
+ skipped: 12
70
+ full_test_exit_code: 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneciel-ai/ciel-runtime",
3
- "version": "0.2.27",
3
+ "version": "0.2.28",
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",