@slkiser/opencode-quota 4.10.4 → 4.10.6
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 +5 -4
- package/dist/lib/google-agy.js +1 -1
- package/dist/lib/opencode-zen-config.d.ts +25 -25
- package/dist/lib/opencode-zen-config.d.ts.map +1 -1
- package/dist/lib/opencode-zen-config.js +140 -69
- package/dist/lib/opencode-zen-config.js.map +1 -1
- package/dist/lib/opencode-zen.d.ts +4 -1
- package/dist/lib/opencode-zen.d.ts.map +1 -1
- package/dist/lib/opencode-zen.js +74 -20
- package/dist/lib/opencode-zen.js.map +1 -1
- package/dist/lib/provider-registration.d.ts +1 -1
- package/dist/lib/provider-registration.d.ts.map +1 -1
- package/dist/lib/provider-registration.js +1 -1
- package/dist/lib/provider-registration.js.map +1 -1
- package/dist/lib/scoped-update-migration.d.ts +5 -3
- package/dist/lib/scoped-update-migration.d.ts.map +1 -1
- package/dist/lib/scoped-update-migration.js +15 -12
- package/dist/lib/scoped-update-migration.js.map +1 -1
- package/dist/lib/scoped-update.d.ts.map +1 -1
- package/dist/lib/scoped-update.js +5 -6
- package/dist/lib/scoped-update.js.map +1 -1
- package/dist/providers/cache-policies.d.ts.map +1 -1
- package/dist/providers/cache-policies.js +11 -10
- package/dist/providers/cache-policies.js.map +1 -1
- package/dist/providers/opencode-zen.d.ts.map +1 -1
- package/dist/providers/opencode-zen.js +88 -36
- package/dist/providers/opencode-zen.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
<a href="https://www.npmjs.com/package/@slkiser/opencode-quota"><img alt="npm downloads" src="https://img.shields.io/npm/dm/%40slkiser%2Fopencode-quota?style=flat-square" /></a>
|
|
14
14
|
<a href="https://github.com/slkiser/opencode-quota/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/slkiser/opencode-quota/ci.yml?style=flat-square&branch=main&label=CI" /></a>
|
|
15
15
|
<a href="./LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square" /></a>
|
|
16
|
+
<a href="https://github.com/anomalyco/opencode/issues/38281"><img alt="Help us get listed: opencode#38281" src="https://img.shields.io/badge/%F0%9F%91%8D_help_us_get_listed-opencode%2338281-blue?style=flat-square" /></a>
|
|
16
17
|
</p>
|
|
17
18
|
|
|
18
19
|
[](https://github.com/slkiser/opencode-quota)
|
|
@@ -58,12 +59,12 @@ OpenCode 1 users stay on 4.x: OpenCode Quota 5 needs OpenCode 2. The updater pin
|
|
|
58
59
|
|
|
59
60
|
The updater prints the complete preview before its own config or cache changes. `--yes` authorizes only the previewed safe config edits and manifest-verified cache cleanup; it never moves or deletes secrets. See [Updating safely](docs/readme/updating.md) for detailed behavior and manual credential steps.
|
|
60
61
|
|
|
61
|
-
**Breaking changes
|
|
62
|
+
**Breaking changes since 4.10.3:**
|
|
62
63
|
|
|
63
64
|
- Qwen Code was removed because Qwen ended its OAuth free tier; use Alibaba Coding Plan.
|
|
64
65
|
- Google Antigravity was removed because its companion plugin is archived and Google rejects it; use Google AGY.
|
|
65
66
|
- Personal Google accounts can no longer use Gemini CLI because Google ended them on 2026-06-18; use Google AGY.
|
|
66
|
-
- OpenCode Zen now
|
|
67
|
+
- OpenCode Zen now uses your `opencode console login` session; the copied Console cookie file is no longer read. See [OpenCode Zen setup](docs/readme/providers.md#opencode-zen).
|
|
67
68
|
|
|
68
69
|
## Choose your setup
|
|
69
70
|
|
|
@@ -157,7 +158,7 @@ Run `npx @slkiser/opencode-quota@4 --help` for command options. See [External in
|
|
|
157
158
|
| Ollama Cloud | Automatic | Remote API | Quota and usage |
|
|
158
159
|
| OpenAI | Automatic | Remote API | Quota |
|
|
159
160
|
| OpenCode Go | Automatic | Remote API | Quota |
|
|
160
|
-
| OpenCode Zen | [Needs setup](docs/readme/providers.md#opencode-zen) |
|
|
161
|
+
| OpenCode Zen | [Needs setup](docs/readme/providers.md#opencode-zen) | Remote API | Budget and balance |
|
|
161
162
|
| OpenRouter | Automatic | Remote API | Budget and spend |
|
|
162
163
|
| Synthetic | Automatic | Remote API | Quota |
|
|
163
164
|
| xAI SuperGrok | Automatic | Remote API | Quota |
|
|
@@ -177,7 +178,7 @@ Run `npx @slkiser/opencode-quota@4 --help` for command options. See [External in
|
|
|
177
178
|
| Google AGY | [Needs setup](docs/readme/providers.md#google-agy-quick-setup) | Remote API | Quota |
|
|
178
179
|
| NanoGPT | Automatic | Remote API | Quota and balance |
|
|
179
180
|
| OpenAI | Automatic | Remote API | Quota |
|
|
180
|
-
| OpenCode Zen | [Needs setup](docs/readme/providers.md#opencode-zen) |
|
|
181
|
+
| OpenCode Zen | [Needs setup](docs/readme/providers.md#opencode-zen) | Remote API | Budget and balance |
|
|
181
182
|
| OpenRouter | Automatic | Remote API | Budget and spend |
|
|
182
183
|
| Synthetic | Automatic | Remote API | Quota |
|
|
183
184
|
| xAI SuperGrok | Automatic | Remote API | Quota |
|
package/dist/lib/google-agy.js
CHANGED
|
@@ -17,7 +17,7 @@ const AGY_TOKEN_REFRESH_URL = "https://oauth2.googleapis.com/token";
|
|
|
17
17
|
const AGY_TOKEN_TIMEOUT_MS = 8_000;
|
|
18
18
|
const AGY_QUOTA_TIMEOUT_MS = 6_000;
|
|
19
19
|
const AGY_ACCOUNTS_CONCURRENCY = 3;
|
|
20
|
-
const AGY_USER_AGENT = "antigravity/cli/1.2.
|
|
20
|
+
const AGY_USER_AGENT = "antigravity/cli/1.2.11 darwin/amd64";
|
|
21
21
|
function createAgyActivityRequestId() {
|
|
22
22
|
return crypto.randomUUID();
|
|
23
23
|
}
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
export interface
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export interface OpenCodeZenConsoleAccount {
|
|
2
|
+
/** Console base URL from the account row, e.g. https://opencode.ai/console */
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
accessToken: string;
|
|
5
|
+
activeOrgId: string;
|
|
4
6
|
}
|
|
5
|
-
export type
|
|
7
|
+
export type ResolvedOpenCodeZenAccount = {
|
|
6
8
|
state: "none";
|
|
7
9
|
} | {
|
|
8
|
-
state: "
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
state: "expired";
|
|
11
|
+
expiryMs: number;
|
|
12
|
+
} | {
|
|
13
|
+
state: "no_active_account";
|
|
14
|
+
} | {
|
|
15
|
+
state: "missing_org";
|
|
16
|
+
} | {
|
|
17
|
+
state: "inactive_account";
|
|
11
18
|
} | {
|
|
12
|
-
state: "
|
|
13
|
-
source: string;
|
|
14
|
-
missing: string;
|
|
19
|
+
state: "invalid_url";
|
|
15
20
|
} | {
|
|
16
|
-
state: "
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
state: "incompatible";
|
|
22
|
+
} | {
|
|
23
|
+
state: "read_error";
|
|
24
|
+
} | {
|
|
25
|
+
state: "configured";
|
|
26
|
+
account: OpenCodeZenConsoleAccount;
|
|
19
27
|
};
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
missing: string | null;
|
|
24
|
-
error: string | null;
|
|
25
|
-
checkedPaths: string[];
|
|
26
|
-
}
|
|
27
|
-
export declare function resolveOpenCodeZenConfig(): Promise<ResolvedOpenCodeZenConfig>;
|
|
28
|
-
export declare const DEFAULT_OPENCODE_ZEN_CONFIG_CACHE_MAX_AGE_MS = 30000;
|
|
29
|
-
export declare function resolveOpenCodeZenConfigCached(params?: {
|
|
28
|
+
export declare function resolveOpenCodeZenAccount(): Promise<ResolvedOpenCodeZenAccount>;
|
|
29
|
+
export declare const DEFAULT_OPENCODE_ZEN_ACCOUNT_CACHE_MAX_AGE_MS = 30000;
|
|
30
|
+
export declare function resolveOpenCodeZenAccountCached(params?: {
|
|
30
31
|
maxAgeMs?: number;
|
|
31
|
-
}): Promise<
|
|
32
|
-
export declare function getOpenCodeZenConfigDiagnostics(): Promise<OpenCodeZenConfigDiagnostics>;
|
|
32
|
+
}): Promise<ResolvedOpenCodeZenAccount>;
|
|
33
33
|
//# sourceMappingURL=opencode-zen-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-zen-config.d.ts","sourceRoot":"","sources":["../../src/lib/opencode-zen-config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"opencode-zen-config.d.ts","sourceRoot":"","sources":["../../src/lib/opencode-zen-config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,yBAAyB;IACxC,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,KAAK,EAAE,mBAAmB,CAAA;CAAE,GAC9B;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,GACxB;IAAE,KAAK,EAAE,kBAAkB,CAAA;CAAE,GAC7B;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,GACxB;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,GACzB;IAAE,KAAK,EAAE,YAAY,CAAA;CAAE,GACvB;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,yBAAyB,CAAA;CAAE,CAAC;AA4JhE,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAErF;AAKD,eAAO,MAAM,6CAA6C,QAAS,CAAC;AAEpE,wBAAsB,+BAA+B,CAAC,MAAM,CAAC,EAAE;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAatC"}
|
|
@@ -1,87 +1,158 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const { configDirs } = getOpencodeRuntimeDirCandidates();
|
|
7
|
-
return configDirs.map((dir) => join(dir, "opencode-quota", "opencode.json"));
|
|
1
|
+
import { statSync } from "node:fs";
|
|
2
|
+
import { openOpenCodeSqliteReadOnly } from "./opencode-sqlite.js";
|
|
3
|
+
import { getOpenCodeDbPath } from "./opencode-storage.js";
|
|
4
|
+
function asString(value) {
|
|
5
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
8
6
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
/** Checks a thrown error (e.g. from statSync) for a stable errno code. */
|
|
8
|
+
function hasErrnoCode(error, code) {
|
|
9
|
+
let current = error;
|
|
10
|
+
for (let depth = 0; current && depth < 5; depth += 1) {
|
|
11
|
+
if (current.code === code)
|
|
12
|
+
return true;
|
|
13
|
+
current = current.cause;
|
|
12
14
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* node:sqlite reports missing files as SQLITE_CANTOPEN (ERR_SQLITE_ERROR), the
|
|
19
|
+
* same errcode it uses for permission problems — so ask the filesystem for the
|
|
20
|
+
* real errno. statSync (unlike existsSync) distinguishes ENOENT from EACCES.
|
|
21
|
+
*/
|
|
22
|
+
function isMissingStateDbFile(dbPath) {
|
|
23
|
+
try {
|
|
24
|
+
statSync(dbPath);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
catch (statError) {
|
|
28
|
+
return hasErrnoCode(statError, "ENOENT");
|
|
15
29
|
}
|
|
16
|
-
return `Failed to read config file: ${String(error)}`;
|
|
17
30
|
}
|
|
18
|
-
|
|
31
|
+
function normalizeBaseUrl(value) {
|
|
32
|
+
const raw = asString(value);
|
|
33
|
+
if (!raw)
|
|
34
|
+
return null;
|
|
35
|
+
let url;
|
|
19
36
|
try {
|
|
20
|
-
|
|
21
|
-
const parsed = JSON.parse(data);
|
|
22
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
23
|
-
return { state: "invalid", error: "Config file must contain a JSON object" };
|
|
24
|
-
}
|
|
25
|
-
return { state: "loaded", config: parsed };
|
|
37
|
+
url = new URL(raw);
|
|
26
38
|
}
|
|
27
|
-
catch
|
|
28
|
-
|
|
29
|
-
return { state: "missing" };
|
|
30
|
-
}
|
|
31
|
-
return { state: "invalid", error: getConfigFileError(error) };
|
|
39
|
+
catch {
|
|
40
|
+
return null;
|
|
32
41
|
}
|
|
42
|
+
if (url.protocol !== "https:")
|
|
43
|
+
return null;
|
|
44
|
+
// Bare "?" / "#" leave search/hash empty but are not a valid Console base.
|
|
45
|
+
if (raw.includes("?") || raw.includes("#"))
|
|
46
|
+
return null;
|
|
47
|
+
if (url.username || url.password || url.search || url.hash)
|
|
48
|
+
return null;
|
|
49
|
+
return url.href.replace(/\/+$/, "");
|
|
33
50
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Reads the active OpenCode Console CLI session (`opencode console login`)
|
|
53
|
+
* from OpenCode's local state database, strictly read-only. Tokens are never
|
|
54
|
+
* refreshed or written here.
|
|
55
|
+
*/
|
|
56
|
+
async function readAccount() {
|
|
57
|
+
const safe = (resolved) => ({
|
|
58
|
+
resolved,
|
|
59
|
+
tokenExpiryMs: null,
|
|
60
|
+
});
|
|
61
|
+
const dbPath = getOpenCodeDbPath();
|
|
62
|
+
if (!dbPath)
|
|
63
|
+
return safe({ state: "none" });
|
|
64
|
+
let conn;
|
|
65
|
+
try {
|
|
66
|
+
conn = await openOpenCodeSqliteReadOnly(dbPath);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Classify by the actual DB path, not the opener's error: node:sqlite
|
|
70
|
+
// surfaces missing files as SQLITE_CANTOPEN (ERR_SQLITE_ERROR) — the same
|
|
71
|
+
// errcode it uses for permission problems — and a wrapped unrelated ENOENT
|
|
72
|
+
// must never hide an existing DB. statSync distinguishes ENOENT (absent)
|
|
73
|
+
// from EACCES (unsearchable parent) without exception-text matching.
|
|
74
|
+
if (isMissingStateDbFile(dbPath))
|
|
75
|
+
return safe({ state: "none" });
|
|
76
|
+
return safe({ state: "read_error" });
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const tables = conn.all(`SELECT name FROM sqlite_master WHERE type = 'table' AND name IN ('account', 'account_state')`);
|
|
80
|
+
const names = new Set(tables.map((row) => row?.name));
|
|
81
|
+
if (!names.has("account") || !names.has("account_state")) {
|
|
82
|
+
return safe({ state: "incompatible" });
|
|
41
83
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
: ""
|
|
46
|
-
|
|
47
|
-
|
|
84
|
+
// Column-level check: an older/newer schema that misses required columns is
|
|
85
|
+
// incompatible, while a failing read (lock, I/O) is a transient read_error.
|
|
86
|
+
const requiredColumns = {
|
|
87
|
+
account_state: new Set(["active_account_id", "active_org_id"]),
|
|
88
|
+
account: new Set(["id", "url", "access_token", "token_expiry"]),
|
|
89
|
+
};
|
|
90
|
+
for (const [table, required] of Object.entries(requiredColumns)) {
|
|
91
|
+
const columns = conn.all(`PRAGMA table_info(${table})`);
|
|
92
|
+
const columnNames = new Set(columns.map((row) => row?.name));
|
|
93
|
+
for (const column of required) {
|
|
94
|
+
if (!columnNames.has(column))
|
|
95
|
+
return safe({ state: "incompatible" });
|
|
96
|
+
}
|
|
48
97
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
98
|
+
const stateRow = conn.get(`SELECT active_account_id, active_org_id FROM "account_state" LIMIT 1`);
|
|
99
|
+
const activeAccountId = asString(stateRow?.active_account_id);
|
|
100
|
+
if (!activeAccountId)
|
|
101
|
+
return safe({ state: "no_active_account" });
|
|
102
|
+
const active = conn.get(`SELECT url, access_token, token_expiry FROM "account" WHERE id = ? LIMIT 1`, [activeAccountId]);
|
|
103
|
+
if (!active)
|
|
104
|
+
return safe({ state: "inactive_account" });
|
|
105
|
+
const activeOrgId = asString(stateRow?.active_org_id);
|
|
106
|
+
if (!activeOrgId)
|
|
107
|
+
return safe({ state: "missing_org" });
|
|
108
|
+
const accessToken = asString(active.access_token);
|
|
109
|
+
if (!accessToken)
|
|
110
|
+
return { resolved: { state: "expired", expiryMs: 0 }, tokenExpiryMs: 0 };
|
|
111
|
+
const expiryMs = typeof active.token_expiry === "number" && Number.isFinite(active.token_expiry)
|
|
112
|
+
? active.token_expiry
|
|
113
|
+
: null;
|
|
114
|
+
if (expiryMs !== null && expiryMs <= Date.now()) {
|
|
115
|
+
// Propagate the already-passed expiry so the cache TTL collapses to 0 and
|
|
116
|
+
// the next read goes back to the DB (e.g. right after a fresh login).
|
|
117
|
+
return { resolved: { state: "expired", expiryMs }, tokenExpiryMs: expiryMs };
|
|
55
118
|
}
|
|
119
|
+
const baseUrl = normalizeBaseUrl(active.url);
|
|
120
|
+
if (!baseUrl)
|
|
121
|
+
return safe({ state: "invalid_url" });
|
|
56
122
|
return {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
123
|
+
resolved: {
|
|
124
|
+
state: "configured",
|
|
125
|
+
account: { baseUrl, accessToken, activeOrgId },
|
|
126
|
+
},
|
|
127
|
+
tokenExpiryMs: expiryMs,
|
|
60
128
|
};
|
|
61
129
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const now = Date.now();
|
|
70
|
-
if (cachedConfig && now - cachedAt < maxAgeMs) {
|
|
71
|
-
return cachedConfig;
|
|
130
|
+
catch {
|
|
131
|
+
// The schema is fine but the read failed (lock, disk I/O, ...): report a
|
|
132
|
+
// transient read error instead of throwing.
|
|
133
|
+
return safe({ state: "read_error" });
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
conn.close();
|
|
72
137
|
}
|
|
73
|
-
cachedConfig = await resolveOpenCodeZenConfig();
|
|
74
|
-
cachedAt = now;
|
|
75
|
-
return cachedConfig;
|
|
76
138
|
}
|
|
77
|
-
export async function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
139
|
+
export async function resolveOpenCodeZenAccount() {
|
|
140
|
+
return (await readAccount()).resolved;
|
|
141
|
+
}
|
|
142
|
+
let cachedAccount = null;
|
|
143
|
+
let cachedExpiresAt = 0;
|
|
144
|
+
export const DEFAULT_OPENCODE_ZEN_ACCOUNT_CACHE_MAX_AGE_MS = 30_000;
|
|
145
|
+
export async function resolveOpenCodeZenAccountCached(params) {
|
|
146
|
+
const maxAgeMs = Math.max(0, params?.maxAgeMs ?? DEFAULT_OPENCODE_ZEN_ACCOUNT_CACHE_MAX_AGE_MS);
|
|
147
|
+
// A zero maxAgeMs explicitly bypasses an unexpired prior cache entry.
|
|
148
|
+
if (maxAgeMs > 0 && cachedAccount && Date.now() < cachedExpiresAt)
|
|
149
|
+
return cachedAccount;
|
|
150
|
+
const { resolved, tokenExpiryMs } = await readAccount();
|
|
151
|
+
// The cache must never outlive the token: cap the TTL at the token's expiry
|
|
152
|
+
// so an expired session triggers a fresh DB read (and a login prompt).
|
|
153
|
+
const ttl = tokenExpiryMs === null ? maxAgeMs : Math.min(maxAgeMs, Math.max(0, tokenExpiryMs - Date.now()));
|
|
154
|
+
cachedAccount = resolved;
|
|
155
|
+
cachedExpiresAt = Date.now() + ttl;
|
|
156
|
+
return resolved;
|
|
86
157
|
}
|
|
87
158
|
//# sourceMappingURL=opencode-zen-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-zen-config.js","sourceRoot":"","sources":["../../src/lib/opencode-zen-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"opencode-zen-config.js","sourceRoot":"","sources":["../../src/lib/opencode-zen-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { OpenCodeZenConsoleAccount } from "./opencode-zen-config.js";
|
|
1
2
|
/**
|
|
2
3
|
* The OpenCode Console reports amounts in micro-cents:
|
|
3
4
|
* one US dollar is 100,000,000 micro-cents (billing units).
|
|
@@ -14,6 +15,8 @@ export interface OpenCodeZenBillingData {
|
|
|
14
15
|
reload: boolean | null;
|
|
15
16
|
reloadAmount: number | null;
|
|
16
17
|
reloadTrigger: number | null;
|
|
18
|
+
/** Org-budget reset ISO timestamp; only set when budgets/org supplies the monthly budget. */
|
|
19
|
+
budgetResetIso: string | null;
|
|
17
20
|
}
|
|
18
21
|
/**
|
|
19
22
|
* billing/status (balance) is required. The other routes are optional: when one fails,
|
|
@@ -27,7 +30,7 @@ export type OpenCodeZenResult = {
|
|
|
27
30
|
success: false;
|
|
28
31
|
error: string;
|
|
29
32
|
};
|
|
30
|
-
export declare function queryOpenCodeZenQuota(
|
|
33
|
+
export declare function queryOpenCodeZenQuota(account: OpenCodeZenConsoleAccount, options?: {
|
|
31
34
|
requestTimeoutMs?: number;
|
|
32
35
|
}): Promise<OpenCodeZenResult>;
|
|
33
36
|
//# sourceMappingURL=opencode-zen.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-zen.d.ts","sourceRoot":"","sources":["../../src/lib/opencode-zen.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"opencode-zen.d.ts","sourceRoot":"","sources":["../../src/lib/opencode-zen.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAM1E;;;GAGG;AACH,eAAO,MAAM,qCAAqC,YAAc,CAAC;AAEjE,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,yFAAyF;IACzF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gFAAgF;IAChF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6FAA6F;IAC7F,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,sBAAsB,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GACjE;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAyLtC,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,yBAAyB,EAClC,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1C,OAAO,CAAC,iBAAiB,CAAC,CA4D5B"}
|
package/dist/lib/opencode-zen.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { sanitizeDisplayText } from "./display-sanitize.js";
|
|
2
2
|
import { fetchWithTimeout } from "./http.js";
|
|
3
|
-
const CONSOLE_API_URL = "https://opencode.ai/console/api";
|
|
4
|
-
const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Gecko/20100101 Firefox/148.0";
|
|
5
3
|
const CONSOLE_TIMEOUT_MS = 10_000;
|
|
6
|
-
const SESSION_ERROR = "OpenCode Console session expired or invalid —
|
|
4
|
+
const SESSION_ERROR = "OpenCode Console session expired or invalid — run `opencode console login` to sign in again";
|
|
7
5
|
/**
|
|
8
6
|
* The OpenCode Console reports amounts in micro-cents:
|
|
9
7
|
* one US dollar is 100,000,000 micro-cents (billing units).
|
|
@@ -75,6 +73,41 @@ function parseMonthlyUsage(json, now) {
|
|
|
75
73
|
}
|
|
76
74
|
return Number.isFinite(total) ? total : invalidResponse();
|
|
77
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Parses the org budget. The org has no budget configured when the Console returns
|
|
78
|
+
* `null`, an empty body, `{}`, or a null limit.
|
|
79
|
+
*/
|
|
80
|
+
function parseOrgBudget(json) {
|
|
81
|
+
if (json === null)
|
|
82
|
+
return { limitMicroCents: null, spentMicroCents: null, resetsAt: null };
|
|
83
|
+
const budget = asRecord(json);
|
|
84
|
+
if (!budget)
|
|
85
|
+
return invalidResponse();
|
|
86
|
+
if (Object.keys(budget).length === 0) {
|
|
87
|
+
return { limitMicroCents: null, spentMicroCents: null, resetsAt: null };
|
|
88
|
+
}
|
|
89
|
+
const limitValue = budget.limitMicroCents;
|
|
90
|
+
if (limitValue === undefined)
|
|
91
|
+
return invalidResponse();
|
|
92
|
+
const limit = limitValue === null ? null : parseMicroCents(limitValue);
|
|
93
|
+
if (limitValue !== null && limit === null)
|
|
94
|
+
return invalidResponse();
|
|
95
|
+
const spentValue = budget.spentMicroCents;
|
|
96
|
+
if (spentValue === undefined)
|
|
97
|
+
return invalidResponse();
|
|
98
|
+
const spent = spentValue === null ? null : parseMicroCents(spentValue);
|
|
99
|
+
if (spentValue !== null && spent === null)
|
|
100
|
+
return invalidResponse();
|
|
101
|
+
const resetsAt = budget.resetsAt;
|
|
102
|
+
if (resetsAt !== null && resetsAt !== undefined && typeof resetsAt !== "string") {
|
|
103
|
+
return invalidResponse();
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
limitMicroCents: limit,
|
|
107
|
+
spentMicroCents: spent,
|
|
108
|
+
resetsAt: typeof resetsAt === "string" ? resetsAt : null,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
78
111
|
function sanitizeMessage(text, secrets = [], maxLength = 120) {
|
|
79
112
|
let sanitized = sanitizeDisplayText(text).replace(/\s+/g, " ").trim();
|
|
80
113
|
for (const secret of secrets) {
|
|
@@ -85,22 +118,21 @@ function sanitizeMessage(text, secrets = [], maxLength = 120) {
|
|
|
85
118
|
}
|
|
86
119
|
async function fetchConsoleRoute(params) {
|
|
87
120
|
try {
|
|
88
|
-
return await fetchWithTimeout(`${
|
|
121
|
+
return await fetchWithTimeout(`${params.account.baseUrl}/api/${params.route}`, {
|
|
89
122
|
request: {
|
|
90
123
|
method: "GET",
|
|
91
124
|
redirect: "manual",
|
|
92
125
|
headers: {
|
|
93
|
-
"User-Agent": USER_AGENT,
|
|
94
126
|
Accept: "application/json",
|
|
95
|
-
|
|
96
|
-
"x-org-id": params.
|
|
127
|
+
Authorization: `Bearer ${params.account.accessToken}`,
|
|
128
|
+
"x-org-id": params.account.activeOrgId,
|
|
97
129
|
},
|
|
98
130
|
},
|
|
99
131
|
timeoutMs: params.timeoutMs,
|
|
100
132
|
consume: async (response) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
133
|
+
// Redirects and 401 mean the whole session is gone; a 403 is treated as
|
|
134
|
+
// a per-route failure so optional routes can fall back gracefully.
|
|
135
|
+
if ((response.status >= 300 && response.status < 400) || response.status === 401) {
|
|
104
136
|
return { success: false, error: SESSION_ERROR };
|
|
105
137
|
}
|
|
106
138
|
if (!response.ok) {
|
|
@@ -114,7 +146,9 @@ async function fetchConsoleRoute(params) {
|
|
|
114
146
|
}
|
|
115
147
|
const text = await response.text();
|
|
116
148
|
try {
|
|
117
|
-
|
|
149
|
+
// An empty body carries no value, so the route parser sees it as JSON null.
|
|
150
|
+
const json = text.trim() === "" ? null : JSON.parse(text);
|
|
151
|
+
return { success: true, data: params.parse(json) };
|
|
118
152
|
}
|
|
119
153
|
catch {
|
|
120
154
|
return {
|
|
@@ -127,45 +161,65 @@ async function fetchConsoleRoute(params) {
|
|
|
127
161
|
}
|
|
128
162
|
catch (error) {
|
|
129
163
|
const message = sanitizeMessage(error instanceof Error ? error.message : String(error), [
|
|
130
|
-
params.
|
|
131
|
-
params.
|
|
164
|
+
params.account.accessToken,
|
|
165
|
+
params.account.activeOrgId,
|
|
132
166
|
]);
|
|
133
167
|
return { success: false, error: `OpenCode Console ${params.route} request failed: ${message}` };
|
|
134
168
|
}
|
|
135
169
|
}
|
|
136
|
-
export async function queryOpenCodeZenQuota(
|
|
170
|
+
export async function queryOpenCodeZenQuota(account, options = {}) {
|
|
137
171
|
const request = {
|
|
138
|
-
|
|
139
|
-
consoleSessionCookie,
|
|
172
|
+
account,
|
|
140
173
|
timeoutMs: options.requestTimeoutMs ?? CONSOLE_TIMEOUT_MS,
|
|
141
174
|
};
|
|
142
175
|
const now = new Date();
|
|
143
|
-
const [balance, creditLimit, autoRecharge, monthlyUsage] = await Promise.all([
|
|
176
|
+
const [balance, creditLimit, autoRecharge, orgBudget, monthlyUsage] = await Promise.all([
|
|
144
177
|
fetchConsoleRoute({ ...request, route: "billing/status", parse: parseBalance }),
|
|
145
178
|
fetchConsoleRoute({ ...request, route: "billing/account", parse: parseCreditLimit }),
|
|
146
179
|
fetchConsoleRoute({ ...request, route: "billing/auto-recharge", parse: parseAutoRecharge }),
|
|
180
|
+
fetchConsoleRoute({ ...request, route: "budgets/org", parse: parseOrgBudget }),
|
|
147
181
|
fetchConsoleRoute({
|
|
148
182
|
...request,
|
|
149
183
|
route: "usage/cost-by-day",
|
|
150
184
|
parse: (json) => parseMonthlyUsage(json, now),
|
|
151
185
|
}),
|
|
152
186
|
]);
|
|
153
|
-
const optional = [creditLimit, autoRecharge, monthlyUsage];
|
|
187
|
+
const optional = [creditLimit, autoRecharge, orgBudget, monthlyUsage];
|
|
154
188
|
if ([balance, ...optional].some((result) => !result.success && result.error === SESSION_ERROR)) {
|
|
155
189
|
return { success: false, error: SESSION_ERROR };
|
|
156
190
|
}
|
|
157
191
|
if (!balance.success)
|
|
158
192
|
return balance;
|
|
193
|
+
// Prefer the org budget when it supplies a positive limit and usable spend;
|
|
194
|
+
// otherwise fall back to the credit limit plus this month's usage costs.
|
|
195
|
+
let monthlyLimit = creditLimit.success ? creditLimit.data : null;
|
|
196
|
+
let usage = monthlyUsage.success ? monthlyUsage.data : null;
|
|
197
|
+
let budgetResetIso = null;
|
|
198
|
+
if (orgBudget.success) {
|
|
199
|
+
const { limitMicroCents, spentMicroCents, resetsAt } = orgBudget.data;
|
|
200
|
+
if (limitMicroCents !== null &&
|
|
201
|
+
limitMicroCents > 0 &&
|
|
202
|
+
spentMicroCents !== null &&
|
|
203
|
+
spentMicroCents >= 0) {
|
|
204
|
+
monthlyLimit = limitMicroCents / OPENCODE_ZEN_BILLING_UNITS_PER_DOLLAR;
|
|
205
|
+
usage = spentMicroCents;
|
|
206
|
+
// Normalize to canonical ISO so downstream result validation never sees a
|
|
207
|
+
// parseable-but-non-ISO reset (e.g. "0") and drops the whole result.
|
|
208
|
+
const resetTimeMs = resetsAt === null ? Number.NaN : Date.parse(resetsAt);
|
|
209
|
+
budgetResetIso = Number.isFinite(resetTimeMs) ? new Date(resetTimeMs).toISOString() : null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
159
212
|
return {
|
|
160
213
|
success: true,
|
|
161
214
|
data: {
|
|
162
215
|
balance: balance.data,
|
|
163
|
-
monthlyLimit
|
|
164
|
-
monthlyUsage:
|
|
216
|
+
monthlyLimit,
|
|
217
|
+
monthlyUsage: usage,
|
|
165
218
|
lastPayment: null,
|
|
166
219
|
...(autoRecharge.success
|
|
167
220
|
? autoRecharge.data
|
|
168
221
|
: { reload: null, reloadAmount: null, reloadTrigger: null }),
|
|
222
|
+
budgetResetIso,
|
|
169
223
|
},
|
|
170
224
|
errors: optional.flatMap((result) => (result.success ? [] : [result.error])),
|
|
171
225
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-zen.js","sourceRoot":"","sources":["../../src/lib/opencode-zen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"opencode-zen.js","sourceRoot":"","sources":["../../src/lib/opencode-zen.ts"],"names":[],"mappings":"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"}
|