opencode-qoder-bridge 0.1.8 → 0.1.10
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 +70 -1
- package/README.md +112 -45
- package/bin/statusline.mjs +30 -6
- package/bin/usage.mjs +6 -5
- package/dist/async-utils.d.ts +8 -0
- package/dist/async-utils.d.ts.map +1 -0
- package/dist/async-utils.js +27 -0
- package/dist/async-utils.js.map +1 -0
- package/dist/auth.d.ts +2 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +26 -7
- package/dist/auth.js.map +1 -1
- package/dist/cost.d.ts +2 -1
- package/dist/cost.d.ts.map +1 -1
- package/dist/cost.js +163 -63
- package/dist/cost.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +5 -2
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +187 -41
- package/dist/index.js.map +1 -1
- package/dist/language-model.d.ts +25 -0
- package/dist/language-model.d.ts.map +1 -1
- package/dist/language-model.js +938 -183
- package/dist/language-model.js.map +1 -1
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +35 -5
- package/dist/logger.js.map +1 -1
- package/dist/mcp-bridge.d.ts.map +1 -1
- package/dist/mcp-bridge.js +71 -7
- package/dist/mcp-bridge.js.map +1 -1
- package/dist/models.d.ts +25 -6
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +444 -85
- package/dist/models.js.map +1 -1
- package/dist/prompt-builder.d.ts.map +1 -1
- package/dist/prompt-builder.js +241 -43
- package/dist/prompt-builder.js.map +1 -1
- package/dist/sdk-auth.d.ts +3 -3
- package/dist/sdk-auth.d.ts.map +1 -1
- package/dist/sdk-auth.js +13 -9
- package/dist/sdk-auth.js.map +1 -1
- package/dist/sdk-session.d.ts.map +1 -1
- package/dist/sdk-session.js +26 -2
- package/dist/sdk-session.js.map +1 -1
- package/dist/session-store.d.ts +14 -3
- package/dist/session-store.d.ts.map +1 -1
- package/dist/session-store.js +451 -46
- package/dist/session-store.js.map +1 -1
- package/dist/state-dir.d.ts.map +1 -1
- package/dist/state-dir.js +2 -1
- package/dist/state-dir.js.map +1 -1
- package/dist/tool-normalizer.d.ts.map +1 -1
- package/dist/tool-normalizer.js +11 -2
- package/dist/tool-normalizer.js.map +1 -1
- package/dist/tui-register.d.ts.map +1 -1
- package/dist/tui-register.js +88 -37
- package/dist/tui-register.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +42 -17
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +16 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +54 -29
- package/dist/usage.js.map +1 -1
- package/package.json +12 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,71 @@ 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.10] - 2026-08-30
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Model discovery now completes a bounded live Qoder catalog lookup during
|
|
12
|
+
plugin startup, so newly available account models are registered
|
|
13
|
+
automatically without a manual model list or cache warm-up restart.
|
|
14
|
+
- Discovery uses the SDK's bundled Worker runtime first, falls back to an
|
|
15
|
+
installed CLI automatically when needed, scopes caches by deployment and
|
|
16
|
+
credential context, and ignores empty or late responses that could otherwise
|
|
17
|
+
replace a known-good catalog.
|
|
18
|
+
|
|
19
|
+
## [0.1.9] - 2026-08-30
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Updated `@qoder-ai/qoder-agent-sdk` to `1.0.30` (paired with `qodercli` 1.1.35).
|
|
24
|
+
- **Plan Mode Integration**: Added `planMode?: boolean` provider option to run in planning mode independently from tool permissions. Registered new `/qoder_plan_mode` tool.
|
|
25
|
+
- **Outbound Proxy Routing**: Added `proxy?: string` provider option for direct qodercli HTTP/HTTPS/SOCKS5 proxy routing without mutating environment variables, with automatic fallback to `HTTPS_PROXY` / `HTTP_PROXY`.
|
|
26
|
+
- **Skill Evolution**: Added `evolution?: EvolutionOptions` provider option to enable autonomous turn-completion skill analysis and recommendations.
|
|
27
|
+
- **Dynamic Live Model Catalog Updates**: Ingests real-time `available_models_update` stream events to synchronize model availability and persistent cache without restarting OpenCode.
|
|
28
|
+
- **Artifacts Tracking**: Ingests `artifacts_update` events during chat turns and surfaces artifact change metadata in `providerMetadata.qoder.artifacts`.
|
|
29
|
+
- **Sessions Tool**: Added `qoder_sessions` tool using SDK's `listSessions()` to inspect recent sessions, titles, and git branches.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- **Runtime Package Boundary**: Moved the runtime-used `@opencode-ai/plugin`
|
|
34
|
+
helper into production dependencies and verified root/provider imports from a
|
|
35
|
+
dev-omitted packed install.
|
|
36
|
+
- **Workspace-Aware Session Safety**: Scoped persisted session mappings by
|
|
37
|
+
workspace, serialized same-key turns, delayed mapping writes until a
|
|
38
|
+
successful turn, and added bounded cross-process state locking.
|
|
39
|
+
- **Catalog, Usage, and Stream Hardening**: Made live model snapshots
|
|
40
|
+
authoritative, bounded discovery/usage requests, closed abort and duplicate
|
|
41
|
+
event races, sanitized malformed SDK usage/metadata, and surfaced typed
|
|
42
|
+
authentication/result failures.
|
|
43
|
+
- **Persistent State and Input Bounds**: Hardened atomic state/config writes,
|
|
44
|
+
model/session cache validation, prompt/image limits, MCP URL/command input,
|
|
45
|
+
and finite cost/statusline accounting.
|
|
46
|
+
- **Unknown Model Transparency**: Unknown requested model IDs are now forwarded
|
|
47
|
+
unchanged to Qoder while the default catalog entry is used only for prompt
|
|
48
|
+
sizing metadata; the bridge no longer silently selects `auto`.
|
|
49
|
+
- **Ephemeral Session Privacy**: Explicitly disables SDK transcript persistence
|
|
50
|
+
for non-persistent turns and auxiliary usage/model discovery queries.
|
|
51
|
+
- **Stream and Boundary Hardening**: Added bounded turn timeouts, abort-aware
|
|
52
|
+
generation failures, bounded query cleanup, malformed-stream rejection,
|
|
53
|
+
replay UUID guards, tool ownership deny rules, diagnostic redaction, and
|
|
54
|
+
stricter MCP URL/command validation.
|
|
55
|
+
- **Release Artifact Safety**: Added a `prepack` rebuild hook, executable usage
|
|
56
|
+
CLI permissions, and a public `./errors` export for the typed error API.
|
|
57
|
+
- **Session Store Concurrency Race Condition**: Added an async mutex queue (`withLock`) to serialize concurrent `ensureQoderSession` and `deleteQoderSession` operations, preventing dropped session records under parallel turns.
|
|
58
|
+
- **Tool Continuation History Trimming**: Fixed a critical bug in `trimToBudget` where the active user prompt was dropped during continuation turns with large assistant/tool outputs, preventing prompts from falling back to `"Hello"`.
|
|
59
|
+
- **Data URL Parsing Hardening**: Added bounded-length and round-trip base64 validation with early rejection of oversized image attachments, preventing avoidable CPU and memory pressure from malformed multi-megabyte inputs.
|
|
60
|
+
- **Stream Controller Abort Safety & Listener Cleanup**: Added `safeEnqueue` and `safeClose` to prevent uncaught `Invalid state: Controller is already closed` exceptions when streams are aborted or cancelled, and cleaned up `abortSignal` event listeners in `language-model.ts` and `sdk-session.ts` to prevent memory leaks on shared signals.
|
|
61
|
+
- **`doGenerate` Provider Metadata**: Fixed `doGenerate` discarding `providerMetadata` (`totalCostUSD`, `contextUsageRatio`, `planMode`, `artifacts`), ensuring parity with `doStream`.
|
|
62
|
+
- **Coalesced Model Cache Writes**: Implemented a coalesced cache write queue in `models.ts` to prevent simultaneous file write contention and eliminate orphaned `.tmp` files under rapid streaming catalog updates.
|
|
63
|
+
- **Atomic File Cleanup & All-Session Reset**: Added `try...finally` temporary file unlinking in `session-store.ts` and `models.ts` to guarantee zero dangling `.tmp` files, and exported `clearAllSessions()` to support full session resets.
|
|
64
|
+
- **Tool Schema & Error Boundaries**: Upgraded plugin tools with `tool()` and `tool.schema` from `@opencode-ai/plugin`, added `key` (and `"all"`) to `qoder_session_reset`, added `dir` and `limit` filtering to `qoder_sessions`, and wrapped tool executions in error boundaries.
|
|
65
|
+
- **Tool Normalization & Path Aliases**: Added `execute_command`, `executecommand`, `run_command`, and `runcommand` mapping to `bash`, added `cmd` alias for command, and added `path` alias for `filePath` across read, write, edit, delete, view, and apply_diff.
|
|
66
|
+
- **MCP Bridge Argument Flexibility**: Converted numeric and boolean arguments in `mcp-bridge` stdio configs without dropping the argument list.
|
|
67
|
+
- **Prompt Serialization Hardening**: Added non-image file attachment serialization in `prompt-builder` so attached text files are preserved, and safely guarded missing `toolCallId` / `toolName`.
|
|
68
|
+
- **TUI & CLI Hardening**: Guarded `latest.model?.providerID` in `tui.ts` against undefined model objects, guarded against non-finite costs (`NaN`) in sidebar and statusline, and trimmed PAT whitespace in `hasQoderPAT()`.
|
|
69
|
+
- **Stress Test Suite**: Added `test/stress.test.mjs` verifying concurrency, massive conversations (1,000 messages), stream aborts, and prototype pollution protection.
|
|
70
|
+
- **CI-Safe Live Stress Coverage**: Made the Qoder-backed stream-abort stress probe opt-in with `QODER_STRESS_E2E=1`, keeping the normal test suite credential-free while preserving live stress coverage when explicitly enabled.
|
|
71
|
+
|
|
7
72
|
## [0.1.8] - 2026-08-26
|
|
8
73
|
|
|
9
74
|
### Fixed
|
|
@@ -78,7 +143,9 @@ All notable changes to this project are documented here. The format follows
|
|
|
78
143
|
session.
|
|
79
144
|
- The `models.json` cache is written atomically with mode 0600 instead of a
|
|
80
145
|
direct partial-write-prone write.
|
|
81
|
-
- Unknown model IDs
|
|
146
|
+
- Unknown model IDs previously fell back to the default model with a debug log
|
|
147
|
+
entry; current releases preserve the requested ID and let Qoder report model
|
|
148
|
+
availability explicitly.
|
|
82
149
|
|
|
83
150
|
## [0.1.3] - 2026-08-20
|
|
84
151
|
|
|
@@ -155,3 +222,5 @@ also verified with an in-process MCP transport.
|
|
|
155
222
|
[0.1.4]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.3...v0.1.4
|
|
156
223
|
[0.1.5]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.4...v0.1.5
|
|
157
224
|
[0.1.8]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.7...v0.1.8
|
|
225
|
+
[0.1.9]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.8...v0.1.9
|
|
226
|
+
[0.1.10]: https://github.com/naoufalelbani/opencode-qoder-bridge/compare/v0.1.9...v0.1.10
|
package/README.md
CHANGED
|
@@ -119,42 +119,19 @@ The ledger accumulates across sessions. Delete `~/.config/opencode-qoder-bridge/
|
|
|
119
119
|
|
|
120
120
|
The bridge discovers the available catalog at startup through the SDK's
|
|
121
121
|
`getAvailableModels()` API. Availability is account-, region-, rollout-, and
|
|
122
|
-
SDK-version-dependent. A
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
| Model ID | Name | Credit multiplier | Vision | Reasoning | Max input | Max output |
|
|
131
|
-
|----------|------|-------------------|--------|-----------|-----------|------------|
|
|
132
|
-
| `auto` | Auto | 1.00x | ✓ | ✗ | 180K | 32K |
|
|
133
|
-
| `ultimate` | Ultimate | 0.80x | ✓ | ✓ | 1M | 32K |
|
|
134
|
-
| `performance` | Performance | 1.10x | ✓ | ✗ | 1M | 32K |
|
|
135
|
-
| `efficient` | Efficient | 0.30x | ✓ | ✗ | 180K | 32K |
|
|
136
|
-
| `lite` | Lite | 0.00x | ✗ | ✗ | 180K | 32K |
|
|
137
|
-
| `cmodel` | Cantus | 1.60x | ✓ | ✓ | 180K | 32K |
|
|
138
|
-
| `qmodel_preview` | Qwen3.8-Max-Preview | 0.01x promo | ✓ | ✓ | 180K | 32K |
|
|
139
|
-
| `qmodel_38max` | Qwen3.8-Max | 0.25x | ✓ | ✓ | 180K | 32K |
|
|
140
|
-
| `qmodel_latest` | Qwen3.7-Max | 0.10x promo | ✓ | ✗ | 1M | 32K |
|
|
141
|
-
| `qmodel` | Qwen3.7-Plus | 0.04x promo | ✓ | ✗ | 1M | 32K |
|
|
142
|
-
| `kmodel_latest` | Kimi-K3 | 0.80x | ✓ | ✗ | 180K | 32K |
|
|
143
|
-
| `kmodel` | Kimi-K2.7-Code | 0.30x | ✓ | ✗ | 256K | 32K |
|
|
144
|
-
| `gm51model` | GLM-5.2 | 0.50x promo | ✓ | ✓ | 1M | 32K |
|
|
145
|
-
| `dmodel` | DeepSeek-V4-Pro | 0.50x | ✓ | ✓ | 1M | 32K |
|
|
146
|
-
| `dfmodel` | DeepSeek-V4-Flash | 0.10x | ✓ | ✓ | 1M | 32K |
|
|
147
|
-
| `mmodel` | MiniMax-M3 | 0.20x | ✓ | ✗ | 1M | 32K |
|
|
148
|
-
|
|
149
|
-
This table is a snapshot, not a hard-coded allowlist. Qoder can vary model
|
|
150
|
-
availability by account, plan, CLI version, or staged rollout. Promotional
|
|
151
|
-
multipliers are time-dependent; the SDK's current `priceFactor` is
|
|
152
|
-
authoritative. Restart OpenCode to refresh the bridge's in-process model cache.
|
|
122
|
+
SDK-version-dependent. A permanent allowlist is intentionally not embedded
|
|
123
|
+
here because the catalog is account- and scene-dependent.
|
|
124
|
+
|
|
125
|
+
There is intentionally no static model table here. Model availability is
|
|
126
|
+
account-, region-, plan-, scene-, SDK-version-, and rollout-dependent, and the
|
|
127
|
+
SDK's live catalog is authoritative for selectable IDs, capabilities, context
|
|
128
|
+
limits, and pricing.
|
|
153
129
|
|
|
154
130
|
Run `opencode models qoder` to inspect the models currently registered with
|
|
155
131
|
OpenCode. The `qoder_models` tool also exposes capabilities, context limits,
|
|
156
|
-
and price multipliers to the agent.
|
|
157
|
-
|
|
132
|
+
and price multipliers to the agent. On each plugin startup, the bridge performs
|
|
133
|
+
bounded live discovery automatically; if Qoder is unavailable, it uses the
|
|
134
|
+
last catalog for the same credential/deployment context and the built-ins.
|
|
158
135
|
|
|
159
136
|
## Configuration
|
|
160
137
|
|
|
@@ -172,7 +149,13 @@ Bridge opencode MCP servers into the SDK by passing provider options:
|
|
|
172
149
|
}
|
|
173
150
|
```
|
|
174
151
|
|
|
152
|
+
Flag names may be written with or without the leading `--`.
|
|
153
|
+
|
|
175
154
|
`config.mcp` servers are bridged into the SDK's `mcpServers` automatically.
|
|
155
|
+
Chat turns have a 30-minute bridge timeout by default; set `options.timeoutMs`
|
|
156
|
+
to a positive value to use a shorter or longer bounded timeout (up to 24 hours).
|
|
157
|
+
Values in `options.env` override inherited process variables rather than
|
|
158
|
+
replacing the complete child environment.
|
|
176
159
|
|
|
177
160
|
### Persistent sessions and permissions
|
|
178
161
|
|
|
@@ -194,9 +177,15 @@ Session persistence is opt-in. Give a provider configuration a stable
|
|
|
194
177
|
|
|
195
178
|
Mappings are stored in
|
|
196
179
|
`~/.config/opencode-qoder-bridge/sessions.json` with restrictive file
|
|
197
|
-
permissions
|
|
198
|
-
|
|
199
|
-
|
|
180
|
+
permissions and are scoped to the configured working directory. The plugin
|
|
181
|
+
uses OpenCode's project directory when available; set `options.cwd` when
|
|
182
|
+
loading the provider directly. Use the `qoder_session_reset` tool to forget
|
|
183
|
+
the mapping. A new session is created automatically if the mapping does not
|
|
184
|
+
exist; existing sessions are resumed through the Qoder SDK.
|
|
185
|
+
|
|
186
|
+
Qoder-native and bridged MCP tools remain provider-owned. If OpenCode supplies
|
|
187
|
+
a function with a colliding native name, the bridge derives a Qoder deny rule
|
|
188
|
+
to avoid executing the same operation in both runtimes.
|
|
200
189
|
|
|
201
190
|
The bridge uses the SDK's safer permission policy by default. To explicitly
|
|
202
191
|
allow all Qoder tools in a trusted local environment, configure for example:
|
|
@@ -218,22 +207,100 @@ Available permission modes are `default`, `acceptEdits`, and
|
|
|
218
207
|
`bypassPermissions`. Only explicitly configure `bypassPermissions` when the
|
|
219
208
|
host environment is trusted.
|
|
220
209
|
|
|
210
|
+
Image inputs may reference `file://`, `~/`, or absolute local paths. Only pass
|
|
211
|
+
paths from trusted callers: the bridge bounds image size but does not sandbox
|
|
212
|
+
or restrict readable local files to the project directory. A current turn is
|
|
213
|
+
limited to 64 images and 40 MiB of decoded image data; excess attachments are
|
|
214
|
+
reported as omitted text.
|
|
215
|
+
|
|
216
|
+
### Plan Mode
|
|
217
|
+
|
|
218
|
+
Plan Mode instructs Qoder to analyze and plan changes without modifying files
|
|
219
|
+
or running action tools. It operates independently from tool permissions,
|
|
220
|
+
preserving your configured `permissionMode`:
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"provider": {
|
|
225
|
+
"qoder": {
|
|
226
|
+
"options": {
|
|
227
|
+
"planMode": true
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Run `/qoder_plan_mode` in OpenCode for quick guidance.
|
|
235
|
+
|
|
236
|
+
### Proxy & Network Routing
|
|
237
|
+
|
|
238
|
+
Pass an outbound proxy URL directly to the Qoder runtime without mutating host
|
|
239
|
+
environment variables (supports `http://`, `https://`, `socks5://`, and `socks://`):
|
|
240
|
+
|
|
241
|
+
```json
|
|
242
|
+
{
|
|
243
|
+
"provider": {
|
|
244
|
+
"qoder": {
|
|
245
|
+
"options": {
|
|
246
|
+
"proxy": "http://127.0.0.1:8888"
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
If `proxy` is omitted, the bridge automatically falls back to `HTTPS_PROXY` or
|
|
254
|
+
`HTTP_PROXY` from your environment.
|
|
255
|
+
|
|
256
|
+
### Skill Evolution
|
|
257
|
+
|
|
258
|
+
Enable autonomous turn-completion skill analysis and recommendations:
|
|
259
|
+
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"provider": {
|
|
263
|
+
"qoder": {
|
|
264
|
+
"options": {
|
|
265
|
+
"evolution": {
|
|
266
|
+
"skill": { "mode": "native" }
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Available Tools
|
|
275
|
+
|
|
276
|
+
The plugin registers several built-in OpenCode tools:
|
|
277
|
+
|
|
278
|
+
- `qoder_usage` — Live account balance, quota percentages, and local cost ledger totals.
|
|
279
|
+
- `qoder_models` — List known Qoder models, context limits, vision/reasoning flags, and multipliers.
|
|
280
|
+
- `qoder_sessions` — List recent Qoder sessions, session IDs, branches, and timestamps via SDK `listSessions()`.
|
|
281
|
+
- `qoder_session_reset` — Forget the persisted Qoder session mapping for the active project.
|
|
282
|
+
- `qoder_plan_mode` — View Plan Mode status and configuration guidance.
|
|
283
|
+
|
|
221
284
|
## Troubleshooting
|
|
222
285
|
|
|
223
286
|
| Problem | Solution |
|
|
224
287
|
|---------|----------|
|
|
225
288
|
| Auth prompt at startup | Run `qoder login`, then restart opencode |
|
|
226
|
-
|
|
|
227
|
-
| Model not found |
|
|
228
|
-
| Missing models in the model list |
|
|
289
|
+
| 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 |
|
|
290
|
+
| Model not found | Run `opencode models qoder` or `/qoder_models`; model IDs are account- and scene-specific |
|
|
291
|
+
| 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 |
|
|
229
292
|
|
|
230
293
|
### How model discovery works
|
|
231
294
|
|
|
232
|
-
At startup the bridge
|
|
233
|
-
|
|
234
|
-
re-queries the server
|
|
235
|
-
|
|
236
|
-
|
|
295
|
+
At startup the bridge performs a bounded live catalog discovery from Qoder
|
|
296
|
+
before returning the provider configuration (`fetchStrategy: "live"` — the
|
|
297
|
+
bundled Worker runtime re-queries the server, with an automatic installed-CLI
|
|
298
|
+
fallback when necessary). Each successful catalog snapshot replaces
|
|
299
|
+
previously discovered dynamic IDs, so retired models do not remain selectable.
|
|
300
|
+
A failed, empty, or slow refresh falls back to the last scoped catalog and the
|
|
301
|
+
built-ins; no `qodercli --list-models` command or manual model configuration is
|
|
302
|
+
required. The startup wait is bounded to 10 seconds, after which OpenCode
|
|
303
|
+
continues with the available cache/fallbacks.
|
|
237
304
|
|
|
238
305
|
## Development
|
|
239
306
|
|
|
@@ -249,7 +316,7 @@ npm run check # full pre-publish verification
|
|
|
249
316
|
### Diagnostics
|
|
250
317
|
|
|
251
318
|
Set `QODER_BRIDGE_DEBUG=1` before launching opencode to emit detailed bridge
|
|
252
|
-
logs (model fallbacks, stream aborts,
|
|
319
|
+
logs (model fallbacks, stream aborts, live catalog discovery, ledger and
|
|
253
320
|
session-store I/O failures). Warnings that need attention are always printed.
|
|
254
321
|
|
|
255
322
|
State files (usage ledger, session mapping, model cache) live under
|
package/bin/statusline.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
2
|
+
import { lstatSync, readFileSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
|
|
@@ -8,20 +8,41 @@ import { join } from "node:path";
|
|
|
8
8
|
function resolveStateDir(env = process.env) {
|
|
9
9
|
const override = env.QODER_BRIDGE_STATE_DIR?.trim();
|
|
10
10
|
if (override) return join(override);
|
|
11
|
-
const configHome = env.XDG_CONFIG_HOME?.trim()
|
|
11
|
+
const configHome = env.XDG_CONFIG_HOME?.trim()
|
|
12
|
+
|| (process.platform === "win32" ? env.APPDATA?.trim() : undefined);
|
|
12
13
|
return join(configHome || join(homedir(), ".config"), "opencode-qoder-bridge");
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
const STATE_FILE = join(resolveStateDir(), "usage.json");
|
|
17
|
+
const MAX_STATE_BYTES = 1_000_000;
|
|
16
18
|
|
|
17
19
|
function fmt(usd) {
|
|
18
|
-
|
|
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;
|
|
19
31
|
}
|
|
20
32
|
|
|
21
33
|
function main() {
|
|
22
34
|
let state = null;
|
|
23
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
|
+
}
|
|
24
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
|
+
}
|
|
25
46
|
} catch {
|
|
26
47
|
process.stdout.write("qoder: no usage yet");
|
|
27
48
|
return;
|
|
@@ -29,12 +50,15 @@ function main() {
|
|
|
29
50
|
|
|
30
51
|
const parts = [
|
|
31
52
|
`cost ${fmt(state.totalCostUsd)}`,
|
|
32
|
-
`turns ${state.turnCount
|
|
33
|
-
`tok ${(state.totalInputTokens
|
|
53
|
+
`turns ${count(state.turnCount)}`,
|
|
54
|
+
`tok ${add(count(state.totalInputTokens), count(state.totalOutputTokens))}`,
|
|
34
55
|
];
|
|
35
56
|
|
|
36
57
|
const last = Array.isArray(state.recent) ? state.recent.at(-1) : null;
|
|
37
|
-
if (last?.model
|
|
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
|
+
}
|
|
38
62
|
|
|
39
63
|
process.stdout.write(`qoder: ${parts.join(" · ")}`);
|
|
40
64
|
}
|
package/bin/usage.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { getLiveUsage, formatUsageReport } from "../dist/usage.js";
|
|
3
3
|
import { summarize, formatCost } from "../dist/cost.js";
|
|
4
|
+
import { describeError } from "../dist/logger.js";
|
|
4
5
|
|
|
5
6
|
async function main() {
|
|
6
7
|
const lines = [];
|
|
@@ -14,11 +15,11 @@ async function main() {
|
|
|
14
15
|
const summary = summarize();
|
|
15
16
|
lines.push("");
|
|
16
17
|
lines.push("Local Usage Ledger");
|
|
17
|
-
lines.push(` Reference cost: ${formatCost(summary
|
|
18
|
-
lines.push(` Turns: ${summary
|
|
19
|
-
lines.push(` Tokens: ${summary
|
|
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`);
|
|
20
21
|
|
|
21
|
-
const models = Object.entries(summary
|
|
22
|
+
const models = Object.entries(summary?.byModel ?? {});
|
|
22
23
|
if (models.length > 0) {
|
|
23
24
|
lines.push(" By model:");
|
|
24
25
|
for (const [name, bucket] of models) {
|
|
@@ -30,6 +31,6 @@ async function main() {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
main().catch((error) => {
|
|
33
|
-
process.stderr.write(`Unable to read Qoder usage: ${
|
|
34
|
+
process.stderr.write(`Unable to read Qoder usage: ${describeError(error)}\n`);
|
|
34
35
|
process.exitCode = 1;
|
|
35
36
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Race SDK operations against a host-side deadline. Aborting the SDK is
|
|
2
|
+
* still the caller's responsibility; this helper guarantees the bridge does
|
|
3
|
+
* not wait forever for a non-cooperative promise. */
|
|
4
|
+
export declare function withTimeout<T>(operation: PromiseLike<T>, timeoutMs: number, message: string): Promise<T>;
|
|
5
|
+
export declare function closeAsyncIterator(iterator: {
|
|
6
|
+
return?: (value?: void | PromiseLike<void>) => PromiseLike<unknown> | unknown;
|
|
7
|
+
}, timeoutMs: number): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=async-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-utils.d.ts","sourceRoot":"","sources":["../src/async-utils.ts"],"names":[],"mappings":"AAAA;;qDAEqD;AACrD,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CASxG;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE;IAAE,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;CAAE,EAC3F,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAQf"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Race SDK operations against a host-side deadline. Aborting the SDK is
|
|
2
|
+
* still the caller's responsibility; this helper guarantees the bridge does
|
|
3
|
+
* not wait forever for a non-cooperative promise. */
|
|
4
|
+
export function withTimeout(operation, timeoutMs, message) {
|
|
5
|
+
let timer;
|
|
6
|
+
const timeout = new Promise((_, reject) => {
|
|
7
|
+
timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
8
|
+
if (typeof timer.unref === "function")
|
|
9
|
+
timer.unref();
|
|
10
|
+
});
|
|
11
|
+
return Promise.race([Promise.resolve(operation), timeout]).finally(() => {
|
|
12
|
+
if (timer)
|
|
13
|
+
clearTimeout(timer);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export async function closeAsyncIterator(iterator, timeoutMs) {
|
|
17
|
+
if (typeof iterator.return !== "function")
|
|
18
|
+
return;
|
|
19
|
+
const closing = Promise.resolve().then(() => iterator.return?.(undefined)).then(() => undefined);
|
|
20
|
+
try {
|
|
21
|
+
await withTimeout(closing, timeoutMs, "SDK iterator cleanup timed out");
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Cleanup is best effort; the request's primary error remains authoritative.
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=async-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-utils.js","sourceRoot":"","sources":["../src/async-utils.ts"],"names":[],"mappings":"AAAA;;qDAEqD;AACrD,MAAM,UAAU,WAAW,CAAI,SAAyB,EAAE,SAAiB,EAAE,OAAe;IAC1F,IAAI,KAAgD,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;QAC/C,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QAChE,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU;YAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IACvD,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;QACtE,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAA2F,EAC3F,SAAiB;IAEjB,IAAI,OAAO,QAAQ,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO;IAClD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACjG,IAAI,CAAC;QACH,MAAM,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,gCAAgC,CAAC,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,6EAA6E;IAC/E,CAAC;AACH,CAAC"}
|
package/dist/auth.d.ts
CHANGED
|
@@ -7,5 +7,6 @@ export declare function isAuthenticated(): boolean;
|
|
|
7
7
|
* Returns null when no separately installed CLI is found. The Qoder SDK can
|
|
8
8
|
* still run through its bundled Worker runtime when credentials are present.
|
|
9
9
|
*/
|
|
10
|
-
export declare function findQoderCLI(): string | null;
|
|
10
|
+
export declare function findQoderCLI(force?: boolean): string | null;
|
|
11
|
+
export declare function resetCachedCliPath(): void;
|
|
11
12
|
//# sourceMappingURL=auth.d.ts.map
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AASA,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAuBD;;;;;;;GAOG;AACH,wBAAgB,YAAY,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AASA,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAuBD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,UAAQ,GAAG,MAAM,GAAG,IAAI,CAIzD;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
package/dist/auth.js
CHANGED
|
@@ -38,12 +38,15 @@ let cachedCliPath;
|
|
|
38
38
|
* Returns null when no separately installed CLI is found. The Qoder SDK can
|
|
39
39
|
* still run through its bundled Worker runtime when credentials are present.
|
|
40
40
|
*/
|
|
41
|
-
export function findQoderCLI() {
|
|
42
|
-
if (cachedCliPath !== undefined)
|
|
41
|
+
export function findQoderCLI(force = false) {
|
|
42
|
+
if (!force && cachedCliPath !== undefined)
|
|
43
43
|
return cachedCliPath;
|
|
44
44
|
cachedCliPath = resolveCli();
|
|
45
45
|
return cachedCliPath;
|
|
46
46
|
}
|
|
47
|
+
export function resetCachedCliPath() {
|
|
48
|
+
cachedCliPath = undefined;
|
|
49
|
+
}
|
|
47
50
|
function resolveCli() {
|
|
48
51
|
const exe = process.platform === "win32" ? "qodercli.exe" : "qodercli";
|
|
49
52
|
for (const dir of (process.env.PATH ?? "").split(delimiter)) {
|
|
@@ -58,12 +61,12 @@ function resolveCli() {
|
|
|
58
61
|
return local;
|
|
59
62
|
const binDir = join(homedir(), ".qoder", "bin", "qodercli");
|
|
60
63
|
try {
|
|
61
|
-
const
|
|
64
|
+
const versions = readdirSync(binDir)
|
|
62
65
|
.filter((f) => f.startsWith("qodercli-"))
|
|
63
|
-
.sort()
|
|
64
|
-
.
|
|
65
|
-
|
|
66
|
-
const p = join(binDir,
|
|
66
|
+
.sort(compareCliVersions)
|
|
67
|
+
.reverse();
|
|
68
|
+
for (const version of versions) {
|
|
69
|
+
const p = join(binDir, version);
|
|
67
70
|
if (isExecutableFile(p))
|
|
68
71
|
return p;
|
|
69
72
|
}
|
|
@@ -73,4 +76,20 @@ function resolveCli() {
|
|
|
73
76
|
}
|
|
74
77
|
return null;
|
|
75
78
|
}
|
|
79
|
+
function compareCliVersions(left, right) {
|
|
80
|
+
const leftParts = left.slice("qodercli-".length).split(/[.-]/);
|
|
81
|
+
const rightParts = right.slice("qodercli-".length).split(/[.-]/);
|
|
82
|
+
const length = Math.max(leftParts.length, rightParts.length);
|
|
83
|
+
for (let i = 0; i < length; i++) {
|
|
84
|
+
const a = leftParts[i] ?? "";
|
|
85
|
+
const b = rightParts[i] ?? "";
|
|
86
|
+
const aNumber = /^\d+$/.test(a) ? Number(a) : NaN;
|
|
87
|
+
const bNumber = /^\d+$/.test(b) ? Number(b) : NaN;
|
|
88
|
+
if (Number.isFinite(aNumber) && Number.isFinite(bNumber) && aNumber !== bNumber)
|
|
89
|
+
return aNumber - bNumber;
|
|
90
|
+
if (a !== b)
|
|
91
|
+
return a.localeCompare(b);
|
|
92
|
+
}
|
|
93
|
+
return left.localeCompare(right);
|
|
94
|
+
}
|
|
76
95
|
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,UAAU,GAAG;IACjB,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC;IAC9C,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC;CAC3C,CAAC;AAEF,MAAM,UAAU,eAAe;IAC7B,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,aAAa,CAAC,CAAS;IAC9B,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAS;IACjC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,CAAC;QACH,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,IAAI,aAAwC,CAAC;AAE7C;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/cost.d.ts
CHANGED
|
@@ -23,9 +23,10 @@ interface PersistedState {
|
|
|
23
23
|
}>;
|
|
24
24
|
recent: TurnCost[];
|
|
25
25
|
}
|
|
26
|
+
export declare function flushLedgerSync(): void;
|
|
26
27
|
export interface RecordInput {
|
|
27
28
|
model: string;
|
|
28
|
-
usage
|
|
29
|
+
usage?: {
|
|
29
30
|
input_tokens?: number | null;
|
|
30
31
|
output_tokens?: number | null;
|
|
31
32
|
cache_read_input_tokens?: number | null;
|
package/dist/cost.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAa5D,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,cAAc;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvG,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAoND,wBAAgB,eAAe,IAAI,IAAI,CAOtC;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxC,2BAA2B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7C,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACzC;AAED,0DAA0D;AAC1D,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,CAoBvD;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IACnC,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAED,wBAAgB,SAAS,IAAI,YAAY,CAUxC;AAED,wBAAgB,WAAW,IAAI,IAAI,CAKlC;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C"}
|