Releases: andrejtonev/opencode-kasper
Releases · andrejtonev/opencode-kasper
Release list
v1.2.0 — non-default agent prompt layouts, plugin overrides, and custom paths
A feature release that hardens the resolver for opencode plugin ecosystems (notably oh-my-opencode), adds support for non-default agent prompt layouts and agents_md_paths, and makes the e2e suite deterministic and actually load-bearing. No breaking changes — the public plugin surface and kasper.jsonc / kasper key config are unchanged.
Highlights
- Real oh-my-opencode integration. The e2e suite now loads the actual
oh-my-opencodepackage via afile://plugin entry, writes the realoh-my-openagent.jsonconfig, and verifies Kasper's write path lands the## Kasper Inferred Instructionssection insisyphus.prompt_appendwhile leavingbuild.prompt_appendbyte-identical. - Plugin-override entries located by name, not value (B1). Previously, with two agents sharing the same prompt text, the first one in insertion order won and Kasper silently edited the wrong agent. The writer now uses the canonical config key directly.
- Display-name → canonical-key fallback. omo reports the agent's display name (
"Sisyphus - ultraworker") asagentName, not the config key (sisyphus). The resolver'slookupAgentEntryWithFallbacknow handles this with exact → case-insensitive → "display name starts with key" (longest match wins), then threads the canonical key through every subsequent lookup. - All four opencode prompt-source shapes supported in plugin override files: inline string,
{file:/abs/path},{path:/abs/path}, andfile:///URIs (cross-platform via WHATWGURL+fileURLToPath). - Non-default
AGENTS.mdlocations via a newagents_md_paths: string[]config field. Walks each entry forAGENTS.mdthenCLAUDE.md, falls back to a local walk-up fromprojectRoot, then to the global opencode dir /~/.claude/CLAUDE.md. HonorsOPENCODE_CONFIG_DIRandOPENCODE_DISABLE_CLAUDE_CODE. Backup directories are namespaced per resolved path.
Fixed
- B1 regression —
appendToPluginOverridePromptnow locates entries by canonical key, not by matchingprompt/prompt_appendvalue. (#6) - B2 regression —
findOverrideInDirnow usesbasename()fromnode:pathso Windows\separators are handled correctly and the standardopencode.json/.jsoncskip fires. (#6) - B3 regression —
runHealthCheckno longer hardcodes<cwd>/AGENTS.md; it runs the resolver first and uses the chosen path + reason. (#6) - B4 regression — Config reload now re-resolves the rules file and pushes new
prompt_pathsinto the agent-prompt manager via newsetResolvedPath()/setResolverInputs()methods. Edits tokasper.jsontake effect without a restart. (#6) - Display-name fallback false positives on hyphenated names — a follow-up to the resolver fix that requires a space (or end-of-string) after the matched key. A test creating
code-quality-0b16404eno longer false-positive matches a globalcode-qualityagent and silently routes the improvement to the wrong file. Closes a real production bug surfaced bytests/auto-update.test.ts. (#6) appendToPluginOverridePromptno longer readsactualKeyasstring | undefined— pre-existing TS errors in the resolver refactor are now resolved.npm run buildandtsc --noEmitare clean for the first time. (#6)file://URIs handled cross-platform — replaced the string-based parser (which broke on Windowsfile:///C:/path) with WHATWGURL+fileURLToPath. Malformed URIs degrade gracefully to theconfigtarget. Fixes 7 Windows CI failures. (#8)- Failed scorings no longer poison a session — the
runEvaluation()fallback path was unconditionally addingpending.sessionIDtoctx.sessionsEvaluatedeven when the scorer returned a fallback card (model unavailable, LLM timeout, etc.). TherunEvaluation()guard then short-circuited any future retry for the rest of the plugin lifetime. A failed scoring is transient; the user should be able to fix their model config and have the next poll pick up the session. The success path is now the only path that marks a session as evaluated. (#7) bun run lintis now clean — removed unused imports intests/e2e/edge-cases-inprocess.test.tsand applied biome formatting acrosstests/.prepublishOnlycan now succeed. (#6)
Added
agents_md_paths: string[]inkasper.jsonc— explicit list of directories to check forAGENTS.md(thenCLAUDE.md). Paths may be absolute, project-relative, or~/.... Each path is checked top-to-bottom; first hit becomes the primary read/write target. If no entry has an existing file, the first entry'sAGENTS.mdis the write target and Kasper creates it on first write. (#6)KASPER_E2E_SCORE_OVERRIDE=<float>test-only env var, read at the top ofScorer.evaluate()insrc/scorer.ts. When set, returns a synthetic low-score card without calling the LLM, making e2e write-path tests deterministic. The override short-circuits the LLM call entirely; production users never set it. (#6){path:...}andfile://URI prompt definition support in plugin override files — the resolver now recognises all four opencode prompt shapes.file://is the form used by oh-my-opencode to redirect built-in agent prompts. (#6, #8)- 33 tests for non-default agent prompt layouts (15 plugin_override resolver, 8 custom-paths resolver, 10 plugin_override manager). (#6)
- 23 tests for the new
AgentsMdResolver(21 resolver, 2 manager). (#6) - 11 in-process unit tests covering all four prompt-source shapes in
tests/e2e/prompt-shapes.test.ts— runs in ~40 ms without spawning opencode. Verifies the resolver's classification, the inline→file promote path (materializeInlinePrompt), and the write-pathfile_uri/external_filereplace semantics. (#6) - 5 in-process tests replacing the USELESS EC-2 and EC-7 from the original audit in
tests/e2e/edge-cases-inprocess.test.ts— 4 unit tests ofisKasperSessionplus 1 disabled-mode integration test. Verified USEFUL via targeted mutations. (#6) - 5 tests for
materializePluginOverrideToFile(previously unverified — the inline-prompt equivalent had 4 tests but the plugin-override version had none). (#6) - 11 B1–B4 regression tests in
tests/b1..b4-regression.test.ts. (#6) - Artifact-verification report (
tests/e2e/ARTIFACT-VERIFICATION.md) — proves via on-disk evidence that Kasper's tests actually produce the artifacts they claim. 11 rows covering omo + Kasper integration, AGENTS.md auto-apply, state.json lifecycle, different prompt definition types, different AGENTS.md locations, and different agent files. Stricter than the mutation audit: proves the test's claim about the side effect, not just that some code path was exercised. (#6) - Mutation audit (
tests/e2e/MUTATION-AUDIT.md) — documents which tests are USEFUL (catch targeted mutations) vs USELESS (vacuous) vs SMOKE (test opencode, not Kasper). Was the basis for the EC-2 / EC-7 fix in this release. (#6) src/path-utils.ts— sharedexpandTilde/fileExists/dirExists/candidateGlobalOpencodeDirshelpers extracted from the two resolvers. Removes ~50 lines of duplicated code and the underscore-prefix re-export code smell. (#6)
Changed
- Test discipline: silent passes are gone. The mutation audit found multiple e2e tests that were vacuous (assertion could never fail) or relied on
if (state) { log warn; return }paths. Every e2e describe block now useswaitForKasperLoaded()inbeforeAllto fail loudly if the plugin symlink is.disabled, and assertions that previously only logged are nowexpect()s. The e2e suite is now 53/53 passing (was 1/9). (#6) oh-my-opencode-livetest is now a real e2e of the integration. Previously the test's omo config was a dead-drop file (.opencode/oh-my-opencode.jsonwas the wrong basename after the package rename tooh-my-openagent) and the npm specifieroh-my-opencodenever actually loaded inopencode serve(the serve command isinstance: false— plugins only load when a per-project instance is created viaopencode run --attach). The test now usesplugin: ["file:///path/to/dist/index.js"]to load the local omo install synchronously. (#6)- E2E suite is deterministic for the auto-apply path —
KASPER_E2E_SCORE_OVERRIDE=0.3is now set in the relevantbeforeAllblocks; the 2 e2e tests that were previously flaky on the LLM judge are now deterministic. (#6) cleanupE2EProjecthonorsKASPER_E2E_KEEP_TMP=1— every e2e test that produces a durable artifact leaves it on disk for inspection. (#6)opencode >=1.15.13e2e compatibility — HTTP Basic Auth,?limit=Non/api/session, and the--attachflow are now handled by the harness.LOG_MAX_LINES300 → 5000 to keep early lifecycle events visible. Scoring timeouts bumped (60 s → 120 s) for the slower LLM judges. (#6)injectSectionrewritten as an exhaustive switch onsource.kindso the TS compiler catches missing cases when a new source kind is added. Idempotency check hardened to block-level match (split on blank lines, then compare) — the previousincludes()check produced a false positive when an existing block was a prefix of the new one. (#6)
Notes
- No public API changes.
package.jsonmain/types/exportsare unchanged. The newKASPER_E2E_SCORE_OVERRIDEis opt-in via env var; existing deployments are unaffected. - Test counts: 542 unit tests pass (up from 470 in 1.1.1); the e2e suite adds another 78 tests (up from 32 in 1.1.0). 27 e2e tests are skipped when the
opencodebinary is not on$PATH(gated behindOPENCODE_E2E=1). - PRs: #6, #7, #8.
- Full changelog: see CHANGELOG.md.