Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
afdd029
docs: spec for cache key rework and header removal
hayate Aug 30, 2026
9c73ec8
docs: revise spec after Codex adversarial review
hayate Aug 30, 2026
b560da9
docs: implementation plan for the cache key rework
hayate Aug 30, 2026
bfeb564
docs: fold the plan review back into the spec
hayate Aug 30, 2026
f045730
feat: resolve a worktree-scoped prompt cache key
hayate Aug 30, 2026
76c9e92
feat: replace the cache key only when it is core's own default
hayate Aug 30, 2026
a52b4fe
feat: add an always-on deduplicated operator warning channel
hayate Aug 30, 2026
cbc569d
feat: apply the resolved cache key and report outcomes
hayate Aug 30, 2026
01a64b6
test: add an opt-in opencode contract probe
hayate Aug 30, 2026
63a2ea0
docs: rewrite README, add changelog and CI
hayate Aug 30, 2026
81668ac
fix: export only the plugin factory, or opencode refuses to load it
hayate Aug 30, 2026
3cdc528
fix: honour the never-throw invariant and surface upstream shape changes
hayate Aug 30, 2026
bdba8f9
refactor: single source of truth for the scope setting
hayate Aug 30, 2026
095ae22
docs: realign the spec with what shipped
hayate Aug 30, 2026
cd2fe26
docs: document the full warning set in the README
hayate Aug 30, 2026
43893f0
fix: harden the logger binding and field detection
hayate Aug 30, 2026
f127ebb
test: close the gaps mutation testing found, and add a binary contrac…
hayate Aug 30, 2026
37dc742
chore: keep the SDD process docs on the fork, not in this PR
hayate Aug 30, 2026
eafa50f
fix: stay silent on providers that have no cache key field
hayate Aug 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: test

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: ["20", "22"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
# No install step: this project has no dependencies.
- run: npm test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
context-cache.log
*.log
63 changes: 63 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Changelog

## 0.2.0

### Breaking

- The plugin no longer writes the `x-session-id`, `conversation_id` or
`session_id` headers. Those names identify a *conversation*, and a
project-stable value is wrong in them: on opencode's OpenAI/Codex path,
`x-session-affinity` keys a WebSocket connection pool whose `busy` and
`fallback` state would then be shared by every concurrent session in the
project. opencode core already sends `x-session-affinity` and `X-Session-Id`
derived from the real session ID. A gateway that parsed the underscore names
must be reconfigured to read core's headers instead.

The plugin also previously wrote `x-session-id` while core writes
`X-Session-Id`. Those are distinct keys in a JavaScript object and only
collapse at the HTTP layer, so both values were reaching the wire.

### Fixed

- The cache key is derived from `PluginInput.worktree` rather than
`process.cwd()`. One `opencode serve` process serving several projects
previously gave all of them the same key, because the plugin factory is
invoked per project while `process.cwd()` stays the server's launch
directory.
- `prompt_cache_key` (deepinfra, cerebras) is now handled. Only the camelCase
spelling was written before, so those providers were unaffected by the plugin.
- The key is replaced only when it still holds opencode's own session-ID
default, so an explicit operator setting, a model or agent option, or another
plugin's value is no longer overwritten.
- Explicit overrides longer than 64 characters or containing non-printable
characters are hashed rather than sent verbatim.
- A degenerate `/` worktree falls back to the session directory, mirroring
opencode's own guard, instead of collapsing every project onto one key.
- The debug log moved out of the plugin directory to
`$XDG_STATE_HOME/opencode/context-cache.log`, so the documented
`./plugins/...` install no longer writes a log file into your repository.

### Added

- `OPENCODE_CONTEXT_CACHE_SCOPE` (`worktree` default, `directory`, `session`).
`session` is a full opt-out and takes precedence over an explicit key.
- `OPENCODE_CONTEXT_CACHE_LOG` to relocate the debug log.
- Plugin `options` support, so scope and key can be set from `opencode.jsonc`.
Environment variables take precedence over options.
- Always-on, deduplicated operator warnings for compatibility failures, so a
renamed upstream field surfaces without the debug flag being on first. A
provider that simply has no cache key field is **not** one of those failures
and is silent: Anthropic and every `@ai-sdk/openai-compatible` provider
(DeepSeek among them) have no such setting, so warning there would fire on a
routine configuration and teach operators to tune out the channel. That case
is recorded in the debug log as `reason=no-fields`.
- A README section stating exactly which providers the plugin does and does not
affect, so its scope is knowable without reading the source.
- A `package.json`, so the plugin can be installed by npm identifier.
- A test suite and CI.

### Removed

- The "digest detection to avoid double-hashing" behavior, which could never
fire: it was only reachable from a precedence level that was itself
unreachable. Explicit overrides are now used verbatim when they are safe.
Loading