jevhooks.git / plugin / types / README.md
1# Chapter 4: types, one atom of state
2
3A hook call is over in milliseconds, and everything it knew goes with it.
4But the band above the prompt has to show the *last* decision, long after
5the hook that made it returned. So the mod keeps one piece of state: an
6**atom**, Claude Code's name for a single named value a plugin can read and
7update from any hook. jevhooks has exactly one, `jevhooks.last`, and this
8folder says what shape it is.
9
10```ts
11export type Decision = { verdict: 'allow' | 'ask' | 'pass'; line: string; ms: number; session_usd: number }
12export type Shown = Decision & { kind: 'command' | 'turn end' }
13
14declare module 'claude-code' {
15  interface PluginState {
16    jevhooks: { last: Shown | null }
17  }
18}
19```
20
21`Decision` is what the daemon sends back for a deciding event. `Shown` adds
22which kind of thing was decided, which is the first word the band prints.
23The `declare module` block is TypeScript's way of adding a field to an
24interface someone else owns: Claude Code's `PluginState` gains a
25`jevhooks` entry, so `read($, last)` and `update($, last, ...)` in
26`register.tsx` are checked against it.
27
28> **Aside: the same type, written twice.** `Decision` here mirrors the Rust
29> struct `Decision` in `crates/jevhooks-events` (chapter 8), field for
30> field, and that copy is kept by hand. Rust and TypeScript do share one
31> definition of what to *do* with an event, because the routing is Rust
32> compiled to JavaScript. The daemon's reply crosses as JSON, and nothing
33> generates this file from the Rust. If you add a field there, add it here.
34
35> **Try it.** `claude plugin validate plugin` reports `declares state:
36> jevhooks.last`, and for `register.tsx`, `state writes: jevhooks.last` and
37> `state reads: jevhooks.last`: one atom, written by `decide`, read by the
38> band. With the engine's types in place, `tsc -p plugin` checks every use.
39
40## For the people who maintain it
41
42### In this folder
43
44| Path | What |
45| --- | --- |
46| [index.d.ts](index.d.ts) | `Decision`, `Shown`, and the plugin's entry in `PluginState`. The manifest points here (`"types"`). |
47
48← Previous: [Chapter 3, hooks/](../hooks/) · Up: [plugin](../) · Next: [Chapter 5, tests/](../tests/) →