opencode-qoder-bridge 0.1.11 → 0.1.12

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/RELEASING.md CHANGED
@@ -1,40 +1,40 @@
1
- # Releasing
2
-
1
+ # Releasing
2
+
3
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.
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
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
-
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
15
  ## Public publish
16
-
17
- Run the complete release gate from a clean checkout:
18
-
19
- ```bash
16
+
17
+ Run the complete release gate from a clean checkout:
18
+
19
+ ```bash
20
20
  npm ci
21
21
  npm run check
22
22
  npm run test:stress
23
23
  QODER_E2E=1 npm run test:e2e # requires qoder login; consumes quota
24
24
  npm pack --dry-run
25
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
-
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
+
35
35
  Verify the registry package and install it through OpenCode:
36
-
37
- ```bash
36
+
37
+ ```bash
38
38
  npm view opencode-qoder-bridge
39
39
  ```
40
40
 
@@ -46,38 +46,38 @@ the bundled Worker runtime is required:
46
46
  npm install-scripts approve @qoder-ai/qoder-agent-sdk@1.0.31
47
47
  npm rebuild @qoder-ai/qoder-agent-sdk
48
48
  ```
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
-
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.
@@ -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
+
@@ -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
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"language-model.d.ts","sourceRoot":"","sources":["../src/language-model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"language-model.d.ts","sourceRoot":"","sources":["../src/language-model.ts"],"names":[],"mappings":"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"}
@@ -180,6 +180,13 @@ function requestTimeoutMs(value) {
180
180
  return DEFAULT_REQUEST_TIMEOUT_MS;
181
181
  return Math.min(MAX_REQUEST_TIMEOUT_MS, Math.max(1, Math.floor(value)));
182
182
  }
183
+ function boundedMilliseconds(value, fallback, max) {
184
+ if (value === undefined)
185
+ return undefined;
186
+ if (typeof value !== "number" || !Number.isFinite(value))
187
+ return fallback;
188
+ return Math.min(max, Math.max(0, Math.floor(value)));
189
+ }
183
190
  function abortError() {
184
191
  const error = new Error("Qoder request aborted");
185
192
  error.name = "AbortError";
@@ -735,6 +742,12 @@ export class QoderLanguageModel {
735
742
  cwd,
736
743
  abortController,
737
744
  };
745
+ const controlRequestTimeoutMs = boundedMilliseconds(this.bridgeOptions.controlRequestTimeoutMs, 60_000, 5 * 60_000);
746
+ if (controlRequestTimeoutMs !== undefined)
747
+ opts.controlRequestTimeoutMs = controlRequestTimeoutMs;
748
+ const closeGraceMs = boundedMilliseconds(this.bridgeOptions.closeGraceMs, 2_000, CLEANUP_GRACE_MS);
749
+ if (closeGraceMs !== undefined)
750
+ opts.closeGraceMs = closeGraceMs;
738
751
  if (onAuthExpired)
739
752
  opts.onAuthExpired = onAuthExpired;
740
753
  if (cli)