@magpie-community/opencode-workbuddy-auth 0.1.34 → 0.1.36

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 (2) hide show
  1. package/index.mjs +44 -3
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -1719,6 +1719,45 @@ function runsOutOf(sum, packages, now = Date.now()) {
1719
1719
  return at ? { runsOutAt: new Date(at).toISOString(), runsOut: amount } : null
1720
1720
  }
1721
1721
 
1722
+ // cycleOf is when the plan's credits start again, as WorkBuddy's own client
1723
+ // says it (getCurrentPlan's refreshAt): the cycle end of the package the
1724
+ // summary names as the subscription (SubscriptionPackageCode), in UTC+8,
1725
+ // with how long the cycle is. Without it the card had used credits and no
1726
+ // reset, and magpie said "Not used yet" beside 46% (windy on Discord,
1727
+ // 2026-10-26). null when the subscription isn't in the lists, or its cycle
1728
+ // is over.
1729
+ function cycleOf(sum, packages, now = Date.now()) {
1730
+ const code = sum?.SubscriptionPackageCode
1731
+ const at = (v) => (typeof v === "string" && /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(v.trim()) ? Date.parse(v.trim().replace(" ", "T") + "+08:00") : 0)
1732
+ const of = (p) => {
1733
+ const end = at(p?.CycleEndTime), start = at(p?.CycleStartTime)
1734
+ if (!(end > now)) return null
1735
+ return { resetsAt: new Date(end).toISOString(), ...(start > 0 && start < end ? { span: (end - start) / 1000 } : {}) }
1736
+ }
1737
+ // A summary that does name one goes by it alone: named and not listed, or
1738
+ // its cycle over, is unknown — a paid plan's cycle is its subscription's,
1739
+ // never the slice's (yetone, #415).
1740
+ if (code) {
1741
+ for (const p of packages ?? []) if (p?.PackageCode === code) return of(p)
1742
+ return null
1743
+ }
1744
+ // A free account's summary names no subscription at all: both sites answer
1745
+ // SubscriptionPackageCode "" (copilot.tencent.com and www.workbuddy.ai,
1746
+ // measured 2026-10-26 on eight CN accounts and one AI one), so this
1747
+ // returned null and the card of an account whose credits are being spent
1748
+ // said nothing of when they come back — the one thing cycleOf is for.
1749
+ //
1750
+ // Its plan's own credits are the slice (CapacityType 4): packagesOf's
1751
+ // free list returns a month's plan_base with it, 00:00:00 to 23:59:59
1752
+ // UTC+8, the same cycle on every account on both sites (500 credits on
1753
+ // the CN site, 100 on the international), and its CycleEndTime is when
1754
+ // the plan gives the next month's back. A slice tells no account apart,
1755
+ // which is why runsOutOf keeps it out: which account to spend first is a
1756
+ // different question from when the plan refills.
1757
+ for (const p of packages ?? []) if (String(p?.CapacityType) === SLICE) return of(p)
1758
+ return null
1759
+ }
1760
+
1722
1761
  // ---- models -----------------------------------------------------------------
1723
1762
 
1724
1763
  // variants are the reasoning levels as OpenCode gives them to the AI SDK.
@@ -2159,12 +2198,14 @@ function makePlugin(site) {
2159
2198
  } catch {}
2160
2199
  if (ent) return { plan: auth.plan || "Enterprise", windows: await spareFree(site, a, [ent]), signIn: said }
2161
2200
  }
2162
- // when the credits left run out, for routing to spend them first;
2201
+ // when the plan's credits start again (cycleOf), and when the credits
2202
+ // left run out, for routing to spend them first (runsOutOf);
2163
2203
  // a list that can't be read leaves it unknown, the card stands
2164
2204
  const credits = out.windows.find((w) => w.name === "Credits")
2165
2205
  if (credits) {
2166
2206
  try {
2167
- Object.assign(credits, runsOutOf(sum, await packagesOf(site, a)) ?? {})
2207
+ const packages = await packagesOf(site, a)
2208
+ Object.assign(credits, cycleOf(sum, packages) ?? {}, runsOutOf(sum, packages) ?? {})
2168
2209
  } catch {}
2169
2210
  }
2170
2211
  await spareFree(site, a, out.windows)
@@ -2291,4 +2332,4 @@ export const WorkBuddyAuthPlugin = makePlugin(SITES.workbuddy)
2291
2332
  export const WorkBuddyAIAuthPlugin = makePlugin(SITES["workbuddy-ai"])
2292
2333
 
2293
2334
  // for tests
2294
- export const _internal = { typeUnions, systemAsUser, systemKey, DEFAULT_SYSTEM, EDGE_READS, fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, 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, priceOf, fresh, SITES, renewing, renewed, SESSION, attend, turnKey, conversationKey, signatureOf, isMessages, withoutUnsigned, withoutSignedThinking, answeredBefore, nativeOf, modelOf, configModels, API_MESSAGES: NPM_MESSAGES, API_CHAT: NPM }
2335
+ export const _internal = { cycleOf, typeUnions, systemAsUser, systemKey, DEFAULT_SYSTEM, EDGE_READS, fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, 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, priceOf, fresh, SITES, renewing, renewed, SESSION, attend, turnKey, conversationKey, signatureOf, isMessages, withoutUnsigned, withoutSignedThinking, answeredBefore, nativeOf, modelOf, configModels, 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.1.34",
3
+ "version": "0.1.36",
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",