opencode-cmd-provider 1.5.2 → 1.6.1

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
@@ -1,5 +1,85 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.6.1 - 2026-08-29
4
+
5
+ Patch release. Catalog refresh to `command-code@1.38.1`, one catalog
6
+ classification re-pin, and two CI fixes for the daily catalog-refresh cron.
7
+
8
+ - **Catalog refresh** — snapshot + capability facts + RSC fixtures refreshed
9
+ to `command-code@1.38.1` (was 1.37.0). Net: 30 → 31 effort entries;
10
+ `tencent/hy4-preview` is the new row (Efforts column now lists
11
+ `low, medium, high`, was empty in 1.37.0). The 62 cost rows are unchanged.
12
+ The deals catalog is unaffected (the new model already had its RSC
13
+ availability + deal info in 1.37.0 fixtures). A follow-up 2026-08-29 cron
14
+ re-captured the RSC fixtures and refreshed `src/catalog/facts.ts` to
15
+ upstream's new values.
16
+ - **Catalog classification** — `tencent/hy4-preview` re-pinned to
17
+ `EFFORTS_MODELS` in `src/catalog/facts.ts`; the prior
18
+ `REASONING_MODELS` classification was a labelling error in 1.6.0 (upstream
19
+ advertises it as an effort-controlled model, not a reasoning model). The
20
+ matching unit-test pin was updated in lockstep.
21
+ - **CI: catalog-refresh heredoc** — `realpath` the relative `.ts` path
22
+ before the `npx tsx -e` heredoc in `.github/workflows/catalog-refresh.yml`.
23
+ The `after` loop passed a bare-relative path (e.g. `src/catalog/snapshot.ts`)
24
+ to the heredoc, which Node's ESM resolver parsed as a package name and
25
+ rejected with `ERR_MODULE_NOT_FOUND`. The `before` loop was unaffected
26
+ because it used `/tmp/...` absolute paths. Locked down with
27
+ `tests/catalog-refresh-extract.test.ts`.
28
+ - **CI: catalog-refresh push** — force-push the `catalog-refresh/${date}`
29
+ branch in `.github/workflows/catalog-refresh.yml`. Two consecutive cron
30
+ runs on the same day land sibling commits on `main`'s HEAD; `git push -u`
31
+ then rejects as non-fast-forward, leaving the cron stuck. `-fu` handles
32
+ both the partial-failure rerun and the fresh-branch case; the branch is
33
+ owned only by this workflow, so there's no clobber risk. The
34
+ `Open PR` step's `gh pr list --head X` already copes correctly with a
35
+ force-pushed tip. Locked down with
36
+ `tests/catalog-refresh-push.test.ts`.
37
+ - **Test fix for the push test** — `tests/catalog-refresh-push.test.ts`'s
38
+ verification `git ls-remote` previously ran from the outer project
39
+ CWD, so it resolved `origin` to GitHub rather than the test's local
40
+ bare remote. It passed only on the day the matching
41
+ `catalog-refresh/${date}` branch happened to exist on GitHub. Now
42
+ passes `-C repo.work` so the `origin` resolution is scoped to the
43
+ test fixture.
44
+
45
+ ## 1.6.0 - 2026-08-28
46
+
47
+ ### Deals pipeline: RSC-primary + daily catalog refresh cron
48
+
49
+ The deals catalog is no longer scraped from HTML tables — it is generated from
50
+ the Command Code docs site's React Server Components (RSC) stream (the docs
51
+ pages fetched with an `rsc: 1` header; see ADR-0005). The HTML live fetch and
52
+ HTML fixtures are gone; `scripts/parse-docs.mjs` keeps its parsers as a
53
+ documented air-gapped fallback.
54
+
55
+ - **RSC parser** — `scripts/parse-rsc.mjs` with committed fixtures
56
+ (`tests/fixtures/rsc-{pricing-limits,goat,pro}.txt`), shape-pinning unit
57
+ tests, a slug-id→snapshot-id alias map, and the shared depth-state-machine
58
+ extracted to `scripts/json-stream.mjs`.
59
+ - **Tier overrides** — `scripts/tier-overrides.mjs` pins the 7 known Command
60
+ Code tier-categorization disagreements to `opensource` so TUI badges stay
61
+ stable.
62
+ - **Daily cron** — `.github/workflows/catalog-refresh.yml` (06:00 UTC +
63
+ `workflow_dispatch`) regenerates snapshot/facts/fixtures/deals, builds,
64
+ tests, and opens a `chore: catalog refresh` PR (body via
65
+ `scripts/diff-catalog.mjs`) only when upstream moved; silent exit when
66
+ nothing drifted.
67
+ - **Fixture lockstep** — `npm run refresh` now re-captures the RSC fixtures
68
+ from the live docs pages (`scripts/capture-rsc-fixtures.mjs`) before
69
+ regenerating the deals catalog, so fixtures, catalog, and tests stay
70
+ consistent. Standalone `refresh:deals` falls back to fixtures on 5xx/network
71
+ and fails loudly on 4xx.
72
+ - **Catalog refresh** — deals/snapshot/facts refreshed to
73
+ `command-code@1.37.0` (new: `tencent/hy4-preview`, classified
74
+ reasoning-capable without explicit efforts); benchmark pins updated to
75
+ upstream's new values (Gemini 3.7 Flash, MiniMax M3).
76
+ - **Fixes** — live RSC URLs corrected (the `/docs/rsc/*` draft routes 404 on
77
+ the real site); the cron now builds before testing (the pack contract test
78
+ needs `dist/` in a fresh checkout); 4xx RSC responses fail loudly instead of
79
+ silently falling back to fixtures.
80
+ - **Follow-ups** — open decisions tracked in issues #89 (shape-pinning value
81
+ pins) and #90 (expired-deal filtering).
82
+
3
83
  ## 1.5.2 - 2026-08-28
4
84
 
5
85
  Chore: catalog refresh to `command-code@1.36.0`, with a deals-coverage gate
package/README.md CHANGED
@@ -101,8 +101,9 @@ opencode run --model commandcode/claude-sonnet-5 "hello"
101
101
  ## Deals intelligence
102
102
 
103
103
  Every Command Code model ships with deal/allowance/benchmark intelligence
104
- (bundled in `src/deals/catalog.ts`), scraped from the Command Code docs. It
105
- surfaces in two places:
104
+ (bundled in `src/deals/catalog.ts`), extracted from the Command Code docs'
105
+ React Server Components (RSC) stream — the structured payload the docs site
106
+ serves for `rsc: 1` requests (see ADR-0005). It surfaces in two places:
106
107
 
107
108
  - **Sidebar** — in a session, the OpenCode sidebar (`ctrl+x b`) shows a
108
109
  `Command Code` section for the selected model: tier, GOAT/Pro allowance,
@@ -118,10 +119,11 @@ spec. The sidebar is a TUI plugin loaded from `tui.json` — which is why
118
119
  installs made before the `./tui` export only wrote the server target and never
119
120
  showed a sidebar. Re-run with `--force` to add `tui.json`.
120
121
 
121
- When the Deals catalog is empty (scraping mitigated), the feature degrades
122
- visibly rather than silently: the sidebar shows a `Deals unavailable` banner
123
- with placeholder rows, and `cmd_plan_summary` reports that no deal data is
124
- bundled. Core (models, auth, streaming) is unaffected.
122
+ When the Deals catalog is empty (the upstream fetch failed or the RSC shape
123
+ changed), the feature degrades visibly rather than silently: the sidebar shows
124
+ a `Deals unavailable` banner with placeholder rows, and `cmd_plan_summary`
125
+ reports that no deal data is bundled. Core (models, auth, streaming) is
126
+ unaffected.
125
127
 
126
128
  ## Model discovery and offline behavior
127
129
 
@@ -161,12 +163,22 @@ auto-registered models only.
161
163
  modalities). Regenerated from the live catalog via `npm run refresh:snapshot`.
162
164
  - Deals — `src/deals/catalog.ts` (per-model tier, benchmarks, deal
163
165
  discounts, `was`/`now` rates, peak/off-peak windows, and GOAT/Pro monthly
164
- allowances for every model). Scraped from the Command Code docs
165
- (`pricing-limits`, `plans/goat`, `plans/pro`; fixtures in
166
- `tests/fixtures/*.html`) via `npm run refresh:deals` (add `-- --fixtures` to
167
- regenerate offline from fixtures; without it, fetches live pages).
168
-
169
- Run `npm run refresh` to regenerate both catalogs at once (offline from fixtures).
166
+ allowances for every model). Extracted from the Command Code docs' RSC
167
+ stream (the `pricing-limits`, `plans/goat`, `plans/pro` pages fetched with
168
+ an `rsc: 1` header; fixtures in `tests/fixtures/rsc-*.txt`) via
169
+ `npm run refresh:deals`. Standalone live runs fall back to the committed
170
+ fixtures on 5xx/network failure and fail loudly on 4xx; add
171
+ `-- --fixtures` to regenerate offline from the committed fixtures.
172
+
173
+ Run `npm run refresh` to regenerate everything at once: the snapshot and
174
+ facts come from the live Command Code catalog, the RSC fixtures are
175
+ re-captured from the live docs pages (`npm run refresh:fixtures`), and the
176
+ deals catalog is regenerated from the fresh fixtures — so fixtures, catalog,
177
+ and tests stay in lockstep. A daily GitHub Actions cron
178
+ (`.github/workflows/catalog-refresh.yml`, 06:00 UTC, also manually
179
+ triggerable via `workflow_dispatch`) runs the same pipeline: when upstream
180
+ moved it opens a `chore: catalog refresh` PR whose body is the human-readable
181
+ diff from `scripts/diff-catalog.mjs`; when nothing drifted it exits silently.
170
182
 
171
183
  Auto-registration adds no network latency to OpenCode startup — the snapshot is
172
184
  bundled, and the plugin never contacts the Command Code API to list models. The
@@ -176,14 +188,14 @@ endpoint being reachable.
176
188
  The following environment variables are intended for tests, local mocks, and
177
189
  compatible API endpoints:
178
190
 
179
- | Variable | Purpose |
180
- | ------------------------------- | -------------------------------------- |
181
- | `COMMANDCODE_API_BASE` | Override the Command Code API base URL |
182
- | `COMMANDCODE_FACTS_URL` | Override the bundled `models.md` URL |
183
- | `COMMANDCODE_MODALITIES_URL` | Override the CLI bundle URL |
184
- | `COMMANDCODE_DEALS_PRICING_URL` | Override the `pricing-limits` docs URL |
185
- | `COMMANDCODE_DEALS_GOAT_URL` | Override the `plans/goat` docs URL |
186
- | `COMMANDCODE_DEALS_PRO_URL` | Override the `plans/pro` docs URL |
191
+ | Variable | Purpose |
192
+ | ----------------------------- | ------------------------------------------ |
193
+ | `COMMANDCODE_API_BASE` | Override the Command Code API base URL |
194
+ | `COMMANDCODE_FACTS_URL` | Override the bundled `models.md` URL |
195
+ | `COMMANDCODE_MODALITIES_URL` | Override the CLI bundle URL |
196
+ | `COMMANDCODE_RSC_PRICING_URL` | Override the `pricing-limits` RSC page URL |
197
+ | `COMMANDCODE_RSC_GOAT_URL` | Override the `plans/goat` RSC page URL |
198
+ | `COMMANDCODE_RSC_PRO_URL` | Override the `plans/pro` RSC page URL |
187
199
 
188
200
  ### Reasoning support
189
201
 
@@ -1,7 +1,7 @@
1
- export declare const FACTS_SOURCE_URL = "https://unpkg.com/command-code@1.36.0/dist/bundled/command-code-knowledge/reference/models.md";
2
- export declare const MODALITIES_SOURCE_URL = "https://unpkg.com/command-code@1.36.0/dist/cli.mjs";
3
- export declare const FACTS_PACKAGE_VERSION = "1.36.0";
4
- export declare const FACTS_LAST_REFRESHED = "2026-08-27";
1
+ export declare const FACTS_SOURCE_URL = "https://unpkg.com/command-code@1.38.2/dist/bundled/command-code-knowledge/reference/models.md";
2
+ export declare const MODALITIES_SOURCE_URL = "https://unpkg.com/command-code@1.38.2/dist/cli.mjs";
3
+ export declare const FACTS_PACKAGE_VERSION = "1.38.2";
4
+ export declare const FACTS_LAST_REFRESHED = "2026-08-29";
5
5
  export declare const MODEL_EFFORTS: Readonly<Record<string, readonly string[]>>;
6
6
  export declare const MODEL_COSTS: Readonly<Record<string, {
7
7
  input: number;
@@ -4,10 +4,10 @@
4
4
  // command-code npm package's bundled model catalog (models.md), plus input
5
5
  // modalities parsed from its CLI bundle (dist/cli.mjs). Regenerate
6
6
  // with `npm run refresh:snapshot`.
7
- export const FACTS_SOURCE_URL = "https://unpkg.com/command-code@1.36.0/dist/bundled/command-code-knowledge/reference/models.md";
8
- export const MODALITIES_SOURCE_URL = "https://unpkg.com/command-code@1.36.0/dist/cli.mjs";
9
- export const FACTS_PACKAGE_VERSION = "1.36.0";
10
- export const FACTS_LAST_REFRESHED = "2026-08-27";
7
+ export const FACTS_SOURCE_URL = "https://unpkg.com/command-code@1.38.2/dist/bundled/command-code-knowledge/reference/models.md";
8
+ export const MODALITIES_SOURCE_URL = "https://unpkg.com/command-code@1.38.2/dist/cli.mjs";
9
+ export const FACTS_PACKAGE_VERSION = "1.38.2";
10
+ export const FACTS_LAST_REFRESHED = "2026-08-29";
11
11
  export const MODEL_EFFORTS = {
12
12
  "deepseek/deepseek-v4-pro": ["high", "max"],
13
13
  "deepseek/deepseek-v4-flash": ["high", "max"],
@@ -18,6 +18,7 @@ export const MODEL_EFFORTS = {
18
18
  "Qwen/Qwen3.8-Max": ["low", "medium", "xhigh"],
19
19
  "Qwen/Qwen3.8-27B": ["low", "medium", "xhigh"],
20
20
  "Qwen/Qwen3.8-Flash": ["low", "medium", "xhigh"],
21
+ "tencent/hy4-preview": ["low", "medium", "high"],
21
22
  "claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"],
22
23
  "claude-sonnet-4-6": ["low", "medium", "high", "xhigh", "max"],
23
24
  "claude-fable-5": ["low", "medium", "high", "xhigh", "max"],
@@ -73,6 +74,7 @@ export const MODEL_COSTS = {
73
74
  "stepfun/Step-3.7-Flash": { input: 0.2, output: 1.15, cacheRead: 0.04, cacheWrite: 0 },
74
75
  "stepfun/Step-3.5-Flash": { input: 0.1, output: 0.3, cacheRead: 0.02, cacheWrite: 0 },
75
76
  "tencent/hy3-paid": { input: 0.14, output: 0.58, cacheRead: 0.035, cacheWrite: 0 },
77
+ "tencent/hy4-preview": { input: 0.834, output: 2.501, cacheRead: 0.042, cacheWrite: 0 },
76
78
  "nvidia/nemotron-3-ultra-550b-a55b": { input: 0.6, output: 2.4, cacheRead: 0.12, cacheWrite: 0 },
77
79
  "thinkingmachines/inkling": { input: 1, output: 4.05, cacheRead: 0.17, cacheWrite: 0 },
78
80
  "thinkingmachines/inkling-small": { input: 0.5, output: 1.2, cacheRead: 0.1, cacheWrite: 0 },
@@ -91,7 +93,7 @@ export const MODEL_COSTS = {
91
93
  "gpt-5.4": { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 },
92
94
  "gpt-5.3-codex": { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 },
93
95
  "gpt-5.4-mini": { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 },
94
- "google/gemini-3.7-flash": { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0.04167 },
96
+ "google/gemini-3.7-flash": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0.08334 },
95
97
  "google/gemini-3.6-flash": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 },
96
98
  "google/gemini-3.5-flash": { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 },
97
99
  "google/gemini-3.5-flash-lite": { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 },
@@ -50,6 +50,7 @@ export const MODEL_SNAPSHOT = [
50
50
  { id: "stepfun/Step-3.7-Flash", name: "Step 3.7 Flash", contextLength: 256000 },
51
51
  { id: "stepfun/Step-3.5-Flash", name: "Step 3.5 Flash", contextLength: 1000000 },
52
52
  { id: "tencent/hy3-paid", name: "Tencent Hy3", contextLength: 262144 },
53
+ { id: "tencent/hy4-preview", name: "Tencent Hy4 Preview", contextLength: 1048576 },
53
54
  { id: "google/gemini-3.7-flash", name: "Gemini 3.7 Flash", contextLength: 1048576 },
54
55
  { id: "google/gemini-3.6-flash", name: "Gemini 3.6 Flash", contextLength: 1000000 },
55
56
  { id: "google/gemini-3.5-flash", name: "Gemini 3.5 Flash", contextLength: 1000000 },
@@ -51,5 +51,5 @@ export interface ModelDeals {
51
51
  export declare const MODEL_DEALS: Readonly<Record<string, ModelDeals>>;
52
52
  export declare const PLAN_CATALOG: Readonly<Record<PlanId, PlanInfo>>;
53
53
  export declare const DEAL_SOURCE_URL = "https://commandcode.ai/docs/resources/pricing-limits";
54
- export declare const DEAL_LAST_REFRESHED = "2026-08-27";
54
+ export declare const DEAL_LAST_REFRESHED = "2026-08-29";
55
55
  export declare const DEAL_PACKAGE_VERSION = "docs";
@@ -5,67 +5,68 @@
5
5
  // enrich the model picker, the sidebar panel, and the plan summary tool
6
6
  // without network access at runtime. Regenerate with `npm run refresh:deals`.
7
7
  export const MODEL_DEALS = {
8
- "claude-fable-5": { tier: "premium", benchmark: { "intelligence": 62.1, "tokPerSec": 67.5 }, free: false },
9
- "claude-haiku-4-5-20251001": { tier: "premium", benchmark: { "intelligence": 24.1, "tokPerSec": 101.1 }, free: false, allowance: { "pro": 20 } },
10
- "claude-opus-4-7": { tier: "premium", benchmark: { "intelligence": 55 }, free: false },
11
- "claude-opus-4-8": { tier: "premium", benchmark: { "intelligence": 57.3 }, free: false },
12
- "claude-opus-5": { tier: "premium", benchmark: { "intelligence": 63.1, "tokPerSec": 54.4 }, free: false },
13
- "claude-sonnet-4-6": { tier: "premium", benchmark: { "intelligence": 48.4 }, free: false, allowance: { "pro": 20 } },
14
- "claude-sonnet-5": { tier: "premium", benchmark: { "intelligence": 55.3, "tokPerSec": 81.9 }, free: false, allowance: { "pro": 20 } },
15
- "deepseek/deepseek-v4-flash": { tier: "opensource", benchmark: { "intelligence": 51.8, "tokPerSec": 114.6 }, peakOffPeak: { "peak": { "input": 0.44, "output": 1.32, "cacheRead": 0.014, "cacheWrite": 0 }, "offPeak": { "input": 0.22, "output": 0.66, "cacheRead": 0.007, "cacheWrite": 0 }, "windows": "01–04 & 06–10 UTC" }, free: false, allowance: { "goat": 60, "pro": 70 } },
8
+ "claude-fable-5": { tier: "premium", benchmark: { "intelligence": 62.1, "tokPerSec": 67.8 }, free: false, allowance: { "goat": 20, "pro": 20 } },
9
+ "claude-haiku-4-5-20251001": { tier: "premium", benchmark: { "intelligence": 24.1, "tokPerSec": 103.9 }, free: false, allowance: { "goat": 20, "pro": 20 } },
10
+ "claude-opus-4-7": { tier: "premium", benchmark: { "intelligence": 55 }, free: false, allowance: { "goat": 20, "pro": 20 } },
11
+ "claude-opus-4-8": { tier: "premium", benchmark: { "intelligence": 57.3 }, free: false, allowance: { "goat": 20, "pro": 20 } },
12
+ "claude-opus-5": { tier: "premium", benchmark: { "intelligence": 63.1, "tokPerSec": 55.5 }, free: false, allowance: { "goat": 20, "pro": 20 } },
13
+ "claude-sonnet-4-6": { tier: "premium", benchmark: { "intelligence": 48.4 }, free: false, allowance: { "goat": 20, "pro": 20 } },
14
+ "claude-sonnet-5": { tier: "premium", benchmark: { "intelligence": 55.3, "tokPerSec": 89.6 }, free: false, allowance: { "goat": 20, "pro": 20 } },
15
+ "deepseek/deepseek-v4-flash": { tier: "opensource", benchmark: { "intelligence": 51.8, "tokPerSec": 129 }, peakOffPeak: { "peak": { "input": 0.44, "output": 1.32, "cacheRead": 0.014, "cacheWrite": 0 }, "offPeak": { "input": 0.22, "output": 0.66, "cacheRead": 0.007, "cacheWrite": 0 }, "windows": "01–04 & 06–10 UTC" }, free: false, allowance: { "goat": 60, "pro": 70 } },
16
16
  "deepseek/deepseek-v4-flash-vision-exp": { tier: "opensource", peakOffPeak: { "peak": { "input": 0.44, "output": 1.32, "cacheRead": 0.014, "cacheWrite": 0 }, "offPeak": { "input": 0.22, "output": 0.66, "cacheRead": 0.007, "cacheWrite": 0 }, "windows": "01–04 & 06–10 UTC" }, free: false, allowance: { "goat": 20, "pro": 30 } },
17
- "deepseek/deepseek-v4-pro": { tier: "opensource", benchmark: { "intelligence": 53.2, "tokPerSec": 75.3 }, peakOffPeak: { "peak": { "input": 1.32, "output": 3.96, "cacheRead": 0.044, "cacheWrite": 0 }, "offPeak": { "input": 0.66, "output": 1.98, "cacheRead": 0.022, "cacheWrite": 0 }, "windows": "01–04 & 06–10 UTC" }, free: false, allowance: { "goat": 20, "pro": 30 } },
18
- "google/gemini-3.1-flash-lite": { tier: "premium", benchmark: { "intelligence": 25.6 }, free: false, allowance: { "pro": 20 } },
19
- "google/gemini-3.5-flash": { tier: "premium", benchmark: { "intelligence": 52 }, free: false, allowance: { "pro": 20 } },
20
- "google/gemini-3.5-flash-lite": { tier: "premium", benchmark: { "intelligence": 37.4, "tokPerSec": 361.2 }, free: false, allowance: { "pro": 20 } },
21
- "google/gemini-3.6-flash": { tier: "premium", benchmark: { "intelligence": 51.6, "tokPerSec": 187.4 }, free: false, allowance: { "pro": 20 } },
22
- "google/gemini-3.7-flash": { tier: "opensource", discount: { "pct": 50, "endsAt": "2026-12-31" }, was: { "input": 1.5, "output": 7.5, "cacheRead": 0.15 }, now: { "input": 0.75, "output": 3.75, "cacheRead": 0.075 }, benchmark: { "intelligence": 56, "tokPerSec": 339.4 }, free: false, allowance: { "goat": 40, "pro": 60 } },
23
- "gpt-5.3-codex": { tier: "premium", benchmark: { "intelligence": 45.5, "tokPerSec": 132.3 }, free: false, allowance: { "pro": 20 } },
24
- "gpt-5.4": { tier: "premium", benchmark: { "intelligence": 53.1 }, free: false, allowance: { "pro": 20 } },
25
- "gpt-5.4-mini": { tier: "premium", benchmark: { "intelligence": 40.9 }, free: false, allowance: { "pro": 20 } },
26
- "gpt-5.5": { tier: "premium", benchmark: { "intelligence": 56.3 }, free: false, allowance: { "pro": 20 } },
27
- "gpt-5.6-luna": { tier: "opensource", benchmark: { "intelligence": 52.3, "tokPerSec": 165 }, overContext: { "input": 0.4, "output": 1.8, "cacheRead": 0.04, "cacheWrite": 0.5 }, free: false, allowance: { "goat": 20, "pro": 30 } },
28
- "gpt-5.6-sol": { tier: "opensource", benchmark: { "intelligence": 60.9, "tokPerSec": 68.7 }, overContext: { "input": 10, "output": 45, "cacheRead": 1, "cacheWrite": 12.5 }, free: false, allowance: { "goat": 70, "pro": 80 } },
29
- "gpt-5.6-terra": { tier: "premium", benchmark: { "intelligence": 56.6, "tokPerSec": 117.1 }, overContext: { "input": 4, "output": 18, "cacheRead": 0.4, "cacheWrite": 5 }, free: false, allowance: { "pro": 20 } },
30
- "meta/muse-spark-1.1": { tier: "premium", benchmark: { "intelligence": 53.2 }, free: false, allowance: { "pro": 20 } },
17
+ "deepseek/deepseek-v4-pro": { tier: "opensource", benchmark: { "intelligence": 53.2, "tokPerSec": 61 }, peakOffPeak: { "peak": { "input": 1.32, "output": 3.96, "cacheRead": 0.044, "cacheWrite": 0 }, "offPeak": { "input": 0.66, "output": 1.98, "cacheRead": 0.022, "cacheWrite": 0 }, "windows": "01–04 & 06–10 UTC" }, free: false, allowance: { "goat": 20, "pro": 30 } },
18
+ "google/gemini-3.1-flash-lite": { tier: "premium", benchmark: { "intelligence": 25.6 }, free: false, allowance: { "goat": 20, "pro": 20 } },
19
+ "google/gemini-3.5-flash": { tier: "premium", benchmark: { "intelligence": 52 }, free: false, allowance: { "goat": 20, "pro": 20 } },
20
+ "google/gemini-3.5-flash-lite": { tier: "premium", benchmark: { "intelligence": 37.4, "tokPerSec": 368.8 }, free: false, allowance: { "goat": 20, "pro": 20 } },
21
+ "google/gemini-3.6-flash": { tier: "premium", benchmark: { "intelligence": 51.6, "tokPerSec": 197.3 }, free: false, allowance: { "goat": 20, "pro": 20 } },
22
+ "google/gemini-3.7-flash": { tier: "opensource", discount: { "pct": 50, "endsAt": "2026-12-31" }, was: { "input": 1.5, "output": 7.5, "cacheRead": 0.15 }, now: { "input": 0.75, "output": 3.75, "cacheRead": 0.075 }, benchmark: { "intelligence": 56, "tokPerSec": 365.9 }, free: false, allowance: { "goat": 20, "pro": 30 } },
23
+ "gpt-5.3-codex": { tier: "premium", benchmark: { "intelligence": 45.5, "tokPerSec": 121.4 }, free: false, allowance: { "goat": 20, "pro": 20 } },
24
+ "gpt-5.4": { tier: "premium", benchmark: { "intelligence": 53.1 }, free: false, allowance: { "goat": 20, "pro": 20 } },
25
+ "gpt-5.4-mini": { tier: "premium", benchmark: { "intelligence": 40.9 }, free: false, allowance: { "goat": 20, "pro": 20 } },
26
+ "gpt-5.5": { tier: "premium", benchmark: { "intelligence": 56.3 }, free: false, allowance: { "goat": 20, "pro": 20 } },
27
+ "gpt-5.6-luna": { tier: "opensource", benchmark: { "intelligence": 52.3, "tokPerSec": 124.1 }, overContext: { "input": 0.4, "output": 1.8, "cacheRead": 0.04, "cacheWrite": 0.5 }, free: false, allowance: { "goat": 20, "pro": 30 } },
28
+ "gpt-5.6-sol": { tier: "opensource", benchmark: { "intelligence": 60.9, "tokPerSec": 69.6 }, overContext: { "input": 10, "output": 45, "cacheRead": 1, "cacheWrite": 12.5 }, free: false, allowance: { "goat": 70, "pro": 80 } },
29
+ "gpt-5.6-terra": { tier: "premium", benchmark: { "intelligence": 56.6, "tokPerSec": 112.8 }, overContext: { "input": 4, "output": 18, "cacheRead": 0.4, "cacheWrite": 5 }, free: false, allowance: { "goat": 20, "pro": 20 } },
30
+ "meta/muse-spark-1.1": { tier: "premium", benchmark: { "intelligence": 53.2 }, free: false, allowance: { "goat": 20, "pro": 20 } },
31
31
  "meta/muse-spark-1.2": { tier: "opensource", benchmark: { "intelligence": 56.8 }, free: false, allowance: { "goat": 20, "pro": 30 } },
32
32
  "meta/muse-spark-1.2-contributor": { tier: "opensource", benchmark: { "intelligence": 56.8 }, free: false, allowance: { "goat": 20, "pro": 30 } },
33
- "minimax/minimax-m2.7-free": { tier: "opensource", free: true },
34
- "minimax/minimax-m3-free": { tier: "opensource", free: true },
35
- "MiniMaxAI/MiniMax-M2.5": { tier: "opensource", benchmark: { "intelligence": 34.5 }, free: false },
36
- "MiniMaxAI/MiniMax-M2.7": { tier: "opensource", benchmark: { "intelligence": 38.9 }, free: false },
37
- "MiniMaxAI/MiniMax-M3": { tier: "opensource", discount: { "pct": 50 }, was: { "input": 0.6, "output": 2.4, "cacheRead": 0.12 }, now: { "input": 0.3, "output": 1.2, "cacheRead": 0.06 }, benchmark: { "intelligence": 45.4, "tokPerSec": 104.4 }, free: false, allowance: { "goat": 47, "pro": 57 } },
38
- "moonshotai/Kimi-K2.5": { tier: "opensource", benchmark: { "intelligence": 36 }, free: false },
39
- "moonshotai/Kimi-K2.6": { tier: "opensource", benchmark: { "intelligence": 45.1 }, free: false },
40
- "moonshotai/Kimi-K2.7-Code": { tier: "opensource", benchmark: { "intelligence": 43, "tokPerSec": 38.2 }, free: false, allowance: { "goat": 60, "pro": 70 } },
33
+ "minimax/minimax-m2.7-free": { tier: "opensource", free: true, benchmark: { "intelligence": 38.9 } },
34
+ "minimax/minimax-m3-free": { tier: "opensource", free: true, benchmark: { "intelligence": 45.4 } },
35
+ "MiniMaxAI/MiniMax-M2.5": { tier: "opensource", benchmark: { "intelligence": 34.5 }, free: false, allowance: { "goat": 20, "pro": 30 } },
36
+ "MiniMaxAI/MiniMax-M2.7": { tier: "opensource", benchmark: { "intelligence": 38.9 }, free: false, allowance: { "goat": 20, "pro": 30 } },
37
+ "MiniMaxAI/MiniMax-M3": { tier: "opensource", discount: { "pct": 50 }, was: { "input": 0.6, "output": 2.4, "cacheRead": 0.12 }, now: { "input": 0.3, "output": 1.2, "cacheRead": 0.06 }, benchmark: { "intelligence": 45.4, "tokPerSec": 111.3 }, free: false, allowance: { "goat": 47, "pro": 57 } },
38
+ "moonshotai/Kimi-K2.5": { tier: "opensource", benchmark: { "intelligence": 36 }, free: false, allowance: { "goat": 20, "pro": 30 } },
39
+ "moonshotai/Kimi-K2.6": { tier: "opensource", benchmark: { "intelligence": 45.1 }, free: false, allowance: { "goat": 20, "pro": 30 } },
40
+ "moonshotai/Kimi-K2.7-Code": { tier: "opensource", benchmark: { "intelligence": 43, "tokPerSec": 39.5 }, free: false, allowance: { "goat": 60, "pro": 70 } },
41
41
  "moonshotai/Kimi-K2.7-Code-Highspeed": { tier: "opensource", free: false, allowance: { "goat": 20, "pro": 30 } },
42
- "moonshotai/Kimi-K3": { tier: "opensource", benchmark: { "intelligence": 59.7, "tokPerSec": 38.6 }, free: false, allowance: { "goat": 20, "pro": 30 } },
43
- "nvidia/nemotron-3-ultra-550b-a55b": { tier: "opensource", benchmark: { "intelligence": 38.3, "tokPerSec": 135.8 }, free: false, allowance: { "goat": 20, "pro": 30 } },
42
+ "moonshotai/Kimi-K3": { tier: "opensource", benchmark: { "intelligence": 59.7, "tokPerSec": 38.4 }, free: false, allowance: { "goat": 20, "pro": 30 } },
43
+ "nvidia/nemotron-3-ultra-550b-a55b": { tier: "opensource", benchmark: { "intelligence": 38.3, "tokPerSec": 174.2 }, free: false, allowance: { "goat": 20, "pro": 30 } },
44
44
  "poolside/laguna-s-2.1-free": { tier: "opensource", free: true },
45
- "Qwen/Qwen3.6-Max-Preview": { tier: "opensource", benchmark: { "intelligence": 41.1 }, free: false },
45
+ "Qwen/Qwen3.6-Max-Preview": { tier: "opensource", benchmark: { "intelligence": 41.1 }, free: false, allowance: { "goat": 20, "pro": 30 } },
46
46
  "Qwen/Qwen3.6-Plus": { tier: "opensource", benchmark: { "intelligence": 40.5 }, overContext: { "input": 2, "output": 6, "cacheRead": 0.2, "cacheWrite": 0 }, free: false, allowance: { "goat": 33, "pro": 43 } },
47
- "Qwen/Qwen3.7-Flash": { tier: "opensource", overContext: { "input": 0.2, "output": 0.8, "cacheRead": 0.04, "cacheWrite": 0.25 }, free: false },
48
- "Qwen/Qwen3.7-Max": { tier: "opensource", benchmark: { "intelligence": 46.7 }, free: false, allowance: { "goat": 33, "pro": 43 } },
49
- "Qwen/Qwen3.7-Plus": { tier: "opensource", benchmark: { "intelligence": 39.4, "tokPerSec": 55.6 }, overContext: { "input": 1.2, "output": 4.8, "cacheRead": 0.24, "cacheWrite": 1.5 }, free: false, allowance: { "goat": 33, "pro": 43 } },
50
- "Qwen/Qwen3.8-27B": { tier: "opensource", benchmark: { "intelligence": 52 }, free: false, allowance: { "goat": 70, "pro": 80 } },
47
+ "Qwen/Qwen3.7-Flash": { tier: "opensource", overContext: { "input": 0.2, "output": 0.8, "cacheRead": 0.04, "cacheWrite": 0.25 }, free: false, allowance: { "goat": 20, "pro": 30 } },
48
+ "Qwen/Qwen3.7-Max": { tier: "opensource", discount: { "pct": 50, "endsAt": "2026-06-22" }, was: { "input": 5, "output": 15, "cacheRead": 1 }, now: { "input": 2.5, "output": 7.5, "cacheRead": 0.5 }, benchmark: { "intelligence": 46.7 }, free: false, allowance: { "goat": 33, "pro": 43 } },
49
+ "Qwen/Qwen3.7-Plus": { tier: "opensource", benchmark: { "intelligence": 39.4, "tokPerSec": 55.5 }, overContext: { "input": 1.2, "output": 4.8, "cacheRead": 0.24, "cacheWrite": 1.5 }, free: false, allowance: { "goat": 33, "pro": 43 } },
50
+ "Qwen/Qwen3.8-27B": { tier: "opensource", benchmark: { "intelligence": 52, "tokPerSec": 50.5 }, free: false, allowance: { "goat": 70, "pro": 80 } },
51
51
  "Qwen/Qwen3.8-Flash": { tier: "opensource", free: false, allowance: { "goat": 20, "pro": 30 } },
52
- "Qwen/Qwen3.8-Max": { tier: "opensource", benchmark: { "intelligence": 58.1, "tokPerSec": 46.7 }, free: false, allowance: { "goat": 20, "pro": 30 } },
53
- "sakana/fugu-ultra": { tier: "premium", free: false },
52
+ "Qwen/Qwen3.8-Max": { tier: "opensource", benchmark: { "intelligence": 58.1, "tokPerSec": 23.6 }, free: false, allowance: { "goat": 20, "pro": 30 } },
53
+ "sakana/fugu-ultra": { tier: "premium", free: false, allowance: { "goat": 20, "pro": 20 } },
54
54
  "stepfun/Step-3.5-Flash": { tier: "opensource", benchmark: { "intelligence": 26.5 }, free: false, allowance: { "goat": 20, "pro": 30 } },
55
- "stepfun/Step-3.7-Flash": { tier: "opensource", benchmark: { "intelligence": 30.9, "tokPerSec": 120.1 }, free: false, allowance: { "goat": 20, "pro": 30 } },
56
- "tencent/hy3-paid": { tier: "opensource", benchmark: { "intelligence": 42.2, "tokPerSec": 74.8 }, free: false, allowance: { "goat": 70, "pro": 80 } },
57
- "thinkingmachines/inkling": { tier: "opensource", benchmark: { "intelligence": 42.3, "tokPerSec": 69.8 }, free: false, allowance: { "goat": 20, "pro": 30 } },
58
- "thinkingmachines/inkling-small": { tier: "opensource", benchmark: { "intelligence": 41.2, "tokPerSec": 61.3 }, free: false, allowance: { "goat": 20, "pro": 30 } },
59
- "xai/grok-4.5": { tier: "opensource", benchmark: { "intelligence": 55.8, "tokPerSec": 51 }, free: false, allowance: { "goat": 20, "pro": 30 } },
60
- "xai/grok-4.6": { tier: "opensource", benchmark: { "intelligence": 60.9, "tokPerSec": 66 }, overContext: { "input": 4, "output": 12, "cacheRead": 1, "cacheWrite": 0 }, free: false, allowance: { "goat": 20, "pro": 30 } },
61
- "xiaomi/mimo-v2.5": { tier: "opensource", discount: { "pct": 98 }, was: { "input": 0.8, "output": 4, "cacheRead": 0.16 }, now: { "input": 0.14, "output": 0.28, "cacheRead": 0.0028 }, benchmark: { "intelligence": 38, "tokPerSec": 61.8 }, free: false, allowance: { "goat": 30, "pro": 40 } },
62
- "xiaomi/mimo-v2.5-pro": { tier: "opensource", discount: { "pct": 99 }, was: { "input": 2, "output": 6, "cacheRead": 0.4 }, now: { "input": 0.435, "output": 0.87, "cacheRead": 0.0036 }, benchmark: { "intelligence": 42.9, "tokPerSec": 58.1 }, free: false, allowance: { "goat": 20, "pro": 30 } },
63
- "z-ai/glm-5.3-flash": { tier: "opensource", free: false, allowance: { "goat": 40, "pro": 50 } },
64
- "zai-org/GLM-5": { tier: "opensource", benchmark: { "intelligence": 40.6 }, free: false },
65
- "zai-org/GLM-5.1": { tier: "opensource", benchmark: { "intelligence": 41, "tokPerSec": 28.2 }, free: false },
66
- "zai-org/GLM-5.2": { tier: "opensource", benchmark: { "intelligence": 52.6, "tokPerSec": 69 }, free: false, allowance: { "goat": 70, "pro": 80 } },
55
+ "stepfun/Step-3.7-Flash": { tier: "opensource", benchmark: { "intelligence": 30.9, "tokPerSec": 94.1 }, free: false, allowance: { "goat": 20, "pro": 30 } },
56
+ "tencent/hy3-paid": { tier: "opensource", benchmark: { "intelligence": 42.2, "tokPerSec": 69.1 }, free: false, allowance: { "goat": 70, "pro": 80 } },
57
+ "tencent/hy4-preview": { tier: "opensource", free: false, allowance: { "goat": 20, "pro": 30 } },
58
+ "thinkingmachines/inkling": { tier: "opensource", benchmark: { "intelligence": 42.3, "tokPerSec": 50.6 }, free: false, allowance: { "goat": 20, "pro": 30 } },
59
+ "thinkingmachines/inkling-small": { tier: "opensource", benchmark: { "intelligence": 41.2, "tokPerSec": 115.5 }, free: false, allowance: { "goat": 20, "pro": 30 } },
60
+ "xai/grok-4.5": { tier: "opensource", benchmark: { "intelligence": 55.8, "tokPerSec": 48.7 }, free: false, allowance: { "goat": 20, "pro": 30 } },
61
+ "xai/grok-4.6": { tier: "opensource", benchmark: { "intelligence": 60.9, "tokPerSec": 60.8 }, overContext: { "input": 4, "output": 12, "cacheRead": 1, "cacheWrite": 0 }, free: false, allowance: { "goat": 20, "pro": 30 } },
62
+ "xiaomi/mimo-v2.5": { tier: "opensource", discount: { "pct": 98 }, was: { "input": 0.8, "output": 4, "cacheRead": 0.16 }, now: { "input": 0.14, "output": 0.28, "cacheRead": 0.0028 }, benchmark: { "intelligence": 38, "tokPerSec": 64.1 }, free: false, allowance: { "goat": 30, "pro": 40 } },
63
+ "xiaomi/mimo-v2.5-pro": { tier: "opensource", discount: { "pct": 99 }, was: { "input": 2, "output": 6, "cacheRead": 0.4 }, now: { "input": 0.435, "output": 0.87, "cacheRead": 0.0036 }, benchmark: { "intelligence": 42.9, "tokPerSec": 43.1 }, free: false, allowance: { "goat": 20, "pro": 30 } },
64
+ "z-ai/glm-5.3-flash": { tier: "opensource", benchmark: { "intelligence": 57.5, "tokPerSec": 41.8 }, free: false, allowance: { "goat": 40, "pro": 50 } },
65
+ "zai-org/GLM-5": { tier: "opensource", benchmark: { "intelligence": 40.6 }, free: false, allowance: { "goat": 20, "pro": 30 } },
66
+ "zai-org/GLM-5.1": { tier: "opensource", benchmark: { "intelligence": 41 }, free: false, allowance: { "goat": 20, "pro": 30 } },
67
+ "zai-org/GLM-5.2": { tier: "opensource", benchmark: { "intelligence": 52.6, "tokPerSec": 68.9 }, free: false, allowance: { "goat": 70, "pro": 80 } },
67
68
  "zai-org/GLM-5.2-Fast": { tier: "opensource", free: false, allowance: { "goat": 20, "pro": 30 } },
68
- "zai-org/GLM-5.3": { tier: "opensource", benchmark: { "intelligence": 59.5, "tokPerSec": 79.6 }, free: false, allowance: { "goat": 20, "pro": 30 } },
69
+ "zai-org/GLM-5.3": { tier: "opensource", benchmark: { "intelligence": 59.5, "tokPerSec": 80.6 }, free: false, allowance: { "goat": 20, "pro": 30 } },
69
70
  };
70
71
  export const PLAN_CATALOG = {
71
72
  go: { price: 1, credits: 10, window5h: 3, windowWeek: 6, display: "Go" },
@@ -77,5 +78,5 @@ export const PLAN_CATALOG = {
77
78
  provider: { price: 15, credits: 0, window5h: 0, windowWeek: 0, display: "Provider" },
78
79
  };
79
80
  export const DEAL_SOURCE_URL = "https://commandcode.ai/docs/resources/pricing-limits";
80
- export const DEAL_LAST_REFRESHED = "2026-08-27";
81
+ export const DEAL_LAST_REFRESHED = "2026-08-29";
81
82
  export const DEAL_PACKAGE_VERSION = "docs";
@@ -37,6 +37,13 @@ export const REASONING_MODELS = new Set([
37
37
  "poolside/laguna-s-2.1-free",
38
38
  "stepfun/Step-3.7-Flash",
39
39
  "tencent/hy3-paid",
40
+ // tencent/hy4-preview is reasoning-capable with explicit efforts
41
+ // (models.md lists `low, medium, high` since command-code@1.38.0,
42
+ // 2026-08-28) — it belongs in MODEL_EFFORTS, not here. Keeping it here
43
+ // would leave a snapshot model classified in both REASONING_MODELS and
44
+ // MODEL_EFFORTS, which breaks the dedicated
45
+ // `tencent/hy4-preview is an efforts model` pin in
46
+ // tests/catalog-metadata.test.ts.
40
47
  "thinkingmachines/inkling",
41
48
  "thinkingmachines/inkling-small",
42
49
  ]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-cmd-provider",
3
- "version": "1.5.2",
3
+ "version": "1.6.1",
4
4
  "description": "Command Code provider + plugin for opencode",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,15 +20,16 @@
20
20
  "typecheck": "tsc --noEmit",
21
21
  "refresh:snapshot": "node scripts/refresh-snapshot.mjs",
22
22
  "refresh:deals": "node scripts/refresh-deals.mjs",
23
- "refresh": "npm run refresh:snapshot && npm run refresh:deals -- --fixtures",
23
+ "refresh": "npm run refresh:snapshot && npm run refresh:fixtures && npm run refresh:deals -- --fixtures",
24
24
  "test": "npm run typecheck && npm run test:unit && npm run test:integration && npm run test:contract && npm run format:check",
25
- "test:unit": "tsx tests/env.test.ts && tsx tests/auth-key.test.ts && tsx tests/converters.test.ts && tsx tests/stream.test.ts && tsx tests/provider-codecs.test.ts && tsx tests/provider-transport.test.ts && tsx tests/provider-parity.test.ts && tsx tests/provider-upgrade-fallback.test.ts && tsx tests/provider-zdr.test.ts && tsx tests/redact.test.ts && tsx tests/cost.test.ts && tsx tests/retry.test.ts && tsx tests/reasoning.test.ts && tsx tests/modalities.test.ts && tsx tests/snapshot.test.ts && tsx tests/refresh-snapshot.test.ts && tsx tests/oauth.test.ts && tsx tests/auth-mirror.test.ts && tsx tests/parse-facts.test.ts && tsx tests/parse-modalities.test.ts && tsx tests/catalog-metadata.test.ts && tsx tests/plugin-models.test.ts && tsx tests/vendor.test.ts && tsx tests/deals-enrichment.test.ts && tsx tests/deals-coverage.test.ts && tsx tests/plan-summary.test.ts && tsx tests/html-tables.test.ts && tsx tests/parse-docs.test.ts && tsx tests/refresh-deals.test.ts && tsx tests/tui-deals-panel.test.ts && tsx tests/plugin-install.test.ts",
25
+ "test:unit": "tsx tests/env.test.ts && tsx tests/auth-key.test.ts && tsx tests/converters.test.ts && tsx tests/stream.test.ts && tsx tests/provider-codecs.test.ts && tsx tests/provider-transport.test.ts && tsx tests/provider-parity.test.ts && tsx tests/provider-upgrade-fallback.test.ts && tsx tests/provider-zdr.test.ts && tsx tests/redact.test.ts && tsx tests/cost.test.ts && tsx tests/retry.test.ts && tsx tests/reasoning.test.ts && tsx tests/modalities.test.ts && tsx tests/snapshot.test.ts && tsx tests/refresh-snapshot.test.ts && tsx tests/oauth.test.ts && tsx tests/auth-mirror.test.ts && tsx tests/parse-facts.test.ts && tsx tests/parse-modalities.test.ts && tsx tests/catalog-metadata.test.ts && tsx tests/plugin-models.test.ts && tsx tests/vendor.test.ts && tsx tests/deals-enrichment.test.ts && tsx tests/deals-coverage.test.ts && tsx tests/plan-summary.test.ts && tsx tests/html-tables.test.ts && tsx tests/parse-docs.test.ts && tsx tests/parse-rsc.test.ts && tsx tests/mock-cc-rsc.test.ts && tsx tests/capture-rsc-fixtures.test.ts && tsx tests/refresh-deals.test.ts && tsx tests/refresh-deals-rsc.test.ts && tsx tests/tier-overrides.test.ts && tsx tests/tui-deals-panel.test.ts && tsx tests/diff-catalog.test.ts && tsx tests/catalog-refresh-extract.test.ts && tsx tests/catalog-refresh-push.test.ts && tsx tests/plugin-install.test.ts",
26
26
  "test:integration": "tsx tests/integration-do-stream.test.ts && tsx tests/integration-do-generate.test.ts",
27
27
  "test:contract": "tsx tests/contract.test.ts",
28
28
  "test:e2e": "node tests/e2e-opencode.mjs",
29
29
  "build:tui": "bun scripts/build-tui.ts",
30
30
  "format": "prettier --write '**/*.{ts,mjs,json,md}'",
31
- "format:check": "prettier --check '**/*.{ts,mjs,json,md}'"
31
+ "format:check": "prettier --check '**/*.{ts,mjs,json,md}'",
32
+ "refresh:fixtures": "node scripts/capture-rsc-fixtures.mjs"
32
33
  },
33
34
  "keywords": [
34
35
  "opencode",