English | Espanol
Thanks for taking the time to improve this plugin. It runs inside every model request of an OpenCode session, so the bar for changes is: predictable, fail-open, and testable without a network.
git clone git@github.com:JoshRob297/opencode-commandcode.git
cd opencode-commandcode
bun install
bun test # offline suite, no network, no quota consumed
bun run typecheck # strict tsc, no emitThe live suite is opt-in and calls the real API (it consumes a negligible amount of quota):
COMMANDCODE_LIVE_TESTS=1 bun testThese are not style preferences; they protect the plugin's guarantees. A change that breaks one of them will be sent back.
- Fail-open. Any plugin error must leave the original request untouched. Never let a hook throw into the OpenCode session.
- Credentials only after an exact host match. Never introduce a substring,
prefix or path-based check on the injection path. New trusted hosts go through
COMMANDCODE_ALLOWED_HOSTS. - Never overwrite a caller's
authorizationheader. - No secrets in logs. The plugin writes session ids, model ids, status codes and error messages. Never bodies, headers or the key.
- Catalog accuracy over catalog size. Do not register models the OpenAI-compatible transport cannot serve. A model that fails when selected is worse than a model that is absent.
- No hardcoded user paths. Use
XDGandos.homedir(); tests must pass for any user. - Pure helpers stay pure.
src/hooks/resilience.tshas no network access and only one filesystem check (the kill-switch sentinel), so its rules can be unit tested in isolation. - Rebuild the Request only when the body actually changed. Return
modified: falsefor clean payloads.
Conventional Commits, imperative, lowercase subject:
<type>(<scope>): <subject>
<body: what and why, wrapped at 72 columns>
<footer: refs, breaking changes>
Types: feat, fix, docs, test, refactor, perf, chore, security.
Scopes: auth, catalog, sanitizer, watchdog, quota, telemetry, docs.
Examples:
fix(auth): require an exact hostname match before injecting the API key
feat(catalog): tag free and promo tiers in the model selector
docs(troubleshooting): document the retired free-tier 403 payload
Keep commits atomic: one logical change plus its tests. Every commit must pass
bun test and bun run typecheck.
- Fill in the pull request template. State the failure mode you observed, not only the change you made.
- Add or update tests. Bug fixes need a regression test that fails before the fix.
- Update
CHANGELOG.mdunder## [Unreleased]. - Docs live in two languages:
README.md+docs/*.md(English) andREADME.es.md+docs/es/*.md(Spanish), plus the translated community files (docs/es/code-of-conduct.md,SECURITY.es.md,CONTRIBUTING.es.md). Behaviour changes must be reflected in both, or say so explicitly in the PR so it can be tracked.
- Put the pure logic in
src/hooks/resilience.tsand export it. - Unit test it in
tests/(no network, no OpenCode instance). - Document the rule in
docs/ARCHITECTURE.md(rule table) and, if configurable, indocs/CONFIGURATION.md. - Wire it in
src/index.tsbehind a capability check (typeof ctx.x?.transform === "function") and wrap it so it cannot throw.
Open an issue using the bug report template. Include the OpenCode version, the
plugin commit, the model id, and the relevant lines from
<state>/commandcode-*.log. Never paste an API key into an issue.