zcode-acp-server 0.1.0 → 0.3.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.
Files changed (223) hide show
  1. package/README.md +192 -9
  2. package/README.zh-CN.md +143 -8
  3. package/dist/backend/client.d.ts +12 -4
  4. package/dist/backend/client.d.ts.map +1 -1
  5. package/dist/backend/client.js +72 -7
  6. package/dist/backend/client.js.map +1 -1
  7. package/dist/backend/credentials.d.ts.map +1 -1
  8. package/dist/backend/credentials.js +2 -1
  9. package/dist/backend/credentials.js.map +1 -1
  10. package/dist/backend/listener.d.ts +12 -4
  11. package/dist/backend/listener.d.ts.map +1 -1
  12. package/dist/backend/listener.js +68 -12
  13. package/dist/backend/listener.js.map +1 -1
  14. package/dist/backend/types.d.ts +1 -1
  15. package/dist/backend/types.d.ts.map +1 -1
  16. package/dist/bin/hub.d.ts +16 -0
  17. package/dist/bin/hub.d.ts.map +1 -0
  18. package/dist/bin/hub.js +41 -0
  19. package/dist/bin/hub.js.map +1 -0
  20. package/dist/bin/quota.d.ts +54 -0
  21. package/dist/bin/quota.d.ts.map +1 -0
  22. package/dist/bin/quota.js +333 -0
  23. package/dist/bin/quota.js.map +1 -0
  24. package/dist/config/auto-compact.d.ts +23 -0
  25. package/dist/config/auto-compact.d.ts.map +1 -0
  26. package/dist/config/auto-compact.js +67 -0
  27. package/dist/config/auto-compact.js.map +1 -0
  28. package/dist/config/mcp-discovery.d.ts +34 -0
  29. package/dist/config/mcp-discovery.d.ts.map +1 -0
  30. package/dist/config/mcp-discovery.js +153 -0
  31. package/dist/config/mcp-discovery.js.map +1 -0
  32. package/dist/config/model-cache.d.ts +12 -1
  33. package/dist/config/model-cache.d.ts.map +1 -1
  34. package/dist/config/model-cache.js +30 -8
  35. package/dist/config/model-cache.js.map +1 -1
  36. package/dist/config/options.d.ts +87 -9
  37. package/dist/config/options.d.ts.map +1 -1
  38. package/dist/config/options.js +248 -45
  39. package/dist/config/options.js.map +1 -1
  40. package/dist/config/plugin-commands.d.ts +24 -0
  41. package/dist/config/plugin-commands.d.ts.map +1 -0
  42. package/dist/config/plugin-commands.js +107 -0
  43. package/dist/config/plugin-commands.js.map +1 -0
  44. package/dist/config/provider-registry.d.ts +60 -0
  45. package/dist/config/provider-registry.d.ts.map +1 -0
  46. package/dist/config/provider-registry.js +128 -0
  47. package/dist/config/provider-registry.js.map +1 -0
  48. package/dist/config/runtime-model.d.ts +54 -18
  49. package/dist/config/runtime-model.d.ts.map +1 -1
  50. package/dist/config/runtime-model.js +105 -61
  51. package/dist/config/runtime-model.js.map +1 -1
  52. package/dist/config/skill-discovery.d.ts +35 -0
  53. package/dist/config/skill-discovery.d.ts.map +1 -0
  54. package/dist/config/skill-discovery.js +188 -0
  55. package/dist/config/skill-discovery.js.map +1 -0
  56. package/dist/handlers/account.d.ts +43 -0
  57. package/dist/handlers/account.d.ts.map +1 -0
  58. package/dist/handlers/account.js +59 -0
  59. package/dist/handlers/account.js.map +1 -0
  60. package/dist/handlers/background-tasks.d.ts +72 -0
  61. package/dist/handlers/background-tasks.d.ts.map +1 -0
  62. package/dist/handlers/background-tasks.js +330 -0
  63. package/dist/handlers/background-tasks.js.map +1 -0
  64. package/dist/handlers/dispatch.d.ts.map +1 -1
  65. package/dist/handlers/dispatch.js +134 -22
  66. package/dist/handlers/dispatch.js.map +1 -1
  67. package/dist/handlers/extensions.d.ts +15 -0
  68. package/dist/handlers/extensions.d.ts.map +1 -1
  69. package/dist/handlers/extensions.js +43 -27
  70. package/dist/handlers/extensions.js.map +1 -1
  71. package/dist/handlers/io.d.ts +31 -3
  72. package/dist/handlers/io.d.ts.map +1 -1
  73. package/dist/handlers/io.js +108 -9
  74. package/dist/handlers/io.js.map +1 -1
  75. package/dist/handlers/replay.d.ts +79 -0
  76. package/dist/handlers/replay.d.ts.map +1 -0
  77. package/dist/handlers/replay.js +252 -0
  78. package/dist/handlers/replay.js.map +1 -0
  79. package/dist/handlers/server-requests.d.ts +20 -4
  80. package/dist/handlers/server-requests.d.ts.map +1 -1
  81. package/dist/handlers/server-requests.js +293 -63
  82. package/dist/handlers/server-requests.js.map +1 -1
  83. package/dist/handlers/session.d.ts +113 -10
  84. package/dist/handlers/session.d.ts.map +1 -1
  85. package/dist/handlers/session.js +932 -277
  86. package/dist/handlers/session.js.map +1 -1
  87. package/dist/handlers/slash.d.ts +37 -1
  88. package/dist/handlers/slash.d.ts.map +1 -1
  89. package/dist/handlers/slash.js +143 -8
  90. package/dist/handlers/slash.js.map +1 -1
  91. package/dist/index.js +76 -12
  92. package/dist/index.js.map +1 -1
  93. package/dist/interaction/adapter.d.ts +19 -33
  94. package/dist/interaction/adapter.d.ts.map +1 -1
  95. package/dist/interaction/adapter.js +80 -79
  96. package/dist/interaction/adapter.js.map +1 -1
  97. package/dist/lazy-sessions.d.ts +35 -0
  98. package/dist/lazy-sessions.d.ts.map +1 -0
  99. package/dist/lazy-sessions.js +98 -0
  100. package/dist/lazy-sessions.js.map +1 -0
  101. package/dist/quota/cache.d.ts +18 -0
  102. package/dist/quota/cache.d.ts.map +1 -0
  103. package/dist/quota/cache.js +32 -0
  104. package/dist/quota/cache.js.map +1 -0
  105. package/dist/quota/client.d.ts +30 -0
  106. package/dist/quota/client.d.ts.map +1 -0
  107. package/dist/quota/client.js +57 -0
  108. package/dist/quota/client.js.map +1 -0
  109. package/dist/quota/color.d.ts +58 -0
  110. package/dist/quota/color.d.ts.map +1 -0
  111. package/dist/quota/color.js +95 -0
  112. package/dist/quota/color.js.map +1 -0
  113. package/dist/quota/combined.d.ts +66 -0
  114. package/dist/quota/combined.d.ts.map +1 -0
  115. package/dist/quota/combined.js +179 -0
  116. package/dist/quota/combined.js.map +1 -0
  117. package/dist/quota/format.d.ts +105 -0
  118. package/dist/quota/format.d.ts.map +1 -0
  119. package/dist/quota/format.js +219 -0
  120. package/dist/quota/format.js.map +1 -0
  121. package/dist/quota/index.d.ts +23 -0
  122. package/dist/quota/index.d.ts.map +1 -0
  123. package/dist/quota/index.js +42 -0
  124. package/dist/quota/index.js.map +1 -0
  125. package/dist/quota/opencode-go/cache.d.ts +17 -0
  126. package/dist/quota/opencode-go/cache.d.ts.map +1 -0
  127. package/dist/quota/opencode-go/cache.js +31 -0
  128. package/dist/quota/opencode-go/cache.js.map +1 -0
  129. package/dist/quota/opencode-go/client.d.ts +28 -0
  130. package/dist/quota/opencode-go/client.d.ts.map +1 -0
  131. package/dist/quota/opencode-go/client.js +48 -0
  132. package/dist/quota/opencode-go/client.js.map +1 -0
  133. package/dist/quota/opencode-go/config.d.ts +37 -0
  134. package/dist/quota/opencode-go/config.d.ts.map +1 -0
  135. package/dist/quota/opencode-go/config.js +58 -0
  136. package/dist/quota/opencode-go/config.js.map +1 -0
  137. package/dist/quota/opencode-go/format.d.ts +36 -0
  138. package/dist/quota/opencode-go/format.d.ts.map +1 -0
  139. package/dist/quota/opencode-go/format.js +87 -0
  140. package/dist/quota/opencode-go/format.js.map +1 -0
  141. package/dist/quota/opencode-go/index.d.ts +30 -0
  142. package/dist/quota/opencode-go/index.d.ts.map +1 -0
  143. package/dist/quota/opencode-go/index.js +108 -0
  144. package/dist/quota/opencode-go/index.js.map +1 -0
  145. package/dist/quota/opencode-go/parse.d.ts +41 -0
  146. package/dist/quota/opencode-go/parse.d.ts.map +1 -0
  147. package/dist/quota/opencode-go/parse.js +75 -0
  148. package/dist/quota/opencode-go/parse.js.map +1 -0
  149. package/dist/quota/opencode-go/types.d.ts +48 -0
  150. package/dist/quota/opencode-go/types.d.ts.map +1 -0
  151. package/dist/quota/opencode-go/types.js +11 -0
  152. package/dist/quota/opencode-go/types.js.map +1 -0
  153. package/dist/quota/parse.d.ts +33 -0
  154. package/dist/quota/parse.d.ts.map +1 -0
  155. package/dist/quota/parse.js +200 -0
  156. package/dist/quota/parse.js.map +1 -0
  157. package/dist/quota/types.d.ts +72 -0
  158. package/dist/quota/types.d.ts.map +1 -0
  159. package/dist/quota/types.js +10 -0
  160. package/dist/quota/types.js.map +1 -0
  161. package/dist/remote/broadcast.d.ts +47 -0
  162. package/dist/remote/broadcast.d.ts.map +1 -0
  163. package/dist/remote/broadcast.js +121 -0
  164. package/dist/remote/broadcast.js.map +1 -0
  165. package/dist/remote/config.d.ts +32 -0
  166. package/dist/remote/config.d.ts.map +1 -0
  167. package/dist/remote/config.js +65 -0
  168. package/dist/remote/config.js.map +1 -0
  169. package/dist/remote/endpoint.d.ts +30 -0
  170. package/dist/remote/endpoint.d.ts.map +1 -0
  171. package/dist/remote/endpoint.js +213 -0
  172. package/dist/remote/endpoint.js.map +1 -0
  173. package/dist/remote/hub-server.d.ts +41 -0
  174. package/dist/remote/hub-server.d.ts.map +1 -0
  175. package/dist/remote/hub-server.js +346 -0
  176. package/dist/remote/hub-server.js.map +1 -0
  177. package/dist/server.d.ts +139 -1
  178. package/dist/server.d.ts.map +1 -1
  179. package/dist/server.js +179 -4
  180. package/dist/server.js.map +1 -1
  181. package/dist/tasks-index.d.ts +14 -4
  182. package/dist/tasks-index.d.ts.map +1 -1
  183. package/dist/tasks-index.js +145 -46
  184. package/dist/tasks-index.js.map +1 -1
  185. package/dist/translators/event-translator.d.ts +33 -0
  186. package/dist/translators/event-translator.d.ts.map +1 -1
  187. package/dist/translators/event-translator.js +101 -0
  188. package/dist/translators/event-translator.js.map +1 -1
  189. package/dist/translators/index.d.ts +1 -1
  190. package/dist/translators/index.d.ts.map +1 -1
  191. package/dist/translators/index.js +1 -1
  192. package/dist/translators/index.js.map +1 -1
  193. package/dist/translators/projection-differ.d.ts +8 -0
  194. package/dist/translators/projection-differ.d.ts.map +1 -1
  195. package/dist/translators/projection-differ.js +19 -9
  196. package/dist/translators/projection-differ.js.map +1 -1
  197. package/dist/translators/tool-helpers.d.ts +28 -0
  198. package/dist/translators/tool-helpers.d.ts.map +1 -1
  199. package/dist/translators/tool-helpers.js +104 -0
  200. package/dist/translators/tool-helpers.js.map +1 -1
  201. package/dist/translators/types.d.ts +38 -1
  202. package/dist/translators/types.d.ts.map +1 -1
  203. package/dist/translators/types.js.map +1 -1
  204. package/dist/utils.d.ts +36 -7
  205. package/dist/utils.d.ts.map +1 -1
  206. package/dist/utils.js +69 -5
  207. package/dist/utils.js.map +1 -1
  208. package/docs/ARCHITECTURE.md +130 -40
  209. package/docs/BACKLOG.md +59 -0
  210. package/docs/DEVELOPMENT.md +31 -0
  211. package/docs/PROTOCOL.md +328 -23
  212. package/docs/REMOTE-CLIENTS.md +260 -0
  213. package/docs/REPLAY-GUIDE.md +131 -0
  214. package/docs/TROUBLESHOOTING.md +131 -14
  215. package/docs/adr/0001-bridge-lifetime-follows-primary-client.md +14 -0
  216. package/docs/adr/0002-stateless-hub-over-per-bridge-acp-endpoints.md +23 -0
  217. package/docs/adr/0003-tail-replay-meta-and-cursor-pagination.md +40 -0
  218. package/docs/agents/domain.md +51 -0
  219. package/docs/agents/issue-tracker.md +22 -0
  220. package/docs/agents/triage-labels.md +15 -0
  221. package/docs/proposals/0001-tail-session-replay.md +136 -0
  222. package/docs/proposals/0002-plan-quota-usage.md +81 -0
  223. package/package.json +10 -6
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Opencode Go usage formatting.
3
+ *
4
+ * Renders the three windows (rolling 5h / weekly 7d / monthly 30d) as progress
5
+ * bars identical in style to the GLM card, so the two sections read as one
6
+ * cohesive card in the combined view. Reuses {@link renderBar} from the GLM
7
+ * formatter for visual consistency.
8
+ */
9
+ import { pickOverlay, renderColorBar } from "../color.js";
10
+ import { formatResetTime, renderBar } from "../format.js";
11
+ /** Label + window-key metadata, in display order. */
12
+ const WINDOW_META = [
13
+ { key: "rolling", label: "5h" },
14
+ { key: "weekly", label: "Week" },
15
+ { key: "monthly", label: "Month" },
16
+ ];
17
+ /**
18
+ * Format a duration in seconds as a compact countdown.
19
+ *
20
+ * - `>= 1d` → `Xd Yh` (e.g. `6d 8h`)
21
+ * - `>= 1h` → `Yh Zm` (e.g. `2h 30m`)
22
+ * - `>= 1m` → `Zm` (e.g. `45m`)
23
+ * - `< 1m` → `<1m`
24
+ */
25
+ export function formatDuration(sec) {
26
+ if (!Number.isFinite(sec) || sec < 60)
27
+ return "<1m";
28
+ const s = Math.floor(sec);
29
+ const days = Math.floor(s / 86_400);
30
+ const hours = Math.floor((s % 86_400) / 3_600);
31
+ const mins = Math.floor((s % 3_600) / 60);
32
+ if (days > 0)
33
+ return `${days}d ${hours}h`;
34
+ if (hours > 0)
35
+ return `${hours}h ${mins}m`;
36
+ return `${mins}m`;
37
+ }
38
+ /** Pad a percent to 2 chars (right-aligned), matching the GLM card. */
39
+ function padPercent(n) {
40
+ return String(n).padStart(2);
41
+ }
42
+ /**
43
+ * Render the Opencode Go section for the requested windows.
44
+ *
45
+ * Used by the combined formatter. The header is always `Opencode Go`; body
46
+ * has one bar line per window. Non-success kinds return a header + a single
47
+ * explanatory line.
48
+ *
49
+ * When `color` is true the bar is a heat-colored 24-bit ANSI bar with the
50
+ * percent overlaid inside (Go windows carry no absolute counters, so the
51
+ * overlay is always `NN%`), mirroring the GLM color layout.
52
+ */
53
+ export function formatGoSection(result, windows, now = Date.now(), color = false) {
54
+ const header = "Opencode Go";
55
+ if (result.kind !== "success") {
56
+ const msg = result.kind === "not_configured"
57
+ ? "not configured (set OPENCODE_GO_WORKSPACE_ID + OPENCODE_GO_AUTH_COOKIE)"
58
+ : result.kind === "auth_error"
59
+ ? "auth expired — refresh your opencode.ai cookie"
60
+ : "unavailable";
61
+ return { header, body: [msg] };
62
+ }
63
+ const elapsedSec = Math.max(0, (now - result.fetchedAt) / 1000);
64
+ const body = WINDOW_META.filter((m) => windows.includes(m.key)).map((m) => {
65
+ const w = result[m.key];
66
+ if (!w) {
67
+ return `${m.label.padEnd(5)} (no data)`;
68
+ }
69
+ // Live countdown: subtract elapsed time since the fetch snapshot, then
70
+ // convert to an absolute reset timestamp (matches the GLM card's layout).
71
+ const remainingSec = Math.max(0, w.resetInSec - elapsedSec);
72
+ const resetAt = result.fetchedAt + remainingSec * 1000;
73
+ const reset = formatResetTime(resetAt) ?? "<1m";
74
+ if (color) {
75
+ const bar = renderColorBar(w.usagePercent, {
76
+ overlay: pickOverlay({ usedPercent: w.usagePercent }),
77
+ });
78
+ return `${m.label.padEnd(5)} ${bar} · ${reset}`;
79
+ }
80
+ const bar = renderBar(w.usagePercent);
81
+ // No leading indent — the bar lines align with GLM's so the two sections
82
+ // read as one card. The section header carries the ` Opencode Go` indent.
83
+ return `${m.label.padEnd(5)} ${bar} ${padPercent(w.usagePercent)}% · ${reset}`;
84
+ });
85
+ return { header, body };
86
+ }
87
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/quota/opencode-go/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Opencode Go usage orchestration — the entry point used by the
3
+ * `zcode-quota` CLI.
4
+ *
5
+ * Flow: credentials (env + config file) → cache check → fetch → redirect/auth
6
+ * check → parse → cache write. Any thrown error degrades to `unavailable`
7
+ * rather than propagating, so the CLI always produces output.
8
+ *
9
+ * A missing/invalid credential pair yields `not_configured`, which the
10
+ * combined view silently skips (vs. `unavailable`, which renders an error
11
+ * line) — so users who only care about GLM see no noise.
12
+ */
13
+ import type { GoQueryResult } from "./types.js";
14
+ /**
15
+ * Query the Opencode Go dashboard and return a normalised {@link GoQueryResult}.
16
+ *
17
+ * - No credentials / invalid → `not_configured`.
18
+ * - Serves a cached result when fresh (< 10s).
19
+ * - HTTP redirect to login (final URL no longer contains the workspace path)
20
+ * → `auth_error`.
21
+ * - Network/timeout/parse failure → `unavailable`.
22
+ */
23
+ export declare function queryGoUsage(): Promise<GoQueryResult>;
24
+ export { clearCache, clearCache as clearGoCache } from "./cache.js";
25
+ export { fetchGoDashboard, dashboardUrl } from "./client.js";
26
+ export { parseGoDashboard, looksLikeDashboard } from "./parse.js";
27
+ export { formatDuration, formatGoSection } from "./format.js";
28
+ export { readConfigFile, CONFIG_PATH, ENV_WORKSPACE_ID, ENV_AUTH_COOKIE } from "./config.js";
29
+ export type { GoQueryResult, GoWindow, GoWindowKey, GoDashboardResponse } from "./types.js";
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/quota/opencode-go/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAgChD;;;;;;;;GAQG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CA6C3D;AAGD,OAAO,EAAE,UAAU,EAAE,UAAU,IAAI,YAAY,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7F,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Opencode Go usage orchestration — the entry point used by the
3
+ * `zcode-quota` CLI.
4
+ *
5
+ * Flow: credentials (env + config file) → cache check → fetch → redirect/auth
6
+ * check → parse → cache write. Any thrown error degrades to `unavailable`
7
+ * rather than propagating, so the CLI always produces output.
8
+ *
9
+ * A missing/invalid credential pair yields `not_configured`, which the
10
+ * combined view silently skips (vs. `unavailable`, which renders an error
11
+ * line) — so users who only care about GLM see no noise.
12
+ */
13
+ import { log } from "../../utils.js";
14
+ import { getCached, setCached } from "./cache.js";
15
+ import { ENV_AUTH_COOKIE, ENV_WORKSPACE_ID, readConfigFile } from "./config.js";
16
+ import { fetchGoDashboard } from "./client.js";
17
+ import { parseGoDashboard } from "./parse.js";
18
+ /** Format validators (match pi-go-bars conventions). */
19
+ const RE_WORKSPACE = /^wrk_[A-Za-z0-9]+$/;
20
+ const COOKIE_PREFIX = "Fe26.2**";
21
+ /**
22
+ * Resolve & validate credentials.
23
+ *
24
+ * Environment variables take precedence over `~/.pi/agent/opencode-go.json`,
25
+ * merged field-by-field: env overrides the same field from the file, but a
26
+ * field present only in the file still counts. Returns `null` when the
27
+ * resolved pair is incomplete or malformed — `queryGoUsage` maps that to
28
+ * `not_configured`.
29
+ */
30
+ function loadCredentials() {
31
+ const file = readConfigFile();
32
+ const workspaceId = process.env[ENV_WORKSPACE_ID] ?? file.workspaceId;
33
+ const authCookie = process.env[ENV_AUTH_COOKIE] ?? file.authCookie;
34
+ if (!workspaceId || !authCookie)
35
+ return null;
36
+ if (!RE_WORKSPACE.test(workspaceId)) {
37
+ log(`opencode-go: invalid workspaceId format (expected wrk_…)`);
38
+ return null;
39
+ }
40
+ if (!authCookie.startsWith(COOKIE_PREFIX)) {
41
+ log(`opencode-go: authCookie does not start with ${COOKIE_PREFIX}`);
42
+ return null;
43
+ }
44
+ return { workspaceId, authCookie };
45
+ }
46
+ /**
47
+ * Query the Opencode Go dashboard and return a normalised {@link GoQueryResult}.
48
+ *
49
+ * - No credentials / invalid → `not_configured`.
50
+ * - Serves a cached result when fresh (< 10s).
51
+ * - HTTP redirect to login (final URL no longer contains the workspace path)
52
+ * → `auth_error`.
53
+ * - Network/timeout/parse failure → `unavailable`.
54
+ */
55
+ export async function queryGoUsage() {
56
+ const cached = getCached();
57
+ if (cached) {
58
+ log("opencode-go: serving cached result");
59
+ return cached;
60
+ }
61
+ const creds = loadCredentials();
62
+ if (!creds)
63
+ return { kind: "not_configured" };
64
+ let result;
65
+ try {
66
+ const resp = await fetchGoDashboard(creds.workspaceId, creds.authCookie);
67
+ // Redirect-to-login detection: an expired cookie silently bounces to the
68
+ // login page with a 200, so we check the final URL rather than the status.
69
+ if (!resp.finalUrl.includes(`/workspace/${creds.workspaceId}/go`)) {
70
+ result = { kind: "auth_error" };
71
+ }
72
+ else {
73
+ const parsed = parseGoDashboard(resp.text);
74
+ if (parsed.parserOutdated) {
75
+ log("opencode-go: dashboard HTML recognised but no windows parsed (parser outdated)");
76
+ result = { kind: "unavailable" };
77
+ }
78
+ else if (!parsed.rolling && !parsed.weekly && !parsed.monthly) {
79
+ // Not a dashboard page at all (e.g. error page the redirect check missed).
80
+ result = { kind: "unavailable" };
81
+ }
82
+ else {
83
+ result = {
84
+ kind: "success",
85
+ // Rolling and weekly are the two windows the CLI shows by default;
86
+ // fall back to zeroes if somehow absent so the type stays simple.
87
+ rolling: parsed.rolling ?? { usagePercent: 0, resetInSec: 0 },
88
+ weekly: parsed.weekly ?? { usagePercent: 0, resetInSec: 0 },
89
+ monthly: parsed.monthly,
90
+ fetchedAt: Date.now(),
91
+ };
92
+ }
93
+ }
94
+ }
95
+ catch (e) {
96
+ log(`opencode-go: fetch failed (${e instanceof Error ? e.message : String(e)})`);
97
+ result = { kind: "unavailable" };
98
+ }
99
+ setCached(result);
100
+ return result;
101
+ }
102
+ // Re-exports for consumers (CLI + tests).
103
+ export { clearCache, clearCache as clearGoCache } from "./cache.js";
104
+ export { fetchGoDashboard, dashboardUrl } from "./client.js";
105
+ export { parseGoDashboard, looksLikeDashboard } from "./parse.js";
106
+ export { formatDuration, formatGoSection } from "./format.js";
107
+ export { readConfigFile, CONFIG_PATH, ENV_WORKSPACE_ID, ENV_AUTH_COOKIE } from "./config.js";
108
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/quota/opencode-go/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Opencode Go dashboard HTML parser.
3
+ *
4
+ * The dashboard is a SolidJS SSR page. Usage data is embedded as hydration
5
+ * assignments inside a `<script>`, in the shape:
6
+ *
7
+ * rollingUsage:$R[N]={usagePercent:<n>,resetInSec:<n>}
8
+ *
9
+ * (field order may vary; `$R[N]` is a Solid hydration reference). This is JS
10
+ * source, not JSON, so we extract with regexes rather than `JSON.parse`. Two
11
+ * independent reference implementations (pi-go-bars, @beyona/pi-zai-usage)
12
+ * use the same approach as of 2026-08, but the format has no stability
13
+ * contract — a frontend change will silently break extraction, which is why
14
+ * {@link looksLikeDashboard} guards against parser rot.
15
+ */
16
+ import type { GoWindow } from "./types.js";
17
+ /**
18
+ * Detect whether the HTML is a dashboard page (vs. a login redirect or error
19
+ * page). Used to distinguish "parser is outdated" from "no windows present".
20
+ */
21
+ export declare function looksLikeDashboard(html: string): boolean;
22
+ /** Result of parsing the dashboard — each window is independently optional. */
23
+ export interface ParsedGoDashboard {
24
+ rolling: GoWindow | null;
25
+ weekly: GoWindow | null;
26
+ monthly: GoWindow | null;
27
+ /**
28
+ * Set when the HTML looks like a dashboard but no windows parsed — the SSR
29
+ * format likely changed. The caller surfaces this as `unavailable`.
30
+ */
31
+ parserOutdated: boolean;
32
+ }
33
+ /**
34
+ * Parse the dashboard HTML into the three windows.
35
+ *
36
+ * `parserOutdated` is true when the page looks like a dashboard (contains the
37
+ * window variable names) but none of the three windows matched — signalling
38
+ * that the SolidJS hydration format has drifted.
39
+ */
40
+ export declare function parseGoDashboard(html: string): ParsedGoDashboard;
41
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../src/quota/opencode-go/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAgD3C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIxD;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAShE"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Opencode Go dashboard HTML parser.
3
+ *
4
+ * The dashboard is a SolidJS SSR page. Usage data is embedded as hydration
5
+ * assignments inside a `<script>`, in the shape:
6
+ *
7
+ * rollingUsage:$R[N]={usagePercent:<n>,resetInSec:<n>}
8
+ *
9
+ * (field order may vary; `$R[N]` is a Solid hydration reference). This is JS
10
+ * source, not JSON, so we extract with regexes rather than `JSON.parse`. Two
11
+ * independent reference implementations (pi-go-bars, @beyona/pi-zai-usage)
12
+ * use the same approach as of 2026-08, but the format has no stability
13
+ * contract — a frontend change will silently break extraction, which is why
14
+ * {@link looksLikeDashboard} guards against parser rot.
15
+ */
16
+ /** Numeric capture group: integer or decimal, optionally negative. */
17
+ const NUM = String.raw `(-?\d+(?:\.\d+)?)`;
18
+ /**
19
+ * Build the two regexes for one window. Solid emits the fields in either
20
+ * order, so we need one pattern per ordering.
21
+ */
22
+ function windowRegexes(name) {
23
+ return [
24
+ new RegExp(String.raw `${name}:\$R\[\d+\]=\{[^}]*usagePercent:${NUM}[^}]*resetInSec:${NUM}[^}]*\}`),
25
+ new RegExp(String.raw `${name}:\$R\[\d+\]=\{[^}]*resetInSec:${NUM}[^}]*usagePercent:${NUM}[^}]*\}`),
26
+ ];
27
+ }
28
+ const [RE_ROLLING_PCT, RE_ROLLING_RST] = windowRegexes("rollingUsage");
29
+ const [RE_WEEKLY_PCT, RE_WEEKLY_RST] = windowRegexes("weeklyUsage");
30
+ const [RE_MONTHLY_PCT, RE_MONTHLY_RST] = windowRegexes("monthlyUsage");
31
+ /**
32
+ * Extract one window. Tries both field orderings; returns `null` if neither
33
+ * matches or the captured numbers are not finite.
34
+ */
35
+ function parseWindow(html, rePct, reRst) {
36
+ let m = rePct.exec(html);
37
+ if (m) {
38
+ const usagePercent = Number(m[1]);
39
+ const resetInSec = Number(m[2]);
40
+ if (Number.isFinite(usagePercent) && Number.isFinite(resetInSec)) {
41
+ return { usagePercent, resetInSec };
42
+ }
43
+ }
44
+ m = reRst.exec(html);
45
+ if (m) {
46
+ const resetInSec = Number(m[1]);
47
+ const usagePercent = Number(m[2]);
48
+ if (Number.isFinite(usagePercent) && Number.isFinite(resetInSec)) {
49
+ return { usagePercent, resetInSec };
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+ /**
55
+ * Detect whether the HTML is a dashboard page (vs. a login redirect or error
56
+ * page). Used to distinguish "parser is outdated" from "no windows present".
57
+ */
58
+ export function looksLikeDashboard(html) {
59
+ return (html.includes("rollingUsage") || html.includes("weeklyUsage") || html.includes("monthlyUsage"));
60
+ }
61
+ /**
62
+ * Parse the dashboard HTML into the three windows.
63
+ *
64
+ * `parserOutdated` is true when the page looks like a dashboard (contains the
65
+ * window variable names) but none of the three windows matched — signalling
66
+ * that the SolidJS hydration format has drifted.
67
+ */
68
+ export function parseGoDashboard(html) {
69
+ const rolling = parseWindow(html, RE_ROLLING_PCT, RE_ROLLING_RST);
70
+ const weekly = parseWindow(html, RE_WEEKLY_PCT, RE_WEEKLY_RST);
71
+ const monthly = parseWindow(html, RE_MONTHLY_PCT, RE_MONTHLY_RST);
72
+ const parserOutdated = rolling === null && weekly === null && monthly === null && looksLikeDashboard(html);
73
+ return { rolling, weekly, monthly, parserOutdated };
74
+ }
75
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/quota/opencode-go/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,sEAAsE;AACtE,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA,mBAAmB,CAAC;AAE1C;;;GAGG;AACH,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO;QACL,IAAI,MAAM,CACR,MAAM,CAAC,GAAG,CAAA,GAAG,IAAI,mCAAmC,GAAG,mBAAmB,GAAG,SAAS,CACvF;QACD,IAAI,MAAM,CACR,MAAM,CAAC,GAAG,CAAA,GAAG,IAAI,iCAAiC,GAAG,qBAAqB,GAAG,SAAS,CACvF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;AACvE,MAAM,CAAC,aAAa,EAAE,aAAa,CAAC,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;AACpE,MAAM,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;AAEvE;;;GAGG;AACH,SAAS,WAAW,CAAC,IAAY,EAAE,KAAa,EAAE,KAAa;IAC7D,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,IAAI,CAAC,EAAE,CAAC;QACN,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACjE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;QACtC,CAAC;IACH,CAAC;IACD,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrB,IAAI,CAAC,EAAE,CAAC;QACN,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACjE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,CACL,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAC/F,CAAC;AACJ,CAAC;AAcD;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;IAElE,MAAM,cAAc,GAClB,OAAO,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAEtF,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;AACtD,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Type definitions for the Opencode Go subscription usage feature.
3
+ *
4
+ * The `zcode-quota` CLI queries the opencode.ai web dashboard (there is no
5
+ * JSON API yet) by scraping the SolidJS SSR hydration payload embedded in
6
+ * `https://opencode.ai/workspace/<id>/go`. Usage is split into three windows:
7
+ * rolling (5h), weekly (7d), monthly (30d). Each window carries only a
8
+ * server-provided `usagePercent` and a relative `resetInSec` countdown.
9
+ */
10
+ /** One usage window — both fields are server-provided. */
11
+ export interface GoWindow {
12
+ /** Used percentage in [0, 100], already computed server-side. */
13
+ usagePercent: number;
14
+ /** Seconds until this window resets (relative countdown, not a timestamp). */
15
+ resetInSec: number;
16
+ }
17
+ /**
18
+ * Result of querying Opencode Go usage — a 4-state sum type.
19
+ *
20
+ * `not_configured` is distinct from `unavailable`: the CLI uses it to silently
21
+ * skip the Go section in default (dual-platform) mode when the user has not
22
+ * supplied credentials, rather than printing an error.
23
+ */
24
+ export type GoQueryResult = {
25
+ kind: "success";
26
+ rolling: GoWindow;
27
+ weekly: GoWindow;
28
+ /** Monthly window is optional — present when the dashboard exposes it. */
29
+ monthly: GoWindow | null;
30
+ /** Epoch ms of the fetch, used to drive the live countdown in the CLI. */
31
+ fetchedAt: number;
32
+ } | {
33
+ kind: "not_configured";
34
+ } | {
35
+ kind: "auth_error";
36
+ } | {
37
+ kind: "unavailable";
38
+ };
39
+ /** The three window keys, in display order. */
40
+ export type GoWindowKey = "rolling" | "weekly" | "monthly";
41
+ /** Raw dashboard fetch result — HTML + the final (post-redirect) URL. */
42
+ export interface GoDashboardResponse {
43
+ status: number;
44
+ text: string;
45
+ /** Final URL after redirects; used to detect redirect-to-login. */
46
+ finalUrl: string;
47
+ }
48
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/quota/opencode-go/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,0DAA0D;AAC1D,MAAM,WAAW,QAAQ;IACvB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GACrB;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,QAAQ,CAAC;IAClB,MAAM,EAAE,QAAQ,CAAC;IACjB,0EAA0E;IAC1E,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAE5B,+CAA+C;AAC/C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE3D,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;CAClB"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Type definitions for the Opencode Go subscription usage feature.
3
+ *
4
+ * The `zcode-quota` CLI queries the opencode.ai web dashboard (there is no
5
+ * JSON API yet) by scraping the SolidJS SSR hydration payload embedded in
6
+ * `https://opencode.ai/workspace/<id>/go`. Usage is split into three windows:
7
+ * rolling (5h), weekly (7d), monthly (30d). Each window carries only a
8
+ * server-provided `usagePercent` and a relative `resetInSec` countdown.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/quota/opencode-go/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Quota response parsing — turns the raw GLM `limits[]` array into a flat list
3
+ * of normalised {@link QuotaItem}s.
4
+ *
5
+ * Design goals (vs. the reference project):
6
+ * - **No hardcoded type whitelist.** Unknown `type` values still render,
7
+ * labelled by their raw type string, so future windows surface
8
+ * automatically.
9
+ * - **Percentage fallback chain** that tolerates inconsistent field sets
10
+ * across limit kinds (some carry absolute counters, some only a legacy
11
+ * `percentage`).
12
+ * - **Labels derived from `type` + `number`**, without magic-number coupling.
13
+ */
14
+ import type { QuotaItem, QuotaResult, RawLimit } from "./types.js";
15
+ /**
16
+ * Parse one raw limit into a {@link QuotaItem}, or `null` if no percentage
17
+ * can be computed (the limit is then dropped from display).
18
+ */
19
+ export declare function parseLimit(limit: RawLimit): QuotaItem | null;
20
+ /**
21
+ * Parse the full API response (already classified by the fetch layer as a
22
+ * `response` with a status + body) into a {@link QuotaResult}.
23
+ *
24
+ * State machine: 429/rate-limit text → `rate_limited`; auth codes/text →
25
+ * `auth_error`; success with zero parseable items → `unavailable`; otherwise
26
+ * the items are returned in original order.
27
+ */
28
+ export declare function parseQuotaEnvelope(envelope: {
29
+ status: number;
30
+ json: unknown;
31
+ text: string;
32
+ }): QuotaResult;
33
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/quota/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAmGnE;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,CA8B5D;AAuBD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,WAAW,CAmCd"}