hexcli 2.8.0__tar.gz → 2.8.1__tar.gz
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.
- {hexcli-2.8.0 → hexcli-2.8.1}/.gitignore +3 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/CHANGELOG.md +47 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/PKG-INFO +110 -146
- {hexcli-2.8.0 → hexcli-2.8.1}/README.md +109 -145
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/__init__.py +1 -1
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/compaction.py +1 -1
- {hexcli-2.8.0 → hexcli-2.8.1}/install.ps1 +17 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/Hex CLI.cmd +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/LICENSE +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/agent.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/assets/hexcli.ico +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/assets/hexcli.png +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/cancel.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/chatlog.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/commands.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/config.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/diffview.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/distribution.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/doctor.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/escalate.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/http_client.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/launcher.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/lineedit.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/llm.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/local_escalation.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/lockfile.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/loop_v2.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/markdown_stream.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/memory.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/network.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/parsing.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/paths.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/prompts.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/protocol_v2.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/repl.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/safety.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/sessions.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/setup_wizard.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/shell_session.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/statusbar.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/stream_render.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/telemetry.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/tools.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/hexcli/ui.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/launcher.py +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/pyproject.toml +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/shellai.cmd +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/shellai.example.json +0 -0
- {hexcli-2.8.0 → hexcli-2.8.1}/shellai.py +0 -0
|
@@ -6,6 +6,53 @@ the Hexagon NPU, not single-run anecdotes.
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## 2.8.1 — 2026-09-12
|
|
10
|
+
|
|
11
|
+
A patch release: nothing model-facing and nothing the launcher hands the
|
|
12
|
+
server changed. Gate: CI green on main; smoke 10/10 on a fresh
|
|
13
|
+
server.
|
|
14
|
+
|
|
15
|
+
- Installer repairs a Windows Terminal profile whose icon path 2.8.0
|
|
16
|
+
invalidated. The icon moved into the package (`hexcli/assets/`) that
|
|
17
|
+
release, but an existing "Hex CLI" profile kept pointing at the old
|
|
18
|
+
`assets/hexcli.png`; Terminal silently falls back to its own logo on a
|
|
19
|
+
missing file. `install.ps1` now rewrites a stale `hexcli.png` icon path
|
|
20
|
+
in a user's own profile with a targeted text edit, leaving the rest of
|
|
21
|
+
the profile untouched, and the fragment it writes already uses the
|
|
22
|
+
package path.
|
|
23
|
+
|
|
24
|
+
- Releases carry the wheel and the source distribution and go to PyPI
|
|
25
|
+
(`pip install hexcli`): `.github/workflows/publish.yml` runs when a
|
|
26
|
+
release is published, builds both, attaches them and publishes through
|
|
27
|
+
PyPI trusted publishing. 2.8.0's files were attached by hand.
|
|
28
|
+
- README rewritten shorter: the PyPI route sits in Install next to the
|
|
29
|
+
installer, the sample transcript the clips made redundant is gone, the
|
|
30
|
+
configuration table keeps the keys people change, memory and logs are a
|
|
31
|
+
short section under Usage, and the clips use absolute links so they
|
|
32
|
+
render on PyPI, in a two-by-two grid; the edit clip plays faster
|
|
33
|
+
(23 s, was 32 s). Version and CI badges at the top.
|
|
34
|
+
- Paper and CLAUDE.md current through 2.8.0: the timeline row and the
|
|
35
|
+
closing state paragraph record the package and the classifier finding,
|
|
36
|
+
and the milestones table breaks across pages instead of running off
|
|
37
|
+
one (it had been overflowing page 9).
|
|
38
|
+
- Paper numbers re-audited against the code and the latest results: the
|
|
39
|
+
window figure shows the 3,696-token server budget and the ~810-token
|
|
40
|
+
history it leaves instead of the disproven 2,600-token cliff; the
|
|
41
|
+
headline is 32/44 at pass^5 (LATEST.md) and 35/48 multi-turn; the
|
|
42
|
+
"9 s per new conversation" figure is retracted as the backend study
|
|
43
|
+
found; a paragraph carries that study's numbers (15.5 tok/s, 0.8 s warm
|
|
44
|
+
first token, polling-off power). ARCHITECTURE.md gets the same pass
|
|
45
|
+
(template in prompts.py, 29 suites, 44 cases, a dated note on the
|
|
46
|
+
pre-Rewind TTFT section) and the README's suite size reads 44.
|
|
47
|
+
- Paper restructured to six pages: the abstract states the v2.8.0 numbers
|
|
48
|
+
and the thesis; the runtime lever (KV rewind, the context re-read) is
|
|
49
|
+
its own section between results and negative results; the status
|
|
50
|
+
section is one paragraph; the milestones table is one line per row; a
|
|
51
|
+
positioning paragraph names what the report sits next to; three
|
|
52
|
+
figures that duplicated prose (chip diagram, prompt anatomy, NPU/CPU
|
|
53
|
+
bars) are gone and their numbers kept in the text. Every figure in the
|
|
54
|
+
paper is unchanged from the audit above.
|
|
55
|
+
|
|
9
56
|
## 2.8.0 — 2026-09-12
|
|
10
57
|
|
|
11
58
|
A minor release by RELEASING.md's rule (the launcher moved and its
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hexcli
|
|
3
|
-
Version: 2.8.
|
|
3
|
+
Version: 2.8.1
|
|
4
4
|
Summary: Local Hexagon NPU terminal agent for Snapdragon X Elite Windows ARM64
|
|
5
5
|
Project-URL: Homepage, https://github.com/NathanL15/Hex-CLI
|
|
6
6
|
Project-URL: Repository, https://github.com/NathanL15/Hex-CLI
|
|
@@ -27,61 +27,37 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
|
|
28
28
|
# Hex CLI
|
|
29
29
|
|
|
30
|
+
[](https://pypi.org/project/hexcli/)
|
|
31
|
+
[](https://github.com/NathanL15/Hex-CLI/actions/workflows/ci.yml)
|
|
32
|
+
|
|
30
33
|
Hex CLI is a coding agent for the Windows terminal, similar to aider or
|
|
31
34
|
Claude Code, that runs a local model on the Snapdragon Hexagon NPU. It reads
|
|
32
35
|
and edits files, runs commands, and checks its own work. The model is
|
|
33
36
|
Qwen3-4B, served by [npurun](https://github.com/bpbonker/npurun). After
|
|
34
37
|
setup it works offline.
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
run; a delete asks first
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
> the median calc in processor.py is wrong for even-length lists, fix it
|
|
59
|
-
|
|
60
|
-
◆ read_file
|
|
61
|
-
▸ [read] processor.py (lines 1-40 of 40)
|
|
62
|
-
|
|
63
|
-
◆ edit_file
|
|
64
|
-
▸ [edit] processor.py (+2 lines)
|
|
65
|
-
~ processor.py (+3 −1)
|
|
66
|
-
@@ -12,4 +12,6 @@
|
|
67
|
-
- return sorted(data)[len(data) // 2]
|
|
68
|
-
+ mid = len(data) // 2
|
|
69
|
-
+ if len(data) % 2 == 0:
|
|
70
|
-
+ return (sorted(data)[mid - 1] + sorted(data)[mid]) / 2
|
|
71
|
-
|
|
72
|
-
◆ run_code
|
|
73
|
-
|
|
74
|
-
Fixed: even-length lists now average the two middle values. The test file
|
|
75
|
-
prints 3.5 for [1, 2, 5, 6].
|
|
76
|
-
|
|
77
|
-
──────────────────────────────────────────────────────────────────
|
|
78
|
-
> ask, or / for commands
|
|
79
|
-
──────────────────────────────────────────────────────────────────
|
|
80
|
-
context ◔ 21% npu 0% mem 12.5/15.6 GB ~\proj (main)
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Your messages sit on a light band, the input box and status line stay on
|
|
84
|
-
the last rows, and the answer streams in above them.
|
|
39
|
+
<table>
|
|
40
|
+
<tr>
|
|
41
|
+
<td width="50%" valign="top">
|
|
42
|
+
<b>Ask something.</b> The answer streams in, markdown and all, above an input box that stays on the last rows.<br><br>
|
|
43
|
+
<img src="https://raw.githubusercontent.com/NathanL15/Hex-CLI/main/docs/gifs/ask.gif" alt="A question answered in bullet points" width="100%">
|
|
44
|
+
</td>
|
|
45
|
+
<td width="50%" valign="top">
|
|
46
|
+
<b>Ask about the machine.</b> Live state comes from a real command, shown as it runs.<br><br>
|
|
47
|
+
<img src="https://raw.githubusercontent.com/NathanL15/Hex-CLI/main/docs/gifs/machine.gif" alt="The CPU name read with a PowerShell command" width="100%">
|
|
48
|
+
</td>
|
|
49
|
+
</tr>
|
|
50
|
+
<tr>
|
|
51
|
+
<td width="50%" valign="top">
|
|
52
|
+
<b>Change code.</b> Every file change prints a diff; when you ask for the tests, they run; <code>/diff</code> shows the turn's changes and <code>/undo</code> takes them back, files included.<br><br>
|
|
53
|
+
<img src="https://raw.githubusercontent.com/NathanL15/Hex-CLI/main/docs/gifs/edit.gif" alt="A docstring added, the tests run, then undone" width="100%">
|
|
54
|
+
</td>
|
|
55
|
+
<td width="50%" valign="top">
|
|
56
|
+
<b>Nothing destructive runs unasked.</b> Commands are classified before they run; a delete asks first.<br><br>
|
|
57
|
+
<img src="https://raw.githubusercontent.com/NathanL15/Hex-CLI/main/docs/gifs/safety.gif" alt="A delete command waits for a y/N before running" width="100%">
|
|
58
|
+
</td>
|
|
59
|
+
</tr>
|
|
60
|
+
</table>
|
|
85
61
|
|
|
86
62
|
## Requirements
|
|
87
63
|
|
|
@@ -93,33 +69,42 @@ Tested on a Snapdragon X Elite. It will not run on x86 machines or on Macs.
|
|
|
93
69
|
|
|
94
70
|
## Install
|
|
95
71
|
|
|
72
|
+
The installer does everything the machine allows:
|
|
73
|
+
|
|
96
74
|
```powershell
|
|
97
75
|
git clone https://github.com/NathanL15/Hex-CLI
|
|
98
76
|
cd Hex-CLI
|
|
99
77
|
.\install.ps1
|
|
100
78
|
```
|
|
101
79
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
It
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
80
|
+
It checks the machine, installs the package, downloads npurun, the model
|
|
81
|
+
and the small embedding model that memory uses, and runs `--doctor` when it
|
|
82
|
+
finishes. It skips steps that are already done, so run it again after
|
|
83
|
+
fixing anything it reports. Everything it writes for you lives in
|
|
84
|
+
`~\.shellai`.
|
|
85
|
+
|
|
86
|
+
The one thing it cannot download is the QAIRT SDK, because Qualcomm does
|
|
87
|
+
not allow redistribution. It prints the instructions for that step and
|
|
88
|
+
picks the SDK up on the next run.
|
|
89
|
+
|
|
90
|
+
Or install from PyPI. The package is the same one the installer uses; you
|
|
91
|
+
install the SDK yourself and the rest downloads itself:
|
|
92
|
+
|
|
93
|
+
```powershell
|
|
94
|
+
pip install hexcli # the hex and hexcli commands
|
|
95
|
+
hexcli --update # downloads npurun
|
|
96
|
+
hex # the first run downloads the model, about 2.5 GB
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`hexcli --doctor` lists what is still missing and the command that fixes
|
|
100
|
+
each item. Every [release](https://github.com/NathanL15/Hex-CLI/releases)
|
|
101
|
+
also carries the wheel and the source distribution.
|
|
102
|
+
|
|
103
|
+
The Start Menu shortcut opens Hex in Windows Terminal, through a profile
|
|
104
|
+
the installer registers, starting in your home folder; `/cwd <path>` moves
|
|
105
|
+
into a project. Without Windows Terminal it uses the classic console, where
|
|
106
|
+
drag-select is off because Hex disables QuickEdit (a click would otherwise
|
|
107
|
+
freeze output); use the window menu's Edit, Mark to copy there.
|
|
123
108
|
|
|
124
109
|
## Usage
|
|
125
110
|
|
|
@@ -133,14 +118,11 @@ hexcli --doctor # check the install
|
|
|
133
118
|
hexcli --update # refresh npurun (and pull the source in a checkout)
|
|
134
119
|
```
|
|
135
120
|
|
|
136
|
-
In a checkout without the package installed, `python launcher.py` and
|
|
137
|
-
`python -m hexcli.agent` are the same two commands.
|
|
138
|
-
|
|
139
121
|
Piped input is added to the request as context, or used as the request if
|
|
140
|
-
there is no argument.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
122
|
+
there is no argument. When stdout is not a terminal the answer is printed
|
|
123
|
+
alone, so `hexcli "..." > answer.txt` and `hexcli "..." | clip` work. In a
|
|
124
|
+
checkout without the package installed, `python launcher.py` and
|
|
125
|
+
`python -m hexcli.agent` are the same two commands.
|
|
144
126
|
|
|
145
127
|
### Commands
|
|
146
128
|
|
|
@@ -165,10 +147,10 @@ work.
|
|
|
165
147
|
| `/doctor` | check the install |
|
|
166
148
|
| `Esc` | cancel the running step |
|
|
167
149
|
|
|
168
|
-
You can add your own
|
|
169
|
-
|
|
170
|
-
sends its content as the prompt
|
|
171
|
-
|
|
150
|
+
You can add your own. Put a `.md` file in `.shellai/commands/` in the
|
|
151
|
+
project, or `~/.shellai/commands/` for all projects, and `/<filename>`
|
|
152
|
+
sends its content as the prompt, with `$ARGUMENTS` replaced by whatever
|
|
153
|
+
follows the command:
|
|
172
154
|
|
|
173
155
|
```powershell
|
|
174
156
|
# .shellai/commands/review.md contains: Review $ARGUMENTS for bugs and style issues.
|
|
@@ -188,21 +170,15 @@ whatever follows the command.
|
|
|
188
170
|
| `Ctrl+V` | paste a block. Nothing is sent until you press Enter |
|
|
189
171
|
| `Shift+Enter` | new line inside the entry |
|
|
190
172
|
| `\` then `Enter` | continue on a new line |
|
|
191
|
-
| `Ctrl+Plus` `Ctrl+Minus` | text size in the classic console |
|
|
192
173
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
The input box stays on the last rows of the window, and the conversation
|
|
197
|
-
scrolls up above it. The status line under it
|
|
198
|
-
shows how full the context is, the NPU load (the counter behind Task
|
|
199
|
-
Manager's NPU graph), memory in use, and the working directory and branch.
|
|
200
|
-
Set `status_bar` to `false` for the old inline prompt.
|
|
174
|
+
The status line under the input box shows how full the context is, the
|
|
175
|
+
NPU load, memory in use, and the working directory and branch. Set
|
|
176
|
+
`status_bar` to `false` for a plain inline prompt.
|
|
201
177
|
|
|
202
178
|
### Project instructions
|
|
203
179
|
|
|
204
180
|
If a project has an `AGENTS.md`, the agent reads it every turn. Keep it
|
|
205
|
-
under about 1,200 characters
|
|
181
|
+
under about 1,200 characters: the model has a 4K token context and your
|
|
206
182
|
request has to fit in there too.
|
|
207
183
|
|
|
208
184
|
### Tools
|
|
@@ -213,9 +189,19 @@ request has to fit in there too.
|
|
|
213
189
|
for the full signatures.
|
|
214
190
|
|
|
215
191
|
`edit_file` tries an exact match first, then a whitespace-tolerant match,
|
|
216
|
-
then a close match if there is exactly one
|
|
217
|
-
|
|
218
|
-
|
|
192
|
+
then a close match if there is exactly one; an ambiguous match returns an
|
|
193
|
+
error rather than a guess. `read_file` reads large files in pages. Every
|
|
194
|
+
file change prints a diff and can be reverted with `/undo`.
|
|
195
|
+
|
|
196
|
+
### Memory and logs
|
|
197
|
+
|
|
198
|
+
Memory is two local stores, one per project and one global, built on
|
|
199
|
+
MiniLM embeddings. When idle, the agent condenses recent turns into short
|
|
200
|
+
notes that later prompts include; `/memory` shows what is stored.
|
|
201
|
+
|
|
202
|
+
Each session is written to `~/.shellai/chatlog/` as a JSONL file: every
|
|
203
|
+
request, every message sent to the model, every reply with its latency,
|
|
204
|
+
every tool call with its output. Secrets in the config are redacted.
|
|
219
205
|
|
|
220
206
|
## Safety
|
|
221
207
|
|
|
@@ -223,18 +209,16 @@ Commands are classified before they run:
|
|
|
223
209
|
|
|
224
210
|
| Level | Examples | Behaviour |
|
|
225
211
|
|---|---|---|
|
|
226
|
-
| destructive | `Remove-Item`, `git reset --hard`, `
|
|
212
|
+
| destructive | `Remove-Item`, `git reset --hard`, `Format-Volume`, `iex` | asks first |
|
|
227
213
|
| sensitive | ssh/gpg/aws keys, hosts file, registry hives, credential stores, `-EncodedCommand` | asks first, denied when non-interactive |
|
|
228
214
|
| safe | `Get-*`, `ls`, `git status` | runs |
|
|
229
215
|
| caution | anything else | runs |
|
|
230
216
|
|
|
231
217
|
File writes stay inside the working directory unless you widen the scope
|
|
232
218
|
with `workspace_write_allow`. Reads can go anywhere. Key and credential
|
|
233
|
-
paths are blocked for all file tools.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
fetch, and is refused when non-interactive. Set `network_access` to
|
|
237
|
-
`"deny"` to remove the tool or `"allow"` to skip the prompt.
|
|
219
|
+
paths are blocked for all file tools. `fetch_url` is the only tool that
|
|
220
|
+
touches the network; it asks before every fetch and is refused when
|
|
221
|
+
non-interactive.
|
|
238
222
|
|
|
239
223
|
Each classified command is appended to `.shellai/audit.log`. Text inside
|
|
240
224
|
files and tool output is treated as data, not instructions. A 4B model does
|
|
@@ -244,45 +228,20 @@ doing so.
|
|
|
244
228
|
## Configuration
|
|
245
229
|
|
|
246
230
|
Config is optional. `~\.shellai\shellai.json` and `.shellai/config.json`
|
|
247
|
-
in a project are merged over the defaults, so you only
|
|
248
|
-
|
|
249
|
-
and `/setup` writes the file for you.
|
|
231
|
+
in a project are merged over the defaults, so you only write the keys you
|
|
232
|
+
change. The ones people change:
|
|
250
233
|
|
|
251
234
|
| Key | Default | Effect |
|
|
252
235
|
|---|---|---|
|
|
253
236
|
| `max_agent_steps` | `15` | tool calls per turn |
|
|
254
|
-
| `live_streaming` | `true` | show the answer as it arrives |
|
|
255
|
-
| `rich_input` | `true` | history, Tab completion, multi-line paste |
|
|
256
|
-
| `side_padding` | `2` | left margin in columns |
|
|
257
|
-
| `status_bar` | `true` | input box and status line at the bottom |
|
|
258
|
-
| `user_highlight` | `true` | light band behind your messages in the transcript |
|
|
259
237
|
| `show_diffs` | `true` | print a diff after each file change |
|
|
238
|
+
| `status_bar` | `true` | input box and status line at the bottom |
|
|
260
239
|
| `workspace_write_scope` | `true` | keep writes inside the working directory |
|
|
261
|
-
| `
|
|
262
|
-
| `network_access` | `"ask"` | `"deny"` or `"allow"` |
|
|
263
|
-
| `require_verification` | `true` | ask the agent to check its own edits |
|
|
264
|
-
| `prompt_split` | `true` | answer plain questions without the tool loop |
|
|
265
|
-
| `escalation_local_model` | `""` | a larger local model to consult when stuck |
|
|
240
|
+
| `network_access` | `"ask"` | `"deny"` removes `fetch_url`, `"allow"` skips the prompt |
|
|
266
241
|
| `memory_enabled` | `true` | semantic memory |
|
|
267
|
-
| `chat_log_enabled` | `true` | write full session logs |
|
|
268
|
-
| `protocol` | `"v1"` | `"v2"` is experimental |
|
|
269
242
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
Each session is written to `~/.shellai/chatlog/` as a JSONL file: every
|
|
273
|
-
request, every message sent to the model, every reply with its latency,
|
|
274
|
-
every tool call with its output. Secrets in the config are redacted.
|
|
275
|
-
`/stats` prints the path of the current file.
|
|
276
|
-
|
|
277
|
-
```powershell
|
|
278
|
-
python tools/chatlog_report.py # summary across all sessions
|
|
279
|
-
python tools/chatlog_report.py --last # replay the most recent session
|
|
280
|
-
python tools/chatlog_report.py --session 1a2b # replay one session by id prefix
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
Memory is two local stores, one per project and one global, built on MiniLM
|
|
284
|
-
embeddings. When idle, the agent condenses recent turns into short notes
|
|
285
|
-
that are included in later prompts. `/memory` shows what is stored.
|
|
243
|
+
`shellai.example.json` lists every key with its default, and `/setup`
|
|
244
|
+
writes the file for you.
|
|
286
245
|
|
|
287
246
|
## Setup by hand
|
|
288
247
|
|
|
@@ -291,7 +250,7 @@ These are the steps `install.ps1` performs. `--doctor` checks each one.
|
|
|
291
250
|
**1. The package**
|
|
292
251
|
|
|
293
252
|
```powershell
|
|
294
|
-
pip install
|
|
253
|
+
pip install hexcli # or, from the checkout: pip install .
|
|
295
254
|
```
|
|
296
255
|
|
|
297
256
|
`ruff` is optional and enables the `lint_code` tool.
|
|
@@ -313,22 +272,26 @@ setx ADSP_LIBRARY_PATH "C:\Qualcomm\AIStack\QAIRT_2.50.0\lib\hexagon-v73\unsigne
|
|
|
313
272
|
If `ADSP_LIBRARY_PATH` is missing, npurun crashes with
|
|
314
273
|
`STATUS_STACK_BUFFER_OVERRUN`.
|
|
315
274
|
|
|
316
|
-
**3. npurun and
|
|
317
|
-
|
|
318
|
-
The NPU server is a fork of npurun, at
|
|
319
|
-
[NathanL15/npurun](https://github.com/NathanL15/npurun) on the
|
|
320
|
-
`hexcli-fork` branch. Each release there has a prebuilt `npurun-arm64.exe`.
|
|
321
|
-
Hex CLI expects one specific build, set by `REQUIRED_NPURUN` in
|
|
322
|
-
`hexcli/launcher.py`. `--doctor` fails on an older build and `--update`
|
|
323
|
-
replaces it (the download goes to `~\.shellai\bin`).
|
|
275
|
+
**3. npurun and the model**
|
|
324
276
|
|
|
325
|
-
|
|
326
|
-
|
|
277
|
+
The NPU server is a fork of npurun at
|
|
278
|
+
[NathanL15/npurun](https://github.com/NathanL15/npurun), branch
|
|
279
|
+
`hexcli-fork`, with a prebuilt `npurun-arm64.exe` on each release. Hex CLI
|
|
280
|
+
expects one specific build, set by `REQUIRED_NPURUN` in
|
|
281
|
+
`hexcli/launcher.py`; `hexcli --update` downloads it to `~\.shellai\bin`
|
|
282
|
+
and `--doctor` fails on an older one. The fork adds the prompt cache
|
|
283
|
+
rewind, usage reporting, exact `max_tokens` and the request watchdog that
|
|
284
|
+
Hex CLI relies on, so upstream npurun will not do. To build it yourself:
|
|
327
285
|
|
|
328
286
|
```powershell
|
|
329
287
|
git clone -b hexcli-fork https://github.com/NathanL15/npurun
|
|
330
288
|
cd npurun
|
|
331
289
|
cmd /c "scripts\dev-shell-local.bat cargo install --path crates\npurun-cli"
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The model downloads on the first `hex` run, or by hand:
|
|
293
|
+
|
|
294
|
+
```powershell
|
|
332
295
|
npurun pull qwen3-4b-instruct-2507 # about 2.5 GB
|
|
333
296
|
```
|
|
334
297
|
|
|
@@ -357,7 +320,7 @@ curl -L -o ~\.shellai\onnx\tokenizer.json https://huggingface.co/sentence-transf
|
|
|
357
320
|
|
|
358
321
|
## Development
|
|
359
322
|
|
|
360
|
-
CI runs `ruff` and
|
|
323
|
+
CI runs `ruff` and 29 offline test suites against a mock backend, so no NPU
|
|
361
324
|
is needed for those:
|
|
362
325
|
|
|
363
326
|
```powershell
|
|
@@ -369,14 +332,15 @@ python evals/test_lineedit.py
|
|
|
369
332
|
|
|
370
333
|
The live evals need the NPU server. They check what the model actually did,
|
|
371
334
|
by looking at the filesystem and the answer, and run each case several
|
|
372
|
-
times because the model is not deterministic
|
|
335
|
+
times because the model is not deterministic:
|
|
373
336
|
|
|
374
337
|
```powershell
|
|
375
338
|
python evals/cases_smoke.py # quick check
|
|
376
|
-
python evals/cases_extended.py --runs 3 #
|
|
339
|
+
python evals/cases_extended.py --runs 3 # 44 cases
|
|
377
340
|
python evals/cases_multiturn.py --runs 3 --think-time 15
|
|
378
341
|
python evals/compare.py <before.json> <after.json>
|
|
379
342
|
python evals/gate.py --baseline <base.json> <candidate.json>
|
|
343
|
+
python tools/chatlog_report.py --last # replay the most recent session
|
|
380
344
|
```
|
|
381
345
|
|
|
382
346
|
Restart the NPU server before each suite. After an hour or two of steady
|
|
@@ -1,60 +1,36 @@
|
|
|
1
1
|
# Hex CLI
|
|
2
2
|
|
|
3
|
+
[](https://pypi.org/project/hexcli/)
|
|
4
|
+
[](https://github.com/NathanL15/Hex-CLI/actions/workflows/ci.yml)
|
|
5
|
+
|
|
3
6
|
Hex CLI is a coding agent for the Windows terminal, similar to aider or
|
|
4
7
|
Claude Code, that runs a local model on the Snapdragon Hexagon NPU. It reads
|
|
5
8
|
and edits files, runs commands, and checks its own work. The model is
|
|
6
9
|
Qwen3-4B, served by [npurun](https://github.com/bpbonker/npurun). After
|
|
7
10
|
setup it works offline.
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
run; a delete asks first
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
> the median calc in processor.py is wrong for even-length lists, fix it
|
|
32
|
-
|
|
33
|
-
◆ read_file
|
|
34
|
-
▸ [read] processor.py (lines 1-40 of 40)
|
|
35
|
-
|
|
36
|
-
◆ edit_file
|
|
37
|
-
▸ [edit] processor.py (+2 lines)
|
|
38
|
-
~ processor.py (+3 −1)
|
|
39
|
-
@@ -12,4 +12,6 @@
|
|
40
|
-
- return sorted(data)[len(data) // 2]
|
|
41
|
-
+ mid = len(data) // 2
|
|
42
|
-
+ if len(data) % 2 == 0:
|
|
43
|
-
+ return (sorted(data)[mid - 1] + sorted(data)[mid]) / 2
|
|
44
|
-
|
|
45
|
-
◆ run_code
|
|
46
|
-
|
|
47
|
-
Fixed: even-length lists now average the two middle values. The test file
|
|
48
|
-
prints 3.5 for [1, 2, 5, 6].
|
|
49
|
-
|
|
50
|
-
──────────────────────────────────────────────────────────────────
|
|
51
|
-
> ask, or / for commands
|
|
52
|
-
──────────────────────────────────────────────────────────────────
|
|
53
|
-
context ◔ 21% npu 0% mem 12.5/15.6 GB ~\proj (main)
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Your messages sit on a light band, the input box and status line stay on
|
|
57
|
-
the last rows, and the answer streams in above them.
|
|
12
|
+
<table>
|
|
13
|
+
<tr>
|
|
14
|
+
<td width="50%" valign="top">
|
|
15
|
+
<b>Ask something.</b> The answer streams in, markdown and all, above an input box that stays on the last rows.<br><br>
|
|
16
|
+
<img src="https://raw.githubusercontent.com/NathanL15/Hex-CLI/main/docs/gifs/ask.gif" alt="A question answered in bullet points" width="100%">
|
|
17
|
+
</td>
|
|
18
|
+
<td width="50%" valign="top">
|
|
19
|
+
<b>Ask about the machine.</b> Live state comes from a real command, shown as it runs.<br><br>
|
|
20
|
+
<img src="https://raw.githubusercontent.com/NathanL15/Hex-CLI/main/docs/gifs/machine.gif" alt="The CPU name read with a PowerShell command" width="100%">
|
|
21
|
+
</td>
|
|
22
|
+
</tr>
|
|
23
|
+
<tr>
|
|
24
|
+
<td width="50%" valign="top">
|
|
25
|
+
<b>Change code.</b> Every file change prints a diff; when you ask for the tests, they run; <code>/diff</code> shows the turn's changes and <code>/undo</code> takes them back, files included.<br><br>
|
|
26
|
+
<img src="https://raw.githubusercontent.com/NathanL15/Hex-CLI/main/docs/gifs/edit.gif" alt="A docstring added, the tests run, then undone" width="100%">
|
|
27
|
+
</td>
|
|
28
|
+
<td width="50%" valign="top">
|
|
29
|
+
<b>Nothing destructive runs unasked.</b> Commands are classified before they run; a delete asks first.<br><br>
|
|
30
|
+
<img src="https://raw.githubusercontent.com/NathanL15/Hex-CLI/main/docs/gifs/safety.gif" alt="A delete command waits for a y/N before running" width="100%">
|
|
31
|
+
</td>
|
|
32
|
+
</tr>
|
|
33
|
+
</table>
|
|
58
34
|
|
|
59
35
|
## Requirements
|
|
60
36
|
|
|
@@ -66,33 +42,42 @@ Tested on a Snapdragon X Elite. It will not run on x86 machines or on Macs.
|
|
|
66
42
|
|
|
67
43
|
## Install
|
|
68
44
|
|
|
45
|
+
The installer does everything the machine allows:
|
|
46
|
+
|
|
69
47
|
```powershell
|
|
70
48
|
git clone https://github.com/NathanL15/Hex-CLI
|
|
71
49
|
cd Hex-CLI
|
|
72
50
|
.\install.ps1
|
|
73
51
|
```
|
|
74
52
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
It
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
53
|
+
It checks the machine, installs the package, downloads npurun, the model
|
|
54
|
+
and the small embedding model that memory uses, and runs `--doctor` when it
|
|
55
|
+
finishes. It skips steps that are already done, so run it again after
|
|
56
|
+
fixing anything it reports. Everything it writes for you lives in
|
|
57
|
+
`~\.shellai`.
|
|
58
|
+
|
|
59
|
+
The one thing it cannot download is the QAIRT SDK, because Qualcomm does
|
|
60
|
+
not allow redistribution. It prints the instructions for that step and
|
|
61
|
+
picks the SDK up on the next run.
|
|
62
|
+
|
|
63
|
+
Or install from PyPI. The package is the same one the installer uses; you
|
|
64
|
+
install the SDK yourself and the rest downloads itself:
|
|
65
|
+
|
|
66
|
+
```powershell
|
|
67
|
+
pip install hexcli # the hex and hexcli commands
|
|
68
|
+
hexcli --update # downloads npurun
|
|
69
|
+
hex # the first run downloads the model, about 2.5 GB
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`hexcli --doctor` lists what is still missing and the command that fixes
|
|
73
|
+
each item. Every [release](https://github.com/NathanL15/Hex-CLI/releases)
|
|
74
|
+
also carries the wheel and the source distribution.
|
|
75
|
+
|
|
76
|
+
The Start Menu shortcut opens Hex in Windows Terminal, through a profile
|
|
77
|
+
the installer registers, starting in your home folder; `/cwd <path>` moves
|
|
78
|
+
into a project. Without Windows Terminal it uses the classic console, where
|
|
79
|
+
drag-select is off because Hex disables QuickEdit (a click would otherwise
|
|
80
|
+
freeze output); use the window menu's Edit, Mark to copy there.
|
|
96
81
|
|
|
97
82
|
## Usage
|
|
98
83
|
|
|
@@ -106,14 +91,11 @@ hexcli --doctor # check the install
|
|
|
106
91
|
hexcli --update # refresh npurun (and pull the source in a checkout)
|
|
107
92
|
```
|
|
108
93
|
|
|
109
|
-
In a checkout without the package installed, `python launcher.py` and
|
|
110
|
-
`python -m hexcli.agent` are the same two commands.
|
|
111
|
-
|
|
112
94
|
Piped input is added to the request as context, or used as the request if
|
|
113
|
-
there is no argument.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
95
|
+
there is no argument. When stdout is not a terminal the answer is printed
|
|
96
|
+
alone, so `hexcli "..." > answer.txt` and `hexcli "..." | clip` work. In a
|
|
97
|
+
checkout without the package installed, `python launcher.py` and
|
|
98
|
+
`python -m hexcli.agent` are the same two commands.
|
|
117
99
|
|
|
118
100
|
### Commands
|
|
119
101
|
|
|
@@ -138,10 +120,10 @@ work.
|
|
|
138
120
|
| `/doctor` | check the install |
|
|
139
121
|
| `Esc` | cancel the running step |
|
|
140
122
|
|
|
141
|
-
You can add your own
|
|
142
|
-
|
|
143
|
-
sends its content as the prompt
|
|
144
|
-
|
|
123
|
+
You can add your own. Put a `.md` file in `.shellai/commands/` in the
|
|
124
|
+
project, or `~/.shellai/commands/` for all projects, and `/<filename>`
|
|
125
|
+
sends its content as the prompt, with `$ARGUMENTS` replaced by whatever
|
|
126
|
+
follows the command:
|
|
145
127
|
|
|
146
128
|
```powershell
|
|
147
129
|
# .shellai/commands/review.md contains: Review $ARGUMENTS for bugs and style issues.
|
|
@@ -161,21 +143,15 @@ whatever follows the command.
|
|
|
161
143
|
| `Ctrl+V` | paste a block. Nothing is sent until you press Enter |
|
|
162
144
|
| `Shift+Enter` | new line inside the entry |
|
|
163
145
|
| `\` then `Enter` | continue on a new line |
|
|
164
|
-
| `Ctrl+Plus` `Ctrl+Minus` | text size in the classic console |
|
|
165
146
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
The input box stays on the last rows of the window, and the conversation
|
|
170
|
-
scrolls up above it. The status line under it
|
|
171
|
-
shows how full the context is, the NPU load (the counter behind Task
|
|
172
|
-
Manager's NPU graph), memory in use, and the working directory and branch.
|
|
173
|
-
Set `status_bar` to `false` for the old inline prompt.
|
|
147
|
+
The status line under the input box shows how full the context is, the
|
|
148
|
+
NPU load, memory in use, and the working directory and branch. Set
|
|
149
|
+
`status_bar` to `false` for a plain inline prompt.
|
|
174
150
|
|
|
175
151
|
### Project instructions
|
|
176
152
|
|
|
177
153
|
If a project has an `AGENTS.md`, the agent reads it every turn. Keep it
|
|
178
|
-
under about 1,200 characters
|
|
154
|
+
under about 1,200 characters: the model has a 4K token context and your
|
|
179
155
|
request has to fit in there too.
|
|
180
156
|
|
|
181
157
|
### Tools
|
|
@@ -186,9 +162,19 @@ request has to fit in there too.
|
|
|
186
162
|
for the full signatures.
|
|
187
163
|
|
|
188
164
|
`edit_file` tries an exact match first, then a whitespace-tolerant match,
|
|
189
|
-
then a close match if there is exactly one
|
|
190
|
-
|
|
191
|
-
|
|
165
|
+
then a close match if there is exactly one; an ambiguous match returns an
|
|
166
|
+
error rather than a guess. `read_file` reads large files in pages. Every
|
|
167
|
+
file change prints a diff and can be reverted with `/undo`.
|
|
168
|
+
|
|
169
|
+
### Memory and logs
|
|
170
|
+
|
|
171
|
+
Memory is two local stores, one per project and one global, built on
|
|
172
|
+
MiniLM embeddings. When idle, the agent condenses recent turns into short
|
|
173
|
+
notes that later prompts include; `/memory` shows what is stored.
|
|
174
|
+
|
|
175
|
+
Each session is written to `~/.shellai/chatlog/` as a JSONL file: every
|
|
176
|
+
request, every message sent to the model, every reply with its latency,
|
|
177
|
+
every tool call with its output. Secrets in the config are redacted.
|
|
192
178
|
|
|
193
179
|
## Safety
|
|
194
180
|
|
|
@@ -196,18 +182,16 @@ Commands are classified before they run:
|
|
|
196
182
|
|
|
197
183
|
| Level | Examples | Behaviour |
|
|
198
184
|
|---|---|---|
|
|
199
|
-
| destructive | `Remove-Item`, `git reset --hard`, `
|
|
185
|
+
| destructive | `Remove-Item`, `git reset --hard`, `Format-Volume`, `iex` | asks first |
|
|
200
186
|
| sensitive | ssh/gpg/aws keys, hosts file, registry hives, credential stores, `-EncodedCommand` | asks first, denied when non-interactive |
|
|
201
187
|
| safe | `Get-*`, `ls`, `git status` | runs |
|
|
202
188
|
| caution | anything else | runs |
|
|
203
189
|
|
|
204
190
|
File writes stay inside the working directory unless you widen the scope
|
|
205
191
|
with `workspace_write_allow`. Reads can go anywhere. Key and credential
|
|
206
|
-
paths are blocked for all file tools.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
fetch, and is refused when non-interactive. Set `network_access` to
|
|
210
|
-
`"deny"` to remove the tool or `"allow"` to skip the prompt.
|
|
192
|
+
paths are blocked for all file tools. `fetch_url` is the only tool that
|
|
193
|
+
touches the network; it asks before every fetch and is refused when
|
|
194
|
+
non-interactive.
|
|
211
195
|
|
|
212
196
|
Each classified command is appended to `.shellai/audit.log`. Text inside
|
|
213
197
|
files and tool output is treated as data, not instructions. A 4B model does
|
|
@@ -217,45 +201,20 @@ doing so.
|
|
|
217
201
|
## Configuration
|
|
218
202
|
|
|
219
203
|
Config is optional. `~\.shellai\shellai.json` and `.shellai/config.json`
|
|
220
|
-
in a project are merged over the defaults, so you only
|
|
221
|
-
|
|
222
|
-
and `/setup` writes the file for you.
|
|
204
|
+
in a project are merged over the defaults, so you only write the keys you
|
|
205
|
+
change. The ones people change:
|
|
223
206
|
|
|
224
207
|
| Key | Default | Effect |
|
|
225
208
|
|---|---|---|
|
|
226
209
|
| `max_agent_steps` | `15` | tool calls per turn |
|
|
227
|
-
| `live_streaming` | `true` | show the answer as it arrives |
|
|
228
|
-
| `rich_input` | `true` | history, Tab completion, multi-line paste |
|
|
229
|
-
| `side_padding` | `2` | left margin in columns |
|
|
230
|
-
| `status_bar` | `true` | input box and status line at the bottom |
|
|
231
|
-
| `user_highlight` | `true` | light band behind your messages in the transcript |
|
|
232
210
|
| `show_diffs` | `true` | print a diff after each file change |
|
|
211
|
+
| `status_bar` | `true` | input box and status line at the bottom |
|
|
233
212
|
| `workspace_write_scope` | `true` | keep writes inside the working directory |
|
|
234
|
-
| `
|
|
235
|
-
| `network_access` | `"ask"` | `"deny"` or `"allow"` |
|
|
236
|
-
| `require_verification` | `true` | ask the agent to check its own edits |
|
|
237
|
-
| `prompt_split` | `true` | answer plain questions without the tool loop |
|
|
238
|
-
| `escalation_local_model` | `""` | a larger local model to consult when stuck |
|
|
213
|
+
| `network_access` | `"ask"` | `"deny"` removes `fetch_url`, `"allow"` skips the prompt |
|
|
239
214
|
| `memory_enabled` | `true` | semantic memory |
|
|
240
|
-
| `chat_log_enabled` | `true` | write full session logs |
|
|
241
|
-
| `protocol` | `"v1"` | `"v2"` is experimental |
|
|
242
215
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
Each session is written to `~/.shellai/chatlog/` as a JSONL file: every
|
|
246
|
-
request, every message sent to the model, every reply with its latency,
|
|
247
|
-
every tool call with its output. Secrets in the config are redacted.
|
|
248
|
-
`/stats` prints the path of the current file.
|
|
249
|
-
|
|
250
|
-
```powershell
|
|
251
|
-
python tools/chatlog_report.py # summary across all sessions
|
|
252
|
-
python tools/chatlog_report.py --last # replay the most recent session
|
|
253
|
-
python tools/chatlog_report.py --session 1a2b # replay one session by id prefix
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
Memory is two local stores, one per project and one global, built on MiniLM
|
|
257
|
-
embeddings. When idle, the agent condenses recent turns into short notes
|
|
258
|
-
that are included in later prompts. `/memory` shows what is stored.
|
|
216
|
+
`shellai.example.json` lists every key with its default, and `/setup`
|
|
217
|
+
writes the file for you.
|
|
259
218
|
|
|
260
219
|
## Setup by hand
|
|
261
220
|
|
|
@@ -264,7 +223,7 @@ These are the steps `install.ps1` performs. `--doctor` checks each one.
|
|
|
264
223
|
**1. The package**
|
|
265
224
|
|
|
266
225
|
```powershell
|
|
267
|
-
pip install
|
|
226
|
+
pip install hexcli # or, from the checkout: pip install .
|
|
268
227
|
```
|
|
269
228
|
|
|
270
229
|
`ruff` is optional and enables the `lint_code` tool.
|
|
@@ -286,22 +245,26 @@ setx ADSP_LIBRARY_PATH "C:\Qualcomm\AIStack\QAIRT_2.50.0\lib\hexagon-v73\unsigne
|
|
|
286
245
|
If `ADSP_LIBRARY_PATH` is missing, npurun crashes with
|
|
287
246
|
`STATUS_STACK_BUFFER_OVERRUN`.
|
|
288
247
|
|
|
289
|
-
**3. npurun and
|
|
290
|
-
|
|
291
|
-
The NPU server is a fork of npurun, at
|
|
292
|
-
[NathanL15/npurun](https://github.com/NathanL15/npurun) on the
|
|
293
|
-
`hexcli-fork` branch. Each release there has a prebuilt `npurun-arm64.exe`.
|
|
294
|
-
Hex CLI expects one specific build, set by `REQUIRED_NPURUN` in
|
|
295
|
-
`hexcli/launcher.py`. `--doctor` fails on an older build and `--update`
|
|
296
|
-
replaces it (the download goes to `~\.shellai\bin`).
|
|
248
|
+
**3. npurun and the model**
|
|
297
249
|
|
|
298
|
-
|
|
299
|
-
|
|
250
|
+
The NPU server is a fork of npurun at
|
|
251
|
+
[NathanL15/npurun](https://github.com/NathanL15/npurun), branch
|
|
252
|
+
`hexcli-fork`, with a prebuilt `npurun-arm64.exe` on each release. Hex CLI
|
|
253
|
+
expects one specific build, set by `REQUIRED_NPURUN` in
|
|
254
|
+
`hexcli/launcher.py`; `hexcli --update` downloads it to `~\.shellai\bin`
|
|
255
|
+
and `--doctor` fails on an older one. The fork adds the prompt cache
|
|
256
|
+
rewind, usage reporting, exact `max_tokens` and the request watchdog that
|
|
257
|
+
Hex CLI relies on, so upstream npurun will not do. To build it yourself:
|
|
300
258
|
|
|
301
259
|
```powershell
|
|
302
260
|
git clone -b hexcli-fork https://github.com/NathanL15/npurun
|
|
303
261
|
cd npurun
|
|
304
262
|
cmd /c "scripts\dev-shell-local.bat cargo install --path crates\npurun-cli"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
The model downloads on the first `hex` run, or by hand:
|
|
266
|
+
|
|
267
|
+
```powershell
|
|
305
268
|
npurun pull qwen3-4b-instruct-2507 # about 2.5 GB
|
|
306
269
|
```
|
|
307
270
|
|
|
@@ -330,7 +293,7 @@ curl -L -o ~\.shellai\onnx\tokenizer.json https://huggingface.co/sentence-transf
|
|
|
330
293
|
|
|
331
294
|
## Development
|
|
332
295
|
|
|
333
|
-
CI runs `ruff` and
|
|
296
|
+
CI runs `ruff` and 29 offline test suites against a mock backend, so no NPU
|
|
334
297
|
is needed for those:
|
|
335
298
|
|
|
336
299
|
```powershell
|
|
@@ -342,14 +305,15 @@ python evals/test_lineedit.py
|
|
|
342
305
|
|
|
343
306
|
The live evals need the NPU server. They check what the model actually did,
|
|
344
307
|
by looking at the filesystem and the answer, and run each case several
|
|
345
|
-
times because the model is not deterministic
|
|
308
|
+
times because the model is not deterministic:
|
|
346
309
|
|
|
347
310
|
```powershell
|
|
348
311
|
python evals/cases_smoke.py # quick check
|
|
349
|
-
python evals/cases_extended.py --runs 3 #
|
|
312
|
+
python evals/cases_extended.py --runs 3 # 44 cases
|
|
350
313
|
python evals/cases_multiturn.py --runs 3 --think-time 15
|
|
351
314
|
python evals/compare.py <before.json> <after.json>
|
|
352
315
|
python evals/gate.py --baseline <base.json> <candidate.json>
|
|
316
|
+
python tools/chatlog_report.py --last # replay the most recent session
|
|
353
317
|
```
|
|
354
318
|
|
|
355
319
|
Restart the NPU server before each suite. After an hour or two of steady
|
|
@@ -270,7 +270,7 @@ def _maybe_auto_compact(
|
|
|
270
270
|
The full summary is suppressed (quiet=True); only a one-line notice prints.
|
|
271
271
|
|
|
272
272
|
Thrash guard: before 2.5.0's window-derived budget, a 2,200-token prompt
|
|
273
|
-
clamped the history budget to the 250-token floor (now ~
|
|
273
|
+
clamped the history budget to the 250-token floor (now ~800 against a
|
|
274
274
|
3,696-token server budget), and the compacted tail usually exceeded it —
|
|
275
275
|
so v2.2 re-fired every single turn, shredding the condensed block a little
|
|
276
276
|
further each time while freeing almost nothing (the user-reported "by the
|
|
@@ -400,6 +400,23 @@ if (-not $NoStartMenu) {
|
|
|
400
400
|
if ($useTerminal) {
|
|
401
401
|
$wtSettings = Join-Path $env:LOCALAPPDATA "Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json"
|
|
402
402
|
$hasOwnProfile = (Test-Path $wtSettings) -and ((Get-Content $wtSettings -Raw) -match '"name"\s*:\s*"Hex CLI"')
|
|
403
|
+
if ($hasOwnProfile -and (Test-Path $iconPng)) {
|
|
404
|
+
# The user's own copy of the profile is left alone, except
|
|
405
|
+
# for an icon path that no longer exists (2.8.0 moved the
|
|
406
|
+
# icon into the package): Terminal falls back to its own
|
|
407
|
+
# logo on a missing file. A targeted text edit, so the
|
|
408
|
+
# user's comments and formatting survive.
|
|
409
|
+
$raw = Get-Content $wtSettings -Raw
|
|
410
|
+
$m = [regex]::Match($raw, '"icon"\s*:\s*"((?:[^"\\]|\\.)*hexcli\.png)"')
|
|
411
|
+
if ($m.Success) {
|
|
412
|
+
$current = $m.Groups[1].Value.Replace('\\', '\')
|
|
413
|
+
if (-not (Test-Path $current)) {
|
|
414
|
+
$raw = $raw.Replace($m.Groups[1].Value, $iconPng.Replace('\', '\\'))
|
|
415
|
+
[IO.File]::WriteAllText($wtSettings, $raw, (New-Object Text.UTF8Encoding $false))
|
|
416
|
+
Write-Ok "Windows Terminal profile icon repaired: $iconPng"
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
403
420
|
if (-not $hasOwnProfile) {
|
|
404
421
|
$fragmentDir = Join-Path $env:LOCALAPPDATA "Microsoft\Windows Terminal\Fragments\Hex CLI"
|
|
405
422
|
New-Item -ItemType Directory -Force -Path $fragmentDir | Out-Null
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|