@howaboua/opencode-usage-plugin 0.0.9 → 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.
- package/README.md +11 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -19
- package/dist/usage/fetch.d.ts.map +1 -1
- package/dist/usage/fetch.js +14 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,7 @@ Track AI provider rate limits and quotas in real-time.
|
|
|
6
6
|
|
|
7
7
|
- **Live rate limits** – See Codex/OpenAI hourly/weekly limits at a glance
|
|
8
8
|
- **Proxy quota stats** – Monitor Mirrowel Proxy credentials and tier usage
|
|
9
|
+
- **Copilot usage** – Track GitHub Copilot chat + completions quotas
|
|
9
10
|
- **Inline status** – Results appear directly in your chat, no context switching
|
|
10
11
|
- **Zero setup** – Auto-detects providers from your existing config
|
|
11
12
|
|
|
@@ -18,7 +19,7 @@ Add to your `opencode.json`:
|
|
|
18
19
|
```json
|
|
19
20
|
{
|
|
20
21
|
"$schema": "https://opencode.ai/config.json",
|
|
21
|
-
"
|
|
22
|
+
"plugin": ["@howaboua/opencode-usage-plugin"]
|
|
22
23
|
}
|
|
23
24
|
```
|
|
24
25
|
|
|
@@ -37,6 +38,7 @@ OpenCode installs dependencies automatically on next launch.
|
|
|
37
38
|
```
|
|
38
39
|
/usage codex
|
|
39
40
|
/usage proxy
|
|
41
|
+
/usage copilot
|
|
40
42
|
```
|
|
41
43
|
|
|
42
44
|
### Support the proxy
|
|
@@ -51,6 +53,7 @@ OpenCode installs dependencies automatically on next launch.
|
|
|
51
53
|
|----------|--------|
|
|
52
54
|
| **Codex / OpenAI** | Auth tokens + `/wham/usage` endpoint |
|
|
53
55
|
| **Mirrowel Proxy** | Local `/v1/quota-stats` endpoint |
|
|
56
|
+
| **GitHub Copilot** | GitHub internal usage APIs |
|
|
54
57
|
|
|
55
58
|
## Configuration
|
|
56
59
|
|
|
@@ -70,21 +73,20 @@ Optional config at `~/.config/opencode/usage-config.jsonc`:
|
|
|
70
73
|
// Show/hide providers in /usage output
|
|
71
74
|
"providers": {
|
|
72
75
|
"openai": true,
|
|
73
|
-
"proxy": true
|
|
76
|
+
"proxy": true,
|
|
77
|
+
"copilot": true
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
80
|
```
|
|
77
81
|
|
|
78
82
|
If missing, the plugin creates a default template on first run.
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
### Copilot auth
|
|
81
85
|
|
|
82
|
-
|
|
83
|
-
# Check DB contents
|
|
84
|
-
bun run debug-db.ts
|
|
86
|
+
Copilot is detected from either of these locations:
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
- `~/.local/share/opencode/copilot-usage-token.json`
|
|
89
|
+
- `~/.local/share/opencode/auth.json` with a `github-copilot` entry
|
|
90
|
+
- `~/.config/opencode/copilot-quota-token.json` (optional override)
|
|
89
91
|
|
|
90
92
|
See `AGENTS.md` for internal architecture.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAMjD,eAAO,MAAM,WAAW,EAAE,MAoCzB,CAAA;AAED,eAAe,WAAW,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -4,29 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { commandHooks, sessionHooks, proxyHooks } from "./hooks";
|
|
6
6
|
import { createUsageState } from "./state";
|
|
7
|
-
import { loadAuths } from "./usage/fetch";
|
|
8
7
|
import { loadUsageConfig } from "./usage/config";
|
|
9
|
-
import { existsSync } from "fs";
|
|
10
|
-
import { getQuotaConfigPath, getUsageTokenPath } from "./providers/copilot/auth";
|
|
11
8
|
export const UsagePlugin = async ({ client }) => {
|
|
12
9
|
const state = createUsageState();
|
|
13
10
|
try {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
state.availableProviders.codex =
|
|
19
|
-
usageConfig?.providers?.openai !== undefined
|
|
20
|
-
? usageConfig.providers.openai
|
|
21
|
-
: Boolean(("codex" in auths && auths["codex"]) || ("openai" in auths && auths["openai"]));
|
|
22
|
-
state.availableProviders.proxy =
|
|
23
|
-
usageConfig?.providers?.proxy !== undefined ? usageConfig.providers.proxy : Boolean(usageConfig?.endpoint);
|
|
24
|
-
const authRecord = auths;
|
|
25
|
-
const hasCopilotAuth = Boolean(authRecord["github-copilot"] ||
|
|
26
|
-
authRecord["copilot"] ||
|
|
27
|
-
existsSync(getQuotaConfigPath()) ||
|
|
28
|
-
existsSync(getUsageTokenPath()));
|
|
29
|
-
state.availableProviders.copilot = usageConfig?.providers?.copilot === false ? false : hasCopilotAuth;
|
|
11
|
+
const usageConfig = await loadUsageConfig().catch(() => ({}));
|
|
12
|
+
state.availableProviders.codex = usageConfig?.providers?.openai !== false;
|
|
13
|
+
state.availableProviders.proxy = usageConfig?.providers?.proxy !== false;
|
|
14
|
+
state.availableProviders.copilot = usageConfig?.providers?.copilot !== false;
|
|
30
15
|
}
|
|
31
16
|
catch (err) { }
|
|
32
17
|
async function sendStatusMessage(sessionID, text) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/usage/fetch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/usage/fetch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAI7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAe5C,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAWlD,CAAA;AAED,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIzE;AAED,wBAAsB,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CA6CnF;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC,CASrD"}
|
package/dist/usage/fetch.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import z from "zod";
|
|
6
6
|
import { providers } from "../providers";
|
|
7
|
+
import { loadUsageConfig } from "./config";
|
|
7
8
|
import { getAuthFilePath } from "../utils";
|
|
8
9
|
import { resolveProviderAuths } from "./registry";
|
|
9
10
|
const authEntrySchema = z
|
|
@@ -36,12 +37,24 @@ export function resolveProviderFilter(filter) {
|
|
|
36
37
|
}
|
|
37
38
|
export async function fetchUsageSnapshots(filter) {
|
|
38
39
|
const targetProvider = resolveProviderFilter(filter);
|
|
40
|
+
const usageConfig = await loadUsageConfig().catch(() => null);
|
|
41
|
+
const providerToggles = usageConfig?.providers ?? {};
|
|
42
|
+
const isProviderEnabled = (id) => {
|
|
43
|
+
if (id === "codex")
|
|
44
|
+
return providerToggles.openai !== false;
|
|
45
|
+
if (id === "proxy")
|
|
46
|
+
return providerToggles.proxy !== false;
|
|
47
|
+
if (id === "copilot")
|
|
48
|
+
return providerToggles.copilot !== false;
|
|
49
|
+
return true;
|
|
50
|
+
};
|
|
39
51
|
const auths = await loadAuths();
|
|
40
52
|
const entries = resolveProviderAuths(auths, null);
|
|
41
53
|
const snapshots = [];
|
|
42
54
|
// Fetch from auth-based providers
|
|
43
55
|
const fetches = entries
|
|
44
56
|
.filter((entry) => !targetProvider || entry.providerID === targetProvider)
|
|
57
|
+
.filter((entry) => isProviderEnabled(entry.providerID))
|
|
45
58
|
.map(async (entry) => {
|
|
46
59
|
const provider = providers[entry.providerID];
|
|
47
60
|
if (!provider?.fetchUsage)
|
|
@@ -53,7 +66,7 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
53
66
|
// Always include special providers (no auth entries needed) if no filter or filter matches
|
|
54
67
|
const specialProviders = ["proxy", "copilot"];
|
|
55
68
|
for (const id of specialProviders) {
|
|
56
|
-
if (!targetProvider || targetProvider === id) {
|
|
69
|
+
if ((!targetProvider || targetProvider === id) && isProviderEnabled(id)) {
|
|
57
70
|
const provider = providers[id];
|
|
58
71
|
if (provider?.fetchUsage) {
|
|
59
72
|
fetches.push(provider
|