opencode-qoder-bridge 0.1.9 → 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 +241 -204
- package/LICENSE +21 -21
- package/README.md +413 -305
- 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 +232 -15
- package/dist/index.js.map +1 -1
- package/dist/language-model.d.ts +3 -0
- package/dist/language-model.d.ts.map +1 -1
- package/dist/language-model.js +55 -5
- package/dist/language-model.js.map +1 -1
- package/dist/models.d.ts +19 -7
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +342 -94
- package/dist/models.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 +9 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +118 -117
package/README.md
CHANGED
|
@@ -1,351 +1,459 @@
|
|
|
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
|
-
## Quick start
|
|
22
|
-
|
|
23
|
-
1. Use Node.js 22.22.2 or newer, or Node.js 24.15.0 or newer.
|
|
24
|
-
|
|
25
|
-
2. Install OpenCode and this plugin:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
npm install -g opencode-ai
|
|
29
|
-
npm install opencode-qoder-bridge
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
3. Authenticate with a Qoder PAT (recommended):
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
export QODER_PERSONAL_ACCESS_TOKEN="pt-..."
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Or use the Qoder CLI login flow:
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
qoder login
|
|
42
|
-
```
|
|
43
|
-
|
|
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
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
1. Use Node.js 22.22.2 or newer, or Node.js 24.15.0 or newer.
|
|
24
|
+
|
|
25
|
+
2. Install OpenCode and this plugin:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g opencode-ai
|
|
29
|
+
npm install opencode-qoder-bridge
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
3. Authenticate with a Qoder PAT (recommended):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
export QODER_PERSONAL_ACCESS_TOKEN="pt-..."
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or use the Qoder CLI login flow:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
qoder login
|
|
42
|
+
```
|
|
43
|
+
|
|
44
44
|
PAT authentication uses the SDK's worker runtime when available and does not
|
|
45
45
|
require a local `qoder login`. CLI authentication remains supported.
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
`~/.config/opencode/opencode.json`:
|
|
51
|
-
|
|
52
|
-
```json
|
|
53
|
-
{
|
|
54
|
-
"plugin": ["opencode-qoder-bridge"]
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
For a local checkout or an unpublished package, point OpenCode at the built
|
|
59
|
-
plugin entry directly:
|
|
60
|
-
|
|
61
|
-
```json
|
|
62
|
-
{
|
|
63
|
-
"plugin": [
|
|
64
|
-
"file:///absolute/path/to/opencode-qoder-bridge/dist/index.js"
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
opencode installs published npm plugins automatically on startup. A bare package
|
|
70
|
-
name must exist in the npm registry; installing an unpublished package only in
|
|
71
|
-
`~/.config/opencode/node_modules` is not enough for current opencode releases.
|
|
72
|
-
Once loaded, the plugin injects the `qoder` provider and all models — no manual
|
|
73
|
-
`provider` block required.
|
|
74
|
-
|
|
75
|
-
## Usage
|
|
47
|
+
With npm 12, dependency install scripts may be blocked by the consuming
|
|
48
|
+
project's script-approval policy. To download SDK `1.0.31`'s bundled Worker
|
|
49
|
+
runtime, approve and rebuild it from that project:
|
|
76
50
|
|
|
77
51
|
```bash
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
opencode -m qoder/performance # interactive
|
|
52
|
+
npm install-scripts approve @qoder-ai/qoder-agent-sdk@1.0.31
|
|
53
|
+
npm rebuild @qoder-ai/qoder-agent-sdk
|
|
81
54
|
```
|
|
82
55
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
`
|
|
56
|
+
If you use a separately installed `qoder` CLI or intentionally set
|
|
57
|
+
`QODER_SKIP_DOWNLOAD=1`, this step is not required; the bridge can use that
|
|
58
|
+
runtime fallback instead.
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
For a published npm installation, add this to
|
|
63
|
+
`~/.config/opencode/opencode.json`:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"plugin": ["opencode-qoder-bridge"]
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For a local checkout or an unpublished package, point OpenCode at the built
|
|
72
|
+
plugin entry directly:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"plugin": [
|
|
77
|
+
"file:///absolute/path/to/opencode-qoder-bridge/dist/index.js"
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
opencode installs published npm plugins automatically on startup. A bare package
|
|
83
|
+
name must exist in the npm registry; installing an unpublished package only in
|
|
84
|
+
`~/.config/opencode/node_modules` is not enough for current opencode releases.
|
|
85
|
+
Once loaded, the plugin injects the `qoder` provider and all models — no manual
|
|
86
|
+
`provider` block required.
|
|
87
|
+
|
|
88
|
+
## Usage
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
opencode run -m qoder/lite "say hello" # free model
|
|
92
|
+
opencode run -m qoder/auto "explain async/await"
|
|
93
|
+
opencode -m qoder/performance # interactive
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Usage & cost
|
|
97
|
+
|
|
98
|
+
Run `qoder-usage` in a terminal for the live report, or add the statusline
|
|
99
|
+
binary to your OpenCode statusline config:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
opencode-qoder-bridge
|
|
103
|
+
# qoder: cost $0.0123 · turns 1 · tok 1500 · last performance
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The package also exports a TUI entry at `opencode-qoder-bridge/tui`. It shows
|
|
107
|
+
live Qoder credits only while the current session's selected provider is
|
|
108
|
+
`qoder`; it stays hidden and does not query quota for other providers. The
|
|
109
|
+
sidebar shows OpenCode's session spend with four-decimal precision and derives
|
|
110
|
+
fractional session Credits from Qoder's cent-denominated reference cost
|
|
111
|
+
(`session.cost * 100`). The value is marked with `~` because Qoder's personal
|
|
112
|
+
SDK exposes only a rounded whole-account quota, not its per-request Credits Log.
|
|
113
|
+
The authoritative account balance still comes from SDK `userQuota`, refreshing
|
|
114
|
+
after each completed Qoder turn and every 30 seconds while active.
|
|
115
|
+
|
|
116
|
+
OpenCode loads server plugins and TUI plugins independently. On its first
|
|
117
|
+
load, the bridge safely adds its bundled TUI entry to the global
|
|
118
|
+
`~/.config/opencode/tui.json`, preserving existing settings. Restart OpenCode
|
|
119
|
+
once after initial installation so the TUI loader can activate it. The regular
|
|
120
|
+
TUI loads these commands; OpenCode's `--mini` interface does not load external
|
|
121
|
+
TUI plugins in current releases. The resulting entry is equivalent to:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"$schema": "https://opencode.ai/tui.json",
|
|
126
|
+
"plugin": ["file:///path/to/opencode-qoder-bridge/dist/tui.js"]
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The ledger accumulates across sessions. Delete `~/.config/opencode-qoder-bridge/usage.json` to reset it.
|
|
131
|
+
|
|
132
|
+
## Models
|
|
133
|
+
|
|
134
|
+
The bridge discovers the available catalog at startup through the SDK's
|
|
135
|
+
`getAvailableModels()` API. Availability is account-, region-, rollout-, and
|
|
136
|
+
SDK-version-dependent. A permanent allowlist is intentionally not embedded
|
|
137
|
+
here because the catalog is account- and scene-dependent.
|
|
138
|
+
|
|
139
|
+
There is intentionally no static model table here. Model availability is
|
|
140
|
+
account-, region-, plan-, scene-, SDK-version-, and rollout-dependent, and the
|
|
141
|
+
SDK's live catalog is authoritative for selectable IDs, capabilities, context
|
|
142
|
+
limits, and pricing.
|
|
143
|
+
|
|
144
|
+
Run `opencode models qoder` to inspect the models currently registered with
|
|
145
|
+
OpenCode. The `qoder_models` tool also exposes capabilities, context limits,
|
|
146
|
+
and price multipliers to the agent. On each plugin startup, the bridge performs
|
|
147
|
+
bounded live discovery automatically; if Qoder is unavailable, it uses the
|
|
148
|
+
last catalog for the same credential/deployment context and the built-ins.
|
|
149
|
+
|
|
150
|
+
## Configuration
|
|
151
|
+
|
|
152
|
+
Bridge opencode MCP servers into the SDK by passing provider options:
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"provider": {
|
|
157
|
+
"qoder": {
|
|
158
|
+
"options": {
|
|
159
|
+
"extraArgs": { "--experimental-mcp-load": null }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Flag names may be written with or without the leading `--`.
|
|
167
|
+
|
|
168
|
+
`config.mcp` servers are bridged into the SDK's `mcpServers` automatically.
|
|
169
|
+
Chat turns have a 30-minute bridge timeout by default; set `options.timeoutMs`
|
|
170
|
+
to a positive value to use a shorter or longer bounded timeout (up to 24 hours).
|
|
171
|
+
Values in `options.env` override inherited process variables rather than
|
|
172
|
+
replacing the complete child environment.
|
|
173
|
+
|
|
174
|
+
### Persistent sessions and permissions
|
|
175
|
+
|
|
176
|
+
Session persistence is opt-in. Give a provider configuration a stable
|
|
177
|
+
`sessionKey` and enable `sessionPersistence`:
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"provider": {
|
|
182
|
+
"qoder": {
|
|
183
|
+
"options": {
|
|
184
|
+
"sessionPersistence": true,
|
|
185
|
+
"sessionKey": "my-project-main"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Mappings are stored in
|
|
193
|
+
`~/.config/opencode-qoder-bridge/sessions.json` with restrictive file
|
|
194
|
+
permissions and are scoped to the configured working directory. The plugin
|
|
195
|
+
uses OpenCode's project directory when available; set `options.cwd` when
|
|
196
|
+
loading the provider directly. Use the `qoder_session_reset` tool to forget
|
|
197
|
+
the mapping. A new session is created automatically if the mapping does not
|
|
198
|
+
exist; existing sessions are resumed through the Qoder SDK.
|
|
199
|
+
|
|
200
|
+
Qoder-native and bridged MCP tools remain provider-owned. If OpenCode supplies
|
|
201
|
+
a function with a colliding native name, the bridge derives a Qoder deny rule
|
|
202
|
+
to avoid executing the same operation in both runtimes.
|
|
203
|
+
|
|
204
|
+
The bridge uses the SDK's safer permission policy by default. To explicitly
|
|
205
|
+
allow all Qoder tools in a trusted local environment, configure for example:
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"provider": {
|
|
210
|
+
"qoder": {
|
|
211
|
+
"options": {
|
|
212
|
+
"permissionMode": "default",
|
|
213
|
+
"allowedTools": ["Read", "Glob", "Grep"]
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Available permission modes are `default`, `acceptEdits`, and
|
|
221
|
+
`bypassPermissions`. Only explicitly configure `bypassPermissions` when the
|
|
222
|
+
host environment is trusted.
|
|
223
|
+
|
|
224
|
+
Image inputs may reference `file://`, `~/`, or absolute local paths. Only pass
|
|
225
|
+
paths from trusted callers: the bridge bounds image size but does not sandbox
|
|
226
|
+
or restrict readable local files to the project directory. A current turn is
|
|
227
|
+
limited to 64 images and 40 MiB of decoded image data; excess attachments are
|
|
228
|
+
reported as omitted text.
|
|
229
|
+
|
|
230
|
+
### Plan Mode
|
|
231
|
+
|
|
232
|
+
Plan Mode instructs Qoder to analyze and plan changes without modifying files
|
|
233
|
+
or running action tools. It operates independently from tool permissions,
|
|
234
|
+
preserving your configured `permissionMode`:
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"provider": {
|
|
239
|
+
"qoder": {
|
|
240
|
+
"options": {
|
|
241
|
+
"planMode": true
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The plugin automatically registers the following local TUI slash commands in
|
|
249
|
+
OpenCode. No manual `opencode.json` edits are required; restart OpenCode after
|
|
250
|
+
installing or updating the plugin, then select the command from the `/`
|
|
251
|
+
autocomplete list:
|
|
252
|
+
|
|
253
|
+
The implementations remain registered, but the TUI marks commands as hidden
|
|
254
|
+
when their prerequisites are absent; it does not disable or delete them. With
|
|
255
|
+
the default configuration, only `/qoder_usage` and `/qoder_models` appear.
|
|
256
|
+
Session commands appear when session persistence, `sessionKey`, or `sessionId`
|
|
257
|
+
is configured. MCP commands appear when at least one MCP server is configured.
|
|
258
|
+
`/qoder_plan_mode` remains hidden because it currently provides guidance only.
|
|
259
|
+
|
|
260
|
+
| Command | Arguments | Purpose |
|
|
261
|
+
|---------|-----------|---------|
|
|
262
|
+
| `/qoder_usage` | none | Show live quota and local cost/token totals. |
|
|
263
|
+
| `/qoder_models` | none | List available Qoder models and capabilities. |
|
|
264
|
+
| `/qoder_sessions` | optional directory and/or limit | List recent Qoder sessions. |
|
|
265
|
+
| `/qoder_session_reset` | optional key, or `all` | Reset persisted session mappings. |
|
|
266
|
+
| `/qoder_session_fork` | optional session ID, directory, title, cutoff | Create an independent session branch. |
|
|
267
|
+
| `/qoder_mcp_status` | none | Inspect MCP connection and OAuth status. |
|
|
268
|
+
| `/qoder_mcp_auth` | server, then optional callback URL | Start or complete MCP OAuth. |
|
|
269
|
+
| `/qoder_plan_mode` | none | Show Plan Mode status and configuration guidance. |
|
|
270
|
+
|
|
271
|
+
These commands execute in the TUI and show their result in a modal box. They do
|
|
272
|
+
not create an LLM turn or consume model tokens. Commands that accept arguments
|
|
273
|
+
open a local input box first. The same names are also registered as tools for
|
|
274
|
+
agent use, which is a separate model-driven path.
|
|
275
|
+
|
|
276
|
+
### Proxy & Network Routing
|
|
277
|
+
|
|
278
|
+
Pass an outbound proxy URL directly to the Qoder runtime without mutating host
|
|
279
|
+
environment variables (supports `http://`, `https://`, `socks5://`, and `socks://`):
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{
|
|
283
|
+
"provider": {
|
|
284
|
+
"qoder": {
|
|
285
|
+
"options": {
|
|
286
|
+
"proxy": "http://127.0.0.1:8888"
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
If `proxy` is omitted, the bridge automatically falls back to `HTTPS_PROXY` or
|
|
294
|
+
`HTTP_PROXY` from your environment.
|
|
295
|
+
|
|
296
|
+
### Memory
|
|
297
|
+
|
|
298
|
+
Memory is opt-in. Native mode lets Qoder consume project/user memory and run
|
|
299
|
+
turn-completion generation while keeping generated content under Qoder's own
|
|
300
|
+
memory controls:
|
|
173
301
|
|
|
174
302
|
```json
|
|
175
303
|
{
|
|
176
304
|
"provider": {
|
|
177
305
|
"qoder": {
|
|
178
306
|
"options": {
|
|
179
|
-
"
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
Mappings are stored in
|
|
188
|
-
`~/.config/opencode-qoder-bridge/sessions.json` with restrictive file
|
|
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.
|
|
198
|
-
|
|
199
|
-
The bridge uses the SDK's safer permission policy by default. To explicitly
|
|
200
|
-
allow all Qoder tools in a trusted local environment, configure for example:
|
|
201
|
-
|
|
202
|
-
```json
|
|
203
|
-
{
|
|
204
|
-
"provider": {
|
|
205
|
-
"qoder": {
|
|
206
|
-
"options": {
|
|
207
|
-
"permissionMode": "default",
|
|
208
|
-
"allowedTools": ["Read", "Glob", "Grep"]
|
|
307
|
+
"memory": {
|
|
308
|
+
"mode": "native",
|
|
309
|
+
"projectScope": true,
|
|
310
|
+
"userScope": false
|
|
311
|
+
}
|
|
209
312
|
}
|
|
210
313
|
}
|
|
211
314
|
}
|
|
212
315
|
}
|
|
213
316
|
```
|
|
214
317
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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.
|
|
318
|
+
The bridge waits up to 10 seconds for Qoder's memory/evolution background work
|
|
319
|
+
after a successful turn, then closes the query. A slow or failed background
|
|
320
|
+
operation is logged in debug mode and does not fail the user turn.
|
|
224
321
|
|
|
225
|
-
###
|
|
322
|
+
### Security Scan
|
|
226
323
|
|
|
227
|
-
|
|
228
|
-
or running action tools. It operates independently from tool permissions,
|
|
229
|
-
preserving your configured `permissionMode`:
|
|
324
|
+
Security checks are opt-in and disabled unless explicitly configured:
|
|
230
325
|
|
|
231
326
|
```json
|
|
232
327
|
{
|
|
233
328
|
"provider": {
|
|
234
329
|
"qoder": {
|
|
235
330
|
"options": {
|
|
236
|
-
"
|
|
331
|
+
"securityScan": {
|
|
332
|
+
"l1StaticCheck": true,
|
|
333
|
+
"l2LightweightScan": true,
|
|
334
|
+
"l3DeepScan": false
|
|
335
|
+
}
|
|
237
336
|
}
|
|
238
337
|
}
|
|
239
338
|
}
|
|
240
339
|
}
|
|
241
340
|
```
|
|
242
341
|
|
|
243
|
-
|
|
342
|
+
L1 runs after supported edits; L2/L3 enable repository scans. These checks do
|
|
343
|
+
not replace the bridge's permission policy and may consume additional Qoder
|
|
344
|
+
credits.
|
|
244
345
|
|
|
245
|
-
###
|
|
346
|
+
### MCP OAuth and session forks
|
|
246
347
|
|
|
247
|
-
|
|
248
|
-
|
|
348
|
+
Use `qoder_mcp_status` to inspect configured server state. For a server with
|
|
349
|
+
`needs-auth`, run `qoder_mcp_auth` without `callbackUrl`, open the returned
|
|
350
|
+
authorization URL, then run it again with the complete OAuth callback URL.
|
|
351
|
+
The bridge keeps the initialized SDK query alive for this two-step flow and
|
|
352
|
+
expires it after ten minutes.
|
|
249
353
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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.
|
|
354
|
+
Use `qoder_session_fork` to create an independent local transcript branch.
|
|
355
|
+
The active provider mapping is intentionally unchanged; continue the returned
|
|
356
|
+
session ID explicitly when you want to work on the fork.
|
|
264
357
|
|
|
265
358
|
### 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.
|
|
359
|
+
|
|
360
|
+
Enable autonomous turn-completion skill analysis and recommendations:
|
|
361
|
+
|
|
362
|
+
```json
|
|
363
|
+
{
|
|
364
|
+
"provider": {
|
|
365
|
+
"qoder": {
|
|
366
|
+
"options": {
|
|
367
|
+
"evolution": {
|
|
368
|
+
"skill": { "mode": "native" }
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Available Tools
|
|
377
|
+
|
|
378
|
+
The plugin registers several built-in OpenCode tools:
|
|
379
|
+
|
|
380
|
+
- `qoder_usage` — Live account balance, quota percentages, and local cost ledger totals.
|
|
381
|
+
- `qoder_models` — List known Qoder models, context limits, vision/reasoning flags, and multipliers.
|
|
382
|
+
- `qoder_sessions` — List recent Qoder sessions, session IDs, branches, and timestamps via SDK `listSessions()`.
|
|
383
|
+
- `qoder_session_reset` — Forget the persisted Qoder session mapping for the active project.
|
|
384
|
+
- `qoder_session_fork` — Fork a local Qoder transcript without changing the active mapping.
|
|
385
|
+
- `qoder_mcp_status` — Show MCP connection, tool-count, and OAuth state.
|
|
386
|
+
- `qoder_mcp_auth` — Start or complete active MCP OAuth authentication.
|
|
291
387
|
- `qoder_plan_mode` — View Plan Mode status and configuration guidance.
|
|
292
|
-
|
|
293
|
-
## Troubleshooting
|
|
294
|
-
|
|
295
|
-
| Problem | Solution |
|
|
296
|
-
|---------|----------|
|
|
297
|
-
| Auth prompt at startup | Run `qoder login`, then restart opencode |
|
|
298
|
-
|
|
|
299
|
-
| Model not found |
|
|
300
|
-
| Missing models in the model list |
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
388
|
+
|
|
389
|
+
## Troubleshooting
|
|
390
|
+
|
|
391
|
+
| Problem | Solution |
|
|
392
|
+
|---------|----------|
|
|
393
|
+
| Auth prompt at startup | Run `qoder login`, then restart opencode |
|
|
394
|
+
| Qoder runtime unavailable | Authenticate with `qoder login` or set `QODER_PERSONAL_ACCESS_TOKEN`; the bridge uses the SDK's bundled Worker runtime for model discovery and can fall back to an installed CLI automatically |
|
|
395
|
+
| Model not found | Run `opencode models qoder` or `/qoder_models`; model IDs are account- and scene-specific |
|
|
396
|
+
| Missing models in the model list | Restart OpenCode; the bridge performs a live catalog lookup automatically and falls back to the last scoped 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 |
|
|
397
|
+
|
|
398
|
+
The SDK package `1.0.31` bundles qodercli `1.1.38`. If the bridge discovers a
|
|
399
|
+
separately installed qodercli first, update that CLI through its normal Qoder
|
|
400
|
+
CLI installer too so the MCP OAuth and oversized-image compaction fixes are
|
|
401
|
+
active on that path.
|
|
402
|
+
|
|
403
|
+
### How model discovery works
|
|
404
|
+
|
|
405
|
+
At startup the bridge performs a bounded live catalog discovery from Qoder
|
|
406
|
+
before returning the provider configuration (`fetchStrategy: "live"` — the
|
|
407
|
+
bundled Worker runtime re-queries the server, with an automatic installed-CLI
|
|
408
|
+
fallback when necessary). Each successful catalog snapshot replaces
|
|
409
|
+
previously discovered dynamic IDs, so retired models do not remain selectable.
|
|
410
|
+
A failed, empty, or slow refresh falls back to the last scoped catalog and the
|
|
411
|
+
built-ins; no `qodercli --list-models` command or manual model configuration is
|
|
412
|
+
required. The startup wait is bounded to 10 seconds, after which OpenCode
|
|
413
|
+
continues with the available cache/fallbacks.
|
|
414
|
+
|
|
415
|
+
## Development
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
npm install
|
|
419
|
+
npm run build # compile to dist/
|
|
420
|
+
npm run typecheck # type-check only
|
|
317
421
|
npm test # build and run the test suite
|
|
422
|
+
npm run test:stress # deterministic stress suite; live abort stress is opt-in
|
|
318
423
|
npm run test:e2e # authenticated real-CLI test; requires QODER_E2E=1
|
|
319
|
-
npm run check # full pre-publish verification
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
### Diagnostics
|
|
323
|
-
|
|
324
|
-
Set `QODER_BRIDGE_DEBUG=1` before launching opencode to emit detailed bridge
|
|
325
|
-
logs (model fallbacks, stream aborts,
|
|
326
|
-
session-store I/O failures). Warnings that need attention are always printed.
|
|
327
|
-
|
|
328
|
-
State files (usage ledger, session mapping, model cache) live under
|
|
329
|
-
`~/.config/opencode-qoder-bridge` by default; override with
|
|
330
|
-
`QODER_BRIDGE_STATE_DIR`, or relocate via `XDG_CONFIG_HOME`.
|
|
331
|
-
|
|
424
|
+
npm run check # full pre-publish verification
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Diagnostics
|
|
428
|
+
|
|
429
|
+
Set `QODER_BRIDGE_DEBUG=1` before launching opencode to emit detailed bridge
|
|
430
|
+
logs (model fallbacks, stream aborts, live catalog discovery, ledger and
|
|
431
|
+
session-store I/O failures). Warnings that need attention are always printed.
|
|
432
|
+
|
|
433
|
+
State files (usage ledger, session mapping, model cache) live under
|
|
434
|
+
`~/.config/opencode-qoder-bridge` by default; override with
|
|
435
|
+
`QODER_BRIDGE_STATE_DIR`, or relocate via `XDG_CONFIG_HOME`.
|
|
436
|
+
|
|
332
437
|
The end-to-end test is intentionally opt-in because it starts Qoder and may
|
|
333
438
|
consume account quota. Run it only after `qoder login`:
|
|
334
|
-
|
|
335
|
-
```bash
|
|
439
|
+
|
|
440
|
+
```bash
|
|
336
441
|
QODER_E2E=1 npm run test:e2e
|
|
337
442
|
```
|
|
338
443
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
444
|
+
To include the live concurrent-abort probe in the stress suite, set
|
|
445
|
+
`QODER_STRESS_E2E=1` as well as a valid Qoder credential.
|
|
446
|
+
|
|
447
|
+
## Security
|
|
448
|
+
|
|
449
|
+
Report suspected vulnerabilities privately as described in
|
|
450
|
+
[SECURITY.md](./SECURITY.md). Do not include Qoder credentials, npm tokens, or
|
|
451
|
+
private prompt content in reports.
|
|
452
|
+
|
|
453
|
+
Maintainer release instructions are in [RELEASING.md](./RELEASING.md).
|
|
454
|
+
Release history is recorded in [CHANGELOG.md](./CHANGELOG.md).
|
|
455
|
+
|
|
456
|
+
## License
|
|
457
|
+
|
|
458
|
+
The bridge source is MIT licensed; see [LICENSE](./LICENSE). Dependencies retain
|
|
459
|
+
their own licenses and terms; see [THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md).
|