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.
- package/README.md +192 -9
- package/README.zh-CN.md +143 -8
- package/dist/backend/client.d.ts +12 -4
- package/dist/backend/client.d.ts.map +1 -1
- package/dist/backend/client.js +72 -7
- package/dist/backend/client.js.map +1 -1
- package/dist/backend/credentials.d.ts.map +1 -1
- package/dist/backend/credentials.js +2 -1
- package/dist/backend/credentials.js.map +1 -1
- package/dist/backend/listener.d.ts +12 -4
- package/dist/backend/listener.d.ts.map +1 -1
- package/dist/backend/listener.js +68 -12
- package/dist/backend/listener.js.map +1 -1
- package/dist/backend/types.d.ts +1 -1
- package/dist/backend/types.d.ts.map +1 -1
- package/dist/bin/hub.d.ts +16 -0
- package/dist/bin/hub.d.ts.map +1 -0
- package/dist/bin/hub.js +41 -0
- package/dist/bin/hub.js.map +1 -0
- package/dist/bin/quota.d.ts +54 -0
- package/dist/bin/quota.d.ts.map +1 -0
- package/dist/bin/quota.js +333 -0
- package/dist/bin/quota.js.map +1 -0
- package/dist/config/auto-compact.d.ts +23 -0
- package/dist/config/auto-compact.d.ts.map +1 -0
- package/dist/config/auto-compact.js +67 -0
- package/dist/config/auto-compact.js.map +1 -0
- package/dist/config/mcp-discovery.d.ts +34 -0
- package/dist/config/mcp-discovery.d.ts.map +1 -0
- package/dist/config/mcp-discovery.js +153 -0
- package/dist/config/mcp-discovery.js.map +1 -0
- package/dist/config/model-cache.d.ts +12 -1
- package/dist/config/model-cache.d.ts.map +1 -1
- package/dist/config/model-cache.js +30 -8
- package/dist/config/model-cache.js.map +1 -1
- package/dist/config/options.d.ts +87 -9
- package/dist/config/options.d.ts.map +1 -1
- package/dist/config/options.js +248 -45
- package/dist/config/options.js.map +1 -1
- package/dist/config/plugin-commands.d.ts +24 -0
- package/dist/config/plugin-commands.d.ts.map +1 -0
- package/dist/config/plugin-commands.js +107 -0
- package/dist/config/plugin-commands.js.map +1 -0
- package/dist/config/provider-registry.d.ts +60 -0
- package/dist/config/provider-registry.d.ts.map +1 -0
- package/dist/config/provider-registry.js +128 -0
- package/dist/config/provider-registry.js.map +1 -0
- package/dist/config/runtime-model.d.ts +54 -18
- package/dist/config/runtime-model.d.ts.map +1 -1
- package/dist/config/runtime-model.js +105 -61
- package/dist/config/runtime-model.js.map +1 -1
- package/dist/config/skill-discovery.d.ts +35 -0
- package/dist/config/skill-discovery.d.ts.map +1 -0
- package/dist/config/skill-discovery.js +188 -0
- package/dist/config/skill-discovery.js.map +1 -0
- package/dist/handlers/account.d.ts +43 -0
- package/dist/handlers/account.d.ts.map +1 -0
- package/dist/handlers/account.js +59 -0
- package/dist/handlers/account.js.map +1 -0
- package/dist/handlers/background-tasks.d.ts +72 -0
- package/dist/handlers/background-tasks.d.ts.map +1 -0
- package/dist/handlers/background-tasks.js +330 -0
- package/dist/handlers/background-tasks.js.map +1 -0
- package/dist/handlers/dispatch.d.ts.map +1 -1
- package/dist/handlers/dispatch.js +134 -22
- package/dist/handlers/dispatch.js.map +1 -1
- package/dist/handlers/extensions.d.ts +15 -0
- package/dist/handlers/extensions.d.ts.map +1 -1
- package/dist/handlers/extensions.js +43 -27
- package/dist/handlers/extensions.js.map +1 -1
- package/dist/handlers/io.d.ts +31 -3
- package/dist/handlers/io.d.ts.map +1 -1
- package/dist/handlers/io.js +108 -9
- package/dist/handlers/io.js.map +1 -1
- package/dist/handlers/replay.d.ts +79 -0
- package/dist/handlers/replay.d.ts.map +1 -0
- package/dist/handlers/replay.js +252 -0
- package/dist/handlers/replay.js.map +1 -0
- package/dist/handlers/server-requests.d.ts +20 -4
- package/dist/handlers/server-requests.d.ts.map +1 -1
- package/dist/handlers/server-requests.js +293 -63
- package/dist/handlers/server-requests.js.map +1 -1
- package/dist/handlers/session.d.ts +113 -10
- package/dist/handlers/session.d.ts.map +1 -1
- package/dist/handlers/session.js +932 -277
- package/dist/handlers/session.js.map +1 -1
- package/dist/handlers/slash.d.ts +37 -1
- package/dist/handlers/slash.d.ts.map +1 -1
- package/dist/handlers/slash.js +143 -8
- package/dist/handlers/slash.js.map +1 -1
- package/dist/index.js +76 -12
- package/dist/index.js.map +1 -1
- package/dist/interaction/adapter.d.ts +19 -33
- package/dist/interaction/adapter.d.ts.map +1 -1
- package/dist/interaction/adapter.js +80 -79
- package/dist/interaction/adapter.js.map +1 -1
- package/dist/lazy-sessions.d.ts +35 -0
- package/dist/lazy-sessions.d.ts.map +1 -0
- package/dist/lazy-sessions.js +98 -0
- package/dist/lazy-sessions.js.map +1 -0
- package/dist/quota/cache.d.ts +18 -0
- package/dist/quota/cache.d.ts.map +1 -0
- package/dist/quota/cache.js +32 -0
- package/dist/quota/cache.js.map +1 -0
- package/dist/quota/client.d.ts +30 -0
- package/dist/quota/client.d.ts.map +1 -0
- package/dist/quota/client.js +57 -0
- package/dist/quota/client.js.map +1 -0
- package/dist/quota/color.d.ts +58 -0
- package/dist/quota/color.d.ts.map +1 -0
- package/dist/quota/color.js +95 -0
- package/dist/quota/color.js.map +1 -0
- package/dist/quota/combined.d.ts +66 -0
- package/dist/quota/combined.d.ts.map +1 -0
- package/dist/quota/combined.js +179 -0
- package/dist/quota/combined.js.map +1 -0
- package/dist/quota/format.d.ts +105 -0
- package/dist/quota/format.d.ts.map +1 -0
- package/dist/quota/format.js +219 -0
- package/dist/quota/format.js.map +1 -0
- package/dist/quota/index.d.ts +23 -0
- package/dist/quota/index.d.ts.map +1 -0
- package/dist/quota/index.js +42 -0
- package/dist/quota/index.js.map +1 -0
- package/dist/quota/opencode-go/cache.d.ts +17 -0
- package/dist/quota/opencode-go/cache.d.ts.map +1 -0
- package/dist/quota/opencode-go/cache.js +31 -0
- package/dist/quota/opencode-go/cache.js.map +1 -0
- package/dist/quota/opencode-go/client.d.ts +28 -0
- package/dist/quota/opencode-go/client.d.ts.map +1 -0
- package/dist/quota/opencode-go/client.js +48 -0
- package/dist/quota/opencode-go/client.js.map +1 -0
- package/dist/quota/opencode-go/config.d.ts +37 -0
- package/dist/quota/opencode-go/config.d.ts.map +1 -0
- package/dist/quota/opencode-go/config.js +58 -0
- package/dist/quota/opencode-go/config.js.map +1 -0
- package/dist/quota/opencode-go/format.d.ts +36 -0
- package/dist/quota/opencode-go/format.d.ts.map +1 -0
- package/dist/quota/opencode-go/format.js +87 -0
- package/dist/quota/opencode-go/format.js.map +1 -0
- package/dist/quota/opencode-go/index.d.ts +30 -0
- package/dist/quota/opencode-go/index.d.ts.map +1 -0
- package/dist/quota/opencode-go/index.js +108 -0
- package/dist/quota/opencode-go/index.js.map +1 -0
- package/dist/quota/opencode-go/parse.d.ts +41 -0
- package/dist/quota/opencode-go/parse.d.ts.map +1 -0
- package/dist/quota/opencode-go/parse.js +75 -0
- package/dist/quota/opencode-go/parse.js.map +1 -0
- package/dist/quota/opencode-go/types.d.ts +48 -0
- package/dist/quota/opencode-go/types.d.ts.map +1 -0
- package/dist/quota/opencode-go/types.js +11 -0
- package/dist/quota/opencode-go/types.js.map +1 -0
- package/dist/quota/parse.d.ts +33 -0
- package/dist/quota/parse.d.ts.map +1 -0
- package/dist/quota/parse.js +200 -0
- package/dist/quota/parse.js.map +1 -0
- package/dist/quota/types.d.ts +72 -0
- package/dist/quota/types.d.ts.map +1 -0
- package/dist/quota/types.js +10 -0
- package/dist/quota/types.js.map +1 -0
- package/dist/remote/broadcast.d.ts +47 -0
- package/dist/remote/broadcast.d.ts.map +1 -0
- package/dist/remote/broadcast.js +121 -0
- package/dist/remote/broadcast.js.map +1 -0
- package/dist/remote/config.d.ts +32 -0
- package/dist/remote/config.d.ts.map +1 -0
- package/dist/remote/config.js +65 -0
- package/dist/remote/config.js.map +1 -0
- package/dist/remote/endpoint.d.ts +30 -0
- package/dist/remote/endpoint.d.ts.map +1 -0
- package/dist/remote/endpoint.js +213 -0
- package/dist/remote/endpoint.js.map +1 -0
- package/dist/remote/hub-server.d.ts +41 -0
- package/dist/remote/hub-server.d.ts.map +1 -0
- package/dist/remote/hub-server.js +346 -0
- package/dist/remote/hub-server.js.map +1 -0
- package/dist/server.d.ts +139 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +179 -4
- package/dist/server.js.map +1 -1
- package/dist/tasks-index.d.ts +14 -4
- package/dist/tasks-index.d.ts.map +1 -1
- package/dist/tasks-index.js +145 -46
- package/dist/tasks-index.js.map +1 -1
- package/dist/translators/event-translator.d.ts +33 -0
- package/dist/translators/event-translator.d.ts.map +1 -1
- package/dist/translators/event-translator.js +101 -0
- package/dist/translators/event-translator.js.map +1 -1
- package/dist/translators/index.d.ts +1 -1
- package/dist/translators/index.d.ts.map +1 -1
- package/dist/translators/index.js +1 -1
- package/dist/translators/index.js.map +1 -1
- package/dist/translators/projection-differ.d.ts +8 -0
- package/dist/translators/projection-differ.d.ts.map +1 -1
- package/dist/translators/projection-differ.js +19 -9
- package/dist/translators/projection-differ.js.map +1 -1
- package/dist/translators/tool-helpers.d.ts +28 -0
- package/dist/translators/tool-helpers.d.ts.map +1 -1
- package/dist/translators/tool-helpers.js +104 -0
- package/dist/translators/tool-helpers.js.map +1 -1
- package/dist/translators/types.d.ts +38 -1
- package/dist/translators/types.d.ts.map +1 -1
- package/dist/translators/types.js.map +1 -1
- package/dist/utils.d.ts +36 -7
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +69 -5
- package/dist/utils.js.map +1 -1
- package/docs/ARCHITECTURE.md +130 -40
- package/docs/BACKLOG.md +59 -0
- package/docs/DEVELOPMENT.md +31 -0
- package/docs/PROTOCOL.md +328 -23
- package/docs/REMOTE-CLIENTS.md +260 -0
- package/docs/REPLAY-GUIDE.md +131 -0
- package/docs/TROUBLESHOOTING.md +131 -14
- package/docs/adr/0001-bridge-lifetime-follows-primary-client.md +14 -0
- package/docs/adr/0002-stateless-hub-over-per-bridge-acp-endpoints.md +23 -0
- package/docs/adr/0003-tail-replay-meta-and-cursor-pagination.md +40 -0
- package/docs/agents/domain.md +51 -0
- package/docs/agents/issue-tracker.md +22 -0
- package/docs/agents/triage-labels.md +15 -0
- package/docs/proposals/0001-tail-session-replay.md +136 -0
- package/docs/proposals/0002-plan-quota-usage.md +81 -0
- 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"}
|