Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
cff4e77
feat(accounts): link standalone GLM Coding Plans
nwparker Oct 2, 2026
f541989
fix(accounts): retain GLM credential results during quota refresh
nwparker Oct 2, 2026
3b84874
fix(accounts): make GLM credential editing desktop-only
nwparker Oct 2, 2026
3208cdb
fix(accounts): mirror the host GLM site in paired clients
nwparker Oct 2, 2026
86076cd
fix(zcode): read the selected v2 Coding Plan credentials
nwparker Oct 2, 2026
4b7ae82
fix(zcode): bound v2 reads and reject invalid model selections
nwparker Oct 2, 2026
697284a
fix(accounts): preserve unknown GLM host credential and site details
nwparker Oct 2, 2026
8dc022e
fix(accounts): report unknown GLM host details and split web settings…
nwparker Oct 2, 2026
fbc9fe5
fix(zcode): reject malformed personal rule containers
nwparker Oct 2, 2026
356f193
test(e2e): preserve isolated home in macOS terminal shells
nwparker Oct 2, 2026
6fcbb60
feat(zcode): open upstream sign-in setup from accounts
nwparker Oct 2, 2026
e5891d0
fix(zcode): refuse unvalidated selected personal overlays
nwparker Oct 2, 2026
2424953
test(zcode): create distinct duplicate provider fixtures
nwparker Oct 2, 2026
79f31fd
Merge frozen GLM Accounts corrections into ZCode v2 stack
nwparker Oct 2, 2026
561e61e
fix(zcode): preserve raw personal config keys before refusal
nwparker Oct 2, 2026
299aab8
fix(zcode): ship required GLM account translation entries
nwparker Oct 2, 2026
ecb40ba
Merge reviewed GLM translation entries into ZCode v2 history
nwparker Oct 2, 2026
13cb1fd
merge: reconcile GLM Accounts with frozen main
nwparker Oct 2, 2026
e378fb2
chore: record GLM reconciliation hook validation
nwparker Oct 2, 2026
ce1f85a
chore: validate installed GLM commit hooks
nwparker Oct 2, 2026
e22d5a5
merge: reconcile ZCode V2 with GLM main candidate
nwparker Oct 2, 2026
38f19b0
test: complete GLM account fixtures and web API inventory
nwparker Oct 3, 2026
f5ead0e
merge: carry GLM account fixture repair into ZCode v2
nwparker Oct 3, 2026
f3adafd
Merge main 3793c58 into GLM plan integration
nwparker Oct 3, 2026
bb34682
Merge reconciled GLM f3adafd into ZCode v2 stack
nwparker Oct 3, 2026
9c65d3b
Merge pinned GLM squash b032867 into ZCode v2 stack
nwparker Oct 3, 2026
414439a
fix(zcode): preserve newer envelopes during rollback publication
nwparker Oct 3, 2026
8ae6ef1
merge: retain both bounded file readers with fixed current main
nwparker Oct 3, 2026
25b26c2
Merge fixed main into ZCode credential compatibility
nwparker Oct 3, 2026
4b11942
Fix Claude retention fixture session input
nwparker Oct 3, 2026
71a5986
Cover current publisher and legacy paired-chat fixture
nwparker Oct 3, 2026
e44878e
fix(e2e): isolate ZCode credential roots
nwparker Oct 4, 2026
feef7f7
Merge current main into ZCode credential safety integration
nwparker Oct 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/main/rate-limits/service-zcode-usage.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { cpSync, mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { readZcodeUsageCredentials } from './zcode-usage-credentials'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { ProviderRateLimits } from '../../shared/rate-limit-types'
import { RateLimitService } from './service'
Expand Down Expand Up @@ -186,4 +190,37 @@ describe('RateLimitService zcode plan credentials', () => {
expect(fetchZcodeRateLimits).toHaveBeenCalledTimes(2)
expect(state.zcode?.session?.usedPercent).toBe(10)
})
it('rejects an old CLI account result after sibling-provider waits', async () => {
const home = mkdtempSync(join(tmpdir(), 'orca-zcode-service-v2-'))
const fixtures = join(import.meta.dirname, '..', 'zcode', 'fixtures', 'v2-upstream')
vi.stubEnv('ZCODE_DATA_BASE_DIR', home)
vi.stubEnv('ZCODE_CREDENTIAL_SECRET', 'synthetic-secret')
try {
cpSync(join(fixtures, 'zai'), join(home, '.zcode', 'v2'), { recursive: true })
const selected = readZcodeUsageCredentials()
if (selected.status !== 'ok') {
throw new Error('Synthetic fixture could not be read')
}
const claude = deferred<ProviderRateLimits>()
vi.mocked(fetchClaudeRateLimits).mockImplementationOnce(() => claude.promise)
vi.mocked(fetchZcodeRateLimits).mockResolvedValueOnce({
...okProvider('zcode', 44, Date.now()),
usageMetadata: {
authProvenance: selected.credentials.authProvenance,
credentialSource: selected.source
}
})
const service = new RateLimitService()
const refreshing = service.refresh()
await vi.waitFor(() => expect(fetchZcodeRateLimits).toHaveBeenCalled())
cpSync(join(fixtures, 'zai-other'), join(home, '.zcode', 'v2'), { recursive: true })
claude.resolve(okProvider('claude', 7))
await refreshing
expect(service.getState().zcode?.status).toBe('unavailable')
expect(service.getState().zcode?.session).toBeNull()
} finally {
vi.unstubAllEnvs()
rmSync(home, { recursive: true, force: true })
}
})
})
13 changes: 12 additions & 1 deletion src/main/rate-limits/service/service-full-cycle-application.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { RateLimitServiceFullCyclePreparation } from './service-full-cycle-preparation'
import { isZcodeUsageCredentialCurrent } from '../zcode-usage-credentials'
import { settleSiblingProviderResult } from './service-sibling-provider-result'
import type { ProviderRateLimits } from './service-types'

Expand Down Expand Up @@ -202,7 +203,17 @@ export abstract class RateLimitServiceFullCycleApplication extends RateLimitServ
}
const grok = settleSiblingProviderResult('grok', grokSettled)
const cursor = settleSiblingProviderResult('cursor', cursorSettled)
const zcode = settleSiblingProviderResult('zcode', zcodeSettled)
const settledZcode = settleSiblingProviderResult('zcode', zcodeSettled)
const zcode = isZcodeUsageCredentialCurrent(settledZcode)
? settledZcode
: {
...settledZcode,
status: 'unavailable' as const,
session: null,
weekly: null,
monthly: null,
error: 'ZCode Coding Plan account changed during refresh'
}
const shouldApplyZcode = zcodeGeneration === this.zcodeFetchGeneration
const antigravity = settleSiblingProviderResult('antigravity', antigravitySettled)
// Why: the stale policy keeps a recent snapshot through a failed refresh, but
Expand Down
142 changes: 142 additions & 0 deletions src/main/rate-limits/zcode-usage-credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { createHmac, randomBytes } from 'node:crypto'
import { readFileSync } from 'node:fs'
import { join } from 'node:path'
import {
readZcodeV2PlanCredential,
localZcodeCredentialHost,
type ZcodeCredentialHost
} from '../zcode/zcode-v2-plan-credentials'
import type { ProviderRateLimits } from '../../shared/rate-limit-types'

const SUPPORTED_HOSTS = new Set(['api.z.ai', 'open.bigmodel.cn', 'dev.bigmodel.cn'])
const CREDENTIAL_IDENTITY_KEY = randomBytes(32)
export const ZCODE_PLAN_CREDENTIAL_SOURCE = 'orca-plan'
export type ZcodePlanCredential = { apiKey: string; baseUrl: string }
export type ZcodeUsageCredentials = { apiKey: string; quotaUrl: string; authProvenance: string }
export type ZcodeUsageCredentialOptions = {
configPath?: string
credentialHost?: ZcodeCredentialHost
}
export type ZcodeUsageCredentialRead =
| { status: 'unavailable' | 'error' }
| { status: 'ok'; credentials: ZcodeUsageCredentials; source: string }

function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value)
}

function readRecord(value: unknown): Record<string, unknown> | null {
return isRecord(value) ? value : null
}

function readMainProvider(model: unknown): string | null {
const name = typeof model === 'string' ? model : readRecord(model)?.main
if (typeof name !== 'string') {
return null
}
const delimiter = name.indexOf('/')
return delimiter > 0 && delimiter < name.length - 1 ? name.slice(0, delimiter) : null
}
function readCredentials(configPath: string): ZcodeUsageCredentials | null {
let config: Record<string, unknown> | null
try {
config = readRecord(JSON.parse(readFileSync(configPath, 'utf8')))
} catch {
return null
}

if (!config) {
return null
}
// A quota from another configured account must never appear as the selected model's quota.
const mainProvider = readMainProvider(config.model)
if (!mainProvider) {
return null
}
const options = readRecord(readRecord(readRecord(config.provider)?.[mainProvider])?.options)
const apiKey = options?.apiKey
const baseURL = options?.baseURL
if (
typeof apiKey !== 'string' ||
!apiKey.trim() ||
/[\r\n]/.test(apiKey) ||
typeof baseURL !== 'string'
) {
return null
}
return resolveUsageCredentials(apiKey, baseURL, mainProvider)
}

export function resolveUsageCredentials(
key: string,
baseUrl: string,
identity: string
): ZcodeUsageCredentials | null {
const apiKey = key.trim()
if (!apiKey || /[\r\n]/.test(apiKey)) {
return null
}
try {
const parsed = new URL(baseUrl)
if (
parsed.protocol !== 'https:' ||
!SUPPORTED_HOSTS.has(parsed.hostname) ||
(parsed.port !== '' && parsed.port !== '443')
) {
return null
}
return {
apiKey,
quotaUrl: `${parsed.origin}/api/monitor/usage/quota/limit`,
authProvenance: createHmac('sha256', CREDENTIAL_IDENTITY_KEY)
.update(JSON.stringify([identity, parsed.origin, apiKey]))
.digest('hex')
}
} catch {
return null
}
}

export function readZcodeUsageCredentials(
options: ZcodeUsageCredentialOptions = {}
): ZcodeUsageCredentialRead {
const host = options.credentialHost ?? localZcodeCredentialHost()
const configPath = options.configPath ?? join(host.home, '.zcode', 'cli', 'config.json')
// An explicit legacy fixture path never probes the developer's credential store.
const v2 =
options.configPath && !options.credentialHost
? { status: 'absent' as const }
: readZcodeV2PlanCredential(host)
if (v2.status === 'error') {
return { status: 'error' }
}
if (v2.status === 'unavailable') {
return { status: 'unavailable' }
}
const credentials =
v2.status === 'ok'
? resolveUsageCredentials(v2.apiKey, v2.baseUrl, v2.identity)
: readCredentials(configPath)
return credentials
? { status: 'ok', credentials, source: v2.status === 'ok' ? v2.configPath : configPath }
: { status: 'unavailable' }
}

export function hasZcodeCliPlanCredentials(configPath?: string): boolean {
return readZcodeUsageCredentials({ configPath }).status === 'ok'
}

export function isZcodeUsageCredentialCurrent(usage: ProviderRateLimits): boolean {
if (
!usage.usageMetadata?.authProvenance ||
!usage.usageMetadata.credentialSource ||
usage.usageMetadata.credentialSource === ZCODE_PLAN_CREDENTIAL_SOURCE
) {
return true
}
const current = readZcodeUsageCredentials()
return (
current.status === 'ok' &&
current.credentials.authProvenance === usage.usageMetadata.authProvenance
)
}
Loading
Loading