@delt/claude-jev-advisor 0.1.2 β 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -30
- package/dist/cli.js +262 -35
- package/dist/context-hook.js +111 -44
- package/dist/rm-hook.js +1474 -93
- package/dist/statusline.js +84 -14
- package/mod/.claude-plugin/plugin.json +14 -14
- package/mod/hooks/register.js +15 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,21 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
Unofficial helpers for [Claude Code](https://claude.com/claude-code), installed as command hooks in `~/.claude/settings.json`. They use [TypeSafe](https://typesafe.ai) Jev for judgments that need to understand the conversation.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
What is sent to TypeSafe's Jev API (`api.typesafe.ai`):
|
|
6
|
+
|
|
7
|
+
- `context`: your last three requests (typed by you, or sent through a channel or from another Claude Code session), each cut to its first 1,000 characters, and Claude's last reply, cut to its first and last 1,500 characters.
|
|
8
|
+
- `rm`: only for a delete it would otherwise ask about, and only when the target is a file this session made or a folder git ignores. It sends the path, the delete command and its description, up to three tool calls of this session that name the target (each cut to 600 characters), and for a folder up to ten of its file names.
|
|
6
9
|
|
|
7
10
|
Not affiliated with Anthropic or TypeSafe.
|
|
8
11
|
|
|
9
12
|
| Helper | What it does | Systems |
|
|
10
13
|
|---|---|---|
|
|
11
14
|
| `context` | At the end of each turn, suggests `/compact` or `/clear` when the conversation is large and the work has reached a stopping point. Shown at the end of Claude Code's bottom row. | Any |
|
|
12
|
-
| `rm` | Asks before a Bash `rm`
|
|
15
|
+
| `rm` | Asks before a Bash or PowerShell command deletes real files (`rm`, `Remove-Item`, `del`, `rd`, also inside `sh -c`, `powershell -Command` or `cmd /c`). Lets temp files through and refuses a delete whose targets it cannot work out. Jev can lift the ask for a test file this session made or a folder git ignores. | Windows |
|
|
13
16
|
|
|
14
17
|
## Requirements
|
|
15
18
|
|
|
16
19
|
- Node.js 18 or later
|
|
17
20
|
- Claude Code (the bottom-row display uses Claude Code mods, an early-access feature that may change between releases)
|
|
18
|
-
- A TypeSafe API key for the `context` helper, in `TYPESAFE_API_KEY` or in a key file (`--key-file`)
|
|
19
|
-
- Windows for the `rm` helper. On other systems `install` skips it and says why.
|
|
21
|
+
- A TypeSafe API key for the `context` helper and for the Jev check of the `rm` helper, in `TYPESAFE_API_KEY` or in a key file (`--key-file`). Without a key, `rm` asks about every real file.
|
|
22
|
+
- Windows for the `rm` helper. On other systems `install` skips it and says why. It reads PowerShell commands with Windows PowerShell, which comes with Windows, or with PowerShell 7 when `pwsh` is on `PATH`, the same one Claude Code uses. It was checked with Windows PowerShell 5.1; PowerShell 7 was not tested.
|
|
20
23
|
|
|
21
24
|
## Install
|
|
22
25
|
|
|
@@ -32,7 +35,9 @@ claude-jev-advisor install
|
|
|
32
35
|
|
|
33
36
|
When the context helper is installed and no key is found, `install` asks for your TypeSafe API key. What you type is hidden. It checks the key with one small Jev call and saves it to `~/.claude/claude-jev-advisor/jev-key.env`. Press Enter to skip; `claude-jev-advisor key` asks again later. Instead of typing it, you can set `TYPESAFE_API_KEY`, or pass `--key-file <path>` to a file holding a line `TYPESAFE_API_KEY=...` (then only that path is saved). The key is never printed or logged. On Windows that file is protected by your user folder's permissions only.
|
|
34
37
|
|
|
35
|
-
Before it changes `~/.claude/settings.json`, `install` copies it to `~/.claude/backups/settings.json.<YYYY-MM-DD-HHmmss>-before-claude-jev-advisor`. If a backup from the same second already exists, it adds `-2`, `-3` and so on instead of overwriting it. It then adds or replaces only this package's entries. Running it again changes nothing.
|
|
38
|
+
Before it changes `~/.claude/settings.json`, `install` copies it to `~/.claude/backups/settings.json.<YYYY-MM-DD-HHmmss>-before-claude-jev-advisor`. If a backup from the same second already exists, it adds `-2`, `-3` and so on instead of overwriting it. It then adds or replaces only this package's entries. Running it again with the same version changes nothing.
|
|
39
|
+
|
|
40
|
+
After upgrading from 0.2 or earlier, run `claude-jev-advisor install rm` again so that the rm hook also covers the PowerShell tool. Until you do, `status` shows `Bash only`.
|
|
36
41
|
|
|
37
42
|
The hooks also reach Claude Code sessions that are already open; the bottom-row display starts with the next new session. Turning a helper on or off applies at once, even to open sessions.
|
|
38
43
|
|
|
@@ -44,6 +49,7 @@ The hooks also reach Claude Code sessions that are already open; the bottom-row
|
|
|
44
49
|
| `claude-jev-advisor uninstall [rm] [context]` | Removes this package's hooks and display from `settings.json` |
|
|
45
50
|
| `claude-jev-advisor on [rm] [context]` / `off [rm] [context]` | Switches helpers on or off without touching `settings.json` |
|
|
46
51
|
| `claude-jev-advisor status` | Shows what is registered and on, the display, whether a key is set, the thresholds and the last judgment |
|
|
52
|
+
| `claude-jev-advisor report [--days 7]` | Lists the `/compact` and `/clear` advice shown and what followed it, and the deletions Jev let through |
|
|
47
53
|
| `claude-jev-advisor key` | Asks for the TypeSafe API key, checks it and saves it (needs an interactive terminal) |
|
|
48
54
|
| `claude-jev-advisor help` | Prints the usage |
|
|
49
55
|
|
|
@@ -51,35 +57,40 @@ If you leave out the helper names, the command applies to all helpers. The displ
|
|
|
51
57
|
|
|
52
58
|
## The context helper
|
|
53
59
|
|
|
54
|
-
When a turn ends, a `Stop` hook reads the size of the conversation from the session transcript. From
|
|
60
|
+
When a turn ends, a `Stop` hook reads the size of the conversation from the session transcript. If the turn's last reply is not in the transcript yet, it waits up to 3 seconds for it. From 250k tokens it asks Jev two questions about the last three requests and the last reply:
|
|
55
61
|
|
|
56
|
-
- has the work asked for
|
|
57
|
-
-
|
|
62
|
+
- has Claude finished or handed back the work asked for, so this is a natural break?
|
|
63
|
+
- does the reply close a whole stage of the work (a plan carried out and pushed, a release, a finished investigation, a design or plan saved as a document), so the next stage can start from the saved results?
|
|
58
64
|
|
|
59
|
-
The answer is saved for the display. Nothing is added to what Claude sees, so it costs no Claude tokens. If Jev does not answer within 8 seconds, only the size is shown.
|
|
65
|
+
The answer is saved for the display. Nothing is added to what Claude sees, so it costs no Claude tokens. If Jev does not answer within 8 seconds, only the size is shown. While a subagent or a workflow runs in the background, the turn counts as work in progress and Jev is not asked; background shells and monitors do not count.
|
|
60
66
|
|
|
61
67
|
| Situation | Shown |
|
|
62
68
|
|---|---|
|
|
63
|
-
| Under
|
|
69
|
+
| Under 250k, or no judgment (no key, Jev unreachable) | `52k` |
|
|
64
70
|
| Work in progress | `π’ 312k` |
|
|
65
|
-
|
|
|
66
|
-
| Work
|
|
67
|
-
| Work unit finished, under 200k | `π’ 150k` |
|
|
71
|
+
| A whole stage closed (from 250k) | `π‘ 312k μλ‘κ² μμνλ 건 μ΄λ μΈμ? /clear` |
|
|
72
|
+
| Work finished, stage goes on (from 250k) | `π‘ 312k μ§κΈκΉμ§ μ 리νκ³ μ΄μ΄κ°λ 건 μ΄λ μΈμ? /compact` |
|
|
68
73
|
| Within 20% of auto-compact | `π΄ 790k 18%`, then ` Β· ` and the `/clear` or `/compact` advice above, or `μμ
μ΄ λλλ©΄ μ 리νκ³ μ΄μ΄κ°λ 건 μ΄λ μΈμ? /compact` while the work is still going |
|
|
69
74
|
|
|
70
75
|
With `--lang en` the advice reads `Start fresh? /clear`, `Wrap up what you have and continue? /compact` and `When this work is done, wrap up and continue? /compact`.
|
|
71
76
|
|
|
72
|
-
|
|
77
|
+
Judging starts at 250k because a conversation passes 100k after a request or two, and compacting a small conversation costs more than it saves. If you set `compactMinTokens` above `minTokens`, finished work between the two stays green. The suggestion is hidden while a new request runs, and a judgment made before a `/compact` is dropped.
|
|
73
78
|
|
|
74
79
|
| `--display` | Where |
|
|
75
80
|
|---|---|
|
|
76
81
|
| `mod` (default) | At the end of the bottom row, after `β΅β΅ β¦ mode on`. A small Claude Code mod in the package's `mod/` folder draws it. The mod is listed in `env.CLAUDE_CODE_PLUGIN_DIRS` and told the data folder through `pluginConfigs`. |
|
|
77
|
-
| `statusline` | Claude Code's status line, the row above the bottom row. An existing status line of yours keeps running first, with our text after it, and is put back when you switch away or uninstall. On Windows that command is
|
|
82
|
+
| `statusline` | Claude Code's status line, the row above the bottom row. An existing status line of yours keeps running first, with our text after it, and is put back when you switch away or uninstall. On Windows that command runs in Git Bash when it is installed and in PowerShell otherwise, as Claude Code runs it; it gets 2 seconds. No red zone, because the auto-compact threshold is not known there. |
|
|
78
83
|
| `message` | A `Stop says: β¦` line in the transcript when there is advice. Claude does not see it. No red zone. |
|
|
79
84
|
|
|
85
|
+
`claude-jev-advisor report` shows each piece of advice with the time, the session, the size, Jev's answers, the start of the last request and what followed: compacted or cleared within the next three requests, auto-compacted, or kept going.
|
|
86
|
+
|
|
80
87
|
## The rm helper
|
|
81
88
|
|
|
82
|
-
It runs before every Bash tool call (`PreToolUse`, matcher `Bash`, 15-second timeout) and looks
|
|
89
|
+
It runs before every Bash and PowerShell tool call (`PreToolUse`, matcher `Bash|PowerShell`, 15-second timeout) and looks at:
|
|
90
|
+
|
|
91
|
+
- Bash: `rm`, `rmdir` and `xargs`
|
|
92
|
+
- PowerShell: `Remove-Item` and its aliases `ri`, `rm`, `del`, `erase`, `rd` and `rmdir`, and `[System.IO.File]::Delete` and `[System.IO.Directory]::Delete`. PowerShell's own parser and parameter binder read the command, so aliases, shortened parameter names, positional paths and nested blocks count as PowerShell reads them. PowerShell is started only when the command holds one of these words or a shell name, and takes about 0.3 seconds.
|
|
93
|
+
- shells started inside a command, up to three levels deep: `sh -c` and `bash -c`, `powershell -Command`, `pwsh -c` and `-EncodedCommand`, and `del`, `erase`, `rd` and `rmdir` in `cmd /c`
|
|
83
94
|
|
|
84
95
|
| Target | Result |
|
|
85
96
|
|---|---|
|
|
@@ -87,23 +98,30 @@ It runs before every Bash tool call (`PreToolUse`, matcher `Bash`, 15-second tim
|
|
|
87
98
|
| A path with a `.superpowers` folder in it | No decision |
|
|
88
99
|
| A path that does not exist | No decision |
|
|
89
100
|
| A git-ignored path inside a build folder (`target`, `build`, `dist`, `out`, `node_modules`, `coverage`, `__pycache__`, `.pytest_cache`, `.gradle`, `.next`, `.nuxt`, `.turbo`, `.cache`, `bin`, `obj`) | No decision |
|
|
90
|
-
|
|
|
101
|
+
| A PowerShell path on a drive that is not a file system (`Env:`, `Alias:`, `Function:`, `Variable:`, `HKCU:`, `HKLM:`, `Cert:`, `WSMan:`, `Registry::`) | No decision |
|
|
102
|
+
| `Remove-Item β¦ -WhatIf` | No decision |
|
|
103
|
+
| A network path (`\\server\share\β¦`) | `ask`, without looking the path up |
|
|
104
|
+
| Any other existing file or folder | `ask`, with the reason `μ€μ νμΌ μμ : <paths>` ("deleting real files"), unless Jev lifts it (below) |
|
|
105
|
+
| A PowerShell command its parser cannot read (a syntax error, PowerShell not answering within 3 seconds, a nested PowerShell command left when the hook has spent 9 seconds reading, an answer it does not expect), or one that deletes and runs code it cannot follow (`& $name`, `Invoke-Expression`, `Start-Process` or `Set-Alias` with an argument it cannot work out, `[scriptblock]::Create`, `.Invoke()`, a `Delete()` method in a command that gets file objects from `Get-Item`, `Get-ChildItem`, `New-Item` or `-PassThru`), or makes a drive with `New-PSDrive` | `ask`, with the reason `μμ λͺ
λ Ήμ λΆμνμ§ λͺ»ν¨: <start of the command>` ("could not read the delete command"). Jev is not asked. |
|
|
91
106
|
| A target it cannot work out | `deny`, with a hint to rewrite the command using literal paths |
|
|
92
107
|
|
|
93
108
|
A target cannot be worked out when it uses:
|
|
94
109
|
|
|
95
|
-
- shell variables
|
|
96
|
-
- command substitution
|
|
97
|
-
- `xargs` feeding `rm`
|
|
110
|
+
- in Bash, shell variables other than literal assignments in the same command and `TEMP`, `TMP`, `TMPDIR`, `HOME`, `USERPROFILE` and `PWD`; in PowerShell, variables other than one plain top-level assignment in the same command (a variable written any other way, such as `+=`, a loop, a function parameter, `Set-Variable`, `$script:`, `-OutVariable`, or its name handed to a command as text, is unknown), `$env:TEMP`, `$env:TMP`, `$env:TMPDIR`, `$env:HOME`, `$env:USERPROFILE`, `$HOME` and `$PWD` (unless the command assigns it); in `cmd`, variables other than `%TEMP%`, `%TMP%`, `%USERPROFILE%` and `%CD%`
|
|
111
|
+
- command substitution, or in PowerShell any expression such as `(Join-Path β¦)`, `$(β¦)` or `@splat`
|
|
112
|
+
- `xargs` feeding `rm` or a shell that deletes, PowerShell pipeline input feeding `Remove-Item` (`Get-ChildItem β¦ | Remove-Item`), or a shell given no script of its own, which reads one from a pipe, a heredoc or a here-string (`β¦ | bash`, `bash <<EOF`, `powershell -`), in a command that holds a delete word
|
|
98
113
|
- brace expansion
|
|
99
114
|
- a wildcard in a folder name
|
|
100
|
-
- a `cd` to such a path earlier in the command
|
|
115
|
+
- a `cd`, `pushd`, `Set-Location` or `Push-Location` to such a path earlier in the command, a `popd` or `Pop-Location`, or a location change inside a PowerShell block; in PowerShell also a relative path inside a loop, a function or a script block when the command changes location anywhere
|
|
116
|
+
- a PowerShell drive other than a drive letter and the non-file drives above, such as one made with `New-PSDrive`
|
|
117
|
+
- a nested shell whose script is not fixed text and holds a delete word, or shells nested more than three deep that delete
|
|
118
|
+
- in `cmd`, a delete on a line that uses `if`, `else`, `for`, `call`, `start` or unquoted parentheses, or starts a command with a name it cannot read: write plain `del` or `rd` lines instead, with names that hold parentheses in double quotes
|
|
101
119
|
|
|
102
120
|
It does not see deletions made any other way:
|
|
103
121
|
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
122
|
+
- in PowerShell, `Remove-ItemProperty`, `Clear-RecycleBin`, an object's `Delete()` in a command that gets no file objects, COM file objects (`Scripting.FileSystemObject`'s `DeleteFile` and `DeleteFolder`), provider methods such as `$ExecutionContext.InvokeProvider.Item.Remove`, and code that builds a command's name or text from pieces while it runs (`[char]` codes, joined strings); the reader is not a sandbox
|
|
123
|
+
- script files: `powershell -File`, `pwsh script.ps1`, `bash script.sh`, a `.bat` file
|
|
124
|
+
- other commands or programs, such as `find -delete`, `git clean`, or Node or Python code that deletes files
|
|
107
125
|
|
|
108
126
|
What its decisions do depends on Claude Code's permission mode:
|
|
109
127
|
|
|
@@ -113,9 +131,20 @@ What its decisions do depends on Claude Code's permission mode:
|
|
|
113
131
|
| `bypassPermissions` | A prompt. Claude Code's documentation does not say this; it was seen in a test on 2026-10-03. | Blocked | Runs |
|
|
114
132
|
| Other modes | A prompt (`dontAsk` refuses the call instead) | Blocked | Claude Code's normal permission handling |
|
|
115
133
|
|
|
134
|
+
### When Jev can lift the ask
|
|
135
|
+
|
|
136
|
+
The facts are checked by code; Jev only judges what the target is for. Jev is asked only when every target of the command is one of these (at most five):
|
|
137
|
+
|
|
138
|
+
| Target | Checked first | Jev is asked |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| A file or folder this session made | Not tracked by git; the first call of this session that names it created it: a Write that made a new file, or a shell command whose `>` redirect, `touch`, `mkdir` or `curl -o` makes it (deletes do not count, and a Read, an Edit or any other shell command first means it was already there; PowerShell's `New-Item`, `Set-Content` and `Out-File` are not recognized yet, so a file made with them keeps the ask); a folder holding a git repository never counts; made after the session started; for a folder, every file inside too, and at most 50 files | Is it a throwaway made only to try something out? |
|
|
141
|
+
| A folder git ignores, outside the build folders above | It is a folder (a single ignored file such as `.env` still asks) | Is it generated output or a cache that is made again? |
|
|
142
|
+
|
|
143
|
+
When Jev answers 0.8 or more for every target, the hook makes no decision (the last column of the table above), and a line like `[jev-advisor] Jevκ° μ΄ μΈμ
μ μν νμΌλ‘ νλ¨ν΄ λ¬»μ§ μκ³ μ§μλλ€: out.json (0.93)` is shown. Otherwise the ask stays, with Jev's answer added: `μ€μ νμΌ μμ : β¦\out.json Β· Jev: μνμ© νμΌμΌ νλ₯ 0.42`. Without a key, when Jev fails, or with `"jev": false`, every real file asks as before. A `deny` is never sent to Jev.
|
|
144
|
+
|
|
116
145
|
`install rm` also replaces an older personal hook at `~/.claude/hooks/rm-guard/rm-guard.mjs` if one is registered. Its files are left in place.
|
|
117
146
|
|
|
118
|
-
If a hook of this package fails in any way, it prints nothing and exits 0, so it never blocks Claude Code.
|
|
147
|
+
If a hook of this package fails in any way, it prints nothing and exits 0, so it never blocks Claude Code. A failure during the Jev check of `rm` leaves the ask in place.
|
|
119
148
|
|
|
120
149
|
## Uninstall
|
|
121
150
|
|
|
@@ -134,26 +163,28 @@ A key saved by `install` or `key` stays in `~/.claude/claude-jev-advisor/jev-key
|
|
|
134
163
|
|
|
135
164
|
| Path | Contents |
|
|
136
165
|
|---|---|
|
|
137
|
-
| `~/.claude/claude-jev-advisor/config.json` | Switches and settings. A missing or broken file reads as the defaults. A value of the wrong type falls back to its default, so only `"enabled": false` turns a helper off. |
|
|
166
|
+
| `~/.claude/claude-jev-advisor/config.json` | Switches and settings that differ from the defaults. A missing or broken file reads as the defaults. A value of the wrong type falls back to its default, so only `"enabled": false` turns a helper off. |
|
|
138
167
|
| `~/.claude/claude-jev-advisor/state/<session>.json` | The last judgment of each open session, read by the display. Removed when the session ends. |
|
|
139
|
-
| `~/.claude/claude-jev-advisor/log/YYYY-MM.jsonl` | One line per judgment: the size, what was sent to Jev (parts of your conversation), the answers and the result. Never the key. |
|
|
168
|
+
| `~/.claude/claude-jev-advisor/log/YYYY-MM.jsonl` | One line per context judgment and per `rm` Jev check: the size, or the tool (`Bash` or `PowerShell`) and the command, what was sent to Jev (parts of your conversation), the answers and the result. Never the key. |
|
|
140
169
|
| `~/.claude/claude-jev-advisor/statusline-before.json` | Your own status line while `--display statusline` is in use |
|
|
141
170
|
| `~/.claude/claude-jev-advisor/jev-key.env` | Your TypeSafe API key, when you typed it in `install` or `key` |
|
|
142
171
|
| `~/.claude/backups/settings.json.*-before-claude-jev-advisor` | Copies of `settings.json` from before each change |
|
|
143
172
|
|
|
144
|
-
|
|
173
|
+
Defaults:
|
|
145
174
|
|
|
146
175
|
```json
|
|
147
176
|
{
|
|
148
177
|
"lang": "ko",
|
|
149
178
|
"keyFile": null,
|
|
150
179
|
"display": "mod",
|
|
151
|
-
"context": { "enabled": true, "minTokens":
|
|
180
|
+
"context": { "enabled": true, "minTokens": 250000, "compactMinTokens": 250000, "redRemainingPct": 20, "unitDoneYes": 0.6, "phaseDoneYes": 0.6 },
|
|
152
181
|
"rm": { "enabled": true, "jev": true, "throwawayYes": 0.8, "maxDirFiles": 50 }
|
|
153
182
|
}
|
|
154
183
|
```
|
|
155
184
|
|
|
156
|
-
`minTokens` is where judging starts, `compactMinTokens` where `/compact` is suggested, `redRemainingPct` where the red zone starts, and `unitDoneYes` / `
|
|
185
|
+
`minTokens` is where judging starts, `compactMinTokens` where `/compact` is suggested, `redRemainingPct` where the red zone starts, and `unitDoneYes` / `phaseDoneYes` are the Jev probabilities needed for "work finished" (`/compact`) and "stage closed" (`/clear`). For `rm`, `jev` switches the Jev check, `throwawayYes` is the probability needed to lift an ask, and `maxDirFiles` the most files a folder of this session may hold.
|
|
186
|
+
|
|
187
|
+
`config.json` keeps only the values you changed, with `"version": 2`. A config written by 0.1.x, which saved every value, has its old default thresholds (`minTokens` 100000, `compactMinTokens` 200000, `unitDoneYes` 0.7) read as unset, so the new defaults apply.
|
|
157
188
|
|
|
158
189
|
## Development
|
|
159
190
|
|