opencode-qoder-bridge 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +240 -216
- package/LICENSE +21 -21
- package/README.md +411 -297
- package/RELEASING.md +72 -62
- package/SECURITY.md +25 -25
- package/THIRD_PARTY_NOTICES.md +18 -18
- package/bin/statusline.mjs +66 -66
- package/bin/usage.mjs +36 -36
- package/dist/command-actions.d.ts +92 -0
- package/dist/command-actions.d.ts.map +1 -0
- package/dist/command-actions.js +641 -0
- package/dist/command-actions.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +188 -2
- package/dist/index.js.map +1 -1
- package/dist/language-model.d.ts.map +1 -1
- package/dist/language-model.js +44 -1
- package/dist/language-model.js.map +1 -1
- package/dist/sdk-control.d.ts +16 -0
- package/dist/sdk-control.d.ts.map +1 -0
- package/dist/sdk-control.js +150 -0
- package/dist/sdk-control.js.map +1 -0
- package/dist/tui-register.d.ts.map +1 -1
- package/dist/tui-register.js +7 -2
- package/dist/tui-register.js.map +1 -1
- package/dist/tui.d.ts +3 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +187 -0
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +5 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +118 -117
package/RELEASING.md
CHANGED
|
@@ -1,73 +1,83 @@
|
|
|
1
|
-
# Releasing
|
|
2
|
-
|
|
3
|
-
## Before
|
|
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.
|
|
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
|
-
##
|
|
16
|
-
|
|
17
|
-
Run the complete release gate from a clean checkout:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
## Before a public 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. Confirm the public GitHub repository is available:
|
|
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
|
+
## Public publish
|
|
16
|
+
|
|
17
|
+
Run the complete release gate from a clean checkout:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
20
|
npm ci
|
|
21
21
|
npm run check
|
|
22
|
+
npm run test:stress
|
|
22
23
|
QODER_E2E=1 npm run test:e2e # requires qoder login; consumes quota
|
|
23
24
|
npm pack --dry-run
|
|
24
|
-
npm publish
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
The end-to-end gate is mandatory for any release that touches
|
|
28
|
-
`src/language-model.ts`, `src/models.ts`, or `src/usage.ts`: unit tests mock
|
|
29
|
-
the SDK, so only `QODER_E2E=1` exercises real streaming, tool calls, provider
|
|
30
|
-
metadata, and live model discovery. Verify before publishing that the dry-run
|
|
31
|
-
tarball contains `dist/` (including `errors.js`, `logger.js`,
|
|
32
|
-
`state-dir.js`) and both `bin/` scripts, and nothing else unexpected.
|
|
33
|
-
|
|
25
|
+
npm publish --access public
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The end-to-end gate is mandatory for any release that touches
|
|
29
|
+
`src/language-model.ts`, `src/models.ts`, or `src/usage.ts`: unit tests mock
|
|
30
|
+
the SDK, so only `QODER_E2E=1` exercises real streaming, tool calls, provider
|
|
31
|
+
metadata, and live model discovery. Verify before publishing that the dry-run
|
|
32
|
+
tarball contains `dist/` (including `errors.js`, `logger.js`,
|
|
33
|
+
`state-dir.js`) and both `bin/` scripts, and nothing else unexpected.
|
|
34
|
+
|
|
34
35
|
Verify the registry package and install it through OpenCode:
|
|
35
|
-
|
|
36
|
-
```bash
|
|
36
|
+
|
|
37
|
+
```bash
|
|
37
38
|
npm view opencode-qoder-bridge
|
|
38
39
|
```
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Trusted publishing
|
|
47
|
-
|
|
48
|
-
After the package exists on npm:
|
|
49
|
-
|
|
50
|
-
1. Open the package settings on npmjs.com.
|
|
51
|
-
2. Add a GitHub Actions trusted publisher for:
|
|
52
|
-
- Owner: `naoufalelbani`
|
|
53
|
-
- Repository: `opencode-qoder-bridge`
|
|
54
|
-
- Workflow: `publish.yml`
|
|
55
|
-
- Allowed action: `npm publish`
|
|
56
|
-
3. Keep the repository public so npm can generate provenance.
|
|
57
|
-
4. Consider configuring the npm package to disallow token-based publishing
|
|
58
|
-
after the trusted workflow succeeds.
|
|
59
|
-
|
|
60
|
-
## Subsequent releases
|
|
61
|
-
|
|
62
|
-
Update `version` using semantic versioning, document the release in
|
|
63
|
-
`CHANGELOG.md`, run the release gate, commit the change, and push a matching
|
|
64
|
-
tag:
|
|
41
|
+
When validating a clean consumer with npm 12, transitive install scripts may be
|
|
42
|
+
blocked by the consumer's policy. Approve the SDK script and rebuild it when
|
|
43
|
+
the bundled Worker runtime is required:
|
|
65
44
|
|
|
66
45
|
```bash
|
|
67
|
-
npm
|
|
68
|
-
|
|
46
|
+
npm install-scripts approve @qoder-ai/qoder-agent-sdk@1.0.31
|
|
47
|
+
npm rebuild @qoder-ai/qoder-agent-sdk
|
|
69
48
|
```
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"plugin": ["opencode-qoder-bridge"]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Trusted publishing
|
|
57
|
+
|
|
58
|
+
After the package exists on npm:
|
|
59
|
+
|
|
60
|
+
1. Open the package settings on npmjs.com.
|
|
61
|
+
2. Add a GitHub Actions trusted publisher for:
|
|
62
|
+
- Owner: `naoufalelbani`
|
|
63
|
+
- Repository: `opencode-qoder-bridge`
|
|
64
|
+
- Workflow: `publish.yml`
|
|
65
|
+
- Allowed action: `npm publish`
|
|
66
|
+
3. Keep the repository public so npm can generate provenance.
|
|
67
|
+
4. Consider configuring the npm package to disallow token-based publishing
|
|
68
|
+
after the trusted workflow succeeds.
|
|
69
|
+
|
|
70
|
+
## Subsequent releases
|
|
71
|
+
|
|
72
|
+
Update `version` using semantic versioning, document the release in
|
|
73
|
+
`CHANGELOG.md`, run the release gate, commit the change, and push a matching
|
|
74
|
+
tag:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm version patch
|
|
78
|
+
git push origin main --follow-tags
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The tag triggers `.github/workflows/publish.yml`. Never reuse a version already
|
|
82
|
+
published to npm.
|
|
83
|
+
|
package/SECURITY.md
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
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 Qoder Agent SDK. Use a personal access token or local Qoder sign-in as
|
|
23
|
-
documented by the SDK; its bundled Worker runtime can be used without a
|
|
24
|
-
separately installed Qoder CLI. Never include files from `~/.qoder/`, npm
|
|
25
|
-
tokens, prompts containing secrets, or local usage ledgers in a report.
|
|
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 Qoder Agent SDK. Use a personal access token or local Qoder sign-in as
|
|
23
|
+
documented by the SDK; its bundled Worker runtime can be used without a
|
|
24
|
+
separately installed Qoder CLI. Never include files from `~/.qoder/`, npm
|
|
25
|
+
tokens, prompts containing secrets, or local usage ledgers in a report.
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -1,18 +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
|
-
|
|
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
|
+
|
package/bin/statusline.mjs
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { lstatSync, readFileSync } from "node:fs";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
|
|
6
|
-
// Mirrors resolveStateDir() from src/state-dir.ts:
|
|
7
|
-
// QODER_BRIDGE_STATE_DIR > XDG_CONFIG_HOME > ~/.config.
|
|
8
|
-
function resolveStateDir(env = process.env) {
|
|
9
|
-
const override = env.QODER_BRIDGE_STATE_DIR?.trim();
|
|
10
|
-
if (override) return join(override);
|
|
11
|
-
const configHome = env.XDG_CONFIG_HOME?.trim()
|
|
12
|
-
|| (process.platform === "win32" ? env.APPDATA?.trim() : undefined);
|
|
13
|
-
return join(configHome || join(homedir(), ".config"), "opencode-qoder-bridge");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const STATE_FILE = join(resolveStateDir(), "usage.json");
|
|
17
|
-
const MAX_STATE_BYTES = 1_000_000;
|
|
18
|
-
|
|
19
|
-
function fmt(usd) {
|
|
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;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function main() {
|
|
34
|
-
let state = null;
|
|
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
|
-
}
|
|
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
|
-
}
|
|
46
|
-
} catch {
|
|
47
|
-
process.stdout.write("qoder: no usage yet");
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const parts = [
|
|
52
|
-
`cost ${fmt(state.totalCostUsd)}`,
|
|
53
|
-
`turns ${count(state.turnCount)}`,
|
|
54
|
-
`tok ${add(count(state.totalInputTokens), count(state.totalOutputTokens))}`,
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
const last = Array.isArray(state.recent) ? state.recent.at(-1) : null;
|
|
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
|
-
}
|
|
62
|
-
|
|
63
|
-
process.stdout.write(`qoder: ${parts.join(" · ")}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
main();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { lstatSync, readFileSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
// Mirrors resolveStateDir() from src/state-dir.ts:
|
|
7
|
+
// QODER_BRIDGE_STATE_DIR > XDG_CONFIG_HOME > ~/.config.
|
|
8
|
+
function resolveStateDir(env = process.env) {
|
|
9
|
+
const override = env.QODER_BRIDGE_STATE_DIR?.trim();
|
|
10
|
+
if (override) return join(override);
|
|
11
|
+
const configHome = env.XDG_CONFIG_HOME?.trim()
|
|
12
|
+
|| (process.platform === "win32" ? env.APPDATA?.trim() : undefined);
|
|
13
|
+
return join(configHome || join(homedir(), ".config"), "opencode-qoder-bridge");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const STATE_FILE = join(resolveStateDir(), "usage.json");
|
|
17
|
+
const MAX_STATE_BYTES = 1_000_000;
|
|
18
|
+
|
|
19
|
+
function fmt(usd) {
|
|
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;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function main() {
|
|
34
|
+
let state = null;
|
|
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
|
+
}
|
|
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
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
process.stdout.write("qoder: no usage yet");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const parts = [
|
|
52
|
+
`cost ${fmt(state.totalCostUsd)}`,
|
|
53
|
+
`turns ${count(state.turnCount)}`,
|
|
54
|
+
`tok ${add(count(state.totalInputTokens), count(state.totalOutputTokens))}`,
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const last = Array.isArray(state.recent) ? state.recent.at(-1) : null;
|
|
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
|
+
}
|
|
62
|
+
|
|
63
|
+
process.stdout.write(`qoder: ${parts.join(" · ")}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
main();
|
package/bin/usage.mjs
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { getLiveUsage, formatUsageReport } from "../dist/usage.js";
|
|
3
|
-
import { summarize, formatCost } from "../dist/cost.js";
|
|
4
|
-
import { describeError } from "../dist/logger.js";
|
|
5
|
-
|
|
6
|
-
async function main() {
|
|
7
|
-
const lines = [];
|
|
8
|
-
const live = await getLiveUsage(true);
|
|
9
|
-
lines.push(
|
|
10
|
-
live
|
|
11
|
-
? formatUsageReport(live)
|
|
12
|
-
: "Live Qoder usage unavailable (not logged in or Qoder runtime unavailable).",
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
const summary = summarize();
|
|
16
|
-
lines.push("");
|
|
17
|
-
lines.push("Local Usage Ledger");
|
|
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`);
|
|
21
|
-
|
|
22
|
-
const models = Object.entries(summary?.byModel ?? {});
|
|
23
|
-
if (models.length > 0) {
|
|
24
|
-
lines.push(" By model:");
|
|
25
|
-
for (const [name, bucket] of models) {
|
|
26
|
-
lines.push(` ${name}: ${formatCost(bucket.costUsd)} (${bucket.turns} turns)`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
process.stdout.write(lines.join("\n"));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
main().catch((error) => {
|
|
34
|
-
process.stderr.write(`Unable to read Qoder usage: ${describeError(error)}\n`);
|
|
35
|
-
process.exitCode = 1;
|
|
36
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { getLiveUsage, formatUsageReport } from "../dist/usage.js";
|
|
3
|
+
import { summarize, formatCost } from "../dist/cost.js";
|
|
4
|
+
import { describeError } from "../dist/logger.js";
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
const lines = [];
|
|
8
|
+
const live = await getLiveUsage(true);
|
|
9
|
+
lines.push(
|
|
10
|
+
live
|
|
11
|
+
? formatUsageReport(live)
|
|
12
|
+
: "Live Qoder usage unavailable (not logged in or Qoder runtime unavailable).",
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const summary = summarize();
|
|
16
|
+
lines.push("");
|
|
17
|
+
lines.push("Local Usage Ledger");
|
|
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`);
|
|
21
|
+
|
|
22
|
+
const models = Object.entries(summary?.byModel ?? {});
|
|
23
|
+
if (models.length > 0) {
|
|
24
|
+
lines.push(" By model:");
|
|
25
|
+
for (const [name, bucket] of models) {
|
|
26
|
+
lines.push(` ${name}: ${formatCost(bucket.costUsd)} (${bucket.turns} turns)`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
process.stdout.write(lines.join("\n"));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
main().catch((error) => {
|
|
34
|
+
process.stderr.write(`Unable to read Qoder usage: ${describeError(error)}\n`);
|
|
35
|
+
process.exitCode = 1;
|
|
36
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Query } from "@qoder-ai/qoder-agent-sdk";
|
|
2
|
+
import type { ModelDiscoveryOptions } from "./models.js";
|
|
3
|
+
import type { QoderBridgeOptions } from "./types.js";
|
|
4
|
+
export declare const QODER_COMMANDS: readonly [{
|
|
5
|
+
readonly name: "qoder_usage";
|
|
6
|
+
readonly title: "Qoder Usage";
|
|
7
|
+
readonly description: "Show live Qoder quota and local cost/token totals.";
|
|
8
|
+
readonly argumentHint: "";
|
|
9
|
+
}, {
|
|
10
|
+
readonly name: "qoder_models";
|
|
11
|
+
readonly title: "Qoder Models";
|
|
12
|
+
readonly description: "List available Qoder models and capabilities.";
|
|
13
|
+
readonly argumentHint: "";
|
|
14
|
+
}, {
|
|
15
|
+
readonly name: "qoder_sessions";
|
|
16
|
+
readonly title: "Qoder Sessions";
|
|
17
|
+
readonly description: "List recent Qoder sessions.";
|
|
18
|
+
readonly argumentHint: "optional: [directory] [limit]";
|
|
19
|
+
}, {
|
|
20
|
+
readonly name: "qoder_session_reset";
|
|
21
|
+
readonly title: "Reset Qoder Session";
|
|
22
|
+
readonly description: "Reset a persisted Qoder session key, or all sessions.";
|
|
23
|
+
readonly argumentHint: "optional: session key or all";
|
|
24
|
+
}, {
|
|
25
|
+
readonly name: "qoder_session_fork";
|
|
26
|
+
readonly title: "Fork Qoder Session";
|
|
27
|
+
readonly description: "Fork a Qoder session without changing the active mapping.";
|
|
28
|
+
readonly argumentHint: "optional: sessionId dir title upToMessageId";
|
|
29
|
+
}, {
|
|
30
|
+
readonly name: "qoder_mcp_status";
|
|
31
|
+
readonly title: "Qoder MCP Status";
|
|
32
|
+
readonly description: "Inspect Qoder MCP connection and OAuth status.";
|
|
33
|
+
readonly argumentHint: "";
|
|
34
|
+
}, {
|
|
35
|
+
readonly name: "qoder_mcp_auth";
|
|
36
|
+
readonly title: "Qoder MCP OAuth";
|
|
37
|
+
readonly description: "Start or complete Qoder MCP OAuth.";
|
|
38
|
+
readonly argumentHint: "server [callbackUrl] [redirectUri]";
|
|
39
|
+
}, {
|
|
40
|
+
readonly name: "qoder_plan_mode";
|
|
41
|
+
readonly title: "Qoder Plan Mode";
|
|
42
|
+
readonly description: "Show Qoder Plan Mode status and configuration guidance.";
|
|
43
|
+
readonly argumentHint: "";
|
|
44
|
+
}];
|
|
45
|
+
export type QoderCommandName = (typeof QODER_COMMANDS)[number]["name"];
|
|
46
|
+
export type CommandResult = {
|
|
47
|
+
title: string;
|
|
48
|
+
output: string;
|
|
49
|
+
variant?: "info" | "success" | "warning" | "error";
|
|
50
|
+
};
|
|
51
|
+
export type PendingMcpAuth = {
|
|
52
|
+
query: Query;
|
|
53
|
+
close: () => Promise<void>;
|
|
54
|
+
timer: ReturnType<typeof setTimeout>;
|
|
55
|
+
};
|
|
56
|
+
export type QoderCommandContext = {
|
|
57
|
+
configuredCwd: string;
|
|
58
|
+
configuredSessionKey?: string;
|
|
59
|
+
configuredSessionId?: string;
|
|
60
|
+
configuredBridgeOptions: QoderBridgeOptions;
|
|
61
|
+
modelEnvironment?: Record<string, string | undefined>;
|
|
62
|
+
modelOptions?: ModelDiscoveryOptions;
|
|
63
|
+
pendingMcpAuth: Map<string, PendingMcpAuth>;
|
|
64
|
+
};
|
|
65
|
+
export type QoderSessionsArguments = {
|
|
66
|
+
dir?: string;
|
|
67
|
+
limit?: number;
|
|
68
|
+
};
|
|
69
|
+
export type QoderSessionForkArguments = {
|
|
70
|
+
sessionId?: string;
|
|
71
|
+
dir?: string;
|
|
72
|
+
title?: string;
|
|
73
|
+
upToMessageId?: string;
|
|
74
|
+
};
|
|
75
|
+
export type QoderMcpAuthArguments = {
|
|
76
|
+
server: string;
|
|
77
|
+
callbackUrl?: string;
|
|
78
|
+
redirectUri?: string;
|
|
79
|
+
};
|
|
80
|
+
export declare function safeDisplay(value: unknown, fallback: string, maxLength?: number): string;
|
|
81
|
+
export declare function closePendingMcpAuth(pendingMcpAuth: Map<string, PendingMcpAuth>, serverName: string): Promise<void>;
|
|
82
|
+
export declare function closeAllPendingMcpAuth(pendingMcpAuth: Map<string, PendingMcpAuth>): Promise<void>;
|
|
83
|
+
export declare function runQoderUsage(_context: QoderCommandContext): Promise<CommandResult>;
|
|
84
|
+
export declare function runQoderModels(context: QoderCommandContext): Promise<CommandResult>;
|
|
85
|
+
export declare function runQoderSessions(_context: QoderCommandContext, input?: QoderSessionsArguments): Promise<CommandResult>;
|
|
86
|
+
export declare function runQoderSessionReset(context: QoderCommandContext, key?: string): Promise<CommandResult>;
|
|
87
|
+
export declare function runQoderSessionFork(context: QoderCommandContext, input?: QoderSessionForkArguments): Promise<CommandResult>;
|
|
88
|
+
export declare function runQoderMcpStatus(context: QoderCommandContext): Promise<CommandResult>;
|
|
89
|
+
export declare function runQoderMcpAuth(context: QoderCommandContext, input: QoderMcpAuthArguments): Promise<CommandResult>;
|
|
90
|
+
export declare function runQoderPlanMode(): CommandResult;
|
|
91
|
+
export declare function executeQoderCommand(name: string, rawArguments: string, context: QoderCommandContext): Promise<CommandResult>;
|
|
92
|
+
//# sourceMappingURL=command-actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-actions.d.ts","sourceRoot":"","sources":["../src/command-actions.ts"],"names":[],"mappings":"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"}
|