@magpie-community/opencode-workbuddy-auth 0.1.16 → 0.1.18
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/README.md +2 -1
- package/index.mjs +35 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,7 +24,8 @@ The package exports `WorkBuddyAuthPlugin` (`workbuddy`) and
|
|
|
24
24
|
- Windows: `~/AppData/Local/CodeBuddyExtension/…`
|
|
25
25
|
- Linux: `~/.local/share/CodeBuddyExtension/…`
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
WorkBuddy 5.6 and later keep the sign-in encrypted, which only the app
|
|
28
|
+
opens, so this way fails there and says so: use the browser sign-in.
|
|
28
29
|
|
|
29
30
|
A browser sign-in is kept as an OpenCode `oauth` auth: the access and
|
|
30
31
|
refresh tokens, their expiry, the user id and the domain; desktop's as a
|
package/index.mjs
CHANGED
|
@@ -931,6 +931,19 @@ function readDesktop(site) {
|
|
|
931
931
|
}
|
|
932
932
|
}
|
|
933
933
|
|
|
934
|
+
// notDesktop says why there is no desktop sign-in to use: WorkBuddy 5.6
|
|
935
|
+
// and later seal its tokens at rest ({$wbEncrypted: 1, envelope}), which
|
|
936
|
+
// only the app itself opens (plugins#18), so the browser sign-in is the way;
|
|
937
|
+
// else the app isn't signed in.
|
|
938
|
+
function notDesktop(site) {
|
|
939
|
+
try {
|
|
940
|
+
const t = JSON.parse(readFileSync(desktopFile(site), "utf8"))?.auth ?? {}
|
|
941
|
+
if (t.accessToken?.$wbEncrypted || t.refreshToken?.$wbEncrypted)
|
|
942
|
+
return `${site.name} desktop keeps its sign-in encrypted (WorkBuddy 5.6 and later), which magpie can't read; sign in with "${site.name} account (browser)" instead`
|
|
943
|
+
} catch {}
|
|
944
|
+
return `${site.name} desktop isn't signed in`
|
|
945
|
+
}
|
|
946
|
+
|
|
934
947
|
// desktopSignIn uses the account WorkBuddy desktop is signed in to: nothing
|
|
935
948
|
// is copied (a copied refresh token would be the app's and the plugin's
|
|
936
949
|
// both, and the first to use it would sign the other out); its file is
|
|
@@ -942,7 +955,7 @@ function desktopSignIn(site) {
|
|
|
942
955
|
method: "auto",
|
|
943
956
|
async callback() {
|
|
944
957
|
const d = readDesktop(site)
|
|
945
|
-
if (!d) return { type: "failed", error:
|
|
958
|
+
if (!d) return { type: "failed", error: notDesktop(site) }
|
|
946
959
|
return { type: "success", refresh: "", access: "", expires: 0, source: "desktop", accountId: d.name || site.name, uid: d.uid }
|
|
947
960
|
},
|
|
948
961
|
}
|
|
@@ -957,7 +970,7 @@ const desktopHeld = new Map()
|
|
|
957
970
|
async function current(site, client, auth) {
|
|
958
971
|
if (auth?.source !== "desktop") return fresh(site, client, auth)
|
|
959
972
|
const d = readDesktop(site)
|
|
960
|
-
if (!d) throw new Error(
|
|
973
|
+
if (!d) throw new Error(notDesktop(site))
|
|
961
974
|
const k = site.id + "|" + d.uid
|
|
962
975
|
const h = desktopHeld.get(k)
|
|
963
976
|
const a = await fresh(site, null, h && h.expires >= d.expires ? h : d)
|
|
@@ -1350,6 +1363,18 @@ const REFUSED_HINT =
|
|
|
1350
1363
|
"WorkBuddy refuses chats from Codex and Claude Code (their system prompt); use it from Hermes, OpenCode or Pi, or add another provider to this group"
|
|
1351
1364
|
const REFUSED = /unapproved channel|illegal api invocation/i
|
|
1352
1365
|
|
|
1366
|
+
// RESTRICTED_HINT is what the user can do about WorkBuddy's 403 code 11140
|
|
1367
|
+
// "request illegal", whose displayMsg says "Your account has been restricted
|
|
1368
|
+
// due to unusual activity" (magpie #1849): the account is out until WorkBuddy
|
|
1369
|
+
// lifts the restriction, which an appeal asks for. It ends the error's
|
|
1370
|
+
// message as magpie's built-in puts it (provider.WBRestrictedHint), word for
|
|
1371
|
+
// word, so magpie rests the account for hours rather than minutes.
|
|
1372
|
+
const RESTRICTED_HINT =
|
|
1373
|
+
"WorkBuddy restricted this account for unusual activity; it stays out until WorkBuddy lifts that, which an appeal (Submit feedback in WorkBuddy) asks for"
|
|
1374
|
+
const RESTRICTED_CODE = 11140
|
|
1375
|
+
// The code is matched whole, as with 14018: 111400 is another error.
|
|
1376
|
+
const RESTRICTED_TEXT = /account has been restricted due to unusual activity|账号存在异常行为|帳號存在異常行為|["']code["']\s*:\s*["']?11140(?![\d.])/i
|
|
1377
|
+
|
|
1353
1378
|
// EXHAUSTED_HINT explains WorkBuddy's requirement of an active package
|
|
1354
1379
|
// even for 0-rate / free models. When an account has no packages or 0 credits,
|
|
1355
1380
|
// WorkBuddy returns code 14018 ("Credits exhausted...").
|
|
@@ -1367,7 +1392,7 @@ function kept(res) {
|
|
|
1367
1392
|
return new Response(res.body, { status: res.status, statusText: res.statusText, headers })
|
|
1368
1393
|
}
|
|
1369
1394
|
|
|
1370
|
-
// explained is res with REFUSED_HINT or EXHAUSTED_HINT added to that refusal's message.
|
|
1395
|
+
// explained is res with REFUSED_HINT, RESTRICTED_HINT or EXHAUSTED_HINT added to that refusal's message.
|
|
1371
1396
|
// Each refusal says the sign-in is kept: the built-in passed WorkBuddy's
|
|
1372
1397
|
// 401 on and never marked a WorkBuddy account lapsed.
|
|
1373
1398
|
async function explained(res) {
|
|
@@ -1386,8 +1411,9 @@ async function explained(res) {
|
|
|
1386
1411
|
const at = v?.error && typeof v.error === "object" ? v.error : v && typeof v === "object" ? v : null
|
|
1387
1412
|
const code = at?.data?.code ?? at?.code ?? v?.code ?? v?.data?.code
|
|
1388
1413
|
const isRefused = REFUSED.test(text)
|
|
1389
|
-
const
|
|
1390
|
-
|
|
1414
|
+
const isRestricted = !isRefused && (Number(code) === RESTRICTED_CODE || RESTRICTED_TEXT.test(text))
|
|
1415
|
+
const isExhausted = !isRestricted && (code === 14018 || Number(code) === 14018 || EXHAUSTED_TEXT.test(text))
|
|
1416
|
+
if (!isRefused && !isRestricted && !isExhausted) return again(text)
|
|
1391
1417
|
|
|
1392
1418
|
let msg = text.trim()
|
|
1393
1419
|
if (at && typeof at.message === "string") msg = at.message
|
|
@@ -1396,9 +1422,9 @@ async function explained(res) {
|
|
|
1396
1422
|
else if (typeof v?.msg === "string" && v.msg) msg = v.msg // WorkBuddy's own {"code", "msg"}
|
|
1397
1423
|
else if (typeof v?.data?.msg === "string") msg = v.data.msg
|
|
1398
1424
|
|
|
1399
|
-
const hint = isRefused ? REFUSED_HINT : EXHAUSTED_HINT
|
|
1400
|
-
const type = isRefused ? "permission_error" : "insufficient_quota"
|
|
1401
|
-
const errCode = isRefused ? null : 14018
|
|
1425
|
+
const hint = isRefused ? REFUSED_HINT : isRestricted ? RESTRICTED_HINT : EXHAUSTED_HINT
|
|
1426
|
+
const type = isRefused || isRestricted ? "permission_error" : "insufficient_quota"
|
|
1427
|
+
const errCode = isRefused ? null : isRestricted ? RESTRICTED_CODE : 14018
|
|
1402
1428
|
msg = `${msg} — ${hint}`
|
|
1403
1429
|
const headers = new Headers(res.headers)
|
|
1404
1430
|
headers.set("content-type", "application/json")
|
|
@@ -1412,4 +1438,4 @@ export const WorkBuddyAuthPlugin = makePlugin(SITES.workbuddy)
|
|
|
1412
1438
|
export const WorkBuddyAIAuthPlugin = makePlugin(SITES["workbuddy-ai"])
|
|
1413
1439
|
|
|
1414
1440
|
// for tests
|
|
1415
|
-
export const _internal = { textOnly, runsOutOf, packagesOf, endOf, enterpriseHeaders, enterpriseOf, liveModels, browserSignIn, withSystem, normalizeToolChoice, fitTools, fitted, renamed, unflagged, usageOf, desktopHeld, explained, REFUSED_HINT, EXHAUSTED_HINT, freeCredits, creditsOf, fresh, SITES, renewing, renewed, SESSION, attend, turnKey, conversationKey, signatureOf }
|
|
1441
|
+
export const _internal = { notDesktop, textOnly, runsOutOf, packagesOf, endOf, enterpriseHeaders, enterpriseOf, liveModels, browserSignIn, withSystem, normalizeToolChoice, fitTools, fitted, renamed, unflagged, usageOf, desktopHeld, explained, REFUSED_HINT, RESTRICTED_HINT, EXHAUSTED_HINT, freeCredits, creditsOf, fresh, SITES, renewing, renewed, SESSION, attend, turnKey, conversationKey, signatureOf }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magpie-community/opencode-workbuddy-auth",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "OpenCode provider plugins for WorkBuddy's plans: WorkBuddy (CodeBuddy, copilot.tencent.com) and WorkBuddy AI (www.workbuddy.ai)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.mjs",
|