Repository navigation
feat: extend the hook contracts to opencode and Crush - #217
Merged
Merged
Conversation
Each contract's mapping table gains a column per harness, so the two newest ones are documented where the other two already are, and session-start gains a fixture line for each provider id — the payload their clients POST is now pinned as bytes like every other. The endpoints needed nothing: `provider` has accepted any id in providers.Registry since it existed, and opencode and Crush have been in that registry since they were spawnable. What the prose adds is the part the code cannot say — which of each harness's events maps onto which report, and which reports it cannot make at all: - opencode reports all four. Its `session.status` carries the state rather than implying it, and its `idle` is the turn ending, which is this contract's `done`. Nothing there reports lich's own `idle`: the event that would say "the CLI has left" is the server exiting with the plugin inside it. - Crush reports two. `PreToolUse` is the only event it has, so a `busy` with nothing to end it would pin a spinner to a card — worse for longer than it is right. It reports its session id and refreshes git status; the refresh runs one tool early, which the ceilings name. Both spell resume (`--session <id>`), and neither is wired: lich only offers a resume it has proof of, and both keep conversations in SQLite where there is no per-session file to glob. The id is stored today so the day one is wired the sessions already carry it. Every row was taken off a real run of each CLI against a stub listener.
4 of 5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Documents the hook contracts for the two harnesses lich could already spawn but never heard from, and pins the payloads their clients send. Contract-first: this is the half that lands before omartelo/lich-plugin#10, which implements it.
What changes
Prose and fixtures only — no endpoint moved.
providerhas accepted any id inproviders.Registrysince the field existed, andopencodeandcrushhave been in that registry since they became spawnable. Each contract's mapping table gains a column per harness, andfixtures/session-start.jsonlgains a line per provider id so both sides assert the same bytes.What the prose adds is the part the code cannot say — which of each harness's events maps onto which report, and which reports it cannot make at all.
opencode reports all four. Its
session.statuscarries the state rather than implying it, and itsidleis the turn ending, which is this contract'sdone. Nothing there reports lich's ownidle: the event that would say "the CLI has left" is the opencode server exiting with the plugin inside it.Crush reports two.
PreToolUseis the only event Crush has. Abusywith nothing to end it would pin a spinner to a card — wrong for longer than it is right — so the state and title columns are empty on purpose, and the plugin registers only the session id and the git-status refresh. That refresh runs one tool early, which is named in the ceilings rather than papered over.Neither resumes yet. Both spell it (
opencode --session <id>,crush --session <id>), butResumeAvailableonly offers a resume it has proof of, and both keep conversations in SQLite where there is no per-session file to glob. The id is stored today so the day one is wired the sessions already carry it.How it was checked
Every row was taken off a real run against a stub listener, not off the harnesses' docs:
crush runin an isolatedXDG_CONFIG_HOME, with the plugin's existing scripts registered. All three reports arrived on the onePreToolUseevent; tool names came back lower-cased (viewto read,writeto write) and the stdin envelope is{event, session_id, cwd, tool_name, tool_input}.opencode servedriven through its own HTTP API against a stub OpenAI-compatible provider, so a turn with a tool call was deterministic and cost nothing. Confirmedsession.created,session.status(busy/idle),permission.asked,file.edited,tool.execute.beforeandsession.updatedcarrying the title, plus that the plugin receivesevent.properties(notevent.data).Test plan
go test ./...— 1193 pass, including the fixture suite over the two new linesgofmt -l .andgo vet ./...cleanbiome check,vitest run(793),tsc --noEmitclean