opencode-qoder-bridge 0.1.10 → 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/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases use
5
5
  [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.1.11] - 2026-09-01
8
+
9
+ ### Added
10
+
11
+ - Automatically registers `/qoder_usage`, `/qoder_models`, `/qoder_sessions`,
12
+ `/qoder_session_reset`, `/qoder_session_fork`, `/qoder_mcp_status`,
13
+ `/qoder_mcp_auth`, and `/qoder_plan_mode` as local OpenCode TUI commands
14
+ without requiring manual `opencode.json` or `tui.json` edits.
15
+ - Displays command results in local modal boxes without creating an LLM turn or
16
+ consuming model tokens; the matching tools remain available for agent use.
17
+ - Updated `@qoder-ai/qoder-agent-sdk` to `1.0.31`, paired with qodercli
18
+ `1.1.38`.
19
+ - Added opt-in SDK-native `memory` and `securityScan` provider options.
20
+ - Flushes configured memory and skill-evolution background work after
21
+ successful turns with a bounded, non-fatal wait.
22
+ - Added `qoder_mcp_status` and `qoder_mcp_auth` tools for MCP health checks and
23
+ Qoder's active OAuth flow.
24
+ - Added `qoder_session_fork` for independent local transcript branches.
25
+
26
+ ### Changed
27
+
28
+ - The bridge package version is `0.1.11`.
29
+
7
30
  ## [0.1.10] - 2026-08-30
8
31
 
9
32
  ### Changed
@@ -224,3 +247,4 @@ also verified with an in-process MCP transport.
224
247
  [0.1.8]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.7...v0.1.8
225
248
  [0.1.9]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.8...v0.1.9
226
249
  [0.1.10]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.9...v0.1.10
250
+ [0.1.11]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.10...v0.1.11
package/README.md CHANGED
@@ -44,6 +44,19 @@ A ground-up rewrite focused on reliability, performance, and first-class usage/c
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
+ With npm 12, dependency install scripts may be blocked by the consuming
48
+ project's script-approval policy. To download the SDK's bundled Worker
49
+ runtime, approve and rebuild the installed SDK version from that project:
50
+
51
+ ```bash
52
+ npm install-scripts approve @qoder-ai/qoder-agent-sdk
53
+ npm rebuild @qoder-ai/qoder-agent-sdk
54
+ ```
55
+
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
+
47
60
  ## Install
48
61
 
49
62
  For a published npm installation, add this to
@@ -100,11 +113,12 @@ SDK exposes only a rounded whole-account quota, not its per-request Credits Log.
100
113
  The authoritative account balance still comes from SDK `userQuota`, refreshing
101
114
  after each completed Qoder turn and every 30 seconds while active.
102
115
 
103
- OpenCode 1.18.5 loads server plugins and TUI plugins independently. On its
104
- first load, the bridge safely adds its bundled TUI entry to the global
105
- `tui.json`, preserving existing settings. Restart OpenCode once after initial
106
- installation so the TUI loader can activate it. The resulting entry is
107
- equivalent to:
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:
108
122
 
109
123
  ```json
110
124
  {
@@ -231,7 +245,33 @@ preserving your configured `permissionMode`:
231
245
  }
232
246
  ```
233
247
 
234
- Run `/qoder_plan_mode` in OpenCode for quick guidance.
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.
235
275
 
236
276
  ### Proxy & Network Routing
237
277
 
@@ -253,6 +293,68 @@ environment variables (supports `http://`, `https://`, `socks5://`, and `socks:/
253
293
  If `proxy` is omitted, the bridge automatically falls back to `HTTPS_PROXY` or
254
294
  `HTTP_PROXY` from your environment.
255
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:
301
+
302
+ ```json
303
+ {
304
+ "provider": {
305
+ "qoder": {
306
+ "options": {
307
+ "memory": {
308
+ "mode": "native",
309
+ "projectScope": true,
310
+ "userScope": false
311
+ }
312
+ }
313
+ }
314
+ }
315
+ }
316
+ ```
317
+
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.
321
+
322
+ ### Security Scan
323
+
324
+ Security checks are opt-in and disabled unless explicitly configured:
325
+
326
+ ```json
327
+ {
328
+ "provider": {
329
+ "qoder": {
330
+ "options": {
331
+ "securityScan": {
332
+ "l1StaticCheck": true,
333
+ "l2LightweightScan": true,
334
+ "l3DeepScan": false
335
+ }
336
+ }
337
+ }
338
+ }
339
+ }
340
+ ```
341
+
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.
345
+
346
+ ### MCP OAuth and session forks
347
+
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.
353
+
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.
357
+
256
358
  ### Skill Evolution
257
359
 
258
360
  Enable autonomous turn-completion skill analysis and recommendations:
@@ -279,6 +381,9 @@ The plugin registers several built-in OpenCode tools:
279
381
  - `qoder_models` — List known Qoder models, context limits, vision/reasoning flags, and multipliers.
280
382
  - `qoder_sessions` — List recent Qoder sessions, session IDs, branches, and timestamps via SDK `listSessions()`.
281
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.
282
387
  - `qoder_plan_mode` — View Plan Mode status and configuration guidance.
283
388
 
284
389
  ## Troubleshooting
@@ -290,6 +395,11 @@ The plugin registers several built-in OpenCode tools:
290
395
  | Model not found | Run `opencode models qoder` or `/qoder_models`; model IDs are account- and scene-specific |
291
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 |
292
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
+
293
403
  ### How model discovery works
294
404
 
295
405
  At startup the bridge performs a bounded live catalog discovery from Qoder
@@ -309,6 +419,7 @@ npm install
309
419
  npm run build # compile to dist/
310
420
  npm run typecheck # type-check only
311
421
  npm test # build and run the test suite
422
+ npm run test:stress # deterministic stress suite; live abort stress is opt-in
312
423
  npm run test:e2e # authenticated real-CLI test; requires QODER_E2E=1
313
424
  npm run check # full pre-publish verification
314
425
  ```
@@ -330,6 +441,9 @@ consume account quota. Run it only after `qoder login`:
330
441
  QODER_E2E=1 npm run test:e2e
331
442
  ```
332
443
 
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
+
333
447
  ## Security
334
448
 
335
449
  Report suspected vulnerabilities privately as described in
package/RELEASING.md CHANGED
@@ -1,27 +1,28 @@
1
1
  # Releasing
2
2
 
3
- ## Before the first release
3
+ ## Before a public release
4
4
 
5
5
  1. Confirm that publishing this integration and using the Qoder name and SDK
6
6
  complies with the current Qoder Product Service Terms. Keep any written
7
7
  permission with the project records.
8
- 2. Create the public GitHub repository:
8
+ 2. Confirm the public GitHub repository is available:
9
9
  `https://github.com/naoufalelbani/opencode-qoder-bridge`.
10
10
  3. Create an npm account, enable two-factor authentication, and run `npm login`.
11
11
  4. Review production dependency advisories with `npm audit --omit=dev`. Do not
12
12
  apply forced or major-version fixes without running the full integration
13
13
  suite.
14
14
 
15
- ## First publish
15
+ ## Public publish
16
16
 
17
17
  Run the complete release gate from a clean checkout:
18
18
 
19
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
+ npm publish --access public
25
26
  ```
26
27
 
27
28
  The end-to-end gate is mandatory for any release that touches
@@ -37,6 +38,15 @@ Verify the registry package and install it through OpenCode:
37
38
  npm view opencode-qoder-bridge
38
39
  ```
39
40
 
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:
44
+
45
+ ```bash
46
+ npm install-scripts approve @qoder-ai/qoder-agent-sdk@1.0.31
47
+ npm rebuild @qoder-ai/qoder-agent-sdk
48
+ ```
49
+
40
50
  ```json
41
51
  {
42
52
  "plugin": ["opencode-qoder-bridge"]
@@ -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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"}