@magpie-community/opencode-workbuddy-auth 0.2.9 → 0.2.11
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 +17 -0
- package/index.mjs +82 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -329,6 +329,12 @@ provider settings in magpie, off by default (#430). When it is on:
|
|
|
329
329
|
|
|
330
330
|
The price list is read again at most once a minute for requests.
|
|
331
331
|
|
|
332
|
+
The switch gives its label and description in magpie's other languages
|
|
333
|
+
(`labels`, `descriptions`: Chinese, Traditional Chinese, Japanese, German),
|
|
334
|
+
and says `filtersModels`, so while it is on magpie says under the models
|
|
335
|
+
that the list is filtered (#590). Both are magpie's own fields; an older
|
|
336
|
+
magpie shows the English words and no note.
|
|
337
|
+
|
|
332
338
|
## Credits in magpie
|
|
333
339
|
|
|
334
340
|
magpie's usage card shows the account's credits from the resource summary.
|
|
@@ -338,6 +344,17 @@ client reads. The daily Free Plan slice isn't counted: it ends at the same
|
|
|
338
344
|
midnight on every account. magpie's smart routing spends the account whose
|
|
339
345
|
credits run out first.
|
|
340
346
|
|
|
347
|
+
The plan's own credits and the rest are two windows. "Credits" is the
|
|
348
|
+
packages whose credits come back each cycle, as WorkBuddy's client lists
|
|
349
|
+
them (Pro monthly or yearly, youth, advanced, flagship, the plan's bonus,
|
|
350
|
+
the free plan's monthly base, the Pro trials, or the subscription the
|
|
351
|
+
summary names), with the plan's cycle, so its pace line is the month's.
|
|
352
|
+
"Extra credits" is the packages that only lapse: gifted and activity
|
|
353
|
+
credits (赠送积分) and bought credit packs. Only one of the two stops the
|
|
354
|
+
account, since WorkBuddy serves it while any credits are left: the extra
|
|
355
|
+
window is set aside until the plan's credits are spent. A summary with
|
|
356
|
+
only one kind keeps the one "Credits" window (akic404 on Discord).
|
|
357
|
+
|
|
341
358
|
An enterprise (team) account's resource summary lists no packages. Its
|
|
342
359
|
credits are read from the enterprise meter
|
|
343
360
|
(`/billing/meter/get-enterprise-user-usage`), the one WorkBuddy's own usage
|
package/index.mjs
CHANGED
|
@@ -2776,20 +2776,49 @@ function pinned(rows, account) {
|
|
|
2776
2776
|
// CycleRemainCapacity at all leaves the window out. TotalCredits is not a
|
|
2777
2777
|
// fallback: an account with no packages at all keeps its unknown allowance,
|
|
2778
2778
|
// as before, so its free models are not skipped.
|
|
2779
|
-
|
|
2779
|
+
//
|
|
2780
|
+
// The plan's own credits and the rest are two windows (akic404 on
|
|
2781
|
+
// Discord): summed, the gifted and activity packages' credits used long
|
|
2782
|
+
// ago put the card at most of its allowance on the first day of the
|
|
2783
|
+
// month, and the plan's pace line said nothing. "Credits" is the packages
|
|
2784
|
+
// whose credits come back each cycle — WorkBuddy's client's own
|
|
2785
|
+
// onlyRefreshCodes (PLAN_CODES), or the subscription the summary names —
|
|
2786
|
+
// and "Extra credits" the ones that only lapse (gift, activity, bought
|
|
2787
|
+
// credit packs, any code the client doesn't list). A summary with only
|
|
2788
|
+
// one kind keeps the one "Credits" window, as before.
|
|
2789
|
+
//
|
|
2790
|
+
// Only one of the two stops the account at a time: WorkBuddy serves it
|
|
2791
|
+
// while any credits are left, so the one set aside is the one whose
|
|
2792
|
+
// running out doesn't stop it — "Extra credits", until the plan's are
|
|
2793
|
+
// spent and extra ones are left.
|
|
2794
|
+
function usageOf(sum, plan, site) {
|
|
2780
2795
|
const out = { plan: plan || (sum?.IsPaidUser ? "Pro" : "Free plan"), windows: [] }
|
|
2781
|
-
|
|
2796
|
+
const ofPlan = planCodes(sum, site)
|
|
2797
|
+
const kinds = { plan: { total: 0, used: 0 }, extra: { total: 0, used: 0 } }
|
|
2798
|
+
let left = 0, bags = 0
|
|
2782
2799
|
for (const p of sum?.Packages ?? []) {
|
|
2783
2800
|
const hasTotal = p?.CycleTotalCapacity != null && p.CycleTotalCapacity !== ""
|
|
2784
2801
|
if (hasTotal) {
|
|
2785
|
-
|
|
2786
|
-
|
|
2802
|
+
const k = kinds[ofPlan(p?.PackageCode) ? "plan" : "extra"]
|
|
2803
|
+
k.total += capacity(p.CycleTotalCapacity)
|
|
2804
|
+
k.used += capacity(p?.CycleUsedCapacity)
|
|
2787
2805
|
} else if (p?.CycleRemainCapacity != null && p.CycleRemainCapacity !== "") {
|
|
2788
2806
|
left += capacity(p.CycleRemainCapacity)
|
|
2789
2807
|
bags++
|
|
2790
2808
|
}
|
|
2791
2809
|
}
|
|
2792
|
-
|
|
2810
|
+
const window = (name, { used, total }) => ({ name, used: (100 * used) / total, display: `${compact(used)} / ${compact(total)}`, amount: used, limit: total, unit: "credits" })
|
|
2811
|
+
const { plan: mine, extra } = kinds
|
|
2812
|
+
if (mine.total > 0 && extra.total > 0) {
|
|
2813
|
+
const credits = window("Credits", mine), more = window("Extra credits", extra)
|
|
2814
|
+
if (mine.used >= mine.total && extra.used < extra.total) credits.aside = true
|
|
2815
|
+
else more.aside = true
|
|
2816
|
+
out.windows.push(credits, more)
|
|
2817
|
+
} else {
|
|
2818
|
+
const total = mine.total + extra.total, used = mine.used + extra.used
|
|
2819
|
+
if (total > 0) out.windows.push(window("Credits", { used, total }))
|
|
2820
|
+
}
|
|
2821
|
+
const total = mine.total + extra.total
|
|
2793
2822
|
if (bags > 0 && (total === 0 || left > 0)) out.windows.push({ name: "Prepaid credits", balance: left, display: `${compact(left)} credits`, unit: "credits" })
|
|
2794
2823
|
return out
|
|
2795
2824
|
}
|
|
@@ -2845,6 +2874,26 @@ const FREE_CODES = [DAILY_CODE, CODE("008", "cfWoLwvjU4"), CODE("035", "ArVxJcGD
|
|
|
2845
2874
|
// lost at the same midnight on every account, so they tell none apart
|
|
2846
2875
|
const SLICE = "4"
|
|
2847
2876
|
|
|
2877
|
+
// PLAN_CODES are the packages whose credits come back each cycle, as
|
|
2878
|
+
// WorkBuddy's client (5.9.x) lists them (onlyRefreshCodes): Pro monthly,
|
|
2879
|
+
// Pro monthly plus, Pro yearly, youth, advanced, flagship, the plan's
|
|
2880
|
+
// bonus (bonus28; bonusIntl, "Plan Bonus Quota"), the international free
|
|
2881
|
+
// plan (freeMonIntl), the Pro trials, and on the China build alone the
|
|
2882
|
+
// free plan's monthly base (freeMon, 套餐基础积分). Every other code only
|
|
2883
|
+
// lapses: gift (006, "Bonus Pack" / Pro trial), activity (007, 赠送积分),
|
|
2884
|
+
// bonus29/30, and the credit packs (009, 036, 038).
|
|
2885
|
+
const PLAN_CODES = [CODE("002", "AkiJS3ZHF5"), CODE("005", "maRGyrHhw1"), CODE("003", "FAnt7lcmRT"), CODE("023", "4xbGhMrE6q"),
|
|
2886
|
+
CODE("026", "BaESVICNoi"), CODE("027", "0FCGVA6vSa"), CODE("028", "NtpWi0jzXs"), CODE("035", "ArVxJcGDsm"),
|
|
2887
|
+
CODE("039", "KRcQj7wUat"), CODE("040", "mi9rCYg46x"), CODE("037", "WxOD3MpI2o")]
|
|
2888
|
+
const FREE_MON = CODE("008", "cfWoLwvjU4")
|
|
2889
|
+
|
|
2890
|
+
// planCodes says whether a package of the summary is the plan's own: one
|
|
2891
|
+
// of PLAN_CODES on that site, or the subscription the summary names.
|
|
2892
|
+
function planCodes(sum, site) {
|
|
2893
|
+
const sub = sum?.SubscriptionPackageCode
|
|
2894
|
+
return (code) => !!code && (code === sub || PLAN_CODES.includes(code) || (!site?.ai && code === FREE_MON))
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2848
2897
|
// beijing is WorkBuddy's own time ("2026-10-13 00:39:27" is UTC+8, as its
|
|
2849
2898
|
// DeductionEndTime for the same package says).
|
|
2850
2899
|
const beijing = (ms) => new Date(ms + 8 * 3600_000).toISOString().slice(0, 19).replace("T", " ")
|
|
@@ -2887,11 +2936,12 @@ function endOf(p) {
|
|
|
2887
2936
|
// packages are lost, and how many (cdredfox on X): smart routing spends
|
|
2888
2937
|
// the account whose credits expire first. Only packages the summary
|
|
2889
2938
|
// counts, with credits left, and not the daily slice; null when none.
|
|
2890
|
-
|
|
2939
|
+
// only narrows it to the packages of one window (the split's, usageOf).
|
|
2940
|
+
function runsOutOf(sum, packages, now = Date.now(), only = () => true) {
|
|
2891
2941
|
const counted = new Set((sum?.Packages ?? []).map((p) => p?.PackageCode))
|
|
2892
2942
|
let at = 0, amount = 0
|
|
2893
2943
|
for (const p of packages ?? []) {
|
|
2894
|
-
if (!counted.has(p?.PackageCode) || p?.PackageCode === DAILY_CODE || String(p?.CapacityType) === SLICE) continue
|
|
2944
|
+
if (!counted.has(p?.PackageCode) || !only(p?.PackageCode) || p?.PackageCode === DAILY_CODE || String(p?.CapacityType) === SLICE) continue
|
|
2895
2945
|
const left = capacity(p?.CycleCapacityRemainPrecise ?? p?.CycleCapacityRemain)
|
|
2896
2946
|
const end = endOf(p)
|
|
2897
2947
|
if (!(left > 0) || end <= now) continue
|
|
@@ -3387,6 +3437,17 @@ function makePlugin(site) {
|
|
|
3387
3437
|
key: FREE_ONLY,
|
|
3388
3438
|
label: "Free models only",
|
|
3389
3439
|
description: `Lists only the models ${site.name} serves at no cost, and turns away a request for any other here instead of sending it, so no credits are spent. A model free only at night counts as paid.`,
|
|
3440
|
+
// the same words in magpie's other languages, and that the list
|
|
3441
|
+
// leaves models out while it is on (plugins#590); magpie's own
|
|
3442
|
+
// fields, which an older magpie and OpenCode leave alone
|
|
3443
|
+
labels: { zh: "仅免费模型", "zh-TW": "僅免費模型", ja: "無料モデルのみ", de: "Nur kostenlose Modelle" },
|
|
3444
|
+
descriptions: {
|
|
3445
|
+
zh: `只列出 ${site.name} 免费提供的模型;其他模型的请求在这里就被拒绝、不会发出,因此不消耗积分。只在夜间免费的模型按付费算。`,
|
|
3446
|
+
"zh-TW": `只列出 ${site.name} 免費提供的模型;其他模型的請求在這裡就被拒絕、不會送出,因此不消耗積分。只在夜間免費的模型以付費計。`,
|
|
3447
|
+
ja: `${site.name} が無料で提供するモデルだけを表示し、ほかのモデルへのリクエストは送信せずここで断るので、クレジットを消費しません。夜間だけ無料のモデルは有料として扱います。`,
|
|
3448
|
+
de: `Listet nur die Modelle, die ${site.name} kostenlos anbietet, und weist eine Anfrage an jedes andere hier ab, statt sie zu senden, sodass keine Credits verbraucht werden. Ein Modell, das nur nachts kostenlos ist, gilt als kostenpflichtig.`,
|
|
3449
|
+
},
|
|
3450
|
+
filtersModels: true,
|
|
3390
3451
|
},
|
|
3391
3452
|
],
|
|
3392
3453
|
async loader(getAuth) {
|
|
@@ -3615,7 +3676,7 @@ function makePlugin(site) {
|
|
|
3615
3676
|
}
|
|
3616
3677
|
said = "renewed"
|
|
3617
3678
|
}
|
|
3618
|
-
const out = usageOf(sum, auth.plan)
|
|
3679
|
+
const out = usageOf(sum, auth.plan, site)
|
|
3619
3680
|
// an enterprise account's summary has no packages: its credits
|
|
3620
3681
|
// are the enterprise meter's (#1904). A personal account's
|
|
3621
3682
|
// refusal of it (10001 "uid or enterpriseID is empty") leaves
|
|
@@ -3630,11 +3691,22 @@ function makePlugin(site) {
|
|
|
3630
3691
|
// when the plan's credits start again (cycleOf), and when the credits
|
|
3631
3692
|
// left run out, for routing to spend them first (runsOutOf);
|
|
3632
3693
|
// a list that can't be read leaves it unknown, the card stands
|
|
3694
|
+
//
|
|
3695
|
+
// Split (usageOf), the plan's cycle is the plan window's alone;
|
|
3696
|
+
// the soonest credits to lapse, of any package, stay on the window
|
|
3697
|
+
// that stops the account, as routing reads none set aside, and
|
|
3698
|
+
// the window set aside says its own.
|
|
3633
3699
|
const credits = out.windows.find((w) => w.name === "Credits")
|
|
3700
|
+
const extra = out.windows.find((w) => w.name === "Extra credits")
|
|
3634
3701
|
if (credits) {
|
|
3635
3702
|
try {
|
|
3636
3703
|
const packages = await packagesOf(site, a)
|
|
3637
|
-
Object.assign(credits, cycleOf(sum, packages) ?? {}
|
|
3704
|
+
Object.assign(credits, cycleOf(sum, packages) ?? {})
|
|
3705
|
+
const ofPlan = planCodes(sum, site)
|
|
3706
|
+
const stops = extra && !extra.aside ? extra : credits
|
|
3707
|
+
Object.assign(stops, runsOutOf(sum, packages) ?? {})
|
|
3708
|
+
const aside = extra ? (stops === credits ? extra : credits) : null
|
|
3709
|
+
if (aside) Object.assign(aside, runsOutOf(sum, packages, Date.now(), (code) => ofPlan(code) === (aside === credits)) ?? {})
|
|
3638
3710
|
} catch {}
|
|
3639
3711
|
}
|
|
3640
3712
|
await spareFree(site, a, out.windows)
|
|
@@ -3790,4 +3862,4 @@ export const WorkBuddyAuthPlugin = makePlugin(SITES.workbuddy)
|
|
|
3790
3862
|
export const WorkBuddyAIAuthPlugin = makePlugin(SITES["workbuddy-ai"])
|
|
3791
3863
|
|
|
3792
3864
|
// for tests
|
|
3793
|
-
export const _internal = { idFor, OFF_TAKEN, replyAfterToolsOn, withDefaultEffort, defaultEffortOf, gzipped, FREE_ONLY, PRICE_TTL, keyAccount, remoteConfig, cycleOf, typeUnions, systemAsUser, systemKey, DEFAULT_SYSTEM, EDGE_READS, fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, accountName, notDesktop, textOnly, runsOutOf, packagesOf, endOf, enterpriseHeaders, enterpriseOf, liveModels, browserSignIn, withSystem, asReasoning, normalizeToolChoice, fitTools, fitted, renamed, unsaid, FILTER_SAYS, unflagged, usageOf, desktopHeld, explained, REFUSED_HINT, RESTRICTED_HINT, EXHAUSTED_HINT, REFUSED_DOC, commaPaused, commaPausedOn, opened, freeCredits, creditsOf, priceOf, fresh, SITES, renewing, renewed, SESSION, attend, scopeOf, turnKey, conversationKey, signatureOf, isMessages, withoutUnsigned, withoutSignedThinking, prepared, answeredBefore, nativeOf, modelOf, configModels, freeWindowOf, tokensShort, freeWindowRows, freeWindowLedger, readLedgerTail, pinned, rowTime, rowAccount, ofAccount, windowOffset, windowReset, FREE_WINDOW_MODELS, FREE_WINDOW_SPAN, FREE_WINDOW_GAP, FREE_WINDOW_LEAD, checkinOf, API_MESSAGES: NPM_MESSAGES, API_CHAT: NPM }
|
|
3865
|
+
export const _internal = { planCodes, idFor, OFF_TAKEN, replyAfterToolsOn, withDefaultEffort, defaultEffortOf, gzipped, FREE_ONLY, PRICE_TTL, keyAccount, remoteConfig, cycleOf, typeUnions, systemAsUser, systemKey, DEFAULT_SYSTEM, EDGE_READS, fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, accountName, notDesktop, textOnly, runsOutOf, packagesOf, endOf, enterpriseHeaders, enterpriseOf, liveModels, browserSignIn, withSystem, asReasoning, normalizeToolChoice, fitTools, fitted, renamed, unsaid, FILTER_SAYS, unflagged, usageOf, desktopHeld, explained, REFUSED_HINT, RESTRICTED_HINT, EXHAUSTED_HINT, REFUSED_DOC, commaPaused, commaPausedOn, opened, freeCredits, creditsOf, priceOf, fresh, SITES, renewing, renewed, SESSION, attend, scopeOf, turnKey, conversationKey, signatureOf, isMessages, withoutUnsigned, withoutSignedThinking, prepared, answeredBefore, nativeOf, modelOf, configModels, freeWindowOf, tokensShort, freeWindowRows, freeWindowLedger, readLedgerTail, pinned, rowTime, rowAccount, ofAccount, windowOffset, windowReset, FREE_WINDOW_MODELS, FREE_WINDOW_SPAN, FREE_WINDOW_GAP, FREE_WINDOW_LEAD, checkinOf, API_MESSAGES: NPM_MESSAGES, API_CHAT: NPM }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magpie-community/opencode-workbuddy-auth",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
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",
|