@arandevcode/opencode-quota-extended 0.1.1 → 0.2.0

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-es.md CHANGED
@@ -21,10 +21,16 @@ Inspirado por [`@slkiser/opencode-quota`](https://github.com/slkiser/opencode-qu
21
21
  <p align="center">🐟 <em>&ldquo;Quien quiera peces que se moje el culo&rdquo;</em> <sub>— para mi padre, que me enseñó a arremangarme y hacer que las cosas pasen</sub>
22
22
  </p>
23
23
 
24
+ <p align="center">
25
+ <a href="https://buymeacoffee.com/arandevcode"><strong>☕ Invítame un café</strong></a>
26
+ <br>
27
+ <sub><a href="https://github.com/sponsors/arandevcode">❤️ Sponsor en GitHub</a></sub>
28
+ </p>
29
+
24
30
  ## Instalación
25
31
 
26
32
  ```sh
27
- opencode plugin @arandevcode/opencode-quota-extended
33
+ opencode plugin --global --force @arandevcode/opencode-quota-extended
28
34
  ```
29
35
 
30
36
  O instala desde GitHub para seguir el desarrollo más reciente:
@@ -38,6 +44,44 @@ O instala desde GitHub para seguir el desarrollo más reciente:
38
44
  }
39
45
  ```
40
46
 
47
+ ## Desinstalación
48
+
49
+ Cuatro pasos, en orden:
50
+
51
+ 1. Quita la entrada del plugin en la config de OpenCode (`~/.config/opencode/opencode.json`):
52
+
53
+ ```jsonc
54
+ // borra las líneas de @arandevcode/opencode-quota-extended dentro de "plugin": []
55
+ {
56
+ "plugin": [
57
+ "@arandevcode/opencode-quota-extended", // ← eliminar
58
+ "@arandevcode/opencode-quota-extended/tui", // ← eliminar
59
+ "@arandevcode/opencode-quota-extended/server" // ← eliminar
60
+ ]
61
+ }
62
+ ```
63
+
64
+ 2. Borra la sidecar de config opcional y el archivo de credenciales de OpenCode Go (solo si los creaste):
65
+
66
+ ```sh
67
+ rm -f ~/.config/opencode/opencode-quota-extended.json
68
+ rm -rf ~/.config/opencode/opencode-quota
69
+ ```
70
+
71
+ 3. (Opcional) Borra el binario CLI global si lo instalaste:
72
+
73
+ ```sh
74
+ npm rm -g @arandevcode/opencode-quota-extended
75
+ ```
76
+
77
+ 4. (Opcional) Borra cualquier clon local del repo que hayas usado para seguir el desarrollo:
78
+
79
+ ```sh
80
+ rm -rf ./opencode-quota-extended
81
+ ```
82
+
83
+ Reinicia OpenCode y el panel de Quota desaparecerá. **Nota:** el plugin **no** toca `~/.local/share/opencode/auth.json` — tus tokens de auth nunca se modifican.
84
+
41
85
  ## CLI
42
86
 
43
87
  Visualiza la cuota desde la terminal sin abrir el TUI:
@@ -55,7 +99,7 @@ npm run quota # desde el directorio del repo
55
99
  <sub><em>-cli example-</em></sub>
56
100
  </p>
57
101
 
58
- Colores de semáforo: verde (ok), naranja (advertencia), rojo (error).
102
+ Colores de semáforo: verde (ok), naranja (advertencia), rojo (error). Todos los colores vienen del tema activo de OpenCode — se adaptan automáticamente a la paleta del usuario.
59
103
 
60
104
  ## Configuración
61
105
 
@@ -79,7 +123,7 @@ Registra un plugin TUI que renderiza un panel `sidebar_content` en la posición
79
123
  | **GitHub Copilot** | Solicitudes Premium (ventana única) | `auth.json` → entrada `github-copilot` |
80
124
  | **OpenCode Go** | 5h, Semanal, Mensual | Archivo de configuración o vars de entorno |
81
125
 
82
- Colores de semáforo: ≥50% verde (`accent`), 25-49% amarillo (`warning`), <25% rojo (`error`).
126
+ Colores de semáforo: ≥50% `theme.success` (verde), 25-49% `theme.warning` (naranja), <25% `theme.error` (rojo).
83
127
 
84
128
  ### Autenticación
85
129
 
@@ -101,6 +145,15 @@ Crea `~/.config/opencode/opencode-quota/opencode-go.json`:
101
145
  | `workspaceId` | ID de tu workspace en OpenCode | Entra en [opencode.ai/go](https://opencode.ai/go). La URL es `https://opencode.ai/workspace/wrk_XXX/go` — copia la parte `wrk_XXX`. |
102
146
  | `authCookie` | Cookie de sesión para autenticación | Abre DevTools (F12) → Application → Cookies → `opencode.ai` → busca la cookie `auth` (empieza con `Fe26.2...`). O ejecuta en la consola: `document.cookie.match(/(?:^\|;\s*)auth=([^;]+)/)?.[1]` |
103
147
 
148
+ **Múltiples workspaces/cuentas:** cualquier archivo `opencode-go-<sufijo>.json` en el mismo directorio añade una sección extra `Opencode GO (<sufijo>)` (p. ej. `opencode-go-work.json` → **Opencode GO (work)**). El `opencode-go.json` base siempre se muestra como **OpenCode Go**.
149
+
150
+ ```sh
151
+ # p. ej. un segundo workspace
152
+ cp ~/.config/opencode/opencode-quota/opencode-go.json \
153
+ ~/.config/opencode/opencode-quota/opencode-go-work.json
154
+ # luego edita workspaceId/authCookie dentro de opencode-go-work.json
155
+ ```
156
+
104
157
  **Setup automatizado** (recomendado):
105
158
  ```sh
106
159
  npm run setup
@@ -128,6 +181,20 @@ npm test # vitest
128
181
  npm run typecheck # type-check sin emitir
129
182
  ```
130
183
 
184
+ ### Patrones TUI y tema
185
+
186
+ Los colores se obtienen en vivo de `api.theme.current`. El mapeo de semáforo respeta el tema:
187
+
188
+ | Restante | Color (clave de tema) | Hex por defecto (AMOLED) |
189
+ |---|---|---|
190
+ | ≥50% | `theme.success` (verde) | `#00ff88` |
191
+ | 25-49% | `theme.warning` (naranja) | `#ffea00` |
192
+ | <25% | `theme.error` (rojo) | `#ff1744` |
193
+
194
+ La barra de progreso sigue el patrón gauge de `opentui-theme-colors`: un `<text>` por celda, `bg={themeColor}` en las celdas llenas y `bg={theme.backgroundElement}` en las vacías, con la etiqueta de porcentaje en primer plano con contraste correcto (`backgroundPanel` en lleno, `textMuted` en vacío). Es el mismo patrón que la barra de contexto en `@arandevcode/opencode-stats`.
195
+
196
+ La barra de ratio antigua con `flexGrow` y los hex hardcodeados (`#6b8e23`, `#ffa500`, `#ff6b6b`) ya no existen.
197
+
131
198
  ### Estructura del proyecto
132
199
 
133
200
  ```
package/README.md CHANGED
@@ -22,10 +22,16 @@ Heavily inspired by [`@slkiser/opencode-quota`](https://github.com/slkiser/openc
22
22
  <em>&ldquo;If you want fish, get your ass wet&rdquo;</em> <sub>— for my father, who taught me to roll up my sleeves and get it done</sub>
23
23
  </p>
24
24
 
25
+ <p align="center">
26
+ <a href="https://buymeacoffee.com/arandevcode"><strong>☕ Buy me a coffee</strong></a>
27
+ <br>
28
+ <sub><a href="https://github.com/sponsors/arandevcode">❤️ Sponsor on GitHub</a></sub>
29
+ </p>
30
+
25
31
  ## Install
26
32
 
27
33
  ```sh
28
- opencode plugin @arandevcode/opencode-quota-extended
34
+ opencode plugin --global --force @arandevcode/opencode-quota-extended
29
35
  ```
30
36
 
31
37
  Or install from GitHub source to follow latest development:
@@ -39,6 +45,44 @@ Or install from GitHub source to follow latest development:
39
45
  }
40
46
  ```
41
47
 
48
+ ## Uninstall
49
+
50
+ Four steps, in order:
51
+
52
+ 1. Remove the plugin entry from your OpenCode config (`~/.config/opencode/opencode.json`):
53
+
54
+ ```jsonc
55
+ // delete the @arandevcode/opencode-quota-extended lines inside "plugin": []
56
+ {
57
+ "plugin": [
58
+ "@arandevcode/opencode-quota-extended", // ← remove
59
+ "@arandevcode/opencode-quota-extended/tui", // ← remove
60
+ "@arandevcode/opencode-quota-extended/server" // ← remove
61
+ ]
62
+ }
63
+ ```
64
+
65
+ 2. Delete the optional sidecar config and OpenCode Go credential file (only if you created them):
66
+
67
+ ```sh
68
+ rm -f ~/.config/opencode/opencode-quota-extended.json
69
+ rm -rf ~/.config/opencode/opencode-quota
70
+ ```
71
+
72
+ 3. (Optional) Remove the global CLI binary if you installed it:
73
+
74
+ ```sh
75
+ npm rm -g @arandevcode/opencode-quota-extended
76
+ ```
77
+
78
+ 4. (Optional) Remove any local source clone you may have used to follow development:
79
+
80
+ ```sh
81
+ rm -rf ./opencode-quota-extended
82
+ ```
83
+
84
+ Restart OpenCode and the Quota panel will be gone. **Note:** the plugin does **not** store or touch `~/.local/share/opencode/auth.json` — your auth tokens are never modified.
85
+
42
86
  ## CLI
43
87
 
44
88
  View quota from the terminal without opening the TUI:
@@ -56,7 +100,7 @@ npm run quota # from the repo directory
56
100
  <sub><em>-cli example-</em></sub>
57
101
  </p>
58
102
 
59
- Traffic-light colors: green (ok), orange (warning), red (error).
103
+ Traffic-light colors: green (ok), orange (warning), red (error). All colors come from the active OpenCode theme — they adapt to the user's palette automatically.
60
104
 
61
105
  ## Configuration
62
106
 
@@ -80,7 +124,7 @@ Registers a TUI plugin that renders a `sidebar_content` panel at order 145, show
80
124
  | **GitHub Copilot** | Premium requests (single window) | `auth.json` → `github-copilot` entry |
81
125
  | **OpenCode Go** | 5h, Weekly, Monthly | Config file or env vars |
82
126
 
83
- Traffic-light colors: ≥50% green (`accent`), 25-49% yellow (`warning`), <25% red (`error`).
127
+ Traffic-light colors: ≥50% `theme.success` (green), 25-49% `theme.warning` (orange), <25% `theme.error` (red).
84
128
 
85
129
  ### Authentication
86
130
 
@@ -102,6 +146,15 @@ Create `~/.config/opencode/opencode-quota/opencode-go.json`:
102
146
  | `workspaceId` | Your OpenCode workspace ID | Log in at [opencode.ai/go](https://opencode.ai/go). The URL is `https://opencode.ai/workspace/wrk_XXX/go` — copy the `wrk_XXX` part. |
103
147
  | `authCookie` | Session cookie for auth | Open DevTools (F12) → Application → Cookies → `opencode.ai` → find the `auth` cookie (starts with `Fe26.2...`). Or run this in the console: `document.cookie.match(/(?:^\|;\s*)auth=([^;]+)/)?.[1]` |
104
148
 
149
+ **Multiple workspaces/accounts:** any `opencode-go-<suffix>.json` file in the same directory adds an extra `Opencode GO (<suffix>)` section (e.g. `opencode-go-work.json` → **Opencode GO (work)**). The base `opencode-go.json` always renders as **OpenCode Go**.
150
+
151
+ ```sh
152
+ # e.g. a second workspace
153
+ cp ~/.config/opencode/opencode-quota/opencode-go.json \
154
+ ~/.config/opencode/opencode-quota/opencode-go-work.json
155
+ # then edit workspaceId/authCookie inside opencode-go-work.json
156
+ ```
157
+
105
158
  **Automated setup** (recommended):
106
159
  ```sh
107
160
  npm run setup
@@ -129,6 +182,20 @@ npm test # vitest
129
182
  npm run typecheck # type-check without emitting
130
183
  ```
131
184
 
185
+ ### TUI Patterns & Theme
186
+
187
+ Colors are sourced live from `api.theme.current`. The traffic-light mapping is theme-aware:
188
+
189
+ | Remaining | Color (theme key) | Hex default (AMOLED) |
190
+ |---|---|---|
191
+ | ≥50% | `theme.success` (green) | `#00ff88` |
192
+ | 25-49% | `theme.warning` (orange) | `#ffea00` |
193
+ | <25% | `theme.error` (red) | `#ff1744` |
194
+
195
+ The progress bar follows the `opentui-theme-colors` gauge pattern: one `<text>` per cell, `bg={themeColor}` on filled cells and `bg={theme.backgroundElement}` on empty cells, with the percent label rendered in the foreground with proper contrast (`backgroundPanel` on filled, `textMuted` on empty). This is the same pattern as the context progress bar in `@arandevcode/opencode-stats`.
196
+
197
+ The old `flexGrow` ratio bar and the hardcoded hex values (`#6b8e23`, `#ffa500`, `#ff6b6b`) are gone.
198
+
132
199
  ### Project structure
133
200
 
134
201
  ```
package/bin/quota.mjs CHANGED
@@ -10,9 +10,9 @@ import { formatResetCombined } from "../dist/lib/reset-format.js";
10
10
  const INDENT = 4;
11
11
 
12
12
  const COLORS = {
13
- ok: "\x1b[38;2;107;131;35m",
14
- warning: "\x1b[38;2;255;165;0m",
15
- error: "\x1b[38;2;255;107;107m",
13
+ ok: "\x1b[32m",
14
+ warning: "\x1b[33m",
15
+ error: "\x1b[31m",
16
16
  };
17
17
  const RESET = "\x1b[0m";
18
18
  const BOLD = "\x1b[1m";
@@ -88,10 +88,9 @@ async function main() {
88
88
  const labelStr = windowLabel(win);
89
89
  console.log(" ".repeat(INDENT) + padRight(labelStr, resetStyle));
90
90
  console.log(" ".repeat(INDENT) + color + bar.filled + bar.empty + RESET);
91
- const combined = `${usedPct(pct)} / `;
92
- const leftStr = `${pct}% left`;
93
- const pad = Math.max(0, cols() - INDENT - stripAnsi(combined + leftStr).length);
94
- console.log(" ".repeat(INDENT + pad) + combined + color + leftStr + RESET);
91
+ const leftStr = `${color}${pct}% left${RESET}`;
92
+ const rightStr = `${DIM}${usedPct(pct)}${RESET}`;
93
+ console.log(" ".repeat(INDENT) + padRight(leftStr, rightStr));
95
94
  }
96
95
  console.log();
97
96
  }
@@ -17,6 +17,25 @@ export type OpenCodeGoConfigResolution = {
17
17
  } | {
18
18
  state: "none";
19
19
  };
20
+ /** A named OpenCode Go instance backed by an opencode-go-<suffix>.json file. */
21
+ export interface OpenCodeGoInstance {
22
+ /** Stable id, e.g. "opencode-go-work". */
23
+ id: string;
24
+ /** Display label, e.g. "Opencode GO (work)". */
25
+ label: string;
26
+ }
27
+ /** Resolve the default OpenCode Go config (env vars, then opencode-go.json). */
20
28
  export declare function resolveOpenCodeGoConfig(): Promise<OpenCodeGoConfigResolution>;
29
+ /** Resolve the config for a specific instance id. */
30
+ export declare function resolveOpenCodeGoInstance(id: string): Promise<OpenCodeGoConfigResolution>;
31
+ /**
32
+ * Discover additional OpenCode Go instances from opencode-go-<suffix>.json
33
+ * files present in the sidecar directory. Returns stable, deduplicated
34
+ * instance descriptors (first directory with a matching file wins).
35
+ */
36
+ export declare function discoverOpenCodeGoInstances(): Promise<OpenCodeGoInstance[]>;
21
37
  export declare function resolveOpenCodeGoConfigCached(): Promise<OpenCodeGoConfigResolution>;
38
+ export declare function resolveOpenCodeGoInstanceCached(id: string): Promise<OpenCodeGoConfigResolution>;
39
+ /** Clear all cached OpenCode Go config resolutions (used by tests). */
40
+ export declare function clearOpenCodeGoConfigCache(): void;
22
41
  //# sourceMappingURL=opencode-go-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"opencode-go-config.d.ts","sourceRoot":"","sources":["../../src/lib/opencode-go-config.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,gBAAgB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,0BAA0B,GAClC;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjE;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,GAAG,YAAY,CAAA;CAAE,GAC9E;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAiCtB,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,0BAA0B,CAAC,CA0CnF;AAKD,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAMzF"}
1
+ {"version":3,"file":"opencode-go-config.d.ts","sourceRoot":"","sources":["../../src/lib/opencode-go-config.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,gBAAgB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,0BAA0B,GAClC;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjE;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,GAAG,YAAY,CAAA;CAAE,GAC9E;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtB,gFAAgF;AAChF,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;CACf;AAoGD,gFAAgF;AAChF,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAInF;AAED,qDAAqD;AACrD,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,0BAA0B,CAAC,CAErC;AAED;;;;GAIG;AACH,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAwBjF;AAKD,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAMzF;AAOD,wBAAsB,+BAA+B,CACnD,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,0BAA0B,CAAC,CAOrC;AAED,uEAAuE;AACvE,wBAAgB,0BAA0B,IAAI,IAAI,CAGjD"}
@@ -1,9 +1,13 @@
1
- import { readFile } from "fs/promises";
1
+ import { readFile, readdir } from "fs/promises";
2
2
  import { homedir } from "os";
3
3
  import { join } from "path";
4
4
  import { xdgConfig } from "xdg-basedir";
5
5
  const SIDECAR_DIR = "opencode-quota";
6
- const SIDECAR_FILE = "opencode-go.json";
6
+ const DEFAULT_FILE = "opencode-go.json";
7
+ const EXTRA_PREFIX = "opencode-go-";
8
+ const EXTRA_LABEL_PREFIX = "Opencode GO";
9
+ const DEFAULT_ID = "opencode-go";
10
+ const DEFAULT_LABEL = "OpenCode Go";
7
11
  function getConfigDirCandidates() {
8
12
  const dirs = [];
9
13
  if (process.env.OPENCODE_CONFIG_DIR) {
@@ -16,8 +20,21 @@ function getConfigDirCandidates() {
16
20
  dirs.push(join(homedir(), ".config", "opencode"));
17
21
  return Array.from(new Set(dirs));
18
22
  }
19
- function getConfigCandidatePaths() {
20
- return getConfigDirCandidates().map((d) => join(d, SIDECAR_DIR, SIDECAR_FILE));
23
+ function getSidecarDirCandidates() {
24
+ return getConfigDirCandidates().map((d) => join(d, SIDECAR_DIR));
25
+ }
26
+ function getDefaultCandidatePaths() {
27
+ return getSidecarDirCandidates().map((d) => join(d, DEFAULT_FILE));
28
+ }
29
+ function getInstanceCandidatePaths(id) {
30
+ if (id === DEFAULT_ID)
31
+ return getDefaultCandidatePaths();
32
+ if (!id.startsWith(EXTRA_PREFIX))
33
+ return [];
34
+ const suffix = id.slice(EXTRA_PREFIX.length);
35
+ if (!suffix)
36
+ return [];
37
+ return getSidecarDirCandidates().map((d) => join(d, `${EXTRA_PREFIX}${suffix}.json`));
21
38
  }
22
39
  function fromEnv() {
23
40
  const workspaceId = process.env.OPENCODE_GO_WORKSPACE_ID?.trim();
@@ -33,51 +50,103 @@ function fromEnv() {
33
50
  missing: workspaceId ? "authCookie" : "workspaceId",
34
51
  };
35
52
  }
53
+ /**
54
+ * Read a single sidecar file and parse it into a resolution.
55
+ * Returns null when the file does not exist.
56
+ */
57
+ async function readFileResolution(path) {
58
+ let raw;
59
+ try {
60
+ raw = await readFile(path, "utf8");
61
+ }
62
+ catch (err) {
63
+ if (err.code === "ENOENT")
64
+ return null;
65
+ return {
66
+ state: "invalid",
67
+ source: path,
68
+ error: err instanceof Error ? err.message : String(err),
69
+ };
70
+ }
71
+ let parsed;
72
+ try {
73
+ parsed = JSON.parse(raw);
74
+ }
75
+ catch (err) {
76
+ return {
77
+ state: "invalid",
78
+ source: path,
79
+ error: err instanceof Error ? err.message : String(err),
80
+ };
81
+ }
82
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
83
+ return { state: "invalid", source: path, error: "Config must be a JSON object" };
84
+ }
85
+ const obj = parsed;
86
+ const workspaceId = typeof obj.workspaceId === "string" ? obj.workspaceId.trim() : "";
87
+ const authCookie = typeof obj.authCookie === "string" ? obj.authCookie.trim() : "";
88
+ if (workspaceId && authCookie) {
89
+ return { state: "configured", config: { workspaceId, authCookie }, source: path };
90
+ }
91
+ return {
92
+ state: "incomplete",
93
+ source: path,
94
+ missing: workspaceId ? "authCookie" : "workspaceId",
95
+ };
96
+ }
97
+ async function resolveFromPaths(paths) {
98
+ for (const path of paths) {
99
+ const resolution = await readFileResolution(path);
100
+ if (resolution === null)
101
+ continue;
102
+ return resolution;
103
+ }
104
+ return { state: "none" };
105
+ }
106
+ /** Resolve the default OpenCode Go config (env vars, then opencode-go.json). */
36
107
  export async function resolveOpenCodeGoConfig() {
37
108
  const envResult = fromEnv();
38
109
  if (envResult.state !== "none")
39
110
  return envResult;
40
- for (const path of getConfigCandidatePaths()) {
41
- let raw;
42
- try {
43
- raw = await readFile(path, "utf8");
44
- }
45
- catch (err) {
46
- if (err.code === "ENOENT")
47
- continue;
48
- return {
49
- state: "invalid",
50
- source: path,
51
- error: err instanceof Error ? err.message : String(err),
52
- };
53
- }
54
- let parsed;
111
+ return resolveFromPaths(getDefaultCandidatePaths());
112
+ }
113
+ /** Resolve the config for a specific instance id. */
114
+ export async function resolveOpenCodeGoInstance(id) {
115
+ return resolveFromPaths(getInstanceCandidatePaths(id));
116
+ }
117
+ /**
118
+ * Discover additional OpenCode Go instances from opencode-go-<suffix>.json
119
+ * files present in the sidecar directory. Returns stable, deduplicated
120
+ * instance descriptors (first directory with a matching file wins).
121
+ */
122
+ export async function discoverOpenCodeGoInstances() {
123
+ const seen = new Set();
124
+ const instances = [];
125
+ for (const dir of getSidecarDirCandidates()) {
126
+ let entries;
55
127
  try {
56
- parsed = JSON.parse(raw);
128
+ entries = await readdir(dir);
57
129
  }
58
- catch (err) {
59
- return {
60
- state: "invalid",
61
- source: path,
62
- error: err instanceof Error ? err.message : String(err),
63
- };
130
+ catch {
131
+ continue;
64
132
  }
65
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
66
- return { state: "invalid", source: path, error: "Config must be a JSON object" };
67
- }
68
- const obj = parsed;
69
- const workspaceId = typeof obj.workspaceId === "string" ? obj.workspaceId.trim() : "";
70
- const authCookie = typeof obj.authCookie === "string" ? obj.authCookie.trim() : "";
71
- if (workspaceId && authCookie) {
72
- return { state: "configured", config: { workspaceId, authCookie }, source: path };
133
+ entries.sort();
134
+ for (const name of entries) {
135
+ if (!name.startsWith(EXTRA_PREFIX))
136
+ continue;
137
+ if (!name.endsWith(".json"))
138
+ continue;
139
+ const suffix = name.slice(EXTRA_PREFIX.length, -".json".length);
140
+ if (!suffix || seen.has(suffix))
141
+ continue;
142
+ seen.add(suffix);
143
+ instances.push({
144
+ id: `${EXTRA_PREFIX}${suffix}`,
145
+ label: `${EXTRA_LABEL_PREFIX} (${suffix})`,
146
+ });
73
147
  }
74
- return {
75
- state: "incomplete",
76
- source: path,
77
- missing: workspaceId ? "authCookie" : "workspaceId",
78
- };
79
148
  }
80
- return { state: "none" };
149
+ return instances;
81
150
  }
82
151
  let cached = null;
83
152
  const CACHE_MAX_AGE_MS = 30_000;
@@ -89,4 +158,19 @@ export async function resolveOpenCodeGoConfigCached() {
89
158
  cached = { at: now, value };
90
159
  return value;
91
160
  }
161
+ const instanceCache = new Map();
162
+ export async function resolveOpenCodeGoInstanceCached(id) {
163
+ const now = Date.now();
164
+ const hit = instanceCache.get(id);
165
+ if (hit && now - hit.at < CACHE_MAX_AGE_MS)
166
+ return hit.value;
167
+ const value = await resolveOpenCodeGoInstance(id);
168
+ instanceCache.set(id, { at: now, value });
169
+ return value;
170
+ }
171
+ /** Clear all cached OpenCode Go config resolutions (used by tests). */
172
+ export function clearOpenCodeGoConfigCache() {
173
+ cached = null;
174
+ instanceCache.clear();
175
+ }
92
176
  //# sourceMappingURL=opencode-go-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"opencode-go-config.js","sourceRoot":"","sources":["../../src/lib/opencode-go-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"opencode-go-config.js","sourceRoot":"","sources":["../../src/lib/opencode-go-config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqE3C,eAAO,MAAM,cAAc,EAAE,QA+F5B,CAAC"}
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA+E3C,eAAO,MAAM,cAAc,EAAE,QAiG5B,CAAC"}
@@ -41,6 +41,20 @@ function windowResetIso(win) {
41
41
  }
42
42
  return undefined;
43
43
  }
44
+ function windowLabel(win, fallback) {
45
+ if (!win)
46
+ return fallback;
47
+ const seconds = win.limit_window_seconds;
48
+ if (typeof seconds !== "number")
49
+ return fallback;
50
+ if (seconds === 18_000)
51
+ return "5h";
52
+ if (seconds === 604_800)
53
+ return "Weekly";
54
+ if (seconds >= 2_592_000 && seconds <= 2_678_400)
55
+ return "Monthly";
56
+ return fallback;
57
+ }
44
58
  function windowFromData(id, label, win) {
45
59
  if (!win)
46
60
  return null;
@@ -119,13 +133,15 @@ export const openaiProvider = {
119
133
  const rateLimit = (data.rate_limit ?? null);
120
134
  const codeReview = (data.code_review_rate_limit ?? null);
121
135
  const windows = [];
122
- const primary = windowFromData("5h", "5h", rateLimit?.primary_window);
136
+ const primaryWindowData = rateLimit?.primary_window;
137
+ const primary = windowFromData("5h", windowLabel(primaryWindowData, "5h"), primaryWindowData);
123
138
  if (primary)
124
139
  windows.push(primary);
125
- const secondary = windowFromData("weekly", "Weekly", rateLimit?.secondary_window);
140
+ const secondaryWindowData = rateLimit?.secondary_window;
141
+ const secondary = windowFromData("weekly", windowLabel(secondaryWindowData, "Weekly"), secondaryWindowData);
126
142
  if (secondary)
127
143
  windows.push(secondary);
128
- const codeReviewPrimary = windowFromData("code-review", "Code Review", codeReview?.primary_window);
144
+ const codeReviewPrimary = windowFromData("code-review", windowLabel(codeReview?.primary_window, "Code Review"), codeReview?.primary_window);
129
145
  if (codeReviewPrimary)
130
146
  windows.push(codeReviewPrimary);
131
147
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAItD,MAAM,SAAS,GAAG,4CAA4C,CAAC;AAC/D,MAAM,UAAU,GAAG,+BAA+B,CAAC;AAEnD,SAAS,aAAa,CAAC,IAAoD;IACzE,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,UAAU,GAA8B,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACtF,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAC7F,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK;YAAE,SAAS;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,UAAU,CAAC,QAAiB;IACnC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC3E,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,cAAc,CAAC;IACjD,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,eAAe,CAAC;IACnD,OAAO,WAAW,QAAQ,GAAG,CAAC;AAChC,CAAC;AAED,SAAS,cAAc,CAAC,GAAwC;IAC9D,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC;IAC7B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAC/C,OAAO,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAChD,CAAC;IACD,MAAM,UAAU,GAAG,GAAG,CAAC,mBAAmB,CAAC;IAC3C,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACrD,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAChE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,cAAc,CACrB,EAAY,EACZ,KAAa,EACb,GAAwC;IAExC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC;IAC9B,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO;QACL,EAAE;QACF,KAAK;QACL,gBAAgB,EAAE,YAAY,CAAC,GAAG,GAAG,IAAI,CAAC;QAC1C,YAAY,EAAE,cAAc,CAAC,GAAG,CAAC;KAClC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,GAAa;IAC3C,IAAI,CAAC;QACH,OAAO,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAa;IACtC,EAAE,EAAE,QAAQ;IACZ,YAAY,EAAE,QAAQ;IAEtB,KAAK,CAAC,WAAW,CAAC,IAAqB;QACrC,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC7C,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,GAAoB;QAC9B,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC7C,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO;oBACL,EAAE,EAAE,QAAQ;oBACZ,KAAK,EAAE,QAAQ;oBACf,MAAM,EAAE,SAAS;oBACjB,OAAO,EAAE,EAAE;oBACX,SAAS;iBACV,CAAC;YACJ,CAAC;YAED,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;gBACpE,OAAO;oBACL,EAAE,EAAE,QAAQ;oBACZ,KAAK,EAAE,QAAQ;oBACf,MAAM,EAAE,OAAO;oBACf,KAAK,EAAE,eAAe;oBACtB,OAAO,EAAE,EAAE;oBACX,SAAS;iBACV,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,GAA2B;gBACtC,aAAa,EAAE,UAAU,KAAK,CAAC,MAAM,EAAE;gBACvC,YAAY,EAAE,UAAU;aACzB,CAAC;YACF,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtE,OAAO,CAAC,oBAAoB,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;YAClD,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAChC,SAAS,EACT,EAAE,OAAO,EAAE,EACX,GAAG,CAAC,gBAAgB,CACrB,CAAC;YAEF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;gBACzC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBACnC,OAAO;oBACL,EAAE,EAAE,QAAQ;oBACZ,KAAK,EAAE,QAAQ;oBACf,MAAM,EAAE,OAAO;oBACf,KAAK,EAAE,oBAAoB,GAAG,CAAC,MAAM,KAAK,OAAO,EAAE;oBACnD,OAAO,EAAE,EAAE;oBACX,SAAS;iBACV,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;YAC3D,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAY,CAAC;YACrD,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAmC,CAAC;YAC9E,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,sBAAsB,IAAI,IAAI,CAAmC,CAAC;YAE3F,MAAM,OAAO,GAAkB,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,cAAqD,CAAC,CAAC;YAC7G,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnC,MAAM,SAAS,GAAG,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAuD,CAAC,CAAC;YACzH,IAAI,SAAS;gBAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvC,MAAM,iBAAiB,GAAG,cAAc,CAAC,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,cAAqD,CAAC,CAAC;YAC1I,IAAI,iBAAiB;gBAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAEvD,OAAO;gBACL,EAAE,EAAE,QAAQ;gBACZ,KAAK;gBACL,MAAM,EAAE,IAAI;gBACZ,OAAO;gBACP,SAAS;aACV,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO;gBACL,EAAE,EAAE,QAAQ;gBACZ,KAAK,EAAE,QAAQ;gBACf,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;gBAC5B,OAAO,EAAE,EAAE;gBACX,SAAS;aACV,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"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"}
@@ -5,8 +5,16 @@
5
5
  * Requires a workspace ID and auth cookie (either via env vars
6
6
  * OPENCODE_GO_WORKSPACE_ID / OPENCODE_GO_AUTH_COOKIE, or a sidecar file at
7
7
  * ~/.config/opencode/opencode-quota/opencode-go.json).
8
+ * Additional instances can be configured via opencode-go-<suffix>.json files,
9
+ * each rendered as its own "Opencode Go <suffix>" section.
8
10
  * Returns up to 3 windows: 5h (rolling), Weekly, Monthly.
9
11
  */
10
12
  import type { Provider } from "./types.js";
13
+ /** Options to create a named OpenCode Go provider instance. */
14
+ export interface OpenCodeGoProviderOptions {
15
+ id: string;
16
+ label: string;
17
+ }
18
+ export declare function createOpenCodeGoProvider(opts: OpenCodeGoProviderOptions): Provider;
11
19
  export declare const opencodeGoProvider: Provider;
12
20
  //# sourceMappingURL=opencode-go.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"opencode-go.d.ts","sourceRoot":"","sources":["../../src/providers/opencode-go.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,YAAY,CAAC;AAyC5D,eAAO,MAAM,kBAAkB,EAAE,QA6EhC,CAAC"}
1
+ {"version":3,"file":"opencode-go.d.ts","sourceRoot":"","sources":["../../src/providers/opencode-go.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,YAAY,CAAC;AAyC5D,+DAA+D;AAC/D,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,yBAAyB,GAAG,QAAQ,CAgFlF;AAED,eAAO,MAAM,kBAAkB,EAAE,QAG/B,CAAC"}
@@ -1,4 +1,4 @@
1
- import { resolveOpenCodeGoConfigCached } from "../lib/opencode-go-config.js";
1
+ import { resolveOpenCodeGoInstanceCached } from "../lib/opencode-go-config.js";
2
2
  import { fetchWithTimeout } from "../lib/http.js";
3
3
  import { clampPercent } from "../lib/reset-format.js";
4
4
  const DASHBOARD_URL_PREFIX = "https://opencode.ai/workspace/";
@@ -22,81 +22,88 @@ function parseWindow(html, field) {
22
22
  }
23
23
  return null;
24
24
  }
25
- export const opencodeGoProvider = {
26
- id: "opencode-go",
27
- defaultLabel: "OpenCode Go",
28
- async isAvailable() {
29
- const r = await resolveOpenCodeGoConfigCached();
30
- return r.state === "configured";
31
- },
32
- async fetch(ctx) {
33
- const fetchedAt = new Date().toISOString();
34
- const base = {
35
- id: "opencode-go",
36
- label: "OpenCode Go",
37
- status: "no-auth",
38
- windows: [],
39
- fetchedAt,
40
- };
41
- const r = await resolveOpenCodeGoConfigCached();
42
- if (r.state === "none")
43
- return { ...base, status: "skipped" };
44
- if (r.state === "incomplete") {
45
- return {
46
- ...base,
47
- status: "error",
48
- error: `Missing ${r.missing} (source: ${r.source})`,
25
+ export function createOpenCodeGoProvider(opts) {
26
+ const { id, label } = opts;
27
+ return {
28
+ id,
29
+ defaultLabel: label,
30
+ async isAvailable() {
31
+ const r = await resolveOpenCodeGoInstanceCached(id);
32
+ return r.state === "configured";
33
+ },
34
+ async fetch(ctx) {
35
+ const fetchedAt = new Date().toISOString();
36
+ const base = {
37
+ id,
38
+ label,
39
+ status: "no-auth",
40
+ windows: [],
41
+ fetchedAt,
49
42
  };
50
- }
51
- if (r.state === "invalid") {
52
- return { ...base, status: "error", error: `Invalid config: ${r.error}` };
53
- }
54
- const { workspaceId, authCookie } = r.config;
55
- try {
56
- const url = `${DASHBOARD_URL_PREFIX}${encodeURIComponent(workspaceId)}${DASHBOARD_URL_SUFFIX}`;
57
- const res = await fetchWithTimeout(url, {
58
- method: "GET",
59
- headers: {
60
- "User-Agent": USER_AGENT,
61
- Accept: "text/html",
62
- Cookie: `auth=${authCookie}`,
63
- },
64
- }, ctx.requestTimeoutMs);
65
- if (!res.ok) {
66
- const text = (await res.text()).slice(0, 120);
43
+ const r = await resolveOpenCodeGoInstanceCached(id);
44
+ if (r.state === "none")
45
+ return { ...base, status: "skipped" };
46
+ if (r.state === "incomplete") {
67
47
  return {
68
48
  ...base,
69
49
  status: "error",
70
- error: `OpenCode Go dashboard error ${res.status}: ${text}`,
50
+ error: `Missing ${r.missing} (source: ${r.source})`,
71
51
  };
72
52
  }
73
- const html = await res.text();
74
- const now = Date.now();
75
- const windows = [];
76
- for (const spec of WINDOWS) {
77
- const parsed = parseWindow(html, spec.field);
78
- if (!parsed)
79
- continue;
80
- windows.push({
81
- id: spec.id,
82
- label: spec.label,
83
- percentRemaining: clampPercent(100 - parsed.usagePercent),
84
- resetTimeIso: new Date(now + parsed.resetInSec * 1000).toISOString(),
85
- });
53
+ if (r.state === "invalid") {
54
+ return { ...base, status: "error", error: `Invalid config: ${r.error}` };
86
55
  }
87
- if (windows.length === 0) {
88
- return {
89
- ...base,
90
- status: "error",
91
- error: "Could not parse any known OpenCode Go dashboard usage windows",
92
- };
56
+ const { workspaceId, authCookie } = r.config;
57
+ try {
58
+ const url = `${DASHBOARD_URL_PREFIX}${encodeURIComponent(workspaceId)}${DASHBOARD_URL_SUFFIX}`;
59
+ const res = await fetchWithTimeout(url, {
60
+ method: "GET",
61
+ headers: {
62
+ "User-Agent": USER_AGENT,
63
+ Accept: "text/html",
64
+ Cookie: `auth=${authCookie}`,
65
+ },
66
+ }, ctx.requestTimeoutMs);
67
+ if (!res.ok) {
68
+ const text = (await res.text()).slice(0, 120);
69
+ return {
70
+ ...base,
71
+ status: "error",
72
+ error: `OpenCode Go dashboard error ${res.status}: ${text}`,
73
+ };
74
+ }
75
+ const html = await res.text();
76
+ const now = Date.now();
77
+ const windows = [];
78
+ for (const spec of WINDOWS) {
79
+ const parsed = parseWindow(html, spec.field);
80
+ if (!parsed)
81
+ continue;
82
+ windows.push({
83
+ id: spec.id,
84
+ label: spec.label,
85
+ percentRemaining: clampPercent(100 - parsed.usagePercent),
86
+ resetTimeIso: new Date(now + parsed.resetInSec * 1000).toISOString(),
87
+ });
88
+ }
89
+ if (windows.length === 0) {
90
+ return {
91
+ ...base,
92
+ status: "error",
93
+ error: "Could not parse any known OpenCode Go dashboard usage windows",
94
+ };
95
+ }
96
+ return { ...base, status: "ok", windows };
97
+ }
98
+ catch (err) {
99
+ const message = err instanceof Error ? err.message : String(err);
100
+ return { ...base, status: "error", error: message.slice(0, 200) };
93
101
  }
94
- return { ...base, status: "ok", windows };
95
- }
96
- catch (err) {
97
- const message = err instanceof Error ? err.message : String(err);
98
- return { ...base, status: "error", error: message.slice(0, 200) };
99
- }
100
- },
101
- };
102
+ },
103
+ };
104
+ }
105
+ export const opencodeGoProvider = createOpenCodeGoProvider({
106
+ id: "opencode-go",
107
+ label: "OpenCode Go",
108
+ });
102
109
  //# sourceMappingURL=opencode-go.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"opencode-go.js","sourceRoot":"","sources":["../../src/providers/opencode-go.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"opencode-go.js","sourceRoot":"","sources":["../../src/providers/opencode-go.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,10 @@
4
4
  * Holds the list of available providers and exposes a single
5
5
  * `collectSnapshot()` that fans out fetches in parallel and returns
6
6
  * a CardsSnapshot suitable for the TUI sidebar and the server tool.
7
+ *
8
+ * OpenCode Go is dynamic: besides the base "opencode-go" instance, any
9
+ * opencode-go-<suffix>.json sidecar file adds an extra "Opencode Go <suffix>"
10
+ * provider.
7
11
  */
8
12
  import type { CardsPluginConfig } from "../config/defaults.js";
9
13
  import type { Provider, ProviderContext } from "./types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,iBAAiB,CAAC;AAYpE,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAE5D;AAED,wBAAgB,aAAa,IAAI,QAAQ,EAAE,CAE1C;AAED,0DAA0D;AAC1D,wBAAgB,YAAY,CAC1B,MAAM,EAAE,iBAAiB,EACzB,UAAU,EAAE,MAAM,GACjB,eAAe,CAMjB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,aAAa,CAAC,CAsDxB"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,iBAAiB,CAAC;AAgBpE,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAE5D;AAED,wBAAgB,aAAa,IAAI,QAAQ,EAAE,CAE1C;AAMD,0DAA0D;AAC1D,wBAAgB,YAAY,CAC1B,MAAM,EAAE,iBAAiB,EACzB,UAAU,EAAE,MAAM,GACjB,eAAe,CAKjB;AAmBD;;;GAGG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,aAAa,CAAC,CA8DxB"}
@@ -1,6 +1,7 @@
1
1
  import { openaiProvider } from "./openai.js";
2
2
  import { copilotProvider } from "./copilot.js";
3
- import { opencodeGoProvider } from "./opencode-go.js";
3
+ import { createOpenCodeGoProvider, opencodeGoProvider, } from "./opencode-go.js";
4
+ import { discoverOpenCodeGoInstances } from "../lib/opencode-go-config.js";
4
5
  const ALL_PROVIDERS = [
5
6
  openaiProvider,
6
7
  copilotProvider,
@@ -12,24 +13,52 @@ export function getProvider(id) {
12
13
  export function listProviders() {
13
14
  return ALL_PROVIDERS.slice();
14
15
  }
16
+ function isOpenCodeGoId(id) {
17
+ return id === "opencode-go" || id.startsWith("opencode-go-");
18
+ }
15
19
  /** Build a ProviderContext for a specific provider id. */
16
20
  export function buildContext(config, providerId) {
17
- const requestTimeoutMs = providerId === "opencode-go"
21
+ const requestTimeoutMs = isOpenCodeGoId(providerId)
18
22
  ? config.opencodeGoTimeoutMs
19
23
  : config.requestTimeoutMs;
20
24
  return { requestTimeoutMs };
21
25
  }
26
+ /**
27
+ * Stable ordering for providers. Base providers follow the configured
28
+ * `enabledProviders` order; extra OpenCode Go instances are appended right
29
+ * after the base "opencode-go" entry.
30
+ */
31
+ function providerOrder(config, id) {
32
+ const idx = config.enabledProviders.indexOf(id);
33
+ if (idx !== -1)
34
+ return idx;
35
+ if (isOpenCodeGoId(id)) {
36
+ const goIdx = config.enabledProviders.indexOf("opencode-go");
37
+ return goIdx !== -1 ? goIdx + 1 : config.enabledProviders.length;
38
+ }
39
+ return config.enabledProviders.length;
40
+ }
22
41
  /**
23
42
  * Collect a snapshot by fanning out fetches in parallel for all
24
43
  * enabled providers that are available.
25
44
  */
26
45
  export async function collectSnapshot(config) {
27
46
  const providers = [];
28
- const tasks = config.enabledProviders.map(async (id) => {
47
+ const defs = [];
48
+ for (const id of config.enabledProviders) {
29
49
  const provider = getProvider(id);
30
50
  if (!provider)
31
- return;
32
- const ctx = buildContext(config, id);
51
+ continue;
52
+ defs.push({ provider });
53
+ if (id === "opencode-go") {
54
+ const extras = await discoverOpenCodeGoInstances();
55
+ for (const instance of extras) {
56
+ defs.push({ provider: createOpenCodeGoProvider(instance) });
57
+ }
58
+ }
59
+ }
60
+ const tasks = defs.map(async ({ provider }) => {
61
+ const ctx = buildContext(config, provider.id);
33
62
  let available = false;
34
63
  try {
35
64
  available = await provider.isAvailable(ctx);
@@ -64,9 +93,11 @@ export async function collectSnapshot(config) {
64
93
  });
65
94
  await Promise.all(tasks);
66
95
  providers.sort((a, b) => {
67
- const order = config.enabledProviders.indexOf(a.id);
68
- const orderB = config.enabledProviders.indexOf(b.id);
69
- return order - orderB;
96
+ const orderA = providerOrder(config, a.id);
97
+ const orderB = providerOrder(config, b.id);
98
+ if (orderA !== orderB)
99
+ return orderA - orderB;
100
+ return a.id.localeCompare(b.id);
70
101
  });
71
102
  return {
72
103
  generatedAt: new Date().toISOString(),
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"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"}
package/dist/tui.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAgB,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAWxF,eAAO,MAAM,mBAAmB,EAAE,SAoGjC,CAAC;AAEF,QAAA,MAAM,YAAY,EAAE,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAGjD,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAgB,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAWxF,eAAO,MAAM,mBAAmB,EAAE,SA2GjC,CAAC;AAEF,QAAA,MAAM,YAAY,EAAE,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAGjD,CAAC;AAEF,eAAe,YAAY,CAAC"}
package/dist/tui.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  /** @jsxImportSource @opentui/solid */
2
- import { createSignal, onCleanup } from "solid-js";
2
+ import { createSignal, ErrorBoundary, onCleanup } from "solid-js";
3
3
  import type { TuiPlugin, TuiPluginApi, TuiPluginModule } from "@opencode-ai/plugin/tui";
4
4
  import { loadCardsConfig } from "./config/loader.js";
5
5
  import { collectSnapshot } from "./providers/registry.js";
@@ -49,7 +49,10 @@ export const quotaCardsTuiPlugin: TuiPlugin = async (api, _options, _meta) => {
49
49
  const v = ++version;
50
50
  collectSnapshot(config).then((next) => {
51
51
  if (v === version) setSnapshot(next);
52
- }).catch(() => {}).finally(() => {
52
+ }).catch((err) => {
53
+ const msg = err instanceof Error ? `${err.message}\n${err.stack}` : String(err);
54
+ try { process.stderr.write(`[quota-cards] snapshot refresh failed: ${msg}\n`); } catch {}
55
+ }).finally(() => {
53
56
  inFlight = false;
54
57
  if (queued) { queued = false; reload(); }
55
58
  });
@@ -68,10 +71,10 @@ export const quotaCardsTuiPlugin: TuiPlugin = async (api, _options, _meta) => {
68
71
 
69
72
  const interval = setInterval(reload, config.refreshIntervalMs ?? REFRESH_INTERVAL_MS);
70
73
  const unsubs = [
71
- api.event.on("session.updated", (e) => { if (e?.properties?.info?.id === sessionID) scheduleRefresh(); }),
72
- api.event.on("message.updated", (e) => { if (e?.properties?.info?.sessionID === sessionID) scheduleRefresh(); }),
73
- api.event.on("message.removed", (e) => { if (e?.properties?.sessionID === sessionID) scheduleRefresh(); }),
74
- api.event.on("tui.session.select", (e) => { if (e?.properties?.sessionID === sessionID) scheduleRefresh(); }),
74
+ api.event.on("session.updated", (e) => { try { if (e?.properties?.info?.id === sessionID) scheduleRefresh(); } catch {} }),
75
+ api.event.on("message.updated", (e) => { try { if (e?.properties?.info?.sessionID === sessionID) scheduleRefresh(); } catch {} }),
76
+ api.event.on("message.removed", (e) => { try { if (e?.properties?.sessionID === sessionID) scheduleRefresh(); } catch {} }),
77
+ api.event.on("tui.session.select", (e) => { try { if (e?.properties?.sessionID === sessionID) scheduleRefresh(); } catch {} }),
75
78
  ];
76
79
 
77
80
  reload();
@@ -103,7 +106,11 @@ export const quotaCardsTuiPlugin: TuiPlugin = async (api, _options, _meta) => {
103
106
  order: config.cardsSidebar.order,
104
107
  slots: {
105
108
  sidebar_content(_ctx: unknown, props: { session_id: string }) {
106
- return <SidebarContentView sessionID={props.session_id} />;
109
+ return (
110
+ <ErrorBoundary fallback={<text fg={api.theme.current.error}>Quota error</text>}>
111
+ <SidebarContentView sessionID={props.session_id} />
112
+ </ErrorBoundary>
113
+ );
107
114
  },
108
115
  },
109
116
  });
@@ -1 +1 @@
1
- {"version":3,"file":"SidebarPanel.d.ts","sourceRoot":"","sources":["../../src/ui/SidebarPanel.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,GAAG,EAAE,YAAY,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,MAAM,aAAa,CAAC;CAC/B,GAAG,GAAG,CAAC,OAAO,CAsBd"}
1
+ {"version":3,"file":"SidebarPanel.d.ts","sourceRoot":"","sources":["../../src/ui/SidebarPanel.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,GAAG,EAAE,YAAY,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,MAAM,aAAa,CAAC;CAC/B,GAAG,GAAG,CAAC,OAAO,CAiCd"}
@@ -19,6 +19,17 @@ export function SidebarPanel(props: {
19
19
  props.snapshot().providers.filter((p) => p.status === "ok").length;
20
20
  const totalCount = () => props.snapshot().providers.length;
21
21
 
22
+ const estimatedHeight = () => {
23
+ let total = 0
24
+ for (const p of props.snapshot().providers) {
25
+ if (p.status === "skipped") continue
26
+ if (p.status === "no-auth" || p.status === "error") { total += 1; continue }
27
+ const n = p.windows?.length ?? 1
28
+ total += 4 * n + 1 // title + gap + n*3 rows + (n-1)*gaps = 4n+1
29
+ }
30
+ return Math.min(total, 50)
31
+ }
32
+
22
33
  return (
23
34
  <box flexDirection="column" gap={0}>
24
35
  <box flexDirection="row" gap={1}>
@@ -26,11 +37,11 @@ export function SidebarPanel(props: {
26
37
  Quota ({providerCount()}/{totalCount()})
27
38
  </text>
28
39
  </box>
29
- <box flexDirection="column" gap={1}>
40
+ <scrollbox viewportCulling={true} height={estimatedHeight()} flexDirection="column" gap={1}>
30
41
  <For each={props.snapshot().providers}>
31
42
  {(p) => <ProviderCards api={props.api} provider={p} showOnlyMultiWindow={props.config.showOnlyMultiWindow} />}
32
43
  </For>
33
- </box>
44
+ </scrollbox>
34
45
  </box>
35
46
  );
36
47
  }
package/dist/ui/cards.tsx CHANGED
@@ -4,7 +4,7 @@ import { TextAttributes } from "@opentui/core";
4
4
  import type { JSX } from "@opentui/solid";
5
5
  import type { TuiThemeCurrent } from "@opencode-ai/plugin/tui";
6
6
  import type { ProviderQuota, QuotaWindow } from "../lib/types.js";
7
- import { trafficLight } from "./progress-bar.js";
7
+ import { trafficLight, trafficLightColorKey } from "./progress-bar.js";
8
8
  import { formatResetCombined } from "../lib/reset-format.js";
9
9
 
10
10
  export function ProviderCards(props: {
@@ -47,11 +47,11 @@ export function ProviderCards(props: {
47
47
  }
48
48
 
49
49
  return (
50
- <box flexDirection="column" gap={0}>
50
+ <box flexDirection="column" gap={0} width="100%">
51
51
  <text fg={theme().text} attributes={TextAttributes.BOLD}>
52
52
  {props.provider.label}
53
53
  </text>
54
- <box flexDirection="column" gap={1}>
54
+ <box flexDirection="column" gap={1} width="100%">
55
55
  <For each={props.provider.windows}>
56
56
  {(window) => <WindowRow api={props.api} window={window} />}
57
57
  </For>
@@ -66,39 +66,48 @@ function WindowRow(props: {
66
66
  }): JSX.Element {
67
67
  const theme = () => props.api.theme.current;
68
68
  const muted = () => theme().textMuted;
69
- const textColor = () => theme().text;
70
69
  const percent = () => props.window.percentRemaining;
71
70
  const light = () => trafficLight(percent());
72
71
  const barColor = () => {
73
- if (light() === "ok") return "#6b8e23";
74
- if (light() === "warning") return "#ffa500";
75
- return "#ff6b6b";
72
+ const key = trafficLightColorKey(light());
73
+ return theme()[key] ?? theme().text;
76
74
  };
77
75
  const label = () => windowDisplayLabel(props.window);
78
76
  const reset = () => formatReset(props.window.resetTimeIso);
79
- const usedPct = () => {
80
- const v = Math.round(100 - percent());
81
- return v >= 0 ? v : 0;
82
- };
83
77
 
84
78
  return (
85
- <box flexDirection="column" gap={0}>
79
+ <box flexDirection="column" gap={0} width="100%">
86
80
  <box flexDirection="row" gap={0} justifyContent="space-between">
87
81
  <text>{label()}</text>
88
82
  <text fg={light() === "error" ? barColor() : muted()}>{reset()}</text>
89
83
  </box>
90
- <box flexDirection="row" height={1}>
91
- <box flexGrow={percent()} backgroundColor={barColor()} />
92
- <box flexGrow={100 - percent()} backgroundColor={theme().backgroundElement} />
93
- </box>
94
- <box flexDirection="row" gap={0} justifyContent="flex-end">
95
- <text fg={textColor()}>{`${usedPct()}% used / `}</text>
96
- <text fg={barColor()}>{`${percent()}% left`}</text>
84
+ <GaugeBar percent={percent()} theme={theme()} barColor={barColor()} />
85
+ <box flexDirection="row" gap={0} justifyContent="space-between">
86
+ <text fg={barColor()}>{percent()}% left</text>
87
+ <text fg={muted()}>{100 - percent()}% used</text>
97
88
  </box>
98
89
  </box>
99
90
  );
100
91
  }
101
92
 
93
+ function GaugeBar(props: { percent: number; theme: any; barColor: any }): JSX.Element {
94
+ const clamped = Math.max(0, Math.min(100, props.percent));
95
+ const WIDTH = 38;
96
+ const filledCount = Math.round((clamped / 100) * WIDTH);
97
+ const emptyCount = WIDTH - filledCount;
98
+
99
+ return (
100
+ <box flexDirection="row" height={1}>
101
+ {filledCount > 0 ? (
102
+ <text fg={props.barColor}>{"▓".repeat(filledCount)}</text>
103
+ ) : null}
104
+ {emptyCount > 0 ? (
105
+ <text fg={props.barColor}>{"░".repeat(emptyCount)}</text>
106
+ ) : null}
107
+ </box>
108
+ );
109
+ }
110
+
102
111
  function windowDisplayLabel(window: QuotaWindow): string {
103
112
  if (
104
113
  typeof window.remaining === "number" &&
@@ -22,6 +22,6 @@ export declare function trafficLight(percentRemaining: number): TrafficLight;
22
22
  /**
23
23
  * Map a traffic-light state to the corresponding TuiThemeCurrent color key.
24
24
  */
25
- export declare function trafficLightColorKey(light: TrafficLight): "accent" | "warning" | "error";
25
+ export declare function trafficLightColorKey(light: TrafficLight): "success" | "warning" | "error";
26
26
  export declare function trafficLightIndicator(light: TrafficLight): string;
27
27
  //# sourceMappingURL=progress-bar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"progress-bar.d.ts","sourceRoot":"","sources":["../../src/ui/progress-bar.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAQA;AAED,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,gBAAgB,EAAE,MAAM,GAAG,YAAY,CAInE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAIxF;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAIjE"}
1
+ {"version":3,"file":"progress-bar.d.ts","sourceRoot":"","sources":["../../src/ui/progress-bar.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAQA;AAED,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,gBAAgB,EAAE,MAAM,GAAG,YAAY,CAInE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAIzF;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAIjE"}
@@ -33,7 +33,7 @@ export function trafficLight(percentRemaining) {
33
33
  */
34
34
  export function trafficLightColorKey(light) {
35
35
  if (light === "ok")
36
- return "accent";
36
+ return "success";
37
37
  if (light === "warning")
38
38
  return "warning";
39
39
  return "error";
@@ -1 +1 @@
1
- {"version":3,"file":"progress-bar.js","sourceRoot":"","sources":["../../src/ui/progress-bar.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,gBAAwB,EAAE,QAAgB,EAAE;IAK5E,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACtF,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;QAC/B,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC;QACtC,KAAK;KACN,CAAC;AACJ,CAAC;AAID;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,gBAAwB;IACnD,IAAI,gBAAgB,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,gBAAgB,IAAI,EAAE;QAAE,OAAO,SAAS,CAAC;IAC7C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAmB;IACtD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAC;IACpC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAmB;IACvD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,GAAG,CAAC;IAC/B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IACpC,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"progress-bar.js","sourceRoot":"","sources":["../../src/ui/progress-bar.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,gBAAwB,EAAE,QAAgB,EAAE;IAK5E,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACtF,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;QAC/B,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC;QACtC,KAAK;KACN,CAAC;AACJ,CAAC;AAID;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,gBAAwB;IACnD,IAAI,gBAAgB,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,gBAAgB,IAAI,EAAE;QAAE,OAAO,SAAS,CAAC;IAC7C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAmB;IACtD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACrC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAmB;IACvD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,GAAG,CAAC;IAC/B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IACpC,OAAO,GAAG,CAAC;AACb,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arandevcode/opencode-quota-extended",
3
- "version": "0.1.1",
4
- "description": "OpenCode plugin: quota usage cards with progress bars (5h / weekly / monthly) for OpenAI, GitHub Copilot and OpenCode Go in the TUI sidebar.",
3
+ "version": "0.2.0",
4
+ "description": "OpenCode plugin: quota usage cards with theme-colored gauge progress bars (5h / weekly / monthly) for OpenAI, GitHub Copilot and OpenCode Go in the TUI sidebar.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -66,6 +66,9 @@
66
66
  "engines": {
67
67
  "node": ">=18.0.0"
68
68
  },
69
+ "publishConfig": {
70
+ "access": "public"
71
+ },
69
72
  "author": "arandevcode",
70
73
  "license": "MIT"
71
74
  }