@magpie-community/opencode-zcode-auth 0.1.14 → 0.1.16

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 +5 -1
  2. package/index.mjs +54 -22
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -31,7 +31,11 @@ over Anthropic's Messages API. Provider id: `zcode`.
31
31
  - Uses the account the ZCode app on this computer is signed in to. For
32
32
  every request it reads ZCode's own credentials (`~/.zcode/v2`), so it
33
33
  follows ZCode as it signs in again, renews its session or switches to a
34
- team's plan.
34
+ team's plan, but only while ZCode is signed in to that same account.
35
+ Once ZCode signs out, or signs in to another account, the sign-in uses
36
+ what it saved when it was added; when that session has run out, it
37
+ asks to be signed in again. It never sends one account's requests with
38
+ another's credentials: to use both, add the app's sign-in once for each.
35
39
  - **GLM Coding Plan API key**
36
40
  - Paste a key (`<id>.<secret>`) and say which site it is from.
37
41
 
package/index.mjs CHANGED
@@ -19,7 +19,7 @@
19
19
  import { createDecipheriv, createHash } from "node:crypto"
20
20
  import { existsSync, readFileSync, readdirSync } from "node:fs"
21
21
  import { arch, homedir, release, userInfo } from "node:os"
22
- import { basename, join } from "node:path"
22
+ import { join } from "node:path"
23
23
  import PROMPT from "./prompt.mjs"
24
24
 
25
25
  const PROVIDER = "zcode"
@@ -1044,7 +1044,7 @@ function ownSignIn() {
1044
1044
  function asZCode() {
1045
1045
  return {
1046
1046
  url: "",
1047
- instructions: "Uses the account the ZCode app is signed in to, and follows it.",
1047
+ instructions: "Uses the account the ZCode app is signed in to, and follows it while ZCode stays signed in to that account.",
1048
1048
  method: "auto",
1049
1049
  async callback() {
1050
1050
  const own = ownSignIn()
@@ -1064,10 +1064,13 @@ function stateOf(auth) {
1064
1064
  s = JSON.parse(auth.refresh)
1065
1065
  } catch {}
1066
1066
  if (s.source === "zcode") {
1067
- // ZCode's own, read now: what it was when this was signed in, if
1068
- // ZCode has since signed out
1067
+ // ZCode's own, read now, while ZCode is signed in to this same
1068
+ // account. Signed out, or signed in to another account since, it is
1069
+ // what it was when this was signed in: another account's key would
1070
+ // send this account's requests as that one, and an expired session
1071
+ // says sign in again (EXPIRED) rather than borrowing another's.
1069
1072
  const own = ownSignIn()
1070
- if (own) {
1073
+ if (own && own.user === String(auth.accountId ?? "")) {
1071
1074
  const { user, ...now } = own
1072
1075
  s = { source: "zcode", device: s.device, plan: s.plan, ...now }
1073
1076
  }
@@ -1299,20 +1302,47 @@ function startHeaders(h, jwt) {
1299
1302
  h.set("x-zcode-trace-id", uuid())
1300
1303
  }
1301
1304
 
1305
+ // WORK_DIR and WORK_GIT are where magpie tells a plugin's fetch the agent
1306
+ // that asked works: the folder, percent-encoded, and "yes" or "no" for a
1307
+ // git repository, each left off when magpie doesn't know it (magpie's
1308
+ // provider.WorkDirHeader and WorkGitHeader). They are for the plugin, not
1309
+ // the vendor.
1310
+ const WORK_DIR = "x-magpie-work-dir"
1311
+ const WORK_GIT = "x-magpie-work-git"
1312
+
1313
+ // workPlace takes WORK_DIR and WORK_GIT off h: {dir?, git?}, what magpie
1314
+ // said of where the agent works.
1315
+ function workPlace(h) {
1316
+ const place = {}
1317
+ const dir = h.get(WORK_DIR)
1318
+ if (dir) {
1319
+ try {
1320
+ place.dir = decodeURIComponent(dir)
1321
+ } catch {}
1322
+ }
1323
+ const git = h.get(WORK_GIT)
1324
+ if (place.dir && (git === "yes" || git === "no")) place.git = git
1325
+ h.delete(WORK_DIR)
1326
+ h.delete(WORK_GIT)
1327
+ return place
1328
+ }
1329
+
1302
1330
  // environment is the prompt's environment section; provider and model
1303
- // name the powered-by line, left out with no model.
1304
- function environment(provider, model) {
1331
+ // name the powered-by line, left out with no model. The plugin runs in
1332
+ // magpie, not in the agent's folder: the working directory and whether it
1333
+ // is a git repository are the agent's, as magpie tells them (place), and
1334
+ // each is left out when it isn't told rather than said as magpie's own
1335
+ // (#86). The agent's shell isn't known here either, so it isn't said; the
1336
+ // platform and OS version are this computer's, as ZCode's X-Os-* headers
1337
+ // say them.
1338
+ function environment(provider, model, place = {}) {
1305
1339
  const e = PROMPT.environment
1306
- const sh = process.env.SHELL || process.env.ComSpec
1307
- const lines = [
1308
- e.heading,
1309
- e.invokedLine,
1310
- `- ${e.cwdLabel}: ${process.cwd()}`,
1311
- `- ${e.gitLabel}: ${e.gitNo}`,
1312
- `- ${e.platformLabel}: ${process.platform}`,
1313
- `- ${e.shellLabel}: ${sh ? basename(sh) : "unknown"}`,
1314
- `- ${e.osVersionLabel}: ${osVersion()}`,
1315
- ]
1340
+ const lines = [e.heading, e.invokedLine]
1341
+ if (place.dir) {
1342
+ lines.push(`- ${e.cwdLabel}: ${place.dir}`)
1343
+ if (place.git) lines.push(`- ${e.gitLabel}: ${place.git === "yes" ? "yes" : e.gitNo}`)
1344
+ }
1345
+ lines.push(`- ${e.platformLabel}: ${process.platform}`, `- ${e.osVersionLabel}: ${osVersion()}`)
1316
1346
  if (model) lines.push(e.poweredByLine.replace("{provider}", provider).replace("{model}", model))
1317
1347
  return lines.join("\n")
1318
1348
  }
@@ -1335,9 +1365,10 @@ function contextPrefix() {
1335
1365
  // system blocks, then the agent's own system text uncached; the context
1336
1366
  // prefix as the first turn; no cache mark in the turns but on the last
1337
1367
  // block of the last; none on the tools; metadata.user_id naming the
1338
- // sign-in's device. site names the powered-by line's provider. A body that
1339
- // isn't a Messages request goes as it is.
1340
- function dress(text, site, device) {
1368
+ // sign-in's device. site names the powered-by line's provider, place where
1369
+ // the agent works (workPlace). A body that isn't a Messages request goes as
1370
+ // it is.
1371
+ function dress(text, site, device, place) {
1341
1372
  if (typeof text !== "string" || !text.includes("messages")) return text
1342
1373
  let b
1343
1374
  try {
@@ -1358,7 +1389,7 @@ function dress(text, site, device) {
1358
1389
  b.system = [
1359
1390
  cached(PROMPT.cliPrefix),
1360
1391
  cached(PROMPT.stableSections.join("\n\n")),
1361
- cached("\n\n" + [PROMPT.beforeEnvironment, environment(provider, model), PROMPT.afterEnvironment].join("\n\n")),
1392
+ cached("\n\n" + [PROMPT.beforeEnvironment, environment(provider, model, place), PROMPT.afterEnvironment].join("\n\n")),
1362
1393
  ...own,
1363
1394
  ]
1364
1395
  b.messages = [contextPrefix(), ...b.messages]
@@ -1498,6 +1529,7 @@ export async function ZCodeAuthPlugin({ client }) {
1498
1529
  }
1499
1530
  }
1500
1531
  let h = new Headers(opts.headers)
1532
+ const place = workPlace(h)
1501
1533
  if (start) {
1502
1534
  if (jwtExpired(s.jwt)) throw new Error(EXPIRED)
1503
1535
  if (!s.jwt) throw new Error("ZCode's sign-in has no key; sign in again")
@@ -1506,7 +1538,7 @@ export async function ZCodeAuthPlugin({ client }) {
1506
1538
  startHeaders(h, s.jwt)
1507
1539
  if (opts.body != null) {
1508
1540
  const text = orig ?? (typeof opts.body === "string" ? opts.body : await new Response(opts.body).text())
1509
- opts.body = dress(text, s.site, s.device)
1541
+ opts.body = dress(text, s.site, s.device, place)
1510
1542
  delete opts.duplex
1511
1543
  h.delete("content-length")
1512
1544
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-zcode-auth",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
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",