hexcli 2.14.0__tar.gz → 2.16.0__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.14.0 → hexcli-2.16.0}/CHANGELOG.md +57 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/PKG-INFO +1 -1
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/__init__.py +1 -1
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/agent.py +6 -1
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/tools.py +11 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/.gitignore +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/Hex CLI.cmd +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/LICENSE +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/README.md +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/assets/hexcli.ico +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/assets/hexcli.png +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/cancel.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/chatlog.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/commands.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/compaction.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/config.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/diffview.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/distribution.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/doctor.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/editing.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/http_client.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/launcher.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/lineedit.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/llm.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/lockfile.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/markdown_stream.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/memory.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/network.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/parsing.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/paths.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/prompts.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/psparse.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/repl.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/safety.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/sessions.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/setup_wizard.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/statusbar.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/stream_render.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/telemetry.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/hexcli/ui.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/install.ps1 +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/launcher.py +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/pyproject.toml +0 -0
- {hexcli-2.14.0 → hexcli-2.16.0}/shellai.example.json +0 -0
|
@@ -4,6 +4,63 @@ Full evidence for every claim below — including the experiments that failed
|
|
|
4
4
|
lives in `docs/V2_PLAN.md` §14. Numbers are pass^k over repeated live runs on
|
|
5
5
|
the Hexagon NPU, not single-run anecdotes.
|
|
6
6
|
|
|
7
|
+
## 2.16.0 — 2026-09-18
|
|
8
|
+
|
|
9
|
+
A minor release: a tool result the model reads changes (`find_files` returns
|
|
10
|
+
a listing where it returned an argument error).
|
|
11
|
+
|
|
12
|
+
> **Gate: PASS** on the pinned 24-case set after one recheck (`agentic-4`
|
|
13
|
+
> and `agentic-5`, neither of which calls `find_files`, missed once at 5
|
|
14
|
+
> runs and then held at 6). Own arm, fresh server, seed 20260918, 8 invalid
|
|
15
|
+
> of 245 runs. Against the v2.11.1 12-run baseline: run-level 402/514 vs
|
|
16
|
+
> 174/222, +0.2 %, Fisher p = 1.00; pass^k 26 → 30 of 46 shared cases,
|
|
17
|
+
> McNemar p = 0.29. **The alias did not fire in this arm**: all ten
|
|
18
|
+
> `find_files` calls carried `glob` (two also sent `pattern`, and `glob`
|
|
19
|
+
> won as designed), so the arm is evidence of no regression, and the case
|
|
20
|
+
> for the change rests on the 21 of 170 recorded calls that would have
|
|
21
|
+
> hit it. `findfile-1` 2/5, all three misses the decoy answer, which is
|
|
22
|
+
> the separate finding still open. Smoke 10/10 on a fresh server.
|
|
23
|
+
|
|
24
|
+
- `find_files` takes `pattern` as its glob when no `glob` is sent. The
|
|
25
|
+
model names the file under the key `search_files` uses in 21 of the 170
|
|
26
|
+
`find_files` calls on record, across eight cases and one of the owner's
|
|
27
|
+
sessions, and each one came back "find_files requires 'glob'". In the
|
|
28
|
+
2.12.0 arm three of `findfile-1`'s twelve runs spent two to three steps
|
|
29
|
+
on it and one reached the step limit that way. The value is what the
|
|
30
|
+
model meant to look for either way, and a bare name is a valid glob for
|
|
31
|
+
that exact name; `glob` still wins when both are sent, and a call with
|
|
32
|
+
neither is still an error.
|
|
33
|
+
|
|
34
|
+
## 2.15.0 — 2026-09-18
|
|
35
|
+
|
|
36
|
+
A minor release: one tool error the model reads is new (`edit_file` on
|
|
37
|
+
identical strings).
|
|
38
|
+
|
|
39
|
+
> **Gate: PASS** on the pinned 24-case set after one recheck (`agentic-5`
|
|
40
|
+
> 4/5, a counting answer with no edit in it, then 6/6). Own arm, fresh
|
|
41
|
+
> server, seed 20260917, 9 invalid of 245 runs. Against the v2.11.1 12-run
|
|
42
|
+
> baseline: run-level 402/514 vs 172/221, −0.4 %, Fisher p = 0.92; pass^k
|
|
43
|
+
> 26 → 28 of 46 shared cases, McNemar p = 0.63. The error fired in the arm
|
|
44
|
+
> on 3 `tests-claim-1` runs and nowhere else; that case went 4/5 against
|
|
45
|
+
> 12/24 (p = 0.34, ceiling). `self-correct-1` read 2/5 in the arm on a
|
|
46
|
+
> server 75 minutes into its traffic (the arm's invalid runs were climbing),
|
|
47
|
+
> and the error had not fired in any of its runs; a paired control on a
|
|
48
|
+
> fresh server, ten runs each on the parent tree and this one, came back
|
|
49
|
+
> **10/10 vs 9/10, p = 1.0**. In the one control run where the error did
|
|
50
|
+
> fire the model had sent a hallucinated `main()` as both strings, was told
|
|
51
|
+
> nothing changed, read the file, and then made the real fix. Smoke miss
|
|
52
|
+
> on `agentic-2` re-measured 9/10 against its recorded 75 %.
|
|
53
|
+
|
|
54
|
+
- `edit_file` refuses an edit whose `old_string` and `new_string` are the
|
|
55
|
+
same text, instead of answering "Edited". 37 of the 840 `edit_file` calls
|
|
56
|
+
on record sent identical strings and were told the edit landed; the model
|
|
57
|
+
then ran or read the file believing it had changed it (`tests-claim-1`:
|
|
58
|
+
"The median function was correctly fixed", after an edit of `mean` to
|
|
59
|
+
itself; `runit-1` before 2.14.0: the broken line edited to itself, twice,
|
|
60
|
+
to the step limit). The tool now says nothing changed and what to send
|
|
61
|
+
instead, and leaves the file byte-identical. A missing file still reports
|
|
62
|
+
the path first.
|
|
63
|
+
|
|
7
64
|
## 2.14.0 — 2026-09-17
|
|
8
65
|
|
|
9
66
|
A minor release: one tool behaves differently for the model (a `write_file`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hexcli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.16.0
|
|
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
|
|
@@ -826,7 +826,12 @@ def execute_tool_call(config: dict[str, Any], action: dict[str, Any], shell_exe:
|
|
|
826
826
|
raise RuntimeError("search_files requires 'pattern'.")
|
|
827
827
|
return search_files_tool(pattern, path, glob_pat, limit)
|
|
828
828
|
if tool == "find_files":
|
|
829
|
-
|
|
829
|
+
# 21 of the 170 find_files calls on record (2026-09-17) sent the
|
|
830
|
+
# name under "pattern", the key search_files uses, and got "requires
|
|
831
|
+
# 'glob'" -- three of findfile-1's twelve runs burned steps on it,
|
|
832
|
+
# one to the step limit. The value is what the model meant to look
|
|
833
|
+
# for either way; a bare name is a valid glob for that exact name.
|
|
834
|
+
glob_pat = str(args.get("glob") or args.get("pattern") or "").strip()
|
|
830
835
|
path = str(args.get("path") or ".").strip() or "."
|
|
831
836
|
if not glob_pat:
|
|
832
837
|
raise RuntimeError("find_files requires 'glob'.")
|
|
@@ -423,6 +423,17 @@ def edit_file_tool(path_text: str, old_string: str, new_string: str) -> str:
|
|
|
423
423
|
raise RuntimeError("edit_file requires a non-empty 'old_string'. Use write_file to overwrite the whole file.")
|
|
424
424
|
if not path.exists():
|
|
425
425
|
raise RuntimeError(f"File not found: {path}.{missing_path_hint(path)}")
|
|
426
|
+
if old_string == new_string:
|
|
427
|
+
# 37 of the 840 edit_file calls on record (2026-09-17) sent the same
|
|
428
|
+
# text as old and new and were told "Edited"; the model then ran or
|
|
429
|
+
# read the file believing it had changed it (tests-claim-1: "The
|
|
430
|
+
# median function was correctly fixed", after an edit of mean to
|
|
431
|
+
# itself). A no-op is not an edit, and saying so is the only way the
|
|
432
|
+
# next step can be the change that was meant.
|
|
433
|
+
raise RuntimeError(
|
|
434
|
+
f"old_string and new_string are identical, so nothing changed in {path}. "
|
|
435
|
+
"Put the changed text in new_string, or read_file to see what is there now."
|
|
436
|
+
)
|
|
426
437
|
content = path.read_text(encoding="utf-8")
|
|
427
438
|
tier = "exact"
|
|
428
439
|
if content.count(old_string) == 1:
|
|
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
|