Repository navigation
Releases: tkhs101/OpenCode-Zen-FreeX
Release list
v0.5.3
Fix: the published model table now matches the route it describes.
On the VPS the gateway offered minimax-m3.1-flash-free a 3,491,182-token window against 1,048,092 the route had served, deepseek-v4.1-flash-free 1,233,222 against the 326,000 measured, big-pickle a 32,000-token output where the route named 131,072 in a refusal, and nemotron-3.5-super-vl-free an 8,192-token output for a model whose 1,000,000-token ask was answered 200.
- An encoded attachment is no longer counted as prompt text: a
data:URI, or a bare base64 field under atype,mime_typeormedia_type, is skipped. A 10 MB screenshot became 3,498,676 "tokens" of base64, and that floor was published back as the model's window. - The estimate scale moves to 3, which drops the brackets measured by the counting that included attachments — those windows were sizes the route was never asked for.
- A completion ceiling the route stated itself (
routeorroute-twinin the table, or a refusal seen at runtime) now outranks a smaller models.dev claim; a larger claim still wins. - With no paid twin, models.dev's row for the route id itself and the canonical aggregate are both read and the larger wins (NVIDIA's canonical 8192 vs the route row's 131072; minimax's canonical 524288 vs the row's 512000).
- The discovery cache version moves to 3, so a listing cached with the old limits is fetched again.
- bun test 775 pass; CI green.
v0.5.2
Fix: a full review closes transport, discovery, limits and workflow defects.
- provider/stream: upstream hop-by-hop and stale body headers are dropped through one shared helper, so a relayed 403 or 429 can no longer forward the
x-hopaConnectiontoken names; the upstream status is kept instead of collapsing every reply to 200. - tool-response: an upstream failure is answered with the project's own message, ABORT_ERR counts as an abort rather than a failure, and a rejected body reader is cancelled with the read error.
- models: the discovery cache is versioned (v2), read through a bounded reader instead of an unbounded one, and refetched when another version wrote it.
- limits: the profile is resolved once per sweep run (a config failure used to be retried three times and charged three requests), and --stale-after now requires digits so a date cannot supply a year.
- entries: audit, sweep, watch and capture share the "argv means script, no argv means import" rule, so importing them no longer throws on Node below 22.18.
- capture: every read target comes back through one helper.
- workflows: the gate fails when a scan stage fails (PIPESTATUS, not pipefail alone), concurrent runs are found by the newest updatedAt rather than creation order, and the PR base and compare links keep the default branch.
- bun test 773 pass, and each of the 12 files also passes on its own; CI green on Node 18.17.0 and 24.x; published to npm as 0.5.2.
v0.5.1
Fix: models.dev output lookup strips the -free suffix and reads the paid twin.
- 'deepseek-v4.1-flash-free' now reads models.dev's 'deepseek-v4.1-flash' in the opencode provider: output 384000, not 1048576. The 0.5.0 maximum was poisoned by resellers that copy context into limit.output.
- Same for glm-5.3-flash (131072), beam (131072), mimo (131072), minimax (524288), longcat (131072), nemotron lightning (262144), etc.
- With no paid twin, the canonical first-party/most-common output is the fallback; models.dev's direct non-canonical entries (big-pickle 32000) are used when available.
- bun test 735 pass; CI green.
v0.5.0
Completion ceilings now follow models.dev's largest claim; only context is measured.
- models.dev is read for both context and output. For every model with a canonical id, the largest limit.output among the entries for that model is the declaration, applied in both directions (it may raise or lower a stale catalogue/table figure).
- The sweep still asks only for sixteen completion tokens and brackets prompts: no output probing. Table/live output tiers remain fallback only for ids models.dev does not describe.
- Tests cover output-only claims, max-not-vote, lowering a stale claim, table/live ignored when models.dev answers, and the no-claim fallback. bun test 731 pass; CI test/node-host/gate green.
- Note: models.dev has no canonical entry for Zen-only ids such as big-pickle; those keep the catalogue/table fallback.
v0.4.0
The plugin now reads the limits snapshot the scheduled workflow publishes, so new measurements reach installed hosts without an npm release.
- Default source: https://raw.githubusercontent.com/tkhs101/OpenCode-Zen-FreeX/main/limits-observed.json (the same limits-observed.json the walls workflow merges into main).
- Startup installs the local cache before the first model list; a background fetch (one per hour, 5 s timeout, single-flight) updates it. No request ever waits on GitHub.
- 256 KiB streamed body cap, version/row/numeric validation (including named windows at the 4M-token ceiling), zero-valid documents never wipe the table; cache writes are atomic and 0600.
- Precedence: explicit file > OPENCODE_ZEN_FREE_LIMITS_SNAPSHOT (path or empty) > cache/remote > bundled. OPENCODE_ZEN_FREE_LIMITS_SNAPSHOT_URL/CACHE/REFRESH_MS/TIMEOUT_MS configure the layer.
- One-time upgrade: 0.3.x does not read the remote; after 0.4.0, workflow data needs no release. Unreachable raw GitHub falls back to cache/bundled (documented; mirror URL supported).
- Audit: R7-01..R7-07 findings fixed and independently verified; bun test 729 pass, CI test/node-host/gate green.
v0.3.1
Patch: the startup discovery cache replaces the older shipped bootstrap table instead of merging under it. A model the live route has already dropped (e.g. Muse Spark 1.3 Contributor Free, 410) is no longer advertised after a restart from cache; a live read still wins and a listing failure still falls back to the cache.
v0.3.0
Free-tier behavior release from the opencode2api comparison.
- Session identity now reads the aliases other agents use (session_id, conversation_id, body conversation_id, Claude Code metadata.user_id) and seeds unnamed conversations with the system prompt plus the opening; previous_response_id is the last explicit signal.
- Chat function names merge by the prefix rule in both the collapse and guard paths, so a repeated or growing name is not read as an unknown tool.
- The last successful model discovery is cached atomically and used as a floor: startup merges it under the bootstrap table, a live read always wins, and a listing failure reports the cache age beside magpie.fellBack.
- limits-sweep classifies a model unavailable only on explicit model-gone answers; limits-watch records that day as history (never a disable switch) and gains a read-only --status [--json] freshness report with exit codes 0/2/1, distinct from --check.
- A free-tier IP-abuse 403 is diagnosed as an egress-IP block instead of a tool-wording problem; no local cooldown or egress rotation.
- R6 reasoning-history repair was measured and deliberately not implemented: real tool round-trips with/without reasoning fields were all 2xx, and the free tier serves no Anthropic model.
- Docs: README/MAINTAINING/.env.example updated for the session rules, discovery cache, status report, and 403 taxonomy.
v0.2.51
Patch release for the v0.2.50 full audit.
Fixes from the OpenCode Review audit and a second review of the fix diff:
- limits: a refusal no longer pins the adaptive bracket at the floor; the wedge path keeps the declaration at or above the served floor; the sweep only reads 400/413 as size refusals, retries only transient failures, never counts an unconfirmed refusal, and charges its budget in requests; limits-watch rejects unknown walls, dates empty attempts, exits 2 for reached-but-empty, and bounds the numbers an unattended merge may publish.
- request path: null host histories no longer throw; signal and opening session keys are separate domains; reply-size limits are UTF-8 bytes; terminal responses no longer overwrite streamed text; Responses/Messages call ids are claimed once per reply and kept stable across frames.
- tools: limits-audit survives null catalogue rows and rows that cannot be built; capture only writes the provider-utils it observed and names CAPTURE_PORT on a taken port; tools-smoke and limits-audit share one base-URL rule; assert-bun-version checks the child process it runs.
- CI: credential scanning runs before repository code, reads HEAD, and scans contents; the gate report is quoted, not interpreted; the Zen probe is push-only; a Node host-smoke job covers 18.17.0 and the current LTS; walls uses one rolling branch/PR, reads the survey exit code, and reports merged only after GitHub says MERGED.
- docs: the numbers, commands, exit codes, and env variables the fixes moved.
Verification: 657 unit tests pass; Node 18.17.0 and 24.x smoke pass; CI green on the release commit.
v0.2.50
Published to npm as opencode-zen-freex@0.2.50.
- fix: the devEngines field npm rejects
- chore: 0.2.50
- docs: the claims the fixes moved
- chore: the workflows and the manifest — a token left in the tree
- fix: the measurement — a raise that lowers, a wall asked for again
- fix: the request path — a name that is not a name, a last event, an id
- fix: a bracket with no evidence of its own may not lower the declaration
- feat: the measured group takes the measurement, and the snapshot says so
- chore: record the walls measured on 2026-10-20 (#7)
- fix: a model the catalogue declares at a million is not measured
- chore: record the walls measured on 2026-10-20 (#6)
- fix: the gate probes with a model the route still serves
- fix: a refusal under a served size is not a bound, and the route's other words
- fix: a bracket seeded at the catalogue number does not pin the second opinion
- fix: a table entry does not lock the second opinion out
- fix: ask models.dev for JSON, or the claim reader walks a string
- feat: a round million is taken at the scale models.dev says it meant
- fix: the sweep reaches past the binary million, so a 1M window is measured
- chore: 0.2.40
- fix: the shell's wording names the shell the tool runs, not the one that captured it
- chore: record the walls measured on 2026-10-19 (#5)