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,333 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Standalone CLI for querying GLM Coding Plan usage — a thin wrapper over the
4
+ * same `queryQuota()` + `formatQuotaPlain()` the `/quota` slash command uses.
5
+ *
6
+ * No ACP server, no zcode subprocess: only reads `~/.zcode/v2/config.json` for
7
+ * credentials and hits the quota HTTP API directly.
8
+ *
9
+ * Usage:
10
+ * zcode-quota one-shot: print the card and exit
11
+ * zcode-quota -w watch mode (default 30s refresh)
12
+ * zcode-quota -w -i 60 watch with a 60s interval
13
+ * zcode-quota -d show per-model MCP detail sub-lines
14
+ * zcode-quota --watch --interval 15
15
+ * zcode-quota -h | --help show help
16
+ *
17
+ * The refresh interval has a 10s floor: the in-memory quota cache TTL is 10s,
18
+ * and a shorter interval would just keep returning the cached value.
19
+ */
20
+ import process from "node:process";
21
+ import { clearCache as clearGlmCache } from "../quota/cache.js";
22
+ import { defaultGoWindows, formatCombinedCardPlain, queryCombined, } from "../quota/combined.js";
23
+ import { clearGoCache } from "../quota/opencode-go/index.js";
24
+ /** Clear both provider caches — used by watch mode per tick for live values. */
25
+ function clearAllCaches() {
26
+ clearGlmCache();
27
+ clearGoCache();
28
+ }
29
+ /** Minimum watch interval (ms). Equals the quota cache TTL. */
30
+ const MIN_INTERVAL_MS = 10_000;
31
+ /** Default watch interval (ms). */
32
+ const DEFAULT_INTERVAL_MS = 30_000;
33
+ // ANSI escape sequences used by watch mode (no external dep — Local First).
34
+ const ANSI = {
35
+ clearScreen: "\x1B[2J\x1B[H", // clear + cursor home
36
+ clearLine: "\x1B[2K", // clear the entire current line
37
+ hideCursor: "\x1B[?25l",
38
+ showCursor: "\x1B[?25h",
39
+ };
40
+ /** Human-readable usage text. */
41
+ const HELP_TEXT = `Usage: zcode-quota [provider] [options]
42
+
43
+ Query usage from the terminal. By default shows both GLM Coding Plan and
44
+ Opencode Go in one card; pass a provider to focus on one.
45
+
46
+ Providers:
47
+ (none) Both GLM + Opencode Go (rolling + weekly + monthly).
48
+ glm GLM Coding Plan only.
49
+ go Opencode Go only (rolling + weekly + monthly).
50
+
51
+ GLM credentials: read from ~/.zcode/v2/config.json (created by the ZCode app).
52
+ Opencode Go credentials (env vars override the config file, field by field):
53
+ Config file ~/.pi/agent/opencode-go.json {"workspaceId":"wrk_…","authCookie":"Fe26.2**…"}
54
+ OPENCODE_GO_WORKSPACE_ID e.g. wrk_abc123 (from the opencode.ai workspace URL)
55
+ OPENCODE_GO_AUTH_COOKIE the "auth" cookie value (starts with Fe26.2**)
56
+ Get the cookie via browser DevTools → Application → Cookies → opencode.ai.
57
+
58
+ Options:
59
+ -w, --watch Watch mode: clear the screen and refresh periodically.
60
+ -i, --interval <seconds> Refresh interval for watch mode (default 30, min 10).
61
+ -d, --detail Show per-model MCP usage detail sub-lines (GLM only).
62
+ -p, --plain Plain monochrome bars (no color, no in-bar overlay).
63
+ Color is the default on a terminal; disabled
64
+ automatically when stdout is piped or redirected.
65
+ -h, --help Show this help and exit.
66
+
67
+ Examples:
68
+ zcode-quota # both providers, print once and exit (color bars)
69
+ zcode-quota go # Opencode Go only (3 windows)
70
+ zcode-quota glm -w # GLM only, live monitor every 30s
71
+ zcode-quota -w -i 60 # both, refresh every 60s
72
+ zcode-quota -d # both, include per-model MCP breakdown
73
+ zcode-quota --plain # both, classic monochrome bars`;
74
+ /**
75
+ * Clamp a raw interval (seconds, optional) to a valid ms value. Returns the
76
+ * clamped value plus whether a user-supplied value was raised to the floor.
77
+ *
78
+ * Exported for unit testing.
79
+ */
80
+ export function resolveIntervalMs(seconds) {
81
+ const requested = (seconds ?? DEFAULT_INTERVAL_MS / 1000) * 1000;
82
+ if (requested < MIN_INTERVAL_MS) {
83
+ return { ms: MIN_INTERVAL_MS, clamped: seconds !== undefined };
84
+ }
85
+ return { ms: requested, clamped: false };
86
+ }
87
+ /**
88
+ * Parse argv into {@link CliOptions}. Supports `-w`/`--watch`, `-h`/`--help`,
89
+ * `-i <n>`/`--interval <n>` (space), `--interval=<n>`, and `-i<n>` (attached).
90
+ * The first non-flag positional arg is the provider (`glm`/`go`); any other
91
+ * value is ignored (treated as `all`). Unknown flags are ignored.
92
+ *
93
+ * Exported for unit testing.
94
+ */
95
+ export function parseArgs(argv) {
96
+ let watch = false;
97
+ let help = false;
98
+ let detail = false;
99
+ let plain = false;
100
+ let interval;
101
+ let provider = "all";
102
+ for (let i = 0; i < argv.length; i++) {
103
+ const arg = argv[i];
104
+ switch (arg) {
105
+ case "-w":
106
+ case "--watch":
107
+ watch = true;
108
+ break;
109
+ case "-d":
110
+ case "--detail":
111
+ detail = true;
112
+ break;
113
+ case "-p":
114
+ case "--plain":
115
+ plain = true;
116
+ break;
117
+ case "-h":
118
+ case "--help":
119
+ help = true;
120
+ break;
121
+ case "-i":
122
+ case "--interval": {
123
+ const next = argv[i + 1];
124
+ if (next !== undefined) {
125
+ const n = Number(next);
126
+ if (Number.isFinite(n))
127
+ interval = n;
128
+ i++; // consume the value
129
+ }
130
+ break;
131
+ }
132
+ default:
133
+ // Support `-i<value>` / `--interval=<value>` attached forms.
134
+ if (arg?.startsWith("--interval=")) {
135
+ const n = Number(arg.slice("--interval=".length));
136
+ if (Number.isFinite(n))
137
+ interval = n;
138
+ }
139
+ else if (arg?.startsWith("-i") && arg.length > 2) {
140
+ const n = Number(arg.slice(2));
141
+ if (Number.isFinite(n))
142
+ interval = n;
143
+ }
144
+ else if (arg === "glm" || arg === "go") {
145
+ // First positional provider token. Only honor the first; a second
146
+ // (e.g. `zcode-quota glm go`) is ignored to keep parsing simple.
147
+ if (provider === "all")
148
+ provider = arg;
149
+ }
150
+ // Other non-flag tokens are ignored (forward-compat / typos).
151
+ break;
152
+ }
153
+ }
154
+ const resolved = resolveIntervalMs(interval);
155
+ return {
156
+ watch,
157
+ detail,
158
+ help,
159
+ plain,
160
+ provider,
161
+ intervalMs: resolved.ms,
162
+ intervalClamped: resolved.clamped,
163
+ };
164
+ }
165
+ /**
166
+ * Sleep helper. Accepts an AbortSignal so SIGINT can break the wait early.
167
+ *
168
+ * NOTE: the timer is deliberately NOT `unref()`-ed. In watch mode this sleep
169
+ * is the only thing keeping the event loop alive between ticks; an unref'd
170
+ * timer lets Node exit immediately after the first frame renders, which
171
+ * silently kills the monitor. Only a real abort (Ctrl-C) should end the wait.
172
+ */
173
+ function sleep(ms, signal) {
174
+ return new Promise((resolve, reject) => {
175
+ const t = setTimeout(resolve, ms);
176
+ signal?.addEventListener("abort", () => {
177
+ clearTimeout(t);
178
+ reject(new Error("aborted"));
179
+ }, { once: true });
180
+ });
181
+ }
182
+ /** Format the watch-mode countdown suffix appended to the first header. */
183
+ function refreshSuffix(remainingSec) {
184
+ return `refresh in ${remainingSec}s`;
185
+ }
186
+ /**
187
+ * Render the card for a given provider selection. Centralises the
188
+ * combined-card formatting so watch and one-shot share one code path. In watch
189
+ * mode the refresh countdown is rendered on the separator row after the first
190
+ * section (its position is fixed whether or not a second section appears).
191
+ *
192
+ * `color` switches the bars to a heat-colored (green→red) 24-bit ANSI layout
193
+ * with the usage numbers overlaid inside. The CLI caller gates this on
194
+ * `stdout.isTTY && !plain`.
195
+ */
196
+ function renderCard(combined, provider, detail, color, refresh) {
197
+ const text = formatCombinedCardPlain(combined, {
198
+ provider,
199
+ glm: { detail },
200
+ goWindows: defaultGoWindows(provider),
201
+ color,
202
+ refreshSuffix: refresh,
203
+ });
204
+ // The refresh line is the one carrying the countdown text. Without a refresh
205
+ // suffix there is no such line. When present it sits right after the first
206
+ // section, so we can find it by matching the suffix.
207
+ let refreshRow = null;
208
+ if (refresh) {
209
+ const lines = text.split("\n");
210
+ const idx = lines.findIndex((l) => l.includes(refresh));
211
+ refreshRow = idx >= 0 ? idx : null;
212
+ }
213
+ return { text, refreshRow };
214
+ }
215
+ /**
216
+ * Full redraw of one watch frame: clear screen, then the card (with the
217
+ * refresh countdown on the separator row after the first section).
218
+ */
219
+ function renderFrame(text) {
220
+ return `${ANSI.clearScreen}${text}`;
221
+ }
222
+ /**
223
+ * Run the watch loop until the process is interrupted. Each tick clears both
224
+ * caches (so the displayed values are fresh, not stale cache hits), queries,
225
+ * and redraws. Between ticks a per-second countdown rewrites only the footer
226
+ * line so the card body doesn't flicker. The combined query never throws —
227
+ * each provider degrades internally — so this loop is robust.
228
+ */
229
+ async function runWatch(intervalMs, provider, detail, color) {
230
+ const intervalSec = Math.round(intervalMs / 1000);
231
+ const controller = new AbortController();
232
+ const restore = () => {
233
+ process.stdout.write(ANSI.showCursor);
234
+ process.stdout.write("\n");
235
+ };
236
+ // Ctrl-C: stop the loop, restore the cursor, exit cleanly.
237
+ const onInt = () => {
238
+ controller.abort();
239
+ restore();
240
+ process.exit(0);
241
+ };
242
+ process.on("SIGINT", onInt);
243
+ process.stdout.write(ANSI.hideCursor);
244
+ try {
245
+ while (!controller.signal.aborted) {
246
+ clearAllCaches(); // bypass caches — always show live values
247
+ const combined = await queryCombined(provider);
248
+ // Full redraw with the countdown starting at the interval max.
249
+ const first = renderCard(combined, provider, detail, color, refreshSuffix(intervalSec));
250
+ process.stdout.write(renderFrame(first.text));
251
+ // Per-second countdown: rewrite only the refresh row (the separator line
252
+ // after the first section), leaving the card body untouched. Its row is
253
+ // fixed for the lifetime of this `combined` result, so we re-render the
254
+ // card with the new countdown purely to extract the refreshed line text,
255
+ // then blast it to that row via cursor-position + clear-line.
256
+ for (let remaining = intervalSec - 1; remaining > 0; remaining--) {
257
+ await sleep(1000, controller.signal).catch(() => undefined);
258
+ if (controller.signal.aborted)
259
+ break;
260
+ const next = renderCard(combined, provider, detail, color, refreshSuffix(remaining));
261
+ if (first.refreshRow !== null && next.refreshRow !== null) {
262
+ const row = first.refreshRow + 1; // ANSI rows are 1-based
263
+ const line = next.text.split("\n")[next.refreshRow] ?? "";
264
+ // Move to (row, col 1), clear the line, write the refreshed countdown.
265
+ process.stdout.write(`\x1B[${row};1H${ANSI.clearLine}${line}`);
266
+ }
267
+ }
268
+ }
269
+ }
270
+ finally {
271
+ restore();
272
+ process.off("SIGINT", onInt);
273
+ }
274
+ }
275
+ /**
276
+ * Print the card once and exit. A fully-unavailable result (no provider could
277
+ * produce data) → stderr + exit 1, so scripts can detect failure. A partial
278
+ * result (at least one provider succeeded or is merely not_configured) goes
279
+ * to stdout with exit 0.
280
+ */
281
+ async function runOnce(provider, detail, color) {
282
+ const combined = await queryCombined(provider);
283
+ const out = renderCard(combined, provider, detail, color).text;
284
+ // Failure = every selected provider ended up unavailable (not merely
285
+ // not_configured, which is a deliberate "skip me" state).
286
+ const glmFailed = combined.glm.kind === "unavailable";
287
+ const goFailed = combined.go.kind === "unavailable";
288
+ const glmSelected = provider === "all" || provider === "glm";
289
+ const goSelected = provider === "all" || provider === "go";
290
+ const selectedFailed = (glmSelected && glmFailed && (!goSelected || goFailed)) ||
291
+ (goSelected && goFailed && (!glmSelected || glmFailed));
292
+ if (selectedFailed) {
293
+ process.stderr.write(out + "\n");
294
+ process.exit(1);
295
+ }
296
+ process.stdout.write(out + "\n");
297
+ }
298
+ async function main() {
299
+ const opts = parseArgs(process.argv.slice(2));
300
+ if (opts.help) {
301
+ process.stdout.write(HELP_TEXT + "\n");
302
+ return;
303
+ }
304
+ if (opts.intervalClamped) {
305
+ process.stderr.write(`zcode-quota: interval below 10s raised to 10s (cache TTL is 10s)\n`);
306
+ }
307
+ // Color is on by default on a real terminal; turn it off when piped/
308
+ // redirected (isTTY is only `true` on a real TTY — Node leaves it
309
+ // `undefined` for pipes/files) or when the user asks for --plain. This
310
+ // matches the common CLI convention (ls, git, grep) and keeps raw escape
311
+ // codes out of captured output.
312
+ const color = process.stdout.isTTY === true && !opts.plain;
313
+ if (opts.watch) {
314
+ await runWatch(opts.intervalMs, opts.provider, opts.detail, color);
315
+ }
316
+ else {
317
+ await runOnce(opts.provider, opts.detail, color);
318
+ }
319
+ }
320
+ // Only auto-run when invoked directly (not when imported by tests). In an ESM
321
+ // build there is no `require.main`, so fall back to a heuristic: if argv[1]
322
+ // (the executed script) ends with this file's path, we are the entry point.
323
+ const invokedDirectly = (() => {
324
+ const entry = process.argv[1] ?? "";
325
+ return entry.endsWith("bin/quota.js") || entry.endsWith("bin/quota.ts");
326
+ })();
327
+ if (invokedDirectly) {
328
+ main().catch((err) => {
329
+ process.stderr.write(`zcode-quota: ${err instanceof Error ? err.message : String(err)}\n`);
330
+ process.exit(1);
331
+ });
332
+ }
333
+ //# sourceMappingURL=quota.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.js","sourceRoot":"","sources":["../../src/bin/quota.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Auto-compact: when the session's context-window usage exceeds a threshold,
3
+ * automatically invoke `session/compact` so the next prompt has room.
4
+ *
5
+ * Configured via `ZCODE_ACP_AUTO_COMPACT_THRESHOLD` (absolute token count;
6
+ * 0/unset = disabled). The compaction target is decided by the zcode backend
7
+ * — we only control *when* to trigger.
8
+ *
9
+ * Triggered from `prompt()` after a successful `end_turn`, before the response
10
+ * returns. Failures are best-effort (logged, never thrown) so they never break
11
+ * the prompt response.
12
+ */
13
+ import type * as acp from "@agentclientprotocol/sdk";
14
+ import type { ZcodeAcpServer } from "../server.js";
15
+ /** ENV: `ZCODE_ACP_AUTO_COMPACT_THRESHOLD` — absolute token count (0 = disabled). */
16
+ export declare function autoCompactThreshold(): number;
17
+ /**
18
+ * If the threshold is configured and the session's current context usage meets
19
+ * or exceeds it, invoke `compact()`. No-op when the threshold is unset/zero,
20
+ * when usage is below the threshold, or on any error (best-effort).
21
+ */
22
+ export declare function maybeAutoCompact(server: ZcodeAcpServer, cx: acp.AgentContext, acpSid: string, zcodeSid: string): Promise<void>;
23
+ //# sourceMappingURL=auto-compact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-compact.d.ts","sourceRoot":"","sources":["../../src/config/auto-compact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,KAAK,GAAG,MAAM,0BAA0B,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAInD,qFAAqF;AACrF,wBAAgB,oBAAoB,IAAI,MAAM,CAG7C;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,cAAc,EACtB,EAAE,EAAE,GAAG,CAAC,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA2Df"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Auto-compact: when the session's context-window usage exceeds a threshold,
3
+ * automatically invoke `session/compact` so the next prompt has room.
4
+ *
5
+ * Configured via `ZCODE_ACP_AUTO_COMPACT_THRESHOLD` (absolute token count;
6
+ * 0/unset = disabled). The compaction target is decided by the zcode backend
7
+ * — we only control *when* to trigger.
8
+ *
9
+ * Triggered from `prompt()` after a successful `end_turn`, before the response
10
+ * returns. Failures are best-effort (logged, never thrown) so they never break
11
+ * the prompt response.
12
+ */
13
+ import { randomUUID } from "node:crypto";
14
+ import { compact } from "../handlers/extensions.js";
15
+ import { log, warn } from "../utils.js";
16
+ import { sendTextChunk } from "../handlers/io.js";
17
+ /** ENV: `ZCODE_ACP_AUTO_COMPACT_THRESHOLD` — absolute token count (0 = disabled). */
18
+ export function autoCompactThreshold() {
19
+ const raw = Number(process.env.ZCODE_ACP_AUTO_COMPACT_THRESHOLD ?? "0");
20
+ return Number.isFinite(raw) && raw > 0 ? raw : 0;
21
+ }
22
+ /**
23
+ * If the threshold is configured and the session's current context usage meets
24
+ * or exceeds it, invoke `compact()`. No-op when the threshold is unset/zero,
25
+ * when usage is below the threshold, or on any error (best-effort).
26
+ */
27
+ export async function maybeAutoCompact(server, cx, acpSid, zcodeSid) {
28
+ const threshold = autoCompactThreshold();
29
+ if (threshold <= 0)
30
+ return; // disabled
31
+ const msgId = randomUUID();
32
+ try {
33
+ // Read current context usage via session/read.
34
+ let used = 0;
35
+ try {
36
+ const backend = server.ensureBackend();
37
+ const resp = await backend.request(server.nextId(), "session/read", { sessionId: zcodeSid }, 5000);
38
+ if (resp.error)
39
+ return;
40
+ const result = (resp.result ?? {});
41
+ used = result.projection?.contextUsed ?? 0;
42
+ }
43
+ catch (e) {
44
+ warn(`auto-compact: session/read failed (${e instanceof Error ? e.message : String(e)})`);
45
+ return;
46
+ }
47
+ if (used < threshold)
48
+ return;
49
+ log(`auto-compact: contextUsed=${used} >= threshold=${threshold}, compacting…`);
50
+ await sendTextChunk(cx, acpSid, `🔄 auto-compact: context usage ${used.toLocaleString()} ≥ threshold ${threshold.toLocaleString()}, compressing…`, msgId);
51
+ // compact() handles: session/compact → waitForTurnIdle → emitInitialUsage.
52
+ const result = (await compact(server, { sessionId: acpSid }, cx));
53
+ if (result.__lockTimeout) {
54
+ await sendTextChunk(cx, acpSid, "⚠ auto-compact timed out (300s) — backend may still be processing", msgId);
55
+ }
56
+ else {
57
+ await sendTextChunk(cx, acpSid, "✓ auto-compact: context compressed", msgId);
58
+ }
59
+ log("auto-compact: done");
60
+ }
61
+ catch (e) {
62
+ warn(`auto-compact: compact failed (${e instanceof Error ? e.message : String(e)})`);
63
+ await sendTextChunk(cx, acpSid, `⚠ auto-compact failed: ${e instanceof Error ? e.message : String(e)}`, msgId);
64
+ // Best-effort: never break the prompt response.
65
+ }
66
+ }
67
+ //# sourceMappingURL=auto-compact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-compact.js","sourceRoot":"","sources":["../../src/config/auto-compact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * MCP server discovery — reads MCP server configurations from the same sources
3
+ * ZCode uses, so `/mcp` can show users exactly which servers are available.
4
+ *
5
+ * Sources:
6
+ * 1. ~/.zcode/cli/config.json → mcp.servers (user-configured)
7
+ * 2. Enabled plugin .mcp.json files (two formats: flat and nested)
8
+ *
9
+ * The ZCode backend loads these automatically and exposes their tools to the
10
+ * model. This module is purely informational — it lists what's configured so
11
+ * users know what's available without needing the TUI.
12
+ */
13
+ /** Information about a discovered MCP server. */
14
+ export interface McpServerInfo {
15
+ name: string;
16
+ type: string;
17
+ command?: string;
18
+ args?: string[];
19
+ url?: string;
20
+ source: string;
21
+ }
22
+ /**
23
+ * Discover all MCP servers from config.json and enabled plugins.
24
+ *
25
+ * Best-effort: failures are logged and swallowed.
26
+ */
27
+ export declare function loadMcpServers(): McpServerInfo[];
28
+ /**
29
+ * Format MCP servers into a human-readable card for the `/mcp` command.
30
+ *
31
+ * Groups by source (config vs plugins) and aligns columns for readability.
32
+ */
33
+ export declare function formatMcpServers(servers: McpServerInfo[]): string;
34
+ //# sourceMappingURL=mcp-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-discovery.d.ts","sourceRoot":"","sources":["../../src/config/mcp-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,iDAAiD;AACjD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAsBD;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,aAAa,EAAE,CAmFhD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,MAAM,CA2BjE"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * MCP server discovery — reads MCP server configurations from the same sources
3
+ * ZCode uses, so `/mcp` can show users exactly which servers are available.
4
+ *
5
+ * Sources:
6
+ * 1. ~/.zcode/cli/config.json → mcp.servers (user-configured)
7
+ * 2. Enabled plugin .mcp.json files (two formats: flat and nested)
8
+ *
9
+ * The ZCode backend loads these automatically and exposes their tools to the
10
+ * model. This module is purely informational — it lists what's configured so
11
+ * users know what's available without needing the TUI.
12
+ */
13
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
14
+ import { homedir } from "node:os";
15
+ import path from "node:path";
16
+ import { compareVersions, log } from "../utils.js";
17
+ const HOME = homedir();
18
+ const CLI_CONFIG_PATH = path.join(HOME, ".zcode", "cli", "config.json");
19
+ const PLUGIN_CACHE_DIR = path.join(HOME, ".zcode", "cli", "plugins", "cache");
20
+ /**
21
+ * Discover all MCP servers from config.json and enabled plugins.
22
+ *
23
+ * Best-effort: failures are logged and swallowed.
24
+ */
25
+ export function loadMcpServers() {
26
+ const results = [];
27
+ let config = null;
28
+ try {
29
+ if (existsSync(CLI_CONFIG_PATH)) {
30
+ config = JSON.parse(readFileSync(CLI_CONFIG_PATH, "utf8"));
31
+ }
32
+ }
33
+ catch (e) {
34
+ log(`mcp-discovery: config read failed (${e instanceof Error ? e.message : String(e)})`);
35
+ return results;
36
+ }
37
+ // 1. User-configured servers from config.json.
38
+ const servers = config?.mcp?.servers ?? {};
39
+ for (const [name, cfg] of Object.entries(servers)) {
40
+ results.push({
41
+ name,
42
+ type: cfg.type ?? "stdio",
43
+ command: cfg.command,
44
+ args: cfg.args,
45
+ url: cfg.url,
46
+ source: "config",
47
+ });
48
+ }
49
+ // 2. Plugin-provided servers from .mcp.json files.
50
+ const enabledPlugins = config?.plugins?.enabledPlugins ?? {};
51
+ for (const [pluginKey, enabledFlag] of Object.entries(enabledPlugins)) {
52
+ if (!enabledFlag)
53
+ continue;
54
+ const atIdx = pluginKey.indexOf("@");
55
+ if (atIdx <= 0)
56
+ continue;
57
+ const pluginName = pluginKey.slice(0, atIdx);
58
+ const marketplace = pluginKey.slice(atIdx + 1);
59
+ const pluginDir = path.join(PLUGIN_CACHE_DIR, marketplace, pluginName);
60
+ if (!existsSync(pluginDir))
61
+ continue;
62
+ // Find the latest version directory.
63
+ let latestVersion = "";
64
+ try {
65
+ for (const entry of readdirSync(pluginDir)) {
66
+ const vDir = path.join(pluginDir, entry);
67
+ if (statSync(vDir).isDirectory() && compareVersions(entry, latestVersion) > 0) {
68
+ latestVersion = entry;
69
+ }
70
+ }
71
+ }
72
+ catch {
73
+ continue;
74
+ }
75
+ if (!latestVersion)
76
+ continue;
77
+ const mcpFile = path.join(pluginDir, latestVersion, ".mcp.json");
78
+ if (!existsSync(mcpFile))
79
+ continue;
80
+ try {
81
+ const mcpConfig = JSON.parse(readFileSync(mcpFile, "utf8"));
82
+ // Two formats:
83
+ // Flat: { "server-name": { "command": "..." } }
84
+ // Nested: { "mcpServers": { "server-name": { ... } } }
85
+ const serverMap = mcpConfig["mcpServers"] ?? mcpConfig;
86
+ for (const [name, cfg] of Object.entries(serverMap)) {
87
+ results.push({
88
+ name,
89
+ type: cfg.type ?? "stdio",
90
+ command: cfg.command,
91
+ args: cfg.args,
92
+ url: cfg.url,
93
+ source: `plugin: ${pluginName}`,
94
+ });
95
+ }
96
+ }
97
+ catch (e) {
98
+ log(`mcp-discovery: failed to read ${mcpFile} (${e instanceof Error ? e.message : String(e)})`);
99
+ }
100
+ }
101
+ log(`mcp-discovery: found ${results.length} MCP server(s)`);
102
+ return results;
103
+ }
104
+ /**
105
+ * Format MCP servers into a human-readable card for the `/mcp` command.
106
+ *
107
+ * Groups by source (config vs plugins) and aligns columns for readability.
108
+ */
109
+ export function formatMcpServers(servers) {
110
+ if (servers.length === 0) {
111
+ return "📡 No MCP servers configured.\nUse the ZCode desktop app to add MCP servers.";
112
+ }
113
+ const configServers = servers.filter((s) => s.source === "config");
114
+ const pluginServers = servers.filter((s) => s.source !== "config");
115
+ const lines = [`📡 MCP Servers (${servers.length})`];
116
+ if (configServers.length > 0) {
117
+ lines.push("", "From config.json:");
118
+ for (const s of configServers) {
119
+ lines.push(` ${pad(s.name, 16)} ${pad(s.type, 6)} ${formatEndpoint(s)}`);
120
+ }
121
+ }
122
+ if (pluginServers.length > 0) {
123
+ lines.push("", "From plugins:");
124
+ for (const s of pluginServers) {
125
+ const pluginLabel = `[${s.source.replace("plugin: ", "")}]`;
126
+ lines.push(` ${pad(s.name, 16)} ${pad(s.type, 6)} ${formatEndpoint(s)} ${pluginLabel}`);
127
+ }
128
+ }
129
+ lines.push("", "MCP tools are auto-invoked by the model when needed.");
130
+ return lines.join("\n");
131
+ }
132
+ /** Format the endpoint/command string for display. */
133
+ function formatEndpoint(s) {
134
+ if (s.url) {
135
+ try {
136
+ const u = new URL(s.url);
137
+ return u.host + u.pathname;
138
+ }
139
+ catch {
140
+ return s.url;
141
+ }
142
+ }
143
+ if (s.command) {
144
+ const args = s.args?.length ? " " + s.args.join(" ") : "";
145
+ return s.command + args;
146
+ }
147
+ return "?";
148
+ }
149
+ /** Pad a string to the given width for column alignment. */
150
+ function pad(s, width) {
151
+ return s.length >= width ? s : s + " ".repeat(width - s.length);
152
+ }
153
+ //# sourceMappingURL=mcp-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-discovery.js","sourceRoot":"","sources":["../../src/config/mcp-discovery.ts"],"names":[],"mappings":"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"}