opencode-qoder-bridge 0.1.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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +185 -0
  3. package/RELEASING.md +64 -0
  4. package/SECURITY.md +24 -0
  5. package/THIRD_PARTY_NOTICES.md +18 -0
  6. package/bin/statusline.mjs +33 -0
  7. package/bin/usage.mjs +35 -0
  8. package/dist/auth.d.ts +10 -0
  9. package/dist/auth.d.ts.map +1 -0
  10. package/dist/auth.js +75 -0
  11. package/dist/auth.js.map +1 -0
  12. package/dist/cost.d.ts +53 -0
  13. package/dist/cost.d.ts.map +1 -0
  14. package/dist/cost.js +173 -0
  15. package/dist/cost.js.map +1 -0
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +148 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/language-model.d.ts +15 -0
  21. package/dist/language-model.d.ts.map +1 -0
  22. package/dist/language-model.js +408 -0
  23. package/dist/language-model.js.map +1 -0
  24. package/dist/mcp-bridge.d.ts +8 -0
  25. package/dist/mcp-bridge.d.ts.map +1 -0
  26. package/dist/mcp-bridge.js +81 -0
  27. package/dist/mcp-bridge.js.map +1 -0
  28. package/dist/models.d.ts +27 -0
  29. package/dist/models.d.ts.map +1 -0
  30. package/dist/models.js +112 -0
  31. package/dist/models.js.map +1 -0
  32. package/dist/prompt-builder.d.ts +30 -0
  33. package/dist/prompt-builder.d.ts.map +1 -0
  34. package/dist/prompt-builder.js +308 -0
  35. package/dist/prompt-builder.js.map +1 -0
  36. package/dist/provider.d.ts +12 -0
  37. package/dist/provider.d.ts.map +1 -0
  38. package/dist/provider.js +17 -0
  39. package/dist/provider.js.map +1 -0
  40. package/dist/sdk-session.d.ts +3 -0
  41. package/dist/sdk-session.d.ts.map +1 -0
  42. package/dist/sdk-session.js +8 -0
  43. package/dist/sdk-session.js.map +1 -0
  44. package/dist/tool-normalizer.d.ts +13 -0
  45. package/dist/tool-normalizer.d.ts.map +1 -0
  46. package/dist/tool-normalizer.js +99 -0
  47. package/dist/tool-normalizer.js.map +1 -0
  48. package/dist/tui-register.d.ts +2 -0
  49. package/dist/tui-register.d.ts.map +1 -0
  50. package/dist/tui-register.js +67 -0
  51. package/dist/tui-register.js.map +1 -0
  52. package/dist/tui.d.ts +9 -0
  53. package/dist/tui.d.ts.map +1 -0
  54. package/dist/tui.js +190 -0
  55. package/dist/tui.js.map +1 -0
  56. package/dist/types.d.ts +34 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +2 -0
  59. package/dist/types.js.map +1 -0
  60. package/dist/usage.d.ts +11 -0
  61. package/dist/usage.d.ts.map +1 -0
  62. package/dist/usage.js +87 -0
  63. package/dist/usage.js.map +1 -0
  64. package/package.json +78 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 opencode-qoder-bridge contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,185 @@
1
+ # opencode-qoder-bridge
2
+
3
+ An [opencode](https://opencode.ai) plugin that bridges **Qoder AI** models into your terminal via the official [`@qoder-ai/qoder-agent-sdk`](https://www.npmjs.com/package/@qoder-ai/qoder-agent-sdk).
4
+
5
+ A ground-up rewrite focused on reliability, performance, and first-class usage/cost visibility.
6
+
7
+ > [!IMPORTANT]
8
+ > This is an independent community project. It is not affiliated with,
9
+ > endorsed by, or sponsored by Qoder or OpenCode. Use of the Qoder SDK and
10
+ > services is subject to the [Qoder Product Service Terms](https://qoder.com/product-service).
11
+
12
+ ## Highlights
13
+
14
+ - **Official SDK, no vendoring** — depends on `@qoder-ai/qoder-agent-sdk` directly. No patched SDK copies, no CLI compat-wrapper scripts.
15
+ - **Correct streaming** — native AI SDK v3 stream-part translation (`content_block_start/delta/stop`, `message_delta`, assistant fallback), reasoning blocks, and tool-call handoff to opencode.
16
+ - **Usage & cost tracking** — every completed turn is recorded to a local ledger (`~/.config/opencode-qoder-bridge/usage.json`) with per-model cost and token totals. Query it via the `qoder_usage` tool or the `opencode-qoder-bridge` statusline binary.
17
+ - **Live quota** — `qoder_usage` also pulls live account quota via the SDK's `getUsageInfo()` (cached 60s).
18
+ - **Reliable lifecycle** — proper abort propagation, idempotent cleanup, and external-abort vs. internal-error distinction so cancellations don't surface as errors.
19
+ - **Image input** — multimodal prompts are passed through the SDK's async-iterable path (base64, data URLs, `file://`, `~/`, and absolute paths).
20
+
21
+ ## Prerequisites
22
+
23
+ 1. Install and log in to the Qoder CLI:
24
+
25
+ ```bash
26
+ qoder login
27
+ ```
28
+
29
+ Credentials are stored under `~/.qoder/.auth/user`.
30
+
31
+ 2. Install opencode:
32
+
33
+ ```bash
34
+ npm install -g opencode-ai
35
+ ```
36
+
37
+ ## Install
38
+
39
+ For a published npm installation, add this to
40
+ `~/.config/opencode/opencode.json`:
41
+
42
+ ```json
43
+ {
44
+ "plugin": ["opencode-qoder-bridge"]
45
+ }
46
+ ```
47
+
48
+ For a local checkout or an unpublished package, point OpenCode at the built
49
+ plugin entry directly:
50
+
51
+ ```json
52
+ {
53
+ "plugin": [
54
+ "file:///absolute/path/to/opencode-qoder-bridge/dist/index.js"
55
+ ]
56
+ }
57
+ ```
58
+
59
+ opencode installs published npm plugins automatically on startup. A bare package
60
+ name must exist in the npm registry; installing an unpublished package only in
61
+ `~/.config/opencode/node_modules` is not enough for current opencode releases.
62
+ Once loaded, the plugin injects the `qoder` provider and all models — no manual
63
+ `provider` block required.
64
+
65
+ ## Usage
66
+
67
+ ```bash
68
+ opencode run -m qoder/lite "say hello" # free model
69
+ opencode run -m qoder/auto "explain async/await"
70
+ opencode -m qoder/performance # interactive
71
+ ```
72
+
73
+ ### Usage & cost
74
+
75
+ Run `/qoder-usage` in OpenCode (it uses the free `qoder/lite` model), run
76
+ `qoder-usage` in a terminal for the same live report, or add the statusline
77
+ binary to your OpenCode statusline config:
78
+
79
+ ```bash
80
+ opencode-qoder-bridge
81
+ # qoder: cost $0.0123 · turns 1 · tok 1500 · last performance
82
+ ```
83
+
84
+ The package also exports a TUI entry at `opencode-qoder-bridge/tui`. It shows
85
+ live Qoder credits only while the current session's selected provider is
86
+ `qoder`; it stays hidden and does not query quota for other providers. The
87
+ sidebar shows OpenCode's session spend with four-decimal precision and derives
88
+ fractional session Credits from Qoder's cent-denominated reference cost
89
+ (`session.cost * 100`). The value is marked with `~` because Qoder's personal
90
+ SDK exposes only a rounded whole-account quota, not its per-request Credits Log.
91
+ The authoritative account balance still comes from SDK `userQuota`, refreshing
92
+ after each completed Qoder turn and every 30 seconds while active.
93
+
94
+ OpenCode 1.18.5 loads server plugins and TUI plugins independently. On its
95
+ first load, the bridge safely adds its bundled TUI entry to the global
96
+ `tui.json`, preserving existing settings. Restart OpenCode once after initial
97
+ installation so the TUI loader can activate it. The resulting entry is
98
+ equivalent to:
99
+
100
+ ```json
101
+ {
102
+ "$schema": "https://opencode.ai/tui.json",
103
+ "plugin": ["file:///path/to/opencode-qoder-bridge/dist/tui.js"]
104
+ }
105
+ ```
106
+
107
+ The ledger accumulates across sessions. Delete `~/.config/opencode-qoder-bridge/usage.json` to reset it.
108
+
109
+ ## Models
110
+
111
+ The bridge discovers the available catalog at startup through the SDK's
112
+ `getAvailableModels()` API. The following is the complete enabled catalog
113
+ returned by a live query on **2026-07-25**:
114
+
115
+ | Model ID | Name | Credit multiplier | Vision | Reasoning | Max input | Max output |
116
+ |----------|------|-------------------|--------|-----------|-----------|------------|
117
+ | `auto` | Auto | 1.00x | ✓ | ✗ | 200K | 32K |
118
+ | `ultimate` | Ultimate | 0.80x | ✓ | ✓ | 1M | 32K |
119
+ | `performance` | Performance | 1.10x | ✓ | ✗ | 1M | 32K |
120
+ | `efficient` | Efficient | 0.30x | ✓ | ✗ | 200K | 32K |
121
+ | `lite` | Lite | 0.00x | ✗ | ✗ | 200K | 32K |
122
+ | `cmodel` | Cantus | 1.60x | ✓ | ✓ | 200K | 32K |
123
+ | `qmodel_preview` | Qwen3.8-Max-Preview | 0.01x promo | ✓ | ✓ | 200K | 32K |
124
+ | `qmodel_latest` | Qwen3.7-Max | 0.10x promo | ✓ | ✗ | 1M | 32K |
125
+ | `qmodel` | Qwen3.7-Plus | 0.04x promo | ✓ | ✗ | 1M | 32K |
126
+ | `kmodel_latest` | Kimi-K3 | 0.80x | ✓ | ✗ | 200K | 32K |
127
+ | `kmodel` | Kimi-K2.7-Code | 0.30x | ✓ | ✗ | 256K | 32K |
128
+ | `gm51model` | GLM-5.2 | 0.50x promo | ✓ | ✓ | 1M | 32K |
129
+ | `dmodel` | DeepSeek-V4-Pro | 0.50x | ✓ | ✓ | 1M | 32K |
130
+ | `dfmodel` | DeepSeek-V4-Flash | 0.10x | ✓ | ✓ | 1M | 32K |
131
+ | `mmodel` | MiniMax-M3 | 0.20x | ✓ | ✗ | 1M | 32K |
132
+
133
+ This table is a snapshot, not a hard-coded allowlist. Qoder can vary model
134
+ availability by account, plan, CLI version, or staged rollout. Promotional
135
+ multipliers are time-dependent; the SDK's current `priceFactor` is
136
+ authoritative. Restart OpenCode to refresh the bridge's in-process model cache.
137
+
138
+ ## Configuration
139
+
140
+ Bridge opencode MCP servers into the SDK by passing provider options:
141
+
142
+ ```json
143
+ {
144
+ "provider": {
145
+ "qoder": {
146
+ "options": {
147
+ "extraArgs": { "--experimental-mcp-load": null }
148
+ }
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ `config.mcp` servers are bridged into the SDK's `mcpServers` automatically.
155
+
156
+ ## Troubleshooting
157
+
158
+ | Problem | Solution |
159
+ |---------|----------|
160
+ | Auth prompt at startup | Run `qoder login`, then restart opencode |
161
+ | `qodercli not found` | Install the Qoder CLI; ensure `qodercli` is on PATH or under `~/.qoder/` |
162
+ | Model not found | Verify the model ID matches the table above |
163
+
164
+ ## Development
165
+
166
+ ```bash
167
+ npm install
168
+ npm run build # compile to dist/
169
+ npm run typecheck # type-check only
170
+ npm test # build and run the test suite
171
+ npm run check # full pre-publish verification
172
+ ```
173
+
174
+ ## Security
175
+
176
+ Report suspected vulnerabilities privately as described in
177
+ [SECURITY.md](./SECURITY.md). Do not include Qoder credentials, npm tokens, or
178
+ private prompt content in reports.
179
+
180
+ Maintainer release instructions are in [RELEASING.md](./RELEASING.md).
181
+
182
+ ## License
183
+
184
+ The bridge source is MIT licensed; see [LICENSE](./LICENSE). Dependencies retain
185
+ their own licenses and terms; see [THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md).
package/RELEASING.md ADDED
@@ -0,0 +1,64 @@
1
+ # Releasing
2
+
3
+ ## Before the first release
4
+
5
+ 1. Confirm that publishing this integration and using the Qoder name and SDK
6
+ complies with the current Qoder Product Service Terms. Keep any written
7
+ permission with the project records.
8
+ 2. Create the public GitHub repository:
9
+ `https://github.com/naoufalelbani/opencode-qoder-bridge`.
10
+ 3. Create an npm account, enable two-factor authentication, and run `npm login`.
11
+ 4. Review production dependency advisories with `npm audit --omit=dev`. Do not
12
+ apply forced or major-version fixes without running the full integration
13
+ suite.
14
+
15
+ ## First publish
16
+
17
+ Run the complete release gate from a clean checkout:
18
+
19
+ ```bash
20
+ npm ci
21
+ npm run check
22
+ npm pack --dry-run
23
+ npm publish
24
+ ```
25
+
26
+ Verify the registry package and install it through OpenCode:
27
+
28
+ ```bash
29
+ npm view opencode-qoder-bridge
30
+ ```
31
+
32
+ ```json
33
+ {
34
+ "plugin": ["opencode-qoder-bridge"]
35
+ }
36
+ ```
37
+
38
+ ## Trusted publishing
39
+
40
+ After the package exists on npm:
41
+
42
+ 1. Open the package settings on npmjs.com.
43
+ 2. Add a GitHub Actions trusted publisher for:
44
+ - Owner: `naoufalelbani`
45
+ - Repository: `opencode-qoder-bridge`
46
+ - Workflow: `publish.yml`
47
+ - Allowed action: `npm publish`
48
+ 3. Keep the repository public so npm can generate provenance.
49
+ 4. Consider configuring the npm package to disallow token-based publishing
50
+ after the trusted workflow succeeds.
51
+
52
+ ## Subsequent releases
53
+
54
+ Update `version` using semantic versioning, run the release gate, commit the
55
+ change, and push a matching tag:
56
+
57
+ ```bash
58
+ npm version patch
59
+ git push origin main --follow-tags
60
+ ```
61
+
62
+ The tag triggers `.github/workflows/publish.yml`. Never reuse a version already
63
+ published to npm.
64
+
package/SECURITY.md ADDED
@@ -0,0 +1,24 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ Please do not open a public issue for a suspected vulnerability.
6
+
7
+ Use GitHub's private vulnerability reporting for this repository:
8
+
9
+ https://github.com/naoufalelbani/opencode-qoder-bridge/security/advisories/new
10
+
11
+ Include the affected version, reproduction steps, impact, and any suggested
12
+ mitigation. You should receive an acknowledgement within seven days.
13
+
14
+ ## Supported versions
15
+
16
+ Security fixes are provided for the latest published version. Users should also
17
+ keep OpenCode, the Qoder CLI, and package dependencies current.
18
+
19
+ ## Credential handling
20
+
21
+ This plugin does not distribute Qoder credentials. Authentication remains with
22
+ the locally installed Qoder CLI. Never include files from `~/.qoder/`, npm
23
+ tokens, prompts containing secrets, or local usage ledgers in a report.
24
+
@@ -0,0 +1,18 @@
1
+ # Third-Party Notices
2
+
3
+ This community project is not affiliated with, endorsed by, or sponsored by
4
+ Qoder or OpenCode.
5
+
6
+ The MIT license in this repository applies only to this project's own source
7
+ code. Runtime dependencies remain subject to their respective licenses and
8
+ terms.
9
+
10
+ In particular, `@qoder-ai/qoder-agent-sdk` is provided by Qoder under the Qoder
11
+ Product Service Terms:
12
+
13
+ https://qoder.com/product-service
14
+
15
+ Installing or using this plugin installs and uses that SDK. Users are
16
+ responsible for reviewing and complying with the Qoder terms and the terms of
17
+ any models or third-party services they access.
18
+
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+
6
+ const STATE_FILE = join(homedir(), ".config", "opencode-qoder-bridge", "usage.json");
7
+
8
+ function fmt(usd) {
9
+ return `$${(usd ?? 0).toFixed(4)}`;
10
+ }
11
+
12
+ function main() {
13
+ let state = null;
14
+ try {
15
+ state = JSON.parse(readFileSync(STATE_FILE, "utf8"));
16
+ } catch {
17
+ process.stdout.write("qoder: no usage yet");
18
+ return;
19
+ }
20
+
21
+ const parts = [
22
+ `cost ${fmt(state.totalCostUsd)}`,
23
+ `turns ${state.turnCount ?? 0}`,
24
+ `tok ${(state.totalInputTokens ?? 0) + (state.totalOutputTokens ?? 0)}`,
25
+ ];
26
+
27
+ const last = Array.isArray(state.recent) ? state.recent.at(-1) : null;
28
+ if (last?.model) parts.push(`last ${last.model}`);
29
+
30
+ process.stdout.write(`qoder: ${parts.join(" · ")}`);
31
+ }
32
+
33
+ main();
package/bin/usage.mjs ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ import { getLiveUsage, formatUsageReport } from "../dist/usage.js";
3
+ import { summarize, formatCost } from "../dist/cost.js";
4
+
5
+ async function main() {
6
+ const lines = [];
7
+ const live = await getLiveUsage(true);
8
+ lines.push(
9
+ live
10
+ ? formatUsageReport(live)
11
+ : "Live Qoder usage unavailable (not logged in or Qoder CLI missing).",
12
+ );
13
+
14
+ const summary = summarize();
15
+ lines.push("");
16
+ 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`);
20
+
21
+ const models = Object.entries(summary.byModel);
22
+ if (models.length > 0) {
23
+ lines.push(" By model:");
24
+ for (const [name, bucket] of models) {
25
+ lines.push(` ${name}: ${formatCost(bucket.costUsd)} (${bucket.turns} turns)`);
26
+ }
27
+ }
28
+
29
+ process.stdout.write(lines.join("\n"));
30
+ }
31
+
32
+ main().catch((error) => {
33
+ process.stderr.write(`Unable to read Qoder usage: ${error instanceof Error ? error.message : String(error)}\n`);
34
+ process.exitCode = 1;
35
+ });
package/dist/auth.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export declare function isAuthenticated(): boolean;
2
+ /**
3
+ * Resolve the qodercli binary. Search order:
4
+ * 1. PATH
5
+ * 2. ~/.qoder/local/qodercli
6
+ * 3. ~/.qoder/bin/qodercli/qodercli-<version> (latest)
7
+ * Returns null when nothing is found.
8
+ */
9
+ export declare function findQoderCLI(): string | null;
10
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AASA,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAuBD;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAI5C"}
package/dist/auth.js ADDED
@@ -0,0 +1,75 @@
1
+ import { accessSync, constants, readdirSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join, delimiter } from "node:path";
4
+ const AUTH_FILES = [
5
+ join(homedir(), ".qoderwork", ".auth", "user"),
6
+ join(homedir(), ".qoder", ".auth", "user"),
7
+ ];
8
+ export function isAuthenticated() {
9
+ return AUTH_FILES.some((p) => isRegularFile(p));
10
+ }
11
+ function isRegularFile(p) {
12
+ try {
13
+ return statSync(p).isFile();
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ function isExecutableFile(p) {
20
+ if (!isRegularFile(p))
21
+ return false;
22
+ if (process.platform === "win32")
23
+ return true;
24
+ try {
25
+ accessSync(p, constants.X_OK);
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ let cachedCliPath;
33
+ /**
34
+ * Resolve the qodercli binary. Search order:
35
+ * 1. PATH
36
+ * 2. ~/.qoder/local/qodercli
37
+ * 3. ~/.qoder/bin/qodercli/qodercli-<version> (latest)
38
+ * Returns null when nothing is found.
39
+ */
40
+ export function findQoderCLI() {
41
+ if (cachedCliPath !== undefined)
42
+ return cachedCliPath;
43
+ cachedCliPath = resolveCli();
44
+ return cachedCliPath;
45
+ }
46
+ function resolveCli() {
47
+ const exe = process.platform === "win32" ? "qodercli.exe" : "qodercli";
48
+ for (const dir of (process.env.PATH ?? "").split(delimiter)) {
49
+ if (!dir)
50
+ continue;
51
+ const p = join(dir, exe);
52
+ if (isExecutableFile(p))
53
+ return p;
54
+ }
55
+ const local = join(homedir(), ".qoder", "local", exe);
56
+ if (isExecutableFile(local))
57
+ return local;
58
+ const binDir = join(homedir(), ".qoder", "bin", "qodercli");
59
+ try {
60
+ const latest = readdirSync(binDir)
61
+ .filter((f) => f.startsWith("qodercli-"))
62
+ .sort()
63
+ .at(-1);
64
+ if (latest) {
65
+ const p = join(binDir, latest);
66
+ if (isExecutableFile(p))
67
+ return p;
68
+ }
69
+ }
70
+ catch {
71
+ /* not installed */
72
+ }
73
+ return null;
74
+ }
75
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,UAAU,GAAG;IACjB,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC;IAC9C,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC;CAC3C,CAAC;AAEF,MAAM,UAAU,eAAe;IAC7B,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,aAAa,CAAC,CAAS;IAC9B,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAS;IACjC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,CAAC;QACH,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,IAAI,aAAwC,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,UAAU,YAAY;IAC1B,IAAI,aAAa,KAAK,SAAS;QAAE,OAAO,aAAa,CAAC;IACtD,aAAa,GAAG,UAAU,EAAE,CAAC;IAC7B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAS,UAAU;IACjB,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;IAEvE,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5D,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACzB,IAAI,gBAAgB,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IACtD,IAAI,gBAAgB,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAE1C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;aAC/B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;aACxC,IAAI,EAAE;aACN,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACV,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC/B,IAAI,gBAAgB,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,mBAAmB;IACrB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
package/dist/cost.d.ts ADDED
@@ -0,0 +1,53 @@
1
+ import type { ModelUsage } from "@qoder-ai/qoder-agent-sdk";
2
+ export interface TurnCost {
3
+ model: string;
4
+ inputTokens: number;
5
+ outputTokens: number;
6
+ cacheReadTokens: number;
7
+ cacheWriteTokens: number;
8
+ costUsd: number;
9
+ durationMs: number;
10
+ turns: number;
11
+ at: number;
12
+ }
13
+ interface PersistedState {
14
+ totalCostUsd: number;
15
+ totalInputTokens: number;
16
+ totalOutputTokens: number;
17
+ turnCount: number;
18
+ byModel: Record<string, {
19
+ costUsd: number;
20
+ inputTokens: number;
21
+ outputTokens: number;
22
+ turns: number;
23
+ }>;
24
+ recent: TurnCost[];
25
+ }
26
+ export interface RecordInput {
27
+ model: string;
28
+ usage: {
29
+ input_tokens?: number | null;
30
+ output_tokens?: number | null;
31
+ cache_read_input_tokens?: number | null;
32
+ cache_creation_input_tokens?: number | null;
33
+ };
34
+ costUsd: number;
35
+ durationMs: number;
36
+ turns: number;
37
+ modelUsage?: Record<string, ModelUsage>;
38
+ }
39
+ /** Record a completed turn into the persistent ledger. */
40
+ export declare function recordTurn(input: RecordInput): TurnCost;
41
+ export interface UsageSummary {
42
+ totalCostUsd: number;
43
+ totalInputTokens: number;
44
+ totalOutputTokens: number;
45
+ turnCount: number;
46
+ byModel: PersistedState["byModel"];
47
+ recent: TurnCost[];
48
+ }
49
+ export declare function summarize(): UsageSummary;
50
+ export declare function resetLedger(): void;
51
+ export declare function formatCost(usd: number): string;
52
+ export {};
53
+ //# sourceMappingURL=cost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAO5D,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;AA6GD,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"}