opencode-qoder-bridge 0.1.8 → 0.1.9

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 (70) hide show
  1. package/CHANGELOG.md +57 -1
  2. package/README.md +110 -37
  3. package/bin/statusline.mjs +30 -6
  4. package/bin/usage.mjs +6 -5
  5. package/dist/async-utils.d.ts +8 -0
  6. package/dist/async-utils.d.ts.map +1 -0
  7. package/dist/async-utils.js +27 -0
  8. package/dist/async-utils.js.map +1 -0
  9. package/dist/auth.d.ts +2 -1
  10. package/dist/auth.d.ts.map +1 -1
  11. package/dist/auth.js +26 -7
  12. package/dist/auth.js.map +1 -1
  13. package/dist/cost.d.ts +2 -1
  14. package/dist/cost.d.ts.map +1 -1
  15. package/dist/cost.js +163 -63
  16. package/dist/cost.js.map +1 -1
  17. package/dist/errors.d.ts.map +1 -1
  18. package/dist/errors.js +5 -2
  19. package/dist/errors.js.map +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +152 -37
  23. package/dist/index.js.map +1 -1
  24. package/dist/language-model.d.ts +22 -0
  25. package/dist/language-model.d.ts.map +1 -1
  26. package/dist/language-model.js +931 -183
  27. package/dist/language-model.js.map +1 -1
  28. package/dist/logger.d.ts +1 -0
  29. package/dist/logger.d.ts.map +1 -1
  30. package/dist/logger.js +35 -5
  31. package/dist/logger.js.map +1 -1
  32. package/dist/mcp-bridge.d.ts.map +1 -1
  33. package/dist/mcp-bridge.js +71 -7
  34. package/dist/mcp-bridge.js.map +1 -1
  35. package/dist/models.d.ts +8 -1
  36. package/dist/models.d.ts.map +1 -1
  37. package/dist/models.js +155 -44
  38. package/dist/models.js.map +1 -1
  39. package/dist/prompt-builder.d.ts.map +1 -1
  40. package/dist/prompt-builder.js +241 -43
  41. package/dist/prompt-builder.js.map +1 -1
  42. package/dist/sdk-auth.d.ts +3 -3
  43. package/dist/sdk-auth.d.ts.map +1 -1
  44. package/dist/sdk-auth.js +13 -9
  45. package/dist/sdk-auth.js.map +1 -1
  46. package/dist/sdk-session.d.ts.map +1 -1
  47. package/dist/sdk-session.js +26 -2
  48. package/dist/sdk-session.js.map +1 -1
  49. package/dist/session-store.d.ts +14 -3
  50. package/dist/session-store.d.ts.map +1 -1
  51. package/dist/session-store.js +451 -46
  52. package/dist/session-store.js.map +1 -1
  53. package/dist/state-dir.d.ts.map +1 -1
  54. package/dist/state-dir.js +2 -1
  55. package/dist/state-dir.js.map +1 -1
  56. package/dist/tool-normalizer.d.ts.map +1 -1
  57. package/dist/tool-normalizer.js +11 -2
  58. package/dist/tool-normalizer.js.map +1 -1
  59. package/dist/tui-register.d.ts.map +1 -1
  60. package/dist/tui-register.js +88 -37
  61. package/dist/tui-register.js.map +1 -1
  62. package/dist/tui.d.ts.map +1 -1
  63. package/dist/tui.js +42 -17
  64. package/dist/tui.js.map +1 -1
  65. package/dist/types.d.ts +14 -4
  66. package/dist/types.d.ts.map +1 -1
  67. package/dist/usage.d.ts.map +1 -1
  68. package/dist/usage.js +54 -29
  69. package/dist/usage.js.map +1 -1
  70. package/package.json +12 -4
package/CHANGELOG.md CHANGED
@@ -4,6 +4,59 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases use
5
5
  [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.1.9] - 2026-08-30
8
+
9
+ ### Added
10
+
11
+ - Updated `@qoder-ai/qoder-agent-sdk` to `1.0.30` (paired with `qodercli` 1.1.35).
12
+ - **Plan Mode Integration**: Added `planMode?: boolean` provider option to run in planning mode independently from tool permissions. Registered new `/qoder_plan_mode` tool.
13
+ - **Outbound Proxy Routing**: Added `proxy?: string` provider option for direct qodercli HTTP/HTTPS/SOCKS5 proxy routing without mutating environment variables, with automatic fallback to `HTTPS_PROXY` / `HTTP_PROXY`.
14
+ - **Skill Evolution**: Added `evolution?: EvolutionOptions` provider option to enable autonomous turn-completion skill analysis and recommendations.
15
+ - **Dynamic Live Model Catalog Updates**: Ingests real-time `available_models_update` stream events to synchronize model availability and persistent cache without restarting OpenCode.
16
+ - **Artifacts Tracking**: Ingests `artifacts_update` events during chat turns and surfaces artifact change metadata in `providerMetadata.qoder.artifacts`.
17
+ - **Sessions Tool**: Added `qoder_sessions` tool using SDK's `listSessions()` to inspect recent sessions, titles, and git branches.
18
+
19
+ ### Fixed
20
+
21
+ - **Runtime Package Boundary**: Moved the runtime-used `@opencode-ai/plugin`
22
+ helper into production dependencies and verified root/provider imports from a
23
+ dev-omitted packed install.
24
+ - **Workspace-Aware Session Safety**: Scoped persisted session mappings by
25
+ workspace, serialized same-key turns, delayed mapping writes until a
26
+ successful turn, and added bounded cross-process state locking.
27
+ - **Catalog, Usage, and Stream Hardening**: Made live model snapshots
28
+ authoritative, bounded discovery/usage requests, closed abort and duplicate
29
+ event races, sanitized malformed SDK usage/metadata, and surfaced typed
30
+ authentication/result failures.
31
+ - **Persistent State and Input Bounds**: Hardened atomic state/config writes,
32
+ model/session cache validation, prompt/image limits, MCP URL/command input,
33
+ and finite cost/statusline accounting.
34
+ - **Unknown Model Transparency**: Unknown requested model IDs are now forwarded
35
+ unchanged to Qoder while the default catalog entry is used only for prompt
36
+ sizing metadata; the bridge no longer silently selects `auto`.
37
+ - **Ephemeral Session Privacy**: Explicitly disables SDK transcript persistence
38
+ for non-persistent turns and auxiliary usage/model discovery queries.
39
+ - **Stream and Boundary Hardening**: Added bounded turn timeouts, abort-aware
40
+ generation failures, bounded query cleanup, malformed-stream rejection,
41
+ replay UUID guards, tool ownership deny rules, diagnostic redaction, and
42
+ stricter MCP URL/command validation.
43
+ - **Release Artifact Safety**: Added a `prepack` rebuild hook, executable usage
44
+ CLI permissions, and a public `./errors` export for the typed error API.
45
+ - **Session Store Concurrency Race Condition**: Added an async mutex queue (`withLock`) to serialize concurrent `ensureQoderSession` and `deleteQoderSession` operations, preventing dropped session records under parallel turns.
46
+ - **Tool Continuation History Trimming**: Fixed a critical bug in `trimToBudget` where the active user prompt was dropped during continuation turns with large assistant/tool outputs, preventing prompts from falling back to `"Hello"`.
47
+ - **Data URL Parsing Hardening**: Added bounded-length and round-trip base64 validation with early rejection of oversized image attachments, preventing avoidable CPU and memory pressure from malformed multi-megabyte inputs.
48
+ - **Stream Controller Abort Safety & Listener Cleanup**: Added `safeEnqueue` and `safeClose` to prevent uncaught `Invalid state: Controller is already closed` exceptions when streams are aborted or cancelled, and cleaned up `abortSignal` event listeners in `language-model.ts` and `sdk-session.ts` to prevent memory leaks on shared signals.
49
+ - **`doGenerate` Provider Metadata**: Fixed `doGenerate` discarding `providerMetadata` (`totalCostUSD`, `contextUsageRatio`, `planMode`, `artifacts`), ensuring parity with `doStream`.
50
+ - **Coalesced Model Cache Writes**: Implemented a coalesced cache write queue in `models.ts` to prevent simultaneous file write contention and eliminate orphaned `.tmp` files under rapid streaming catalog updates.
51
+ - **Atomic File Cleanup & All-Session Reset**: Added `try...finally` temporary file unlinking in `session-store.ts` and `models.ts` to guarantee zero dangling `.tmp` files, and exported `clearAllSessions()` to support full session resets.
52
+ - **Tool Schema & Error Boundaries**: Upgraded plugin tools with `tool()` and `tool.schema` from `@opencode-ai/plugin`, added `key` (and `"all"`) to `qoder_session_reset`, added `dir` and `limit` filtering to `qoder_sessions`, and wrapped tool executions in error boundaries.
53
+ - **Tool Normalization & Path Aliases**: Added `execute_command`, `executecommand`, `run_command`, and `runcommand` mapping to `bash`, added `cmd` alias for command, and added `path` alias for `filePath` across read, write, edit, delete, view, and apply_diff.
54
+ - **MCP Bridge Argument Flexibility**: Converted numeric and boolean arguments in `mcp-bridge` stdio configs without dropping the argument list.
55
+ - **Prompt Serialization Hardening**: Added non-image file attachment serialization in `prompt-builder` so attached text files are preserved, and safely guarded missing `toolCallId` / `toolName`.
56
+ - **TUI & CLI Hardening**: Guarded `latest.model?.providerID` in `tui.ts` against undefined model objects, guarded against non-finite costs (`NaN`) in sidebar and statusline, and trimmed PAT whitespace in `hasQoderPAT()`.
57
+ - **Stress Test Suite**: Added `test/stress.test.mjs` verifying concurrency, massive conversations (1,000 messages), stream aborts, and prototype pollution protection.
58
+ - **CI-Safe Live Stress Coverage**: Made the Qoder-backed stream-abort stress probe opt-in with `QODER_STRESS_E2E=1`, keeping the normal test suite credential-free while preserving live stress coverage when explicitly enabled.
59
+
7
60
  ## [0.1.8] - 2026-08-26
8
61
 
9
62
  ### Fixed
@@ -78,7 +131,9 @@ All notable changes to this project are documented here. The format follows
78
131
  session.
79
132
  - The `models.json` cache is written atomically with mode 0600 instead of a
80
133
  direct partial-write-prone write.
81
- - Unknown model IDs fall back to the default model with a debug log entry.
134
+ - Unknown model IDs previously fell back to the default model with a debug log
135
+ entry; current releases preserve the requested ID and let Qoder report model
136
+ availability explicitly.
82
137
 
83
138
  ## [0.1.3] - 2026-08-20
84
139
 
@@ -155,3 +210,4 @@ also verified with an in-process MCP transport.
155
210
  [0.1.4]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.3...v0.1.4
156
211
  [0.1.5]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.4...v0.1.5
157
212
  [0.1.8]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.7...v0.1.8
213
+ [0.1.9]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.8...v0.1.9
package/README.md CHANGED
@@ -119,37 +119,23 @@ The ledger accumulates across sessions. Delete `~/.config/opencode-qoder-bridge/
119
119
 
120
120
  The bridge discovers the available catalog at startup through the SDK's
121
121
  `getAvailableModels()` API. Availability is account-, region-, rollout-, and
122
- SDK-version-dependent. A live query on **2026-08-20** returned:
123
-
124
- | Model ID | Name | Credit multiplier | Vision | Reasoning | Max input | Max output |
125
- |----------|------|-------------------|--------|-----------|-----------|------------|
126
-
127
- The following are known or historical model IDs. Some may be obsolete or
128
- unavailable for a particular account and are not an availability guarantee:
129
-
130
- | Model ID | Name | Credit multiplier | Vision | Reasoning | Max input | Max output |
131
- |----------|------|-------------------|--------|-----------|-----------|------------|
132
- | `auto` | Auto | 1.00x | ✓ | ✗ | 180K | 32K |
133
- | `ultimate` | Ultimate | 0.80x | ✓ | ✓ | 1M | 32K |
134
- | `performance` | Performance | 1.10x | ✓ | ✗ | 1M | 32K |
135
- | `efficient` | Efficient | 0.30x | ✓ | ✗ | 180K | 32K |
136
- | `lite` | Lite | 0.00x | ✗ | ✗ | 180K | 32K |
137
- | `cmodel` | Cantus | 1.60x | ✓ | ✓ | 180K | 32K |
138
- | `qmodel_preview` | Qwen3.8-Max-Preview | 0.01x promo | ✓ | ✓ | 180K | 32K |
139
- | `qmodel_38max` | Qwen3.8-Max | 0.25x | ✓ | ✓ | 180K | 32K |
140
- | `qmodel_latest` | Qwen3.7-Max | 0.10x promo | ✓ | ✗ | 1M | 32K |
141
- | `qmodel` | Qwen3.7-Plus | 0.04x promo | ✓ | ✗ | 1M | 32K |
142
- | `kmodel_latest` | Kimi-K3 | 0.80x | ✓ | ✗ | 180K | 32K |
143
- | `kmodel` | Kimi-K2.7-Code | 0.30x | ✓ | ✗ | 256K | 32K |
144
- | `gm51model` | GLM-5.2 | 0.50x promo | ✓ | ✓ | 1M | 32K |
145
- | `dmodel` | DeepSeek-V4-Pro | 0.50x | ✓ | ✓ | 1M | 32K |
146
- | `dfmodel` | DeepSeek-V4-Flash | 0.10x | ✓ | ✓ | 1M | 32K |
147
- | `mmodel` | MiniMax-M3 | 0.20x | ✓ | ✗ | 1M | 32K |
148
-
149
- This table is a snapshot, not a hard-coded allowlist. Qoder can vary model
150
- availability by account, plan, CLI version, or staged rollout. Promotional
151
- multipliers are time-dependent; the SDK's current `priceFactor` is
152
- authoritative. Restart OpenCode to refresh the bridge's in-process model cache.
122
+ SDK-version-dependent. A permanent allowlist is intentionally not embedded
123
+ here because the catalog is account- and scene-dependent.
124
+
125
+ The following is the current model snapshot returned by `qodercli --list-models`
126
+ on 2026-08-30:
127
+
128
+ | Model |
129
+ |-------|
130
+ | `Qwen3.8-Max` |
131
+ | `Qwen3.8-Flash` |
132
+ | `Qwen3.7-Max` |
133
+ | `Qwen3.7-Plus` |
134
+
135
+ This is an account-, region-, plan-, CLI-version-, and rollout-dependent
136
+ snapshot. The CLI command reports display names only; the bridge's SDK catalog
137
+ is authoritative for model IDs, capabilities, context limits, and pricing.
138
+ Run `qodercli --list-models` and restart OpenCode to refresh the local view.
153
139
 
154
140
  Run `opencode models qoder` to inspect the models currently registered with
155
141
  OpenCode. The `qoder_models` tool also exposes capabilities, context limits,
@@ -172,7 +158,13 @@ Bridge opencode MCP servers into the SDK by passing provider options:
172
158
  }
173
159
  ```
174
160
 
161
+ Flag names may be written with or without the leading `--`.
162
+
175
163
  `config.mcp` servers are bridged into the SDK's `mcpServers` automatically.
164
+ Chat turns have a 30-minute bridge timeout by default; set `options.timeoutMs`
165
+ to a positive value to use a shorter or longer bounded timeout (up to 24 hours).
166
+ Values in `options.env` override inherited process variables rather than
167
+ replacing the complete child environment.
176
168
 
177
169
  ### Persistent sessions and permissions
178
170
 
@@ -194,9 +186,15 @@ Session persistence is opt-in. Give a provider configuration a stable
194
186
 
195
187
  Mappings are stored in
196
188
  `~/.config/opencode-qoder-bridge/sessions.json` with restrictive file
197
- permissions. Use the `qoder_session_reset` tool to forget the mapping. A new
198
- session is created automatically if the mapping does not exist; existing
199
- sessions are resumed through the Qoder SDK.
189
+ permissions and are scoped to the configured working directory. The plugin
190
+ uses OpenCode's project directory when available; set `options.cwd` when
191
+ loading the provider directly. Use the `qoder_session_reset` tool to forget
192
+ the mapping. A new session is created automatically if the mapping does not
193
+ exist; existing sessions are resumed through the Qoder SDK.
194
+
195
+ Qoder-native and bridged MCP tools remain provider-owned. If OpenCode supplies
196
+ a function with a colliding native name, the bridge derives a Qoder deny rule
197
+ to avoid executing the same operation in both runtimes.
200
198
 
201
199
  The bridge uses the SDK's safer permission policy by default. To explicitly
202
200
  allow all Qoder tools in a trusted local environment, configure for example:
@@ -218,6 +216,80 @@ Available permission modes are `default`, `acceptEdits`, and
218
216
  `bypassPermissions`. Only explicitly configure `bypassPermissions` when the
219
217
  host environment is trusted.
220
218
 
219
+ Image inputs may reference `file://`, `~/`, or absolute local paths. Only pass
220
+ paths from trusted callers: the bridge bounds image size but does not sandbox
221
+ or restrict readable local files to the project directory. A current turn is
222
+ limited to 64 images and 40 MiB of decoded image data; excess attachments are
223
+ reported as omitted text.
224
+
225
+ ### Plan Mode
226
+
227
+ Plan Mode instructs Qoder to analyze and plan changes without modifying files
228
+ or running action tools. It operates independently from tool permissions,
229
+ preserving your configured `permissionMode`:
230
+
231
+ ```json
232
+ {
233
+ "provider": {
234
+ "qoder": {
235
+ "options": {
236
+ "planMode": true
237
+ }
238
+ }
239
+ }
240
+ }
241
+ ```
242
+
243
+ Run `/qoder_plan_mode` in OpenCode for quick guidance.
244
+
245
+ ### Proxy & Network Routing
246
+
247
+ Pass an outbound proxy URL directly to the Qoder runtime without mutating host
248
+ environment variables (supports `http://`, `https://`, `socks5://`, and `socks://`):
249
+
250
+ ```json
251
+ {
252
+ "provider": {
253
+ "qoder": {
254
+ "options": {
255
+ "proxy": "http://127.0.0.1:8888"
256
+ }
257
+ }
258
+ }
259
+ }
260
+ ```
261
+
262
+ If `proxy` is omitted, the bridge automatically falls back to `HTTPS_PROXY` or
263
+ `HTTP_PROXY` from your environment.
264
+
265
+ ### Skill Evolution
266
+
267
+ Enable autonomous turn-completion skill analysis and recommendations:
268
+
269
+ ```json
270
+ {
271
+ "provider": {
272
+ "qoder": {
273
+ "options": {
274
+ "evolution": {
275
+ "skill": { "mode": "native" }
276
+ }
277
+ }
278
+ }
279
+ }
280
+ }
281
+ ```
282
+
283
+ ### Available Tools
284
+
285
+ The plugin registers several built-in OpenCode tools:
286
+
287
+ - `qoder_usage` — Live account balance, quota percentages, and local cost ledger totals.
288
+ - `qoder_models` — List known Qoder models, context limits, vision/reasoning flags, and multipliers.
289
+ - `qoder_sessions` — List recent Qoder sessions, session IDs, branches, and timestamps via SDK `listSessions()`.
290
+ - `qoder_session_reset` — Forget the persisted Qoder session mapping for the active project.
291
+ - `qoder_plan_mode` — View Plan Mode status and configuration guidance.
292
+
221
293
  ## Troubleshooting
222
294
 
223
295
  | Problem | Solution |
@@ -225,15 +297,16 @@ host environment is trusted.
225
297
  | Auth prompt at startup | Run `qoder login`, then restart opencode |
226
298
  | `qodercli not found` | Authenticate with `qoder login` or set `QODER_PERSONAL_ACCESS_TOKEN`; the SDK can use its bundled runtime, while an installed CLI is preferred when available |
227
299
  | Model not found | Verify the model ID matches the table above |
228
- | Missing models in the model list | Run `/qoder_models`; the bridge refreshes the live catalog at every startup and falls back to the last cached catalog plus the built-ins (`lite`, `auto`, `performance`) when offline. If your account serves models in a different Qoder scene, set `QODER_SCENE` before launching opencode (or via provider option `env`) |
300
+ | Missing models in the model list | Run `/qoder_models`; the bridge refreshes the live catalog at startup and falls back to the last cached catalog plus the built-ins (`lite`, `auto`, `performance`) when offline. If your account serves models in a different Qoder scene, set `QODER_SCENE` before launching opencode |
229
301
 
230
302
  ### How model discovery works
231
303
 
232
304
  At startup the bridge immediately exposes cached/built-in models, then
233
305
  refreshes the live catalog from Qoder (`fetchStrategy: "live"` — the CLI
234
306
  re-queries the server and falls back to its local cache if the server returns
235
- nothing). Discovered models override built-ins with the same ID; a failed
236
- refresh never removes previously known models.
307
+ nothing). Each successful catalog snapshot replaces previously discovered
308
+ dynamic IDs, so retired models do not remain selectable. A failed refresh
309
+ keeps the last known catalog and the built-ins.
237
310
 
238
311
  ## Development
239
312
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { readFileSync } from "node:fs";
2
+ import { lstatSync, readFileSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { join } from "node:path";
5
5
 
@@ -8,20 +8,41 @@ import { join } from "node:path";
8
8
  function resolveStateDir(env = process.env) {
9
9
  const override = env.QODER_BRIDGE_STATE_DIR?.trim();
10
10
  if (override) return join(override);
11
- const configHome = env.XDG_CONFIG_HOME?.trim();
11
+ const configHome = env.XDG_CONFIG_HOME?.trim()
12
+ || (process.platform === "win32" ? env.APPDATA?.trim() : undefined);
12
13
  return join(configHome || join(homedir(), ".config"), "opencode-qoder-bridge");
13
14
  }
14
15
 
15
16
  const STATE_FILE = join(resolveStateDir(), "usage.json");
17
+ const MAX_STATE_BYTES = 1_000_000;
16
18
 
17
19
  function fmt(usd) {
18
- return `$${(usd ?? 0).toFixed(4)}`;
20
+ const n = typeof usd === "number" && Number.isFinite(usd) ? usd : 0;
21
+ return `$${n.toFixed(4)}`;
22
+ }
23
+
24
+ function count(value) {
25
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
26
+ }
27
+
28
+ function add(left, right) {
29
+ const total = left + right;
30
+ return Number.isFinite(total) ? total : Number.MAX_SAFE_INTEGER;
19
31
  }
20
32
 
21
33
  function main() {
22
34
  let state = null;
23
35
  try {
36
+ const info = lstatSync(STATE_FILE);
37
+ if (!info.isFile() || info.isSymbolicLink() || info.size > MAX_STATE_BYTES) {
38
+ process.stdout.write("qoder: no usage yet");
39
+ return;
40
+ }
24
41
  state = JSON.parse(readFileSync(STATE_FILE, "utf8"));
42
+ if (!state || typeof state !== "object" || Array.isArray(state)) {
43
+ process.stdout.write("qoder: no usage yet");
44
+ return;
45
+ }
25
46
  } catch {
26
47
  process.stdout.write("qoder: no usage yet");
27
48
  return;
@@ -29,12 +50,15 @@ function main() {
29
50
 
30
51
  const parts = [
31
52
  `cost ${fmt(state.totalCostUsd)}`,
32
- `turns ${state.turnCount ?? 0}`,
33
- `tok ${(state.totalInputTokens ?? 0) + (state.totalOutputTokens ?? 0)}`,
53
+ `turns ${count(state.turnCount)}`,
54
+ `tok ${add(count(state.totalInputTokens), count(state.totalOutputTokens))}`,
34
55
  ];
35
56
 
36
57
  const last = Array.isArray(state.recent) ? state.recent.at(-1) : null;
37
- if (last?.model) parts.push(`last ${last.model}`);
58
+ if (typeof last?.model === "string" && last.model) {
59
+ const model = last.model.replace(/[\u0000-\u001f\u007f]/g, " ").slice(0, 256);
60
+ parts.push(`last ${model}`);
61
+ }
38
62
 
39
63
  process.stdout.write(`qoder: ${parts.join(" · ")}`);
40
64
  }
package/bin/usage.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { getLiveUsage, formatUsageReport } from "../dist/usage.js";
3
3
  import { summarize, formatCost } from "../dist/cost.js";
4
+ import { describeError } from "../dist/logger.js";
4
5
 
5
6
  async function main() {
6
7
  const lines = [];
@@ -14,11 +15,11 @@ async function main() {
14
15
  const summary = summarize();
15
16
  lines.push("");
16
17
  lines.push("Local Usage Ledger");
17
- lines.push(` Reference cost: ${formatCost(summary.totalCostUsd)}`);
18
- lines.push(` Turns: ${summary.turnCount}`);
19
- lines.push(` Tokens: ${summary.totalInputTokens} in / ${summary.totalOutputTokens} out`);
18
+ lines.push(` Reference cost: ${formatCost(summary?.totalCostUsd ?? 0)}`);
19
+ lines.push(` Turns: ${summary?.turnCount ?? 0}`);
20
+ lines.push(` Tokens: ${summary?.totalInputTokens ?? 0} in / ${summary?.totalOutputTokens ?? 0} out`);
20
21
 
21
- const models = Object.entries(summary.byModel);
22
+ const models = Object.entries(summary?.byModel ?? {});
22
23
  if (models.length > 0) {
23
24
  lines.push(" By model:");
24
25
  for (const [name, bucket] of models) {
@@ -30,6 +31,6 @@ async function main() {
30
31
  }
31
32
 
32
33
  main().catch((error) => {
33
- process.stderr.write(`Unable to read Qoder usage: ${error instanceof Error ? error.message : String(error)}\n`);
34
+ process.stderr.write(`Unable to read Qoder usage: ${describeError(error)}\n`);
34
35
  process.exitCode = 1;
35
36
  });
@@ -0,0 +1,8 @@
1
+ /** Race SDK operations against a host-side deadline. Aborting the SDK is
2
+ * still the caller's responsibility; this helper guarantees the bridge does
3
+ * not wait forever for a non-cooperative promise. */
4
+ export declare function withTimeout<T>(operation: PromiseLike<T>, timeoutMs: number, message: string): Promise<T>;
5
+ export declare function closeAsyncIterator(iterator: {
6
+ return?: (value?: void | PromiseLike<void>) => PromiseLike<unknown> | unknown;
7
+ }, timeoutMs: number): Promise<void>;
8
+ //# sourceMappingURL=async-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-utils.d.ts","sourceRoot":"","sources":["../src/async-utils.ts"],"names":[],"mappings":"AAAA;;qDAEqD;AACrD,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CASxG;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE;IAAE,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;CAAE,EAC3F,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAQf"}
@@ -0,0 +1,27 @@
1
+ /** Race SDK operations against a host-side deadline. Aborting the SDK is
2
+ * still the caller's responsibility; this helper guarantees the bridge does
3
+ * not wait forever for a non-cooperative promise. */
4
+ export function withTimeout(operation, timeoutMs, message) {
5
+ let timer;
6
+ const timeout = new Promise((_, reject) => {
7
+ timer = setTimeout(() => reject(new Error(message)), timeoutMs);
8
+ if (typeof timer.unref === "function")
9
+ timer.unref();
10
+ });
11
+ return Promise.race([Promise.resolve(operation), timeout]).finally(() => {
12
+ if (timer)
13
+ clearTimeout(timer);
14
+ });
15
+ }
16
+ export async function closeAsyncIterator(iterator, timeoutMs) {
17
+ if (typeof iterator.return !== "function")
18
+ return;
19
+ const closing = Promise.resolve().then(() => iterator.return?.(undefined)).then(() => undefined);
20
+ try {
21
+ await withTimeout(closing, timeoutMs, "SDK iterator cleanup timed out");
22
+ }
23
+ catch {
24
+ // Cleanup is best effort; the request's primary error remains authoritative.
25
+ }
26
+ }
27
+ //# sourceMappingURL=async-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-utils.js","sourceRoot":"","sources":["../src/async-utils.ts"],"names":[],"mappings":"AAAA;;qDAEqD;AACrD,MAAM,UAAU,WAAW,CAAI,SAAyB,EAAE,SAAiB,EAAE,OAAe;IAC1F,IAAI,KAAgD,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;QAC/C,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QAChE,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU;YAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IACvD,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;QACtE,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAA2F,EAC3F,SAAiB;IAEjB,IAAI,OAAO,QAAQ,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO;IAClD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACjG,IAAI,CAAC;QACH,MAAM,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,gCAAgC,CAAC,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,6EAA6E;IAC/E,CAAC;AACH,CAAC"}
package/dist/auth.d.ts CHANGED
@@ -7,5 +7,6 @@ export declare function isAuthenticated(): boolean;
7
7
  * Returns null when no separately installed CLI is found. The Qoder SDK can
8
8
  * still run through its bundled Worker runtime when credentials are present.
9
9
  */
10
- export declare function findQoderCLI(): string | null;
10
+ export declare function findQoderCLI(force?: boolean): string | null;
11
+ export declare function resetCachedCliPath(): void;
11
12
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AASA,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAuBD;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAI5C"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AASA,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAuBD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,UAAQ,GAAG,MAAM,GAAG,IAAI,CAIzD;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
package/dist/auth.js CHANGED
@@ -38,12 +38,15 @@ let cachedCliPath;
38
38
  * Returns null when no separately installed CLI is found. The Qoder SDK can
39
39
  * still run through its bundled Worker runtime when credentials are present.
40
40
  */
41
- export function findQoderCLI() {
42
- if (cachedCliPath !== undefined)
41
+ export function findQoderCLI(force = false) {
42
+ if (!force && cachedCliPath !== undefined)
43
43
  return cachedCliPath;
44
44
  cachedCliPath = resolveCli();
45
45
  return cachedCliPath;
46
46
  }
47
+ export function resetCachedCliPath() {
48
+ cachedCliPath = undefined;
49
+ }
47
50
  function resolveCli() {
48
51
  const exe = process.platform === "win32" ? "qodercli.exe" : "qodercli";
49
52
  for (const dir of (process.env.PATH ?? "").split(delimiter)) {
@@ -58,12 +61,12 @@ function resolveCli() {
58
61
  return local;
59
62
  const binDir = join(homedir(), ".qoder", "bin", "qodercli");
60
63
  try {
61
- const latest = readdirSync(binDir)
64
+ const versions = readdirSync(binDir)
62
65
  .filter((f) => f.startsWith("qodercli-"))
63
- .sort()
64
- .at(-1);
65
- if (latest) {
66
- const p = join(binDir, latest);
66
+ .sort(compareCliVersions)
67
+ .reverse();
68
+ for (const version of versions) {
69
+ const p = join(binDir, version);
67
70
  if (isExecutableFile(p))
68
71
  return p;
69
72
  }
@@ -73,4 +76,20 @@ function resolveCli() {
73
76
  }
74
77
  return null;
75
78
  }
79
+ function compareCliVersions(left, right) {
80
+ const leftParts = left.slice("qodercli-".length).split(/[.-]/);
81
+ const rightParts = right.slice("qodercli-".length).split(/[.-]/);
82
+ const length = Math.max(leftParts.length, rightParts.length);
83
+ for (let i = 0; i < length; i++) {
84
+ const a = leftParts[i] ?? "";
85
+ const b = rightParts[i] ?? "";
86
+ const aNumber = /^\d+$/.test(a) ? Number(a) : NaN;
87
+ const bNumber = /^\d+$/.test(b) ? Number(b) : NaN;
88
+ if (Number.isFinite(aNumber) && Number.isFinite(bNumber) && aNumber !== bNumber)
89
+ return aNumber - bNumber;
90
+ if (a !== b)
91
+ return a.localeCompare(b);
92
+ }
93
+ return left.localeCompare(right);
94
+ }
76
95
  //# sourceMappingURL=auth.js.map
package/dist/auth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/cost.d.ts CHANGED
@@ -23,9 +23,10 @@ interface PersistedState {
23
23
  }>;
24
24
  recent: TurnCost[];
25
25
  }
26
+ export declare function flushLedgerSync(): void;
26
27
  export interface RecordInput {
27
28
  model: string;
28
- usage: {
29
+ usage?: {
29
30
  input_tokens?: number | null;
30
31
  output_tokens?: number | null;
31
32
  cache_read_input_tokens?: number | null;
@@ -1 +1 @@
1
- {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAS5D,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,cAAc;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvG,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAqJD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QACL,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxC,2BAA2B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7C,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACzC;AAED,0DAA0D;AAC1D,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,CA+BvD;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IACnC,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAED,wBAAgB,SAAS,IAAI,YAAY,CAUxC;AAED,wBAAgB,WAAW,IAAI,IAAI,CAGlC;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C"}
1
+ {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAa5D,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,cAAc;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvG,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAoND,wBAAgB,eAAe,IAAI,IAAI,CAOtC;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxC,2BAA2B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7C,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACzC;AAED,0DAA0D;AAC1D,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,CAoBvD;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IACnC,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAED,wBAAgB,SAAS,IAAI,YAAY,CAUxC;AAED,wBAAgB,WAAW,IAAI,IAAI,CAKlC;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C"}