@magpie-community/opencode-zcode-auth 0.1.7 → 0.1.8

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 (3) hide show
  1. package/README.md +32 -2
  2. package/index.mjs +214 -55
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -54,12 +54,42 @@ Before each request, the plugin checks which plan the account is on, and
54
54
  asks again every 10 minutes:
55
55
 
56
56
  - If the key's account has a GLM Coding Plan
57
- (`/api/biz/subscription/list`), requests go to that plan.
58
- - Otherwise they go to the Start Plan.
57
+ (`/api/biz/subscription/list`), its requests go to that plan —
58
+ except for a model the account's gift plans also serve, which goes to
59
+ the gift first (see below).
60
+ - Otherwise they go to the gift plans.
59
61
 
60
62
  Every request carries the key as both `x-api-key` and
61
63
  `Authorization: Bearer`.
62
64
 
65
+ **Spending the gift first.** An account with a GLM Coding Plan can also
66
+ hold gift plans from ZCode activities, ones that expire on a fixed date.
67
+ Their allowance would lapse unused if every request went to the coding
68
+ plan, so the plugin reads the gift's balance (per the sign-in's session,
69
+ kept for 10 minutes) and sends a request for a model the gift still has
70
+ quota to spend to the gift first, dressed as ZCode's own. A bucket is
71
+ judged spent only by its `remaining_units` — a missing one is unknown,
72
+ not spent — and a model whose every bucket says none goes straight to
73
+ the coding plan without asking. When the gift can't serve the request —
74
+ any answer 400 or over (its 405, its 401, its 5xx), or its quota error
75
+ (code 1113 "Insufficient balance or no resource package", code 1005
76
+ "exceed quota limit", which it can answer inside an HTTP 200) — the
77
+ plugin replays the request once to the coding plan, as the agent sent
78
+ it. Only a quota answer keeps that model off the gift for a minute; a
79
+ refusal that says nothing about quota is asked again next request. Every
80
+ 429 counts as spent, Z.ai's 1302/1303 rate limits among them. A stream's
81
+ body is never read or buffered on the way.
82
+
83
+ ## The usage card
84
+
85
+ An account with both plans shows both allowances: the coding plan's
86
+ windows first, then the gift's buckets, each with its own name, models
87
+ and end. The card's plan and term stay the coding plan's. A gift read
88
+ that fails leaves just the coding card — magpie hides a card's windows
89
+ behind an error, so a gift hiccup must not black out a working Coding
90
+ Plan. A gift that goes out of date while requests use it simply stops
91
+ showing.
92
+
63
93
  ## Models
64
94
 
65
95
  The models are the ones ZCode offers for the account's plan. They come
package/index.mjs CHANGED
@@ -130,48 +130,103 @@ const num = (v) => {
130
130
  return typeof n === "number" && Number.isFinite(n) ? n : undefined
131
131
  }
132
132
 
133
- // startPlan is the Start Plan the account has now ({name, until}), as
134
- // ZCode reads its balance: an "active" plan past its end is over.
133
+ // startPlan is the gift an account can spend now ({models}), as ZCode reads
134
+ // its balance: several plans can be active at once, and a model routes to
135
+ // the gift when any of them has a live bucket serving it — a bucket past
136
+ // its plan's own end, or one whose remaining_units says none, is skipped
137
+ // rather than asked and refused. models are those live buckets' names.
135
138
  async function startPlan(jwt, device) {
136
139
  if (!jwt) throw new Error("not signed in to ZCode")
137
140
  if (jwtExpired(jwt)) throw new Error(EXPIRED)
138
141
  const b = (await call("GET", `${ZCODE}/api/v1/zcode-plan/billing/balance?app_version=${APP_VERSION}`, { auth: "Bearer " + jwt, device })) ?? {}
139
142
  const now = num(b.server_time) > 0 ? num(b.server_time) : Date.now() / 1000
140
- const isStart = (x) => x.includes("start-plan") || x.includes("start plan")
141
- for (const p of b.plans ?? []) {
142
- if (String(p.status ?? "").trim().toLowerCase() !== "active") continue
143
- const end = num(p.ends_at)
144
- if (end > 0 && end <= now) continue
145
- const id = String(p.plan_id ?? "").trim().toLowerCase()
146
- const n = String(p.name ?? "").trim().toLowerCase()
147
- if ((id || n) && !isStart(id) && !isStart(n)) continue
148
- return { name: first(p.name, "Start Plan"), until: end > 0 ? end * 1000 : 0 }
143
+ const same = (x, p) => (x.user_plan_id && p.user_plan_id ? x.user_plan_id === p.user_plan_id : String(x.plan_id ?? "") === String(p.plan_id ?? ""))
144
+ const plans = Array.isArray(b.plans) ? b.plans : []
145
+ const balances = Array.isArray(b.balances) ? b.balances : []
146
+ const ms = new Set()
147
+ let any = false
148
+ let name = ""
149
+ for (const p of plans) {
150
+ const st = String(p?.status ?? "").trim().toLowerCase()
151
+ const end = num(p?.ends_at)
152
+ if (st !== "active" || (end > 0 && end <= now)) continue
153
+ any = true
154
+ if (!name) name = String(p?.name ?? "").trim()
155
+ for (const x of balances) {
156
+ if (!same(x, p)) continue
157
+ const exp = num(x.expires_at)
158
+ if (exp > 0 && exp <= now) continue
159
+ // a bucket spends when it has quota: only remaining_units says so, and
160
+ // a model whose every bucket says none drops out of models, so its
161
+ // requests go to the coding plan without first asking the gift
162
+ if ((num(x.remaining_units) ?? 1) <= 0) continue
163
+ for (const c of Array.isArray(x.capabilities) ? x.capabilities : []) {
164
+ const m = String(c ?? "").trim().replace(/^model:/, "").trim()
165
+ if (m) ms.add(m)
166
+ }
167
+ }
149
168
  }
150
- return null
169
+ return any ? { name: name || "Start Plan", models: [...ms] } : null
151
170
  }
152
171
 
153
- // onStart says whether an account's requests go to the Start Plan: when it
154
- // has ZCode's token and no coding plan key, or a key whose account has no
155
- // coding plan. Asked again after 10 minutes (a minute when unsure).
172
+ // plansOf says where an account's requests go and what more it can spend:
173
+ // {start, gift}. start is what onStart said: an account with no coding plan
174
+ // sends every request to the gift and reads no balance to do it; a team's
175
+ // seat, a sign-in with no ZCode token and a key whose plan-list read found
176
+ // no gift stay on the coding plan. gift is what a coding account also holds:
177
+ // the gift plans ({models}), and its requests spend the gift for a model it
178
+ // serves, until it says it is spent (see blocked). Asked again after 10
179
+ // minutes (a minute when unsure — a plan-list read that failed is retried
180
+ // sooner; a gift read that failed simply leaves gift null until the next
181
+ // ask).
156
182
  const routes = new Map()
157
- async function onStart(s) {
158
- if (!s.jwt || isTeam(s)) return false // a team's seat is on the team's plan
159
- if (!s.key) return true
183
+ async function plansOf(s) {
184
+ if (isTeam(s) || !s.jwt) return { start: false, gift: null }
185
+ if (!s.key) return { start: true, gift: null }
160
186
  const id = s.key + "\0" + s.jwt
161
187
  const r = routes.get(id)
162
- if (r && Date.now() - r.at < r.ttl) return r.start
188
+ if (r && Date.now() - r.at < r.ttl) return r
163
189
  let start = false
190
+ let gift = null
164
191
  let sure = false
165
192
  try {
166
- start = !(await plan(s))
193
+ if (!(await plan(s))) start = true
194
+ else gift = await startPlan(s.jwt, s.device).catch(() => null)
167
195
  sure = true
168
196
  } catch {
197
+ // the plan list could not be read: a key account takes the dual route
198
+ // (start stays false, the gift is kept, a minute's ttl), so a gift
199
+ // refusal still replays to the coding plan rather than blacking out
169
200
  try {
170
- if (await startPlan(s.jwt, s.device)) start = sure = true
201
+ gift = await startPlan(s.jwt, s.device)
202
+ sure = false
171
203
  } catch {}
172
204
  }
173
- routes.set(id, { start, at: Date.now(), ttl: sure ? 600_000 : 60_000 })
174
- return start
205
+ const out = { start, gift, at: Date.now(), ttl: sure ? 600_000 : 60_000 }
206
+ routes.set(id, out)
207
+ return out
208
+ }
209
+
210
+ // blocked remembers the models a gift said it has none left for: a key+jwt+
211
+ // model for a minute, so one turn that is refused does not ask again.
212
+ const blocked = new Map()
213
+
214
+ // giftServes: the gift's buckets name their models lowercased ("glm-5.3-
215
+ // flash"); what is asked for arrives as the plan lists it ("GLM-5.3-Flash").
216
+ const giftServes = (gift, m) => (gift.models ?? []).some((x) => x.toLowerCase() === m.toLowerCase())
217
+
218
+ // spentUp is the gift saying it has nothing left to spend: its own no-
219
+ // resource-package code 1113, its "exceed quota limit" 1005 — a spent gift
220
+ // can answer a 200 with a JSON body carrying one of those codes. Every 429
221
+ // counts as spent, Z.ai's 1302/1303 rate limits among them.
222
+ function spentUp(text, status) {
223
+ if (status === 429) return true
224
+ let b
225
+ try { b = JSON.parse(text) } catch { return false }
226
+ if (!b || typeof b !== "object") return false
227
+ const code = (v) => String(v ?? "")
228
+ const c1 = code(b.code), c2 = code(b.error?.code)
229
+ return c1 === "1113" || c1 === "1005" || c2 === "1113" || c2 === "1005"
175
230
  }
176
231
 
177
232
  // ---- keys ------------------------------------------------------------------------
@@ -366,10 +421,12 @@ function startNum(v) {
366
421
  return undefined
367
422
  }
368
423
 
369
- // startUsage is the Start Plan's allowance: a window for each of its
370
- // buckets, a model's tokens for the day or for the plan's time. A plan
371
- // still "active" past its end is over, and its buckets are left out.
372
- async function startUsage(s) {
424
+ // giftOf reads the balance and returns the gift's card fields: its plans and
425
+ // windows. Several plans can be active at once, so every live plan's buckets
426
+ // show, each keeping its own models and end; the plan and end put on the
427
+ // card (for a gift-only account) are the soonest-ending live plan's. null
428
+ // when there is no live plan to show.
429
+ async function giftOf(s) {
373
430
  if (!s.jwt) throw new Error("not signed in to ZCode")
374
431
  if (jwtExpired(s.jwt)) throw new Error(EXPIRED)
375
432
  const b = (await call("GET", `${ZCODE}/api/v1/zcode-plan/billing/balance?app_version=${APP_VERSION}`, { auth: "Bearer " + s.jwt, device: s.device })) ?? {}
@@ -382,7 +439,7 @@ async function startUsage(s) {
382
439
  if (end > 0 && end <= now && p.status.trim().toLowerCase() === "active") p.status = "expired"
383
440
  if (p.status.trim().toLowerCase() === "expired") over.add(p.user_plan_id + "\0" + p.plan_id)
384
441
  }
385
- const same = (x, p) => (x.user_plan_id && p.user_plan_id ? x.user_plan_id === p.user_plan_id : x.plan_id === p.plan_id)
442
+ const same = (x, p) => (x.user_plan_id && p.user_plan_id ? x.user_plan_id === p.user_plan_id : String(x.plan_id ?? "") === String(p.plan_id ?? ""))
386
443
  const balances = (Array.isArray(b.balances) ? b.balances : [])
387
444
  .map((x) => ({ ...x, user_plan_id: str(x?.user_plan_id), plan_id: str(x?.plan_id) }))
388
445
  .filter((x) => {
@@ -395,32 +452,41 @@ async function startUsage(s) {
395
452
  return keep
396
453
  })
397
454
 
455
+ // every live plan counts as the gift: no plan-name filter decides it,
456
+ // the balance says what the session can spend
398
457
  let active = null
399
458
  for (const p of plans) {
400
459
  if (p.status.trim().toLowerCase() !== "active") continue
401
- const id = p.plan_id.trim().toLowerCase(), n = str(p.name).trim().toLowerCase()
402
- const isStart = (x) => x.includes("start-plan") || x.includes("start plan")
403
- if ((id || n) && !isStart(id) && !isStart(n)) continue
404
460
  const end = startNum(p.ends_at)
405
- active = { name: first(str(p.name), "Start Plan"), until: end > 0 ? new Date(Math.trunc(end) * 1000).toISOString() : "" }
406
- break
461
+ if (end > 0 && end <= now) continue
462
+ if (active && !(end > 0 && (!startNum(active.end) || end < startNum(active.end)))) continue
463
+ active = { name: first(str(p.name), "Start Plan"), end, until: end > 0 ? new Date(Math.trunc(end) * 1000).toISOString() : "" }
407
464
  }
408
- if (!active) return { error: "this account has no GLM Coding Plan, and ZCode's Start Plan has ended or was never started" }
465
+ if (!active) return null
409
466
  const out = { plan: active.name, windows: [] }
410
467
  if (active.until) Object.assign(out, { until: active.until, renew: "off" })
468
+ const live = plans.filter((p) => {
469
+ if (p.status.trim().toLowerCase() !== "active") return false
470
+ const end = startNum(p.ends_at)
471
+ return !(end > 0 && end <= now)
472
+ })
411
473
  for (const x of balances) {
474
+ const owner = live.find((p) => same(x, p))
475
+ if (!owner) continue
476
+ const exp = startNum(x.expires_at)
477
+ if (exp > 0 && exp <= now) continue // a bucket past its own end is over
412
478
  const total = startNum(x.total_units), left = startNum(x.remaining_units)
413
479
  let used = startNum(x.used_units)
414
480
  if (total === undefined && used === undefined && left === undefined) continue
415
481
  const models = (Array.isArray(x.capabilities) ? x.capabilities : [])
416
482
  .map((c) => String(c ?? "").trim().replace(/^model:/, "").trim()).filter(Boolean)
417
- const w = { name: first(str(x.show_name), models.join(", "), "Credits"), used: 0 }
483
+ const base = first(str(x.show_name), models.join(", "), "Credits")
484
+ const w = { name: base, used: 0, _plan: str(owner.name) }
418
485
  if (used === undefined) used = total !== undefined && left !== undefined ? total - left : 0
419
486
  if (total > 0) {
420
487
  w.used = (100 * used) / total
421
488
  w.display = `${compact(used)} / ${compact(total)}`
422
489
  }
423
- const exp = startNum(x.expires_at)
424
490
  if (exp > 0) w.resetsAt = new Date(Math.trunc(exp) * 1000).toISOString()
425
491
  let span = 0
426
492
  for (const p of plans) {
@@ -440,6 +506,37 @@ async function startUsage(s) {
440
506
  return out
441
507
  }
442
508
 
509
+ // startUsage is a gift-only account's card: its buckets, or the words
510
+ // for having none to show. The card's header already names the plan, so
511
+ // the windows keep their own names.
512
+ const NO_START = "this account has no GLM Coding Plan, and ZCode's Start Plan has ended or was never started"
513
+ async function startUsage(s) {
514
+ const g = await giftOf(s)
515
+ if (!g) return { error: NO_START }
516
+ for (const w of g.windows) delete w._plan
517
+ return g
518
+ }
519
+
520
+ // dualUsage is an account with both a Coding Plan and a gift: its card shows
521
+ // both allowances, the Coding windows first and the gift's buckets after,
522
+ // each keeping its own models and end. The gift's windows carry their plan's
523
+ // name as a prefix so they are not mistaken for the coding plan's own. A
524
+ // gift read that fails leaves just the Coding card: magpie hides a card's
525
+ // windows behind an error and leaves it out of the menu bar and auto-switch,
526
+ // so erroring here would hide a working Coding Plan over a gift hiccup.
527
+ async function dualUsage(s) {
528
+ const out = await codingUsage(s)
529
+ try {
530
+ const g = await giftOf(s)
531
+ if (g) out.windows = [...out.windows, ...g.windows.map((w) => {
532
+ const p = w._plan
533
+ delete w._plan
534
+ return p && p !== w.name ? { ...w, name: p + " · " + w.name } : w
535
+ })]
536
+ } catch {}
537
+ return out
538
+ }
539
+
443
540
  // periodOf reads an entitlement's period: "daily", "weekly", "monthly".
444
541
  function periodOf(p) {
445
542
  p = p.toLowerCase()
@@ -989,6 +1086,26 @@ const entry = (m) => ({
989
1086
  })
990
1087
 
991
1088
  // model is a model as OpenCode's provider hands it to provider.models.
1089
+ // modelOf reads the model a Messages body asks for.
1090
+ function modelOf(text) {
1091
+ try {
1092
+ const m = JSON.parse(text)?.model
1093
+ return typeof m === "string" ? m : ""
1094
+ } catch {
1095
+ return ""
1096
+ }
1097
+ }
1098
+
1099
+ // kept passes a response on as it came, the account kept: the built-in
1100
+ // never marked a ZCode account lapsed nor cleared one.
1101
+ function kept(res, text) {
1102
+ const h = new Headers(res.headers)
1103
+ h.delete("content-length")
1104
+ h.delete("content-encoding")
1105
+ h.set("X-Magpie-Sign-In", "kept")
1106
+ return new Response(text !== undefined ? text : res.body, { status: res.status, statusText: res.statusText, headers: h })
1107
+ }
1108
+
992
1109
  function model(m, url) {
993
1110
  const e = entry(m)
994
1111
  return {
@@ -1168,7 +1285,7 @@ export async function ZCodeAuthPlugin({ client }) {
1168
1285
  async models(provider, { auth } = {}) {
1169
1286
  const s = stateOf(auth)
1170
1287
  if (!s) return provider.models
1171
- const start = await onStart(s).catch(() => false)
1288
+ const start = await plansOf(s).then((r) => r.start).catch(() => false)
1172
1289
  const base = start ? START_BASE : s.base
1173
1290
  let ms = modelsOf(await zcodeConfig().catch(() => null), planID(base))
1174
1291
  // ZCode's config can't be had: its table stands in, and magpie keeps
@@ -1196,14 +1313,7 @@ export async function ZCodeAuthPlugin({ client }) {
1196
1313
  if (!s) throw new Error("not signed in to ZCode")
1197
1314
  let url = input instanceof Request ? input.url : String(input)
1198
1315
  const opts = input instanceof Request ? { method: input.method, headers: input.headers, body: input.body, signal: input.signal, duplex: "half", ...init } : { ...init }
1199
- const start = await onStart(s)
1200
- // the request goes to the plan the account is on, wherever it was made for
1201
- for (const b of [START_BASE, ZAI_BASE, BIGMODEL_BASE]) {
1202
- if (url.startsWith(b)) {
1203
- url = (start ? START_BASE : s.base) + url.slice(b.length)
1204
- break
1205
- }
1206
- }
1316
+ const { start: alone, gift } = await plansOf(s)
1207
1317
  let key = s.key
1208
1318
  if (isTeam(s) && !key) {
1209
1319
  key = await teamKey(s)
@@ -1212,32 +1322,79 @@ export async function ZCodeAuthPlugin({ client }) {
1212
1322
  await client?.auth?.set?.({ path: { id }, body: next }).catch?.(() => {})
1213
1323
  }
1214
1324
  }
1215
- const h = new Headers(opts.headers)
1325
+ // a dual account's body is read ahead of sending, so a gift that
1326
+ // says it is spent can spend nothing and replay what was asked for
1327
+ let start = alone
1328
+ let orig
1329
+ if (!alone && gift && opts.body != null) {
1330
+ orig = opts.body = typeof opts.body === "string" ? opts.body : await new Response(opts.body).text()
1331
+ delete opts.duplex
1332
+ const m = modelOf(orig)
1333
+ // a ZCode sign-in past its end reaches no gift: the coding plan
1334
+ // takes the request, as it did before the gift was known
1335
+ start = !!m && !jwtExpired(s.jwt) && giftServes(gift, m) && Date.now() >= (blocked.get(s.key + "\0" + s.jwt + "\0" + m) ?? 0)
1336
+ }
1337
+ const swap = (base) => {
1338
+ for (const b of [START_BASE, ZAI_BASE, BIGMODEL_BASE]) {
1339
+ if (url.startsWith(b)) {
1340
+ url = base + url.slice(b.length)
1341
+ break
1342
+ }
1343
+ }
1344
+ }
1345
+ let h = new Headers(opts.headers)
1216
1346
  if (start) {
1217
1347
  if (jwtExpired(s.jwt)) throw new Error(EXPIRED)
1218
1348
  if (!s.jwt) throw new Error("ZCode's sign-in has no key; sign in again")
1349
+ swap(START_BASE)
1219
1350
  // the Start Plan is served only to what looks like ZCode's own request
1220
1351
  startHeaders(h, s.jwt)
1221
1352
  if (opts.body != null) {
1222
- const text = typeof opts.body === "string" ? opts.body : await new Response(opts.body).text()
1353
+ const text = orig ?? (typeof opts.body === "string" ? opts.body : await new Response(opts.body).text())
1223
1354
  opts.body = dress(text, s.site, s.device)
1224
1355
  delete opts.duplex
1225
1356
  h.delete("content-length")
1226
1357
  }
1227
1358
  } else {
1228
1359
  if (!key) throw new Error("ZCode's sign-in has no key; sign in again")
1360
+ swap(s.base)
1229
1361
  h.delete("authorization")
1230
1362
  h.set("x-api-key", key)
1231
1363
  h.set("Authorization", "Bearer " + key)
1232
1364
  }
1233
- const res = await fetch(url, { ...opts, headers: h })
1365
+ let res = await fetch(url, { ...opts, headers: h })
1366
+ // a dual account's gift answer that can't serve the request goes
1367
+ // to its coding plan instead, as the agent sent it: any status
1368
+ // 400 or over (its 405, its 401, its 5xx — a paid plan is waiting,
1369
+ // and a gift that keeps refusing would otherwise black out the
1370
+ // account), and its quota answers inside a 200. Only a quota
1371
+ // answer keeps that model off the gift for a minute: a refusal
1372
+ // that says nothing about quota is asked again next request.
1373
+ // Every 429 counts as spent, Z.ai's 1302/1303 rate limits among
1374
+ // them — replaying one to the coding plan is the good answer, and
1375
+ // the minute's block keeps a rate limit from being knocked twice.
1376
+ // A stream's body is never read here.
1377
+ if (start && !alone) {
1378
+ const json = (res.headers.get("content-type") ?? "").includes("application/json")
1379
+ if (res.status >= 400 || json) {
1380
+ const text = await res.text()
1381
+ const spent = spentUp(text, res.status)
1382
+ if (!spent && res.status < 400) return kept(res, text)
1383
+ if (spent) {
1384
+ for (const [k, until] of blocked) if (Date.now() >= until) blocked.delete(k)
1385
+ blocked.set(s.key + "\0" + s.jwt + "\0" + modelOf(orig), Date.now() + 60_000)
1386
+ }
1387
+ swap(s.base)
1388
+ h = new Headers(opts.headers)
1389
+ h.delete("authorization")
1390
+ h.set("x-api-key", key)
1391
+ h.set("Authorization", "Bearer " + key)
1392
+ res = await fetch(url, { ...opts, body: orig, headers: h })
1393
+ }
1394
+ }
1234
1395
  // the plan's answer goes on as it came, the account kept: the
1235
1396
  // built-in never marked a ZCode account lapsed nor cleared one
1236
- const kept = new Headers(res.headers)
1237
- kept.delete("content-length")
1238
- kept.delete("content-encoding")
1239
- kept.set("X-Magpie-Sign-In", "kept")
1240
- return new Response(res.body, { status: res.status, statusText: res.statusText, headers: kept })
1397
+ return kept(res)
1241
1398
  },
1242
1399
  }
1243
1400
  },
@@ -1269,7 +1426,9 @@ export async function ZCodeAuthPlugin({ client }) {
1269
1426
  }
1270
1427
  return saved(await teamUsage(s, key))
1271
1428
  }
1272
- if (await onStart(s)) return saved(await startUsage(s))
1429
+ const { start, gift } = await plansOf(s)
1430
+ if (start) return saved(await startUsage(s))
1431
+ if (gift) return saved(await dualUsage(s))
1273
1432
  return saved(await codingUsage(s))
1274
1433
  } catch (e) {
1275
1434
  return saved({ error: e?.message ?? String(e) })
@@ -1300,4 +1459,4 @@ export async function ZCodeAuthPlugin({ client }) {
1300
1459
  }
1301
1460
 
1302
1461
  // for tests
1303
- export const _internal = { entry, limitWindows, termOf, startUsage, routes, teamKeys, ownSignIn, stateOf, dress, PROMPT }
1462
+ export const _internal = { entry, limitWindows, termOf, startUsage, routes, blocked, plansOf, giftOf, dualUsage, spentUp, giftServes, modelOf, teamKeys, ownSignIn, stateOf, dress, PROMPT }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-zcode-auth",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "OpenCode provider plugin: signs in to Z.ai's or BigModel's (智谱) GLM Coding Plan as ZCode does, including team seats and ZCode's Start Plan",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",