@magpie-community/opencode-kiro-auth 0.1.0 → 0.1.1

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 +49 -2
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -266,13 +266,18 @@ function regionOf(profile, signedIn) {
266
266
  return String(signedIn ?? "").startsWith("eu-") ? "eu-central-1" : "us-east-1"
267
267
  }
268
268
 
269
+ // STATUS_TEXT is Go's http.StatusText for the answers Kiro gives.
270
+ const STATUS_TEXT = { 400: "Bad Request", 401: "Unauthorized", 403: "Forbidden", 404: "Not Found", 408: "Request Timeout",
271
+ 409: "Conflict", 413: "Request Entity Too Large", 429: "Too Many Requests", 500: "Internal Server Error", 502: "Bad Gateway",
272
+ 503: "Service Unavailable", 504: "Gateway Timeout" }
273
+
269
274
  class KiroError extends Error {
270
275
  constructor(status, body) {
271
276
  let msg = ""
272
277
  try {
273
278
  msg = JSON.parse(body)?.message ?? ""
274
279
  } catch {}
275
- super(msg ? `Kiro: ${msg} (${status})` : `Kiro: HTTP ${status}`)
280
+ super(msg ? `Kiro: ${msg} (${status})` : `Kiro: ${STATUS_TEXT[status] ?? ""}`)
276
281
  this.status = status
277
282
  }
278
283
  }
@@ -333,6 +338,38 @@ function usageLimits(a, email) {
333
338
  const planName = (title) =>
334
339
  String(title ?? "").toLowerCase().split(/\s+/).filter(Boolean).map((w) => (w === "kiro" ? "Kiro" : w[0].toUpperCase() + w.slice(1))).join(" ")
335
340
 
341
+ // goG is Go's %g of x: an exponent from a million up.
342
+ function goG(x) {
343
+ const [m, e] = x.toExponential().split("e")
344
+ const exp = Number(e)
345
+ if (exp < -4 || exp >= 6) return `${m}e${exp < 0 ? "-" : "+"}${String(Math.abs(exp)).padStart(2, "0")}`
346
+ return String(x)
347
+ }
348
+
349
+ // usageOf is the allowance Get-Usage-Limits tells, as magpie's built-in
350
+ // said it: the account's email, the credits of each allowance, the month's and a free trial's
351
+ // while it runs.
352
+ function usageOf(l) {
353
+ const at = (secs) => (secs > 0 ? new Date(Math.trunc(secs) * 1000).toISOString() : undefined)
354
+ const count = (used, limit) => used.toFixed(2).replace(/0+$/, "").replace(/\.$/, "") + " / " + goG(limit)
355
+ const num = (x) => (typeof x === "number" && Number.isFinite(x) ? x : 0)
356
+ const windows = []
357
+ for (const u of l?.usageBreakdownList ?? []) {
358
+ const t = u?.freeTrialInfo
359
+ if (t && String(t.freeTrialStatus ?? "").toUpperCase() === "ACTIVE" && num(t.usageLimitWithPrecision) > 0) {
360
+ const used = num(t.currentUsageWithPrecision), limit = num(t.usageLimitWithPrecision)
361
+ windows.push({ name: "Free trial", used: (100 * used) / limit, resetsAt: at(num(t.freeTrialExpiry)), display: count(used, limit) })
362
+ }
363
+ const used = num(u?.currentUsageWithPrecision), limit = num(u?.usageLimitWithPrecision)
364
+ if (limit <= 0) continue
365
+ const reset = num(u?.nextDateReset) || num(l?.nextDateReset)
366
+ windows.push({ name: u?.displayNamePlural || u?.displayName || "Credits", used: (100 * used) / limit, resetsAt: at(reset),
367
+ display: count(used, limit), span: 30 * 24 * 3600 })
368
+ }
369
+ const email = l?.userInfo?.email
370
+ return { plan: planName(l?.subscriptionInfo?.subscriptionTitle), ...(typeof email === "string" && email ? { user: email } : {}), windows }
371
+ }
372
+
336
373
  // ---- the account, as the plugin holds it -------------------------------------------
337
374
 
338
375
  // credOf is the sign-in a stored auth names: a key, one signed in here, or
@@ -1255,6 +1292,16 @@ export async function KiroAuthPlugin({ client } = {}) {
1255
1292
  },
1256
1293
  }
1257
1294
  },
1295
+ // the account's credits, as magpie's built-in showed them
1296
+ async usage(getAuth) {
1297
+ const auth = await getAuth()
1298
+ if (!(auth?.type === "api" && auth.key) && auth?.type !== "oauth") return { error: "not signed in" }
1299
+ try {
1300
+ return usageOf(await usageLimits(await creds(auth), true))
1301
+ } catch (e) {
1302
+ return { error: e.message }
1303
+ }
1304
+ },
1258
1305
  methods: [
1259
1306
  { type: "oauth", label: "Kiro (Google, GitHub, AWS Builder ID, IAM Identity Center)", authorize: browserSignIn },
1260
1307
  { type: "oauth", label: "Kiro CLI's or Kiro IDE's sign-in", authorize: ownSignIn },
@@ -1289,4 +1336,4 @@ export async function KiroAuthPlugin({ client } = {}) {
1289
1336
  }
1290
1337
 
1291
1338
  // for tests
1292
- export const _internal = { buildKiro, events, reply, failure, toolID, thinking, readCLI, readIDE, regionOf, planName, frames }
1339
+ export const _internal = { usageOf, buildKiro, events, reply, failure, toolID, thinking, readCLI, readIDE, regionOf, planName, frames }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-kiro-auth",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Kiro subscriptions (Free, Pro, Pro+, Power) in OpenCode and magpie",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",