Commit Graph

549 Commits

Author SHA1 Message Date
Julius Brussee b36219e2b1 chore(release): cut @caveman-ai/cli 1.3.3 on the bin-v1.1.6 runtime
Bump every BINARY_RELEASE pin to bin-v1.1.6 and regenerate the compiled
agent-skills bundle, which still carried the pre-ASD-STE100 caveman skill.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
bin-v1.1.6 cli-v1.3.3
2026-09-04 02:18:53 +02:00
Julius Brussee b82c0ad42c chore(release): v2.6.0
Bump the bootstrap pin lockstep (install.sh, install.ps1, bin/install.js,
package.json, README, INSTALL) to the v2.6.0 release.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
v2.6.0
2026-09-04 02:13:29 +02:00
github-actions[bot] 1298e2ecb0 chore: sync SKILL.md copies [skip ci] 2026-09-03 23:57:44 +00:00
Julius Brussee 0574b85a19 feat(skill): always mix ASD-STE100 clarity register into caveman
One idea per sentence, short sentences, active voice, one word one meaning,
imperative instructions, no ambiguous pronouns. Caveman cuts filler; the
controlled-English rules keep what makes meaning unambiguous.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
2026-09-04 01:57:34 +02:00
Julius Brussee 3e62063e40 fix(codex): compress array-shaped tool output, record route eligibility, stop config self-corruption and hook stacking
Live-tested Codex 0.149 through the proxy and found four defects:

- proxy: custom_tool_call_output.output is an ARRAY of input_text parts on
  Codex 0.149+. The Responses extractor accepted only the string form, so
  every real Codex tool turn had an empty live zone and the subscription
  route compressed nothing (75-116 KB requests, zero savings). The captured
  real request now compresses; regression test pins the array shape.
- proxy: the /chatgpt route never recorded compression eligibility, so the
  CLI told every Codex subscription user "your agent never reached the
  compression layer" even when routing worked.
- cli: codexNativeConfig ran the legacy table strippers before removing its
  own marker blocks; the stripper swallowed the tables end marker, so the
  block enable had just written failed its own re-parse as "corrupted" on
  the next wrap and doctor reported drift forever. Markers come off first.
- cli: nativeHooksDocument matched caveman hook entries by exact command
  string, so a binary path change (upgrade, moved install) appended a new
  hook set per event instead of replacing it. Match on managed identity.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
2026-09-04 01:57:14 +02:00
Julius Brussee 9911e5fd0d test(cli): kilo install assertion derives from the profile pin
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
2026-09-03 20:54:29 +02:00
Julius Brussee ee2f8a8522 test(agents): derive pins from profiles instead of literals
The compile test hardcoded kilo@7.5.6 and the drift test hunted the live
registry for a prerelease pin, so the nightly-drift bump in 18a8c09 turned
main red. Read the pin from agents/profiles at test time and synthesize the
prerelease registry the drift test needs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
2026-09-03 20:52:43 +02:00
Julius Brussee 695703c0d5 fix(pi): per-model originals and compat-mount routing for custom providers
- cache original base URLs per model, not per provider, so a same-provider
  model with its own endpoint stays direct (#973)
- proxy publishes its named compat mounts in the run-state file; the pi
  extension routes a custom provider through /w/pi/compat/<name> only when a
  mount with that name and a matching host is published (#952, #970)
- hostOf compares host:port so loopback relays on different ports differ

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
2026-09-03 20:49:23 +02:00
Julius Brussee 87325d89e1 fix(extension): Firefox pack in release gate, e2e opt-in, min version 140
Follow-ups on the #936 merge: npm run package now emits the Firefox zip
too; the Firefox e2e (which fetches web-ext through npx) is no longer part
of test:all; strict_min_version drops to 140.0, the desktop floor for
data_collection_permissions (no gecko_android target is declared).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
2026-09-03 20:39:12 +02:00
Julius Brussee 478688d1bb Merge branch 'pr-936' 2026-09-03 20:38:43 +02:00
Julius Brussee 8c5fba6410 docs(claude): hook stdin readers must return on first complete JSON, not EOF
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
2026-09-03 20:36:25 +02:00
Julius Brussee 18a8c091d8 chore(agents): bump tested pins after local probe (closes #958 #959 #960 #961 #962 #963 #964)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
2026-09-03 20:36:03 +02:00
Julius Brussee 9ed2c398de fix(cli): host hook callbacks return on first complete JSON payload, not EOF
shrink-hook (PreToolUse), the memory recall hook (UserPromptSubmit) and
native-hook are invoked directly by hosts and read stdin to EOF. Under the
Windows pipe implementation the host's close can lag arbitrarily (#729/#833,
#949), so a hook with its work done sat until the host's timeout. Same fix
shape as native-hook-fast and the Go bridge: resolve on the first complete
JSON object, keep the 2 MiB cap, unref stdin so the process can exit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
2026-09-03 20:36:01 +02:00
Julius Brussee 7b5a9e1260 fix(hooks): strengthen per-turn caveman reinforcement (#951)
Merges PR #951: the UserPromptSubmit reminder now restates the concrete
style rules for the active level instead of a bare status banner, so the
model holds caveman style after competing mid-session instructions.
Checksum manifest regenerated after the #954 merge. Fixes #303.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W2f7Lf7G9erA7YNn5SXPEj
2026-09-03 20:32:53 +02:00
akshitnanda f4668fb211 fix(proxy): native-hook bridge returns on first complete JSON payload, not EOF (#965)
The JS adapter already returns on the first complete JSON object because the Windows pipe close can lag arbitrarily (#729/#833), but the Go bridge in front of it still blocked on EOF, so under 'codex exec' on Windows the SessionStart hook never reached the daemon spawn. Refs #949.
2026-09-03 20:32:19 +02:00
Alot1z 1360b604a2 test(compress): regression tests for first-text-block selection (#957)
Co-authored-by: Alot1z <alot1z@users.noreply.github.com>
2026-09-03 20:32:15 +02:00
Alot1z 7b889f0122 fix(stats): pin number formatting to en-US (#954)
* fix(stats): pin number formatting to en-US

toLocaleString() renders per host locale, so the suite's "1,250"
expectations fail on non-en-US hosts (observed de-DE: 1.234 vs 1,234).
fmt() pins the locale for all formatted display; 52/52 incl. a de-DE
regression test.

* chore(hooks): refresh integrity manifest

* fix(stats): clean merge-conflict debris from checksums.sha256

Lines 6-10 held an unresolved conflict block (stray HEAD/edd4205 markers and a
duplicated caveman-stats.js line) flagged in review; the integrity regex
silently skipped it, but a future manual edit could trip over the duplicate.
Rewrote the manifest to exactly one canonical line per file; all hashes
re-verified against the working tree (caveman-stats.js 8650f63... is the
intended refresh on this branch).

---------

Co-authored-by: Alot1z <alot1z@users.noreply.github.com>
2026-09-03 20:32:11 +02:00
github-actions[bot] 0a6be5d46a chore: sync SKILL.md copies [skip ci] 2026-09-03 18:31:55 +00:00
akshitnanda bd5f12d673 fix(agents): drop Claude-only tools frontmatter so Gemini CLI loads cavecrew agents (#966)
Signed-off-by: Akshit Nanda <akshit.nanda91@gmail.com>
2026-09-03 20:31:44 +02:00
Zsolt 218ffd695b fix(pi): route only default provider endpoints (#972)
* fix(pi): route only default provider endpoints

The extension routed a provider by name. A provider with the name openai
that points at a local relay or at Azure got the gateway route, and the
gateway sent the request to api.openai.com. The local relay got no
request, and the request failed with a 401 error.

The extension now routes a provider only when the host of its original
base URL is the upstream host of the proxy route. The router caches the
original base URL before the first override, because the registry
reports the gateway route after an override. A mismatch keeps direct
mode and names the endpoint in the pass-through notice. The same rule
keeps a moved opencode-go endpoint away from the stale built-in mount.

The stub provider fixture now declares three providers: openai on the
real host, opencode-go on the real host, and anthropic on a dead
loopback port. New integration tests drive an opencode-go model through
the compat mount path and keep a custom-endpoint provider direct.

Fixes #970
Fixes #971

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>

* docs(pi): state that pi keeps provider overrides in memory

The review of #972 asked about a stale override from an earlier pi
process. Pi keeps extension provider overrides in memory only, so a new
process starts from the original base URL. The comment on the originals
map now records this fact.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>

---------

Signed-off-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>
Co-authored-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 20:29:40 +02:00
Zsolt f73d98fc8e fix(proxy): send x-api-key on compat /v1/messages (#969)
* fix(proxy): send x-api-key on compat /v1/messages

A named compat mount mapped every credential to Authorization: Bearer.
The Anthropic client in Pi sends x-api-key to /v1/messages. OpenCode Go
rejects a Bearer header on that path with 401 "Missing API key.". Thus
the opencode-go anthropic-messages models failed through the proxy.

The named adapter now maps the credential by the wire protocol of the
path. A request to /compat/<name>/v1/messages gets x-api-key and a
default anthropic-version. Every other path keeps Bearer. The gateway
env fallback puts the key in the header that the adapter emitted, so
the upstream never gets two credentials.

New tests cover the header mapping at the adapter, the gateway fallback,
and the full standalone handler with the /w/pi prefix. A test also
shows that a user compat.opencode-go entry replaces the built-in
upstream on the adapter path. The docs describe the header rule.

Fixes #967
Fixes #968

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>

* docs(proxy): add the compat header rule to AGENTS.md

proxy/AGENTS.md carries the same auth bullet as proxy/CLAUDE.md. This
commit adds the same header rule to both files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>

* fix(proxy): keep a real bearer on compat /v1/messages

Review of #969 found two risks. The Anthropic-path remap relabeled a
real inbound Bearer token as x-api-key on every named compat mount.
This broke the rule that an inbound credential keeps its auth scheme.
The remap now skips a real Bearer token. The gateway placeholder is not
a real credential, so the remap still moves it to x-api-key, and the
env fallback replaces it in that header.

The fallback test for x-api-key used a direct map lookup that depends
on canonical header keys. It now uses Header.Get. The openai and
openai_compatible fallback cases are separate, so each guard list
names only the headers that its adapter can emit.

New tests show that a real Bearer stays Bearer on /v1/messages at the
adapter, in the gateway fallback, and through the standalone handler.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>

---------

Signed-off-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>
Co-authored-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 20:29:36 +02:00
Alot1z 81b3327f21 fix(extension): guard content-script css against relative url() at stage verify
A relative url() in a content-script stylesheet resolves against the page
origin (the D1 @font-face 404/403 defect, KB #6441) and no amount of
allowlisting catches it - the reference looks valid, it just can never
load. Fail the pack for both targets whenever the css the manifest
registers as content_scripts references a non-absolute url(), driven off
the manifest so new stylesheets are covered automatically.
2026-09-03 17:30:56 +02:00
Alot1z 62475f91c4 test(extension): keep process.exit at module top level in firefox-e2e (KB 5486)
All three skip/exit outcomes now resolve through main()'s return value and a
single top-level exit, so no process.exit can preempt the cleanup finally
(web-ext tree kill, BiDi close, temp-dir removal). Mutation pass 2/2 on the
guard's key assertions (KB 5489): wrong site host -> indicator FAIL; altered
primer text -> primer FAIL; both reverted, final run 5/5.
2026-09-03 17:20:29 +02:00
Alot1z a6b6b59e17 test(extension): codify the real-Firefox injection guard as npm run test:firefox
The Firefox proof (injection + full-primer send, FF 155) existed only as a
one-off drive and a KB recipe; any edit could silently decay it back into a
claim. scripts/firefox-e2e.mjs rebuilds the Firefox stage, installs it in real
Firefox via web-ext (release-safe temporary add-on) and asserts over a raw
WebDriver BiDi session on the same instance (--args=--remote-debugging-port,
KB #6443) that the indicator injects, a trusted Enter sends the full primer,
and no extension-sourced console errors appear. Skips with exit 0 and a clear
message when Firefox (FIREFOX_BIN override) or web-ext is unavailable, so
test:all never breaks on machines without Firefox. Wired as test:firefox and
added to test:all, mirroring the existing test:browser split (npm test stays
the fast hermetic unit/contract suite).
2026-09-03 17:18:05 +02:00
Alot1z 1b6f8e8715 fix(extension): drop indicator font-face that 404s on every chat page
Content-script CSS is injected into chat pages, so its relative url()s resolve
against the page origin: the indicator's @font-face requested geist-mono.woff2
from the page host (measured 404 on a local harness, 403 on chatgpt.com) and
never loaded, while every chat page ate a failed cross-origin request. Remove
the dead font-face and its now-consumerless web_accessible_resources entry;
fonts stay shipped for the popup, which loads them from the extension origin.
2026-09-03 16:58:14 +02:00
Alot1z 8ba806a98d fix(extension): pass addons-linter clean on the Firefox build
Add the mandatory data_collection_permissions disclosure (none) and raise
strict_min_version to 142.0, the floor the key requires on desktop (140+)
and Android (142+). web-ext lint on the staged build now reports
0 errors / 0 warnings / 0 notices. README load instructions point at the
staged build, since the template intentionally carries no version field.
2026-09-03 14:26:01 +02:00
Alot1z e0b059e6ad fix(extension): address AMO review on the Firefox port
Three items from the #936 maintainer review:
- gecko id is now a UUID-style id ({2bcb73e7-...}) that claims no domain
  (AMO ids are permanent); removed the Co-Authored-By footer from the
  Firefox README while touching it.
- the Firefox manifest template no longer carries a version: the firefox
  pack target injects the shared version (package.json == Chrome manifest,
  validated) at pack time, so the two manifests cannot drift.
- background uses the Firefox MV3 event-page form (background.scripts);
  service_worker dropped, strict_min_version 121.0 kept as a conservative
  floor with the corrected rationale. The stage verifier now also validates
  background.scripts references.

Verification: extension unit suite 11/11 (new firefox-template contract
test), firefox pack + stage verification green, chrome pack unaffected.
2026-09-03 13:43:20 +02:00
Alot1z 54de3c9ffc fix(extension): repair Firefox manifest for AMO submission
The shipped gecko.id pointed at an unowned domain and the background
block declared both service_worker and scripts, which WebExtensions
reject together. Use a stable add-on id, keep a single MV3 service
worker, and derive the packed Firefox version from the shared source so
the two manifests cannot drift at pack time.
2026-09-03 03:06:39 +02:00
Alot1z 2da16bf53b build(extension): AMO-ready firefox pack target for the zip builder
`node build-extension-zip.mjs firefox` stages the shared runtime flat
(WebExtensions forbid ../ escapes), swaps in the firefox manifest, and verifies
against the package allowlist -> dist/caveman-browser-firefox-<ver>.zip. The
chrome target is unchanged.

Co-Authored-By: Alot1z <Alot1z@users.noreply.github.com>
Signed-off-by: Alot1z <Alot1z@users.noreply.github.com>
2026-09-03 03:06:39 +02:00
Alot1z f0de2ad357 feat(extension): Firefox port of the Caveman Mode extension (#810)
Same runtime files as the Chrome MV3 extension (directive injection on
chatgpt/claude/gemini), Firefox-tuned manifest: browser_specific_settings.gecko
id + strict_min_version 121, service-worker fallback via background.scripts.
Flat, root-relative paths so it stages standalone for AMO.

Closes #810

Co-Authored-By: Alot1z <Alot1z@users.noreply.github.com>
Signed-off-by: Alot1z <Alot1z@users.noreply.github.com>
2026-09-03 03:06:38 +02:00
Akshit Nanda 17d029d999 fix(hooks): strengthen caveman reinforcement
Signed-off-by: Akshit Nanda <akshit.nanda91@gmail.com>
2026-09-02 09:21:29 -05:00
Julius Brussee 3b74643f4d fix(cli): wait for a freshly started proxy's run state before judging its owner
A proxy caveman just started binds its port before its run state is
readable, so the immediate probe could report a foreign owner on slower
runners. Poll briefly after start and restart. Test fixes for CI: pin
XDG_CONFIG_HOME for in-process Kilo assertions, import the profile scope
checker through a file URL so Windows can load it, and skip the sh-stub
gh reporter tests on Windows.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:48:49 +02:00
github-actions[bot] da322e71dd chore: sync SKILL.md copies [skip ci] 2026-09-02 13:39:28 +00:00
Julius Brussee f9a039a93d chore(release): cut v2.5.0 and @caveman-ai/cli 1.3.2 on the bin-v1.1.5 runtime
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
bin-v1.1.5 cli-v1.3.2 v2.5.0
2026-09-02 15:39:01 +02:00
Julius Brussee 14b1c15f2a fix(cli): fail closed on unverifiable proxy owners, strip attributed routes on direct launch
Review follow-ups to #945: a listener caveman did not start this run and
cannot prove it owns (foreign process, or a proxy binary too old to
answer) now launches direct, and the direct-launch strip removes the
agent-attributed /w/<agent> route as well as the bare gateway URL, so a
leaked outer route never reaches the child. Qwen's ACP and extension
listing guards accept yargs camelCase spellings. Proxy-aware fetch no
longer sets an IP literal as TLS servername (rejected on Node 26). The
conformance-pin test fixture follows the pinned-upstream-binary job.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:39:01 +02:00
Julius Brussee d6c1cd39af fix(cli): launch direct when a foreign process owns the proxy port
A foreign listener on 127.0.0.1:8787 used to get the banner but still
receive the routed launch, which would send the operator's provider
keys to a process caveman does not own (#945). Treat it like a gate
mismatch and fall back to a direct launch.

Also: Claude Code refuses Remote Control behind any non-first-party
ANTHROPIC_BASE_URL, so `caveman claude remote-control` launches direct
and the limitation is documented (#947); caveman-compress reads the
first text block instead of content[0] so a leading tool_use block no
longer crashes after a paid call (closes #932's report); hook checksum
manifest regenerated after #794.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:25:28 +02:00
Julius Brussee c24123dd2b Merge remote-tracking branch 'origin/main'
# Conflicts:
#	README.md
#	docs/technical/agent-profile-registry.md
#	packages/cli/src/index.ts
#	packages/cli/tests/subscription-recovery.runtime.mjs
#	proxy/internal/gateway/chatgpt.go
#	proxy/internal/gateway/proxy.go
#	proxy/internal/gateway/retrieve_tool.go
#	proxy/internal/gateway/server.go
#	proxy/internal/gateway/subscription_live_zone_test.go
2026-09-02 15:19:57 +02:00
Julius Brussee d9faebc2b2 docs(readme): rewrite the front door around measured savings
Two-size install story, a What-you-save section with static SVG charts
rendered from the committed benchmark table, and plain-language copy
for non-programmers. Charts regenerate with benchmarks/render_charts.py.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:18:19 +02:00
Julius Brussee 7684fb1cef fix(cli): name per-session recovery and lock Qwen/Kilo control surfaces
Bare start never stamps global recovery; the banner now says which
sessions compress (those whose agent carries caveman_retrieve) and the
status mcp-missing row keys off any installed MCP marker.

Qwen: refuse extension, ACP, session-restore, control-command, and
enforced-auth surfaces that could reactivate a provider route outside
the locked session; replace modelProviders/providerProtocol wholesale
in the routed profile; keep web search and workflows off via env.
Kilo: daemon and console launch direct since they outlive the wrap.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:18:19 +02:00
Julius Brussee 41819dcba0 feat(proxy): prove MCP recovery from the request tool list
A bare proxy serves whichever client connects, so a machine-level MCP
install marker can never bind to one request. Read the namespaced
caveman retrieve tool out of the request's own tool list instead, so
subscription and OAuth sessions on a standalone proxy reach the live
zone when their agent carries the tool (#908).

Cache-breakpoint planning and the provider-native cache optimizers now
default on in optimization modes; explicit off and unknown values still
fail closed, and record mode never runs them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:18:19 +02:00
Julius Brussee 8dffbb2602 chore: remove cacheengine from this repo
The standalone cache planner is no longer in scope here. Drop the
directory and its BSL listing, license scope note, contributor note,
and the verify_repo license-boundary entry.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:18:19 +02:00
github-actions[bot] b2258d9719 chore: sync SKILL.md copies [skip ci] 2026-09-02 13:16:01 +00:00
Pedro Henrique Lopes De Melo 758c69e11b fix(stats): count each API response once, not once per content-block line (#794)
* fix(stats): count each API response once, not once per content-block line

* test(stats): cover response-line dedupe, retry path, and no-id fallback
2026-09-02 15:15:56 +02:00
Amir Fathi dbbc0929b0 fix(compress): validate candidates before touching the live file (#938)
compress_file() wrote each un-validated candidate straight to the live
source file and validated it in place. An interruption (Ctrl-C,
SIGTERM, OOM, or a harness killing the process) between that write and
a passing validation left the live file holding un-validated or
garbage output, with the out-of-tree backup as the only recovery path.

Each candidate is now staged next to the source and validated there;
the live file is written only once a candidate passes, and left
untouched if every attempt fails.

Fixes #544

Signed-off-by: Amir Fathi <amirfathi.me@gmail.com>
2026-09-02 15:15:51 +02:00
s4kura d88f5319bb fix: update retired benchmark model (#937)
Signed-off-by: Iams4kura <126048986+Iams4kura@users.noreply.github.com>
2026-09-02 15:15:47 +02:00
Julius Brussee b4de606fb8 Merge pull request #948 from zsltg/fix/pi-opencode-go-routing
fix(pi): route opencode-go through compat mount
2026-09-02 11:58:22 +02:00
Zsolt Gaspar 455f462407 docs(proxy): document built-in opencode-go compat mount
The proxy now registers /compat/opencode-go/ with a default upstream
and the OPENCODE_API_KEY credential variable. Add the mount and the
user override to the provider docs. Add the variable to the
credential list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>
2026-09-01 21:49:47 +02:00
Zsolt Gaspar 8c5bd6989f fix(pi): route opencode-go through compat mount
The pi extension routed models by wire protocol only. OpenCode Go
models use the OpenAI protocol, so the gateway sent them to
api.openai.com. The OpenCode Go key then caused a 401 error.

The extension now routes by provider and API. OpenCode Go models go
to the /w/pi/compat/opencode-go mount. The extension does not route
unknown providers and shows a pass-through warning.

The standalone proxy registers a built-in compat mount with the
upstream https://opencode.ai/zen/go. The config package holds the
built-in table, so the mount and its key policy come from one place.
A user compat entry with the same name wins. Keyless requests to this
mount use OPENCODE_API_KEY, not OPENAI_COMPAT_API_KEY.

Fixes #946

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Zsolt Gaspar <17578237+zsltg@users.noreply.github.com>
2026-09-01 21:49:47 +02:00
Julius Brussee 60dbb92d62 fix(proxy): lock Qwen side-route surfaces 2026-08-30 06:33:04 +02:00
Julius Brussee cdf3e16bfc fix(proxy): keep Qwen extension guard bounded 2026-08-30 06:15:33 +02:00