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,219 @@
1
+ /**
2
+ * Quota result formatting — renders a {@link QuotaResult} as a multi-line
3
+ * plain-text card inside a ```text fenced block.
4
+ *
5
+ * The whole card is wrapped in a fenced code block so the editor renders it in
6
+ * a monospace, bordered, copy-able frame. Monospace also normalises the block
7
+ * element widths (▓/░ are NOT marked East-Asian-Wide, but some proportional
8
+ * chat fonts stretch them; a code frame guarantees 1-cell-per-bar).
9
+ *
10
+ * The progress bar uses two block characters at {@link BAR_WIDTH}-cell width
11
+ * for a clean, precise fill (each cell = 5%):
12
+ * █ (U+2588, full block) — used portion
13
+ * ░ (U+2591, light shade) — remaining portion
14
+ * Inside a monospace code block the full-block reads as a solid, high-impact
15
+ * fill for used quota, with the light shade marking the remainder.
16
+ */
17
+ import { pickOverlay, renderColorBar } from "./color.js";
18
+ /**
19
+ * Progress-bar cell count. 20 cells = 5% granularity, fine enough to read
20
+ * real usage at a glance while still fitting a code-block frame on one line.
21
+ */
22
+ const BAR_WIDTH = 20;
23
+ /** Filled / empty cell characters. */
24
+ const CHAR_FULL = "█";
25
+ const CHAR_EMPTY = "░";
26
+ /** Pad a percent number to 2 chars (right-aligned). */
27
+ function padPercent(n) {
28
+ return String(n).padStart(2);
29
+ }
30
+ /**
31
+ * Render a {@link BAR_WIDTH}-cell progress bar for a used-percent in [0, 100].
32
+ *
33
+ * 0% → all empty; 100% → all full; otherwise the used portion is `█` and the
34
+ * rest is `░`, rounded to the nearest cell (each cell = 10%).
35
+ */
36
+ export function renderBar(usedPercent) {
37
+ const clamped = Math.max(0, Math.min(100, usedPercent));
38
+ const filled = Math.round((clamped / 100) * BAR_WIDTH);
39
+ const empty = BAR_WIDTH - filled;
40
+ return CHAR_FULL.repeat(filled) + CHAR_EMPTY.repeat(empty);
41
+ }
42
+ /**
43
+ * Format a reset timestamp (ms) as a local `MM-DD HH:MM` string, or `null`.
44
+ *
45
+ * Exported so the Opencode Go formatter can reuse the same layout (Go windows
46
+ * carry only a relative `resetInSec`; the caller converts that to an absolute
47
+ * ms timestamp against the fetch snapshot first).
48
+ */
49
+ export function formatResetTime(nextResetTime) {
50
+ if (nextResetTime === undefined || !Number.isFinite(nextResetTime))
51
+ return null;
52
+ const d = new Date(nextResetTime);
53
+ if (Number.isNaN(d.getTime()))
54
+ return null;
55
+ const mm = String(d.getMonth() + 1).padStart(2, "0");
56
+ const dd = String(d.getDate()).padStart(2, "0");
57
+ const hh = String(d.getHours()).padStart(2, "0");
58
+ const min = String(d.getMinutes()).padStart(2, "0");
59
+ return `${mm}-${dd} ${hh}:${min}`;
60
+ }
61
+ /** Capitalise the first letter of a plan level (e.g. "pro" → "Pro"). */
62
+ function capitalise(s) {
63
+ if (!s)
64
+ return "";
65
+ return s.charAt(0).toUpperCase() + s.slice(1);
66
+ }
67
+ /**
68
+ * Build the trailing annotation for an item: reset time first (so all items
69
+ * align), then the absolute used counter last (only some limits carry it).
70
+ */
71
+ function formatTrailing(item) {
72
+ const parts = [];
73
+ const reset = formatResetTime(item.nextResetTime);
74
+ if (reset)
75
+ parts.push(reset);
76
+ // Absolute used counter — only some limit kinds carry it (MCP/TIME_LIMIT).
77
+ // The total is intentionally omitted: it is a fixed allowance already
78
+ // expressed by the percentage bar, so showing `/1000` adds no information.
79
+ if (typeof item.usedCount === "number" && Number.isFinite(item.usedCount)) {
80
+ parts.push(`${item.usedCount}`);
81
+ }
82
+ return parts.length > 0 ? ` · ${parts.join(" · ")}` : "";
83
+ }
84
+ /**
85
+ * Color-mode trailing annotation: reset time only. The percent and the
86
+ * used/total counter are already overlaid inside the colored bar (see
87
+ * {@link pickOverlay}), so the right margin just carries the reset stamp.
88
+ */
89
+ function formatTrailingColor(item) {
90
+ const reset = formatResetTime(item.nextResetTime);
91
+ return reset ? ` · ${reset}` : "";
92
+ }
93
+ /** Right-pad a model code for aligned detail sub-lines. */
94
+ const DETAIL_LABEL_WIDTH = 14;
95
+ /** Resolve partial options into complete flags. */
96
+ function resolveOptions(opts) {
97
+ return {
98
+ detail: opts?.detail ?? true,
99
+ compact: opts?.compact ?? false,
100
+ color: opts?.color ?? false,
101
+ };
102
+ }
103
+ /** Render one quota item line (+ indented detail sub-lines if present). */
104
+ function formatItem(item, showDetail, color = false) {
105
+ const lines = [];
106
+ if (color) {
107
+ // Color mode: the percent (or used/total) is overlaid inside the heat bar,
108
+ // so the right margin carries only the reset stamp.
109
+ const bar = renderColorBar(item.usedPercent, { overlay: pickOverlay(item) });
110
+ lines.push(`${item.label.padEnd(5)} ${bar}${formatTrailingColor(item)}`);
111
+ }
112
+ else {
113
+ const bar = renderBar(item.usedPercent);
114
+ lines.push(`${item.label.padEnd(5)} ${bar} ${padPercent(item.usedPercent)}%${formatTrailing(item)}`);
115
+ }
116
+ if (showDetail && item.detail && item.detail.length > 0) {
117
+ const last = item.detail.length - 1;
118
+ item.detail.forEach((d, i) => {
119
+ const branch = i === last ? "└" : "├";
120
+ const name = d.modelCode.padEnd(DETAIL_LABEL_WIDTH);
121
+ lines.push(` ${branch} ${name}${d.usage}`);
122
+ });
123
+ }
124
+ return lines;
125
+ }
126
+ /** Error/fallback messages keyed by `kind`. */
127
+ const STATUS_MESSAGES = {
128
+ auth_error: "🔒 Quota auth expired — re-login in the ZCode app",
129
+ rate_limited: "⏳ Quota service busy, try again shortly",
130
+ unavailable: "⚠ Quota info unavailable",
131
+ };
132
+ /**
133
+ * Render the GLM section (header + one bar line per item) without the fence
134
+ * or divider.
135
+ *
136
+ * Non-success kinds return a header of `"GLM Coding Plan"` and a single
137
+ * explanatory body line, mirroring {@link formatQuota}'s non-success prose
138
+ * (just split into header/body for composability).
139
+ *
140
+ * In `compact` mode the MCP item is collapsed into a trailing annotation on
141
+ * the 5h line (`· MCP (used/total)`) and its own bar line + detail sub-lines
142
+ * are dropped — used by the combined dual-provider CLI view to keep the merged
143
+ * card short. The standalone `glm` subcommand and `/quota` slash command use
144
+ * the full layout.
145
+ */
146
+ export function renderGlmSection(result, opts) {
147
+ const header = "GLM Coding Plan";
148
+ if (result.kind !== "success") {
149
+ return { header, body: [STATUS_MESSAGES[result.kind]] };
150
+ }
151
+ const { detail, compact, color } = resolveOptions(opts);
152
+ const title = `${header}${result.level ? ` · ${capitalise(result.level)}` : ""}`;
153
+ if (compact) {
154
+ // Find the MCP item to fold into the 5h line as a trailing note.
155
+ const mcp = result.items.find((it) => it.key === "mcp");
156
+ const mcpNote = formatMcpNote(mcp);
157
+ const body = result.items
158
+ .filter((it) => it.key !== "mcp")
159
+ .map((it) => formatItem(it, false, color)[0].replace(/$/, mcpNote && it.key === "token_5h" ? mcpNote : ""));
160
+ // If 5h is somehow absent but MCP exists, surface MCP as its own line so
161
+ // the data isn't lost.
162
+ const has5h = result.items.some((it) => it.key === "token_5h");
163
+ if (mcp && !has5h && mcpNote) {
164
+ body.push(formatItem(mcp, false, color)[0]);
165
+ }
166
+ return { header: title, body };
167
+ }
168
+ const body = result.items.flatMap((item) => formatItem(item, detail, color));
169
+ return { header: title, body };
170
+ }
171
+ /**
172
+ * Build the MCP trailing note for compact mode: ` · MCP N` when the item
173
+ * carries an absolute counter, ` · MCP NN%` when it only has a percentage, or
174
+ * `""` when there is no MCP item.
175
+ */
176
+ function formatMcpNote(mcp) {
177
+ if (!mcp)
178
+ return "";
179
+ if (typeof mcp.usedCount === "number" && Number.isFinite(mcp.usedCount)) {
180
+ return ` · MCP ${mcp.usedCount}`;
181
+ }
182
+ return ` · MCP ${padPercent(mcp.usedPercent)}%`;
183
+ }
184
+ /**
185
+ * Render a {@link QuotaResult} as a multi-line plain-text card wrapped in a
186
+ * ```text fenced block.
187
+ *
188
+ * The fence makes the editor render the card in a monospace, bordered, copy-
189
+ * able frame — without it the proportional chat font mangles block-element
190
+ * widths (▓/░ render at different glyph advances and can look stretched), and
191
+ * the divider/bars lose their alignment.
192
+ *
193
+ * Success → header line + divider + one progress-bar line per item (plus
194
+ * indented per-model detail where present). Non-success kinds → a single
195
+ * explanatory line, unfenced (they are short prose, not a card).
196
+ */
197
+ export function formatQuota(result, opts) {
198
+ if (result.kind !== "success") {
199
+ return STATUS_MESSAGES[result.kind];
200
+ }
201
+ const section = renderGlmSection(result, opts);
202
+ // Divider spans the longest line so the frame looks balanced; 34 ≈ label(5)
203
+ // + space(1) + bar(20) + spaces(2) + "NN%"(3) + trailing-room(3).
204
+ const divider = "─".repeat(34);
205
+ return ["```text", section.header, divider, ...section.body, "```"].join("\n");
206
+ }
207
+ /**
208
+ * {@link formatQuota} without the ```text fence — for raw terminal output.
209
+ *
210
+ * The fence is only useful inside an editor chat frame (where it triggers a
211
+ * bordered, copy-able code block). A real terminal renders the fence as
212
+ * literal ```` ``` ```` characters, so the standalone CLI strips it.
213
+ * Non-success kinds are already unfenced short prose, returned unchanged.
214
+ */
215
+ export function formatQuotaPlain(result, opts) {
216
+ const card = formatQuota(result, opts);
217
+ return result.kind === "success" ? card.replace(/^```text\n/, "").replace(/\n```$/, "") : card;
218
+ }
219
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/quota/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Quota orchestration — the single entry point used by the `/quota` slash
3
+ * command.
4
+ *
5
+ * Flow: cache check → fetch → parse → cache write. Any thrown error (missing
6
+ * apiKey, network/timeout) degrades to `unavailable` rather than propagating,
7
+ * so the command always produces a user-visible message.
8
+ */
9
+ import type { QuotaResult } from "./types.js";
10
+ /**
11
+ * Query the GLM quota API and return a normalised {@link QuotaResult}.
12
+ *
13
+ * Serves a cached result when fresh (< 10s). On fetch failure the result is
14
+ * `unavailable`; on a successful fetch the parsed envelope is cached and
15
+ * returned.
16
+ */
17
+ export declare function queryQuota(): Promise<QuotaResult>;
18
+ export { formatQuota, formatQuotaPlain } from "./format.js";
19
+ export { parseLimit, parseQuotaEnvelope } from "./parse.js";
20
+ export { renderBar } from "./format.js";
21
+ export type { FormatOptions } from "./format.js";
22
+ export type { QuotaItem, QuotaResult, RawLimit } from "./types.js";
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/quota/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;GAMG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC,CAkBvD;AAGD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Quota orchestration — the single entry point used by the `/quota` slash
3
+ * command.
4
+ *
5
+ * Flow: cache check → fetch → parse → cache write. Any thrown error (missing
6
+ * apiKey, network/timeout) degrades to `unavailable` rather than propagating,
7
+ * so the command always produces a user-visible message.
8
+ */
9
+ import { getCached, setCached } from "./cache.js";
10
+ import { fetchQuotaResponse } from "./client.js";
11
+ import { log } from "../utils.js";
12
+ import { parseQuotaEnvelope } from "./parse.js";
13
+ /**
14
+ * Query the GLM quota API and return a normalised {@link QuotaResult}.
15
+ *
16
+ * Serves a cached result when fresh (< 10s). On fetch failure the result is
17
+ * `unavailable`; on a successful fetch the parsed envelope is cached and
18
+ * returned.
19
+ */
20
+ export async function queryQuota() {
21
+ const cached = getCached();
22
+ if (cached) {
23
+ log("quota: serving cached result");
24
+ return cached;
25
+ }
26
+ let result;
27
+ try {
28
+ const resp = await fetchQuotaResponse();
29
+ result = parseQuotaEnvelope(resp);
30
+ }
31
+ catch (e) {
32
+ log(`quota: fetch failed (${e instanceof Error ? e.message : String(e)})`);
33
+ result = { kind: "unavailable" };
34
+ }
35
+ setCached(result);
36
+ return result;
37
+ }
38
+ // Re-exports for consumers (slash handler + CLI + tests).
39
+ export { formatQuota, formatQuotaPlain } from "./format.js";
40
+ export { parseLimit, parseQuotaEnvelope } from "./parse.js";
41
+ export { renderBar } from "./format.js";
42
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/quota/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGhD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,MAAM,EAAE,CAAC;QACX,GAAG,CAAC,8BAA8B,CAAC,CAAC;QACpC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,MAAmB,CAAC;IACxB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,kBAAkB,EAAE,CAAC;QACxC,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,wBAAwB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3E,MAAM,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;IACnC,CAAC;IAED,SAAS,CAAC,MAAM,CAAC,CAAC;IAClB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,0DAA0D;AAC1D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * In-memory TTL cache for Opencode Go results.
3
+ *
4
+ * Mirrors {@link ../../cache.ts} but typed for {@link GoQueryResult}. Same
5
+ * 10s TTL — short enough that the countdown stays accurate in watch mode,
6
+ * long enough to debounce rapid repeats. No file persistence, no sharding.
7
+ */
8
+ import type { GoQueryResult } from "./types.js";
9
+ /** Return the cached result if still fresh, else `null`. */
10
+ export declare function getCached(): GoQueryResult | null;
11
+ /** Store a fresh result, stamping it with the current time. */
12
+ export declare function setCached(result: GoQueryResult): void;
13
+ /** Clear the cache (test helper, and used by CLI watch mode per tick). */
14
+ export declare function clearCache(): void;
15
+ /** Override the clock (test-only). Pass `undefined` to restore real time. */
16
+ export declare function setClock(fn?: () => number): void;
17
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/quota/opencode-go/cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAUhD,4DAA4D;AAC5D,wBAAgB,SAAS,IAAI,aAAa,GAAG,IAAI,CAGhD;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAErD;AAED,0EAA0E;AAC1E,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAEhD"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * In-memory TTL cache for Opencode Go results.
3
+ *
4
+ * Mirrors {@link ../../cache.ts} but typed for {@link GoQueryResult}. Same
5
+ * 10s TTL — short enough that the countdown stays accurate in watch mode,
6
+ * long enough to debounce rapid repeats. No file persistence, no sharding.
7
+ */
8
+ /** How long a cached result is served before re-querying. */
9
+ const TTL_MS = 10_000;
10
+ let slot = null;
11
+ /** Inject a fake clock — only tests should need this. */
12
+ let now = () => Date.now();
13
+ /** Return the cached result if still fresh, else `null`. */
14
+ export function getCached() {
15
+ if (slot && now() - slot.at < TTL_MS)
16
+ return slot.result;
17
+ return null;
18
+ }
19
+ /** Store a fresh result, stamping it with the current time. */
20
+ export function setCached(result) {
21
+ slot = { result, at: now() };
22
+ }
23
+ /** Clear the cache (test helper, and used by CLI watch mode per tick). */
24
+ export function clearCache() {
25
+ slot = null;
26
+ }
27
+ /** Override the clock (test-only). Pass `undefined` to restore real time. */
28
+ export function setClock(fn) {
29
+ now = fn ?? (() => Date.now());
30
+ }
31
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/quota/opencode-go/cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,6DAA6D;AAC7D,MAAM,MAAM,GAAG,MAAM,CAAC;AAEtB,IAAI,IAAI,GAAiD,IAAI,CAAC;AAE9D,yDAAyD;AACzD,IAAI,GAAG,GAAiB,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;AAEzC,4DAA4D;AAC5D,MAAM,UAAU,SAAS;IACvB,IAAI,IAAI,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM;QAAE,OAAO,IAAI,CAAC,MAAM,CAAC;IACzD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,SAAS,CAAC,MAAqB;IAC7C,IAAI,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;AAC/B,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,UAAU;IACxB,IAAI,GAAG,IAAI,CAAC;AACd,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,EAAiB;IACxC,GAAG,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Opencode Go dashboard HTTP client.
3
+ *
4
+ * There is no JSON API for Go subscription usage. The only data source is the
5
+ * authenticated web dashboard at `https://opencode.ai/workspace/<id>/go`,
6
+ * which serves an HTML page with usage embedded in a SolidJS SSR hydration
7
+ * payload. We fetch the HTML here and hand it to the parser.
8
+ *
9
+ * Credentials come from environment variables (set by the user) — not from
10
+ * `~/.zcode/v2/config.json`, since Opencode Go is unrelated to the ZCode
11
+ * provider the bridge talks to.
12
+ */
13
+ /** Build the dashboard URL for a workspace. */
14
+ export declare function dashboardUrl(workspaceId: string): string;
15
+ /**
16
+ * Fetch the Go dashboard HTML.
17
+ *
18
+ * @throws on non-2xx responses, network errors, or timeout. The caller maps
19
+ * these to `unavailable`. A redirect-to-login is NOT thrown here —
20
+ * the final URL is returned so the orchestrator can classify it as
21
+ * `auth_error`.
22
+ */
23
+ export declare function fetchGoDashboard(workspaceId: string, authCookie: string, fetchImpl?: typeof globalThis.fetch): Promise<{
24
+ status: number;
25
+ text: string;
26
+ finalUrl: string;
27
+ }>;
28
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/quota/opencode-go/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,+CAA+C;AAC/C,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,OAAO,UAAU,CAAC,KAAwB,GACpD,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAe7D"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Opencode Go dashboard HTTP client.
3
+ *
4
+ * There is no JSON API for Go subscription usage. The only data source is the
5
+ * authenticated web dashboard at `https://opencode.ai/workspace/<id>/go`,
6
+ * which serves an HTML page with usage embedded in a SolidJS SSR hydration
7
+ * payload. We fetch the HTML here and hand it to the parser.
8
+ *
9
+ * Credentials come from environment variables (set by the user) — not from
10
+ * `~/.zcode/v2/config.json`, since Opencode Go is unrelated to the ZCode
11
+ * provider the bridge talks to.
12
+ */
13
+ /** Request timeout (ms). The dashboard is a full HTML page; allow a bit more. */
14
+ const TIMEOUT_MS = 10_000;
15
+ /**
16
+ * Browser-like User-Agent. opencode.ai returns a login redirect for
17
+ * unauthenticated requests; sending a real browser UA avoids any
18
+ * bot-detection short-circuit that would bypass the dashboard route.
19
+ */
20
+ const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Gecko/20100101 Firefox/148.0";
21
+ /** Build the dashboard URL for a workspace. */
22
+ export function dashboardUrl(workspaceId) {
23
+ return `https://opencode.ai/workspace/${workspaceId}/go`;
24
+ }
25
+ /**
26
+ * Fetch the Go dashboard HTML.
27
+ *
28
+ * @throws on non-2xx responses, network errors, or timeout. The caller maps
29
+ * these to `unavailable`. A redirect-to-login is NOT thrown here —
30
+ * the final URL is returned so the orchestrator can classify it as
31
+ * `auth_error`.
32
+ */
33
+ export async function fetchGoDashboard(workspaceId, authCookie, fetchImpl = globalThis.fetch) {
34
+ const url = dashboardUrl(workspaceId);
35
+ const resp = await fetchImpl(url, {
36
+ method: "GET",
37
+ headers: {
38
+ Cookie: `auth=${authCookie}`,
39
+ "User-Agent": USER_AGENT,
40
+ Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
41
+ },
42
+ redirect: "follow",
43
+ signal: AbortSignal.timeout(TIMEOUT_MS),
44
+ });
45
+ const text = await resp.text();
46
+ return { status: resp.status, text, finalUrl: resp.url };
47
+ }
48
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/quota/opencode-go/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,iFAAiF;AACjF,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B;;;;GAIG;AACH,MAAM,UAAU,GAAG,8EAA8E,CAAC;AAElG,+CAA+C;AAC/C,MAAM,UAAU,YAAY,CAAC,WAAmB;IAC9C,OAAO,iCAAiC,WAAW,KAAK,CAAC;AAC3D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,WAAmB,EACnB,UAAkB,EAClB,YAAqC,UAAU,CAAC,KAAK;IAErD,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACP,MAAM,EAAE,QAAQ,UAAU,EAAE;YAC5B,YAAY,EAAE,UAAU;YACxB,MAAM,EAAE,iEAAiE;SAC1E;QACD,QAAQ,EAAE,QAAQ;QAClB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC;KACxC,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAC/B,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Opencode Go credential discovery.
3
+ *
4
+ * Credentials may come from two sources, merged field-by-field with
5
+ * **environment variables taking precedence** over the config file:
6
+ * 1. `OPENCODE_GO_WORKSPACE_ID` / `OPENCODE_GO_AUTH_COOKIE` env vars
7
+ * (best for CI / scripts / temporary overrides).
8
+ * 2. `~/.pi/agent/opencode-go.json` — `{ workspaceId, authCookie }`
9
+ * (the convention used by the @beyona/pi-zai-usage Pi extension, so users
10
+ * who already configured it there get reuse for free).
11
+ *
12
+ * A field present in env overrides the same field from the file; a field only
13
+ * in the file is still used. This lets a user keep their stable workspaceId in
14
+ * the file while rotating the cookie via env, etc. Both fields must resolve to
15
+ * a valid pair — a missing/invalid one yields `not_configured`.
16
+ */
17
+ /** Env var names — documented in the CLI help and README. */
18
+ export declare const ENV_WORKSPACE_ID = "OPENCODE_GO_WORKSPACE_ID";
19
+ export declare const ENV_AUTH_COOKIE = "OPENCODE_GO_AUTH_COOKIE";
20
+ /** Config file path (matches the @beyona/pi-zai-usage convention). */
21
+ export declare const CONFIG_PATH: string;
22
+ /** Shape of the JSON config file. */
23
+ interface OpencodeGoConfig {
24
+ workspaceId?: string;
25
+ authCookie?: string;
26
+ }
27
+ /**
28
+ * Read (best-effort) the JSON config file. Returns an empty object on any
29
+ * error — missing file, parse error, or wrong shape all degrade to "no fields
30
+ * contributed", which the caller treats as `not_configured`.
31
+ *
32
+ * Best-effort mirrors {@link ../../backend/credentials.ts}: a missing or
33
+ * corrupt config must never crash the bridge, only log.
34
+ */
35
+ export declare function readConfigFile(filePath?: string): OpencodeGoConfig;
36
+ export {};
37
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/quota/opencode-go/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAQH,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,6BAA6B,CAAC;AAC3D,eAAO,MAAM,eAAe,4BAA4B,CAAC;AAEzD,sEAAsE;AACtE,eAAO,MAAM,WAAW,QAKvB,CAAC;AAEF,qCAAqC;AACrC,UAAU,gBAAgB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,GAAE,MAAoB,GAAG,gBAAgB,CAsB/E"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Opencode Go credential discovery.
3
+ *
4
+ * Credentials may come from two sources, merged field-by-field with
5
+ * **environment variables taking precedence** over the config file:
6
+ * 1. `OPENCODE_GO_WORKSPACE_ID` / `OPENCODE_GO_AUTH_COOKIE` env vars
7
+ * (best for CI / scripts / temporary overrides).
8
+ * 2. `~/.pi/agent/opencode-go.json` — `{ workspaceId, authCookie }`
9
+ * (the convention used by the @beyona/pi-zai-usage Pi extension, so users
10
+ * who already configured it there get reuse for free).
11
+ *
12
+ * A field present in env overrides the same field from the file; a field only
13
+ * in the file is still used. This lets a user keep their stable workspaceId in
14
+ * the file while rotating the cookie via env, etc. Both fields must resolve to
15
+ * a valid pair — a missing/invalid one yields `not_configured`.
16
+ */
17
+ import { readFileSync } from "node:fs";
18
+ import path from "node:path";
19
+ import process from "node:process";
20
+ import { log } from "../../utils.js";
21
+ /** Env var names — documented in the CLI help and README. */
22
+ export const ENV_WORKSPACE_ID = "OPENCODE_GO_WORKSPACE_ID";
23
+ export const ENV_AUTH_COOKIE = "OPENCODE_GO_AUTH_COOKIE";
24
+ /** Config file path (matches the @beyona/pi-zai-usage convention). */
25
+ export const CONFIG_PATH = path.join(process.env.HOME || process.env.USERPROFILE || "~", ".pi", "agent", "opencode-go.json");
26
+ /**
27
+ * Read (best-effort) the JSON config file. Returns an empty object on any
28
+ * error — missing file, parse error, or wrong shape all degrade to "no fields
29
+ * contributed", which the caller treats as `not_configured`.
30
+ *
31
+ * Best-effort mirrors {@link ../../backend/credentials.ts}: a missing or
32
+ * corrupt config must never crash the bridge, only log.
33
+ */
34
+ export function readConfigFile(filePath = CONFIG_PATH) {
35
+ try {
36
+ const raw = readFileSync(filePath, "utf8");
37
+ const parsed = JSON.parse(raw);
38
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
39
+ log(`opencode-go: config file is not a JSON object (${filePath})`);
40
+ return {};
41
+ }
42
+ const cfg = parsed;
43
+ return {
44
+ workspaceId: typeof cfg.workspaceId === "string" ? cfg.workspaceId : undefined,
45
+ authCookie: typeof cfg.authCookie === "string" ? cfg.authCookie : undefined,
46
+ };
47
+ }
48
+ catch (e) {
49
+ // ENOENT (most common — user hasn't created the file) is silent; other
50
+ // read/parse errors are logged but still non-fatal.
51
+ const msg = e instanceof Error ? e.message : String(e);
52
+ if (!/ENOENT/.test(msg)) {
53
+ log(`opencode-go: config read failed (${filePath}): ${msg}`);
54
+ }
55
+ return {};
56
+ }
57
+ }
58
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/quota/opencode-go/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAErC,6DAA6D;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,0BAA0B,CAAC;AAC3D,MAAM,CAAC,MAAM,eAAe,GAAG,yBAAyB,CAAC;AAEzD,sEAAsE;AACtE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAClC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,EAClD,KAAK,EACL,OAAO,EACP,kBAAkB,CACnB,CAAC;AAQF;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB,WAAW;IAC3D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;QAC1C,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,GAAG,CAAC,kDAAkD,QAAQ,GAAG,CAAC,CAAC;YACnE,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,GAAG,GAAG,MAAiC,CAAC;QAC9C,OAAO;YACL,WAAW,EAAE,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;YAC9E,UAAU,EAAE,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;SAC5E,CAAC;IACJ,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,uEAAuE;QACvE,oDAAoD;QACpD,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,GAAG,CAAC,oCAAoC,QAAQ,MAAM,GAAG,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,36 @@
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 type { GoQueryResult, GoWindowKey } from "./types.js";
10
+ /**
11
+ * Format a duration in seconds as a compact countdown.
12
+ *
13
+ * - `>= 1d` → `Xd Yh` (e.g. `6d 8h`)
14
+ * - `>= 1h` → `Yh Zm` (e.g. `2h 30m`)
15
+ * - `>= 1m` → `Zm` (e.g. `45m`)
16
+ * - `< 1m` → `<1m`
17
+ */
18
+ export declare function formatDuration(sec: number): string;
19
+ /** A rendered section: a header line and zero or more body lines. */
20
+ export interface RenderedSection {
21
+ header: string;
22
+ body: string[];
23
+ }
24
+ /**
25
+ * Render the Opencode Go section for the requested windows.
26
+ *
27
+ * Used by the combined formatter. The header is always `Opencode Go`; body
28
+ * has one bar line per window. Non-success kinds return a header + a single
29
+ * explanatory line.
30
+ *
31
+ * When `color` is true the bar is a heat-colored 24-bit ANSI bar with the
32
+ * percent overlaid inside (Go windows carry no absolute counters, so the
33
+ * overlay is always `NN%`), mirroring the GLM color layout.
34
+ */
35
+ export declare function formatGoSection(result: GoQueryResult, windows: readonly GoWindowKey[], now?: number, color?: boolean): RenderedSection;
36
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/quota/opencode-go/format.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS7D;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASlD;AAOD,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,GAAG,GAAE,MAAmB,EACxB,KAAK,UAAQ,GACZ,eAAe,CAqCjB"}