Skip to content

Commit 8dca421

Browse files
committed
Improved compliance
1 parent 5e27fc2 commit 8dca421

7 files changed

Lines changed: 29 additions & 21 deletions

File tree

‎config.example.yaml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ models:
5353
identity:
5454
# Mirrors process.env.ZCODE_APP_VERSION in the ZCode bundle.
5555
# Must be printable ASCII; non-conforming values fall back to the default.
56-
# Default: "3.12.3" (current ZCode release). Override to match your real client.
57-
appVersion: "3.12.3"
56+
# Default: "3.14.0" (current ZCode release). Override to match your real client.
57+
appVersion: "3.14.0"
5858
# X-Title suffix → "Z Code@{sourceTitle}". Default "cli".
5959
sourceTitle: "cli"
6060
# HTTP-Referer URL. Default "https://zcode.z.ai".

‎src/auth/oauth.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ describe("ZaiOAuthClient (server-mediated cli login)", () => {
175175
expect(interstitial).toStartWith("https://zcode.z.ai/app/oauth/login?");
176176
const inner = new URL(interstitial);
177177
expect(inner.searchParams.get("redirect")).toBe("zcode://oauth/callback");
178-
expect(inner.searchParams.get("app_version")).toBe("3.12.3");
178+
expect(inner.searchParams.get("app_version")).toBe("3.14.0");
179179
} finally {
180180
await client.close();
181181
}
@@ -256,7 +256,7 @@ describe("BigmodelPollOAuthClient (server-mediated cli login)", () => {
256256
expect(url.origin + url.pathname).toBe("https://bigmodel.cn/login");
257257
const interstitial = url.searchParams.get("redirect") ?? "";
258258
expect(interstitial).toStartWith("https://zcode.z.ai/app/oauth/login?");
259-
expect(new URL(interstitial).searchParams.get("app_version")).toBe("3.12.3");
259+
expect(new URL(interstitial).searchParams.get("app_version")).toBe("3.14.0");
260260
expect(url.searchParams.get("redirect_uri")).toBeNull();
261261
expect(started.callbackUrl).toBe("");
262262
} finally {

‎src/config/loader.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ models:
377377
const path = writeYaml(`
378378
`);
379379
const cfg = loadConfig(path);
380-
expect(cfg.identity.appVersion).toBe("3.12.3");
380+
expect(cfg.identity.appVersion).toBe("3.14.0");
381381
expect(cfg.identity.sourceTitle).toBe("cli");
382382
expect(cfg.identity.refererOrigin).toBe("https://zcode.z.ai");
383383
});
@@ -411,6 +411,6 @@ identity:
411411
appVersion: "v3.3.3-中文"
412412
`);
413413
const cfg = loadConfig(path);
414-
expect(cfg.identity.appVersion).toBe("3.12.3");
414+
expect(cfg.identity.appVersion).toBe("3.14.0");
415415
});
416416
});

‎src/config/loader.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const ENV = {
2828

2929
/** Mirrors the ZCode desktop release (`_reverse/NOTEPAD.md`); bump per client
3030
* release or User-Agent/X-ZCode-App-Version become distinguishable. */
31-
export const DEFAULT_APP_VERSION = "3.12.3";
31+
export const DEFAULT_APP_VERSION = "3.14.0";
3232

3333
const DEFAULTS = {
3434
PORT: 8080,

‎src/config/template.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ models:
6262
identity:
6363
# Mirrors process.env.ZCODE_APP_VERSION in the ZCode bundle.
6464
# Must be printable ASCII; non-conforming values fall back to the default.
65-
# Default: "3.11.2" (current ZCode release). Override to match your real client.
66-
appVersion: "3.11.2"
65+
# Default: "3.14.0" (current ZCode release). Override to match your real client.
66+
appVersion: "3.14.0"
6767
# X-Title suffix → "Z Code@{sourceTitle}". Default "cli".
6868
sourceTitle: "cli"
6969
# HTTP-Referer URL. Default "https://zcode.z.ai".

‎src/proxy/identity.test.ts‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,20 +146,22 @@ describe("buildIdentityHeaders", () => {
146146

147147
// --- New behaviour matching `pio` in the current ZCode bundle ---
148148

149-
it("emits headers in the exact `TV` order", () => {
149+
it("emits headers in the exact `TV` runtime insertion order", () => {
150150
// Clear env-gated headers so the order assertion is deterministic;
151151
// X-Client-Language/X-Client-Timezone are always present (unknown fallback).
152+
// Order = spread-base {User-Agent, HTTP-Referer, X-Title} + appended keys
153+
// (NOTEPAD §E correction — overrides keep their base positions).
152154
const savedRC = process.env.ZCODE_IDENTITY_RELEASE_CHANNEL;
153155
const savedDM = process.env.ZCODE_IDENTITY_DEVICE_MID;
154156
delete process.env.ZCODE_IDENTITY_RELEASE_CHANNEL;
155157
delete process.env.ZCODE_IDENTITY_DEVICE_MID;
156158
try {
157159
const h = buildIdentityHeaders(BASE);
158160
expect(Object.keys(h)).toEqual([
159-
"HTTP-Referer",
160161
"User-Agent",
161-
"X-ZCode-App-Version",
162+
"HTTP-Referer",
162163
"X-Title",
164+
"X-ZCode-App-Version",
163165
"X-Platform",
164166
"X-Release-Channel",
165167
"X-Client-Language",

‎src/proxy/identity.ts‎

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -156,28 +156,34 @@ export function buildLlmIdentityHeaders(id: ProxyIdentity): Record<string, strin
156156
}
157157

158158
/**
159-
* Context-shaped identity headers — mirrors the 3.12.3 host builder `TV`
159+
* Context-shaped identity headers — mirrors the host builder
160+
* `TV` (3.12.3 chunk-ZH56ETHO) / `c5` (3.14.0 chunk-WFF5YMZO) / bundle `IJt`
160161
* (buildZCodeSourceHeadersFromContext), reached via the endpoint-routing
161-
* source-headers factory (`V6n`). 3.12.3 changes vs 3.11: X-ZCode-Agent is
162-
* GONE from this plane, and language/timezone are always present with the
163-
* "unknown" fallback. Consumers: endpoint-routing.ts (source headers),
164-
* claim/client.ts, routes-quota.ts, async bridge.
162+
* source-headers factory (`V6n`). X-ZCode-Agent is GONE from this plane, and
163+
* language/timezone are always present with the "unknown" fallback. Consumers:
164+
* endpoint-routing.ts (source headers), claim/client.ts, routes-quota.ts,
165+
* async bridge.
165166
*
166-
* Order (bundle `TV`):
167-
* HTTP-Referer, User-Agent, [X-ZCode-App-Version], X-Title, [X-Platform],
167+
* Order — RUNTIME INSERTION order, not source written order (2026-09-19
168+
* correction, `_reverse/NOTEPAD.md` §E): the official builder spreads a
169+
* 3-key base first (`yE`/`cU`/`Llr` = `{"User-Agent","HTTP-Referer","X-Title"}`)
170+
* and then overrides/adds keys. JS spread semantics keep overridden keys at
171+
* their base positions, so the wire order is:
172+
* User-Agent, HTTP-Referer, X-Title, [X-ZCode-App-Version], [X-Platform],
168173
* [X-Release-Channel], X-Client-Language, X-Client-Timezone,
169174
* [X-Os-Category], [X-Os-Version], [X-Device-Mid]
175+
* (verified byte-level against both the 3.12.3 and 3.14.0 bundles/hosts).
170176
*
171177
* Returns `Record<string, string>` rather than a fixed interface because
172178
* several headers are conditionally omitted.
173179
*/
174180
export function buildIdentityHeaders(id: ProxyIdentity): Record<string, string> {
175181
const v = resolveIdentityValues(id);
176182
return {
177-
"HTTP-Referer": id.refererOrigin,
178183
"User-Agent": `ZCode/${v.n ?? "unknown"}`,
179-
...(v.n ? { "X-ZCode-App-Version": v.n } : {}),
184+
"HTTP-Referer": id.refererOrigin,
180185
"X-Title": `Z Code@${id.sourceTitle}`,
186+
...(v.n ? { "X-ZCode-App-Version": v.n } : {}),
181187
...(v.platform && v.arch ? { "X-Platform": `${v.platform}-${v.arch}` } : {}),
182188
...(v.releaseChannel ? { "X-Release-Channel": v.releaseChannel } : {}),
183189
"X-Client-Language": v.clientLanguage ?? "unknown",

0 commit comments

Comments
 (0)