Commit graph

5132 commits

Author SHA1 Message Date
Charles Bine
867471c7d3 fix(#484): drop noisy "parse failed" note on JSON/YAML fragments
LLMs routinely emit JSON/YAML *fragments* in fenced blocks — a bare
`"key": "value"` line, snippets with `...`, trailing commas — which
legitimately fail JSON.parse. initTreeViews() stamped an unstyled
`<div class="tree-parse-note">parse failed</div>` below such blocks,
producing bare white text under an otherwise-clean code box.

The note was incidental, not designed: it was bolted onto the YAML
lazy-load commit (29a31a6e), has no CSS, no behavior test, and originally
even fired on *valid* YAML before the CDN script finished loading (later
fixed). The block still renders as syntax-highlighted raw, so the note
added only noise.

Remove the note insertion; fall through silently to raw view. The per-block
Raw/Tree toggle, YAML lazy-load, and the #484 default-view config are all
unchanged. The `parse_failed_note` i18n key is intentionally retained (kept
green by test_chinese_locale.py) to avoid touching all 13 locales.

Verification: ./scripts/test.sh tests/test_issue484_json_tree_viewer.py
tests/test_chinese_locale.py — 29 passed.
2026-06-24 22:14:27 +00:00
nesquena-hermes
7043b45f5d
Release WO (v0.51.634): cache profile skill stats with mtime probe (#4847, closes #4783)
Release WO (v0.51.634): cache profile skill stats with mtime probe (#4847, closes #4783)
2026-06-24 15:11:46 -07:00
nesquena-hermes
97372c8207 test(#4783): remove un-portable node_modules-prune filesystem test
The buried far-future mtime kept bleeding into the probe value on CI's shard-0
runners despite repeated attempts to make it deterministic. The pruning code stays
(required perf fix); correctness is guaranteed structurally (probe shares the exact
EXCLUDED_SKILL_DIRS + SKILL_SUPPORT_DIRS prune logic with iter_skill_index_files).

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 22:07:40 +00:00
nesquena-hermes
87782a9d68 test(#4783): pin legitimate tree mtime so the prune test is filesystem-timing independent
CI shard-0 still flaked: float int(far_future*1e9) rounding left probe ~38ns above
the threshold because the legitimate vendored/ tree's mtime on CI tracked the
buried-tree creation. Now pin skills_dir/skill/SKILL.md/config.yaml to a known
modest mtime AFTER building the buried far-future node_modules subtree, and assert
probe < far_future - 1s. Deterministic across filesystems; still non-vacuous
(fails with prune disabled even when node_modules itself is stamped far-future).

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 22:03:15 +00:00
nesquena-hermes
41687073d6 test(#4783): make node_modules-prune test deterministic (CI fix)
The before/after assertion was fragile — creating node_modules between the two
probe calls bumped the (non-pruned) vendored/ ancestor mtime, so 'after==before'
failed on CI's filesystem timing. Rewrote to a timing-independent assertion: a
FAR-FUTURE mtime buried inside the pruned node_modules/ must NOT appear in the
probe value (probe < far_future_ns), which holds even if node_modules itself is
bumped, because the prune removes it from dirnames before the stat loop.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 21:56:26 +00:00
nesquena-hermes
e17ace2c5d Release WO (v0.51.634): cache profile skill stats with mtime probe (#4847, closes #4783) 2026-06-24 21:51:00 +00:00
nesquena-hermes
af1649f558 test(#4783): update test_skills_stats_cache to assert the fixed mtime-probe behavior
The pre-existing test asserted the OLD bug: 'add a skill within the 8s TTL ->
still get stale (1,1)'. That stale window is exactly what #4783 fixes — adding a
skill bumps the skills-dir mtime, the per-call probe catches it, and counts now
update immediately (2,2). Updated the assertions to the corrected contract +
added a no-change-serves-cache step. (Test lived in test_profile_skills_stats.py,
not the PR's test_issue4783 file, so the contributor missed it.)

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 21:41:15 +00:00
nesquena-hermes
3fbc7d71d3 fix(#4783): prune dependency trees in mtime probe to match compute path (gate finding 4)
Codex round-4 found my followlinks=True change introduced a perf regression: the
probe os.walk lacked the .git/.venv/node_modules/site-packages + skill-support-dir
pruning that iter_skill_index_files applies, so a skill vendoring a dependency
tree made this EVERY-CALL probe walk thousands of irrelevant files — defeating the
cache's whole purpose. The probe now prunes dirnames[:] with the same
EXCLUDED_SKILL_DIRS + SKILL_SUPPORT_DIRS sets as the compute path. Regression test
(change deep inside node_modules/ must not move the probe) added + non-vacuous.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 21:27:22 +00:00
nesquena-hermes
e4e3b46830 fix(#4783): mtime probe follows symlinked skill dirs to match compute path (gate finding 3)
Codex round-3 reproduced: _skill_tree_max_mtime_ns used os.walk(followlinks=False)
while the compute path iter_skill_index_files uses followlinks=True, so an edit to
a symlinked skill's target SKILL.md was invisible to the probe (stale up to TTL).
Added followlinks=True to the probe walk so it descends symlinked skill dirs and
sees target mtime changes. Regression test added + proven non-vacuous.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 21:21:57 +00:00
nesquena-hermes
8a46d88daf fix(#4783): TTL expiry always recomputes (safety net for mtime-preserving changes) (gate finding 2)
Codex re-gate: my prior 'TTL-expired + unchanged-mtime -> refresh TTL, no recompute'
branch could leave counts stale INDEFINITELY for an mtime-PRESERVING out-of-band
change (e.g. a git checkout restoring the old mtime) — worse than master's 8s
recompute. Codex proved it (cached (2,2) stayed (2,2) while a fresh compute returned
(1,2)). Now: within TTL + unchanged mtime serves cached (perf win kept); mtime
changed OR TTL expired both force a full recompute (the TTL is a genuine safety
net). Updated the row-2 test to assert the safety recompute.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 21:16:16 +00:00
nesquena-hermes
7d38b0cd9f fix(#4783): probe skill mtime on every call so out-of-band changes aren't hidden for the full TTL (gate finding)
Codex gate found a SILENT regression: the cache returned on a zero-I/O fast path
while inside the 300s TTL, so _skill_tree_max_mtime_ns never ran during the TTL
window and an out-of-band (CLI/git) skill create/edit/delete was invisible for up
to 5 minutes — WORSE than master's ~8s stale window. Restructured so the cheap
stat-only mtime probe runs on EVERY call (prompt change detection); the TTL now
only bounds the expensive SKILL.md recompute. Unchanged mtime still serves cached
+ refreshes TTL with no recompute (the perf win is preserved). Updated 2 tests
that encoded the flawed zero-I/O design + added a within-TTL-change regression
(proven non-vacuous).

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 21:08:19 +00:00
Rod Boev
fdf9adbd02 Catch nested skill deletions in the mtime probe 2026-06-24 20:52:31 +00:00
Rod Boev
c7d156c570 fix(profiles): snapshot mtime before compute to prevent TOCTOU stale cache (#4783) 2026-06-24 20:52:31 +00:00
Rod Boev
9ce8deff5d fix: remove unused importlib and os imports 2026-06-24 20:52:31 +00:00
Rod Boev
970345f74d fix: restore sys.modules after test to prevent api package pollution 2026-06-24 20:52:31 +00:00
Rod Boev
0d6932dcce fix: invalidate skills cache on toggle/save/delete and stat skills_dir for deletion detection 2026-06-24 20:52:31 +00:00
Rod Boev
18528a88f0 perf(#4783): two-tier mtime cache for profile skills stats 2026-06-24 20:52:31 +00:00
nesquena-hermes
d13da425e9
Release WN (v0.51.633): collapsed tool cards preview result not call args (#4851, closes #4752)
Release WN (v0.51.633): collapsed tool cards preview result not call args (#4851, closes #4752)
2026-06-24 13:49:19 -07:00
nesquena-hermes
2de2599e8c Release WN (v0.51.633): collapsed tool cards preview result not call args (#4851, closes #4752) 2026-06-24 20:45:30 +00:00
Rod Boev
2ca65abefa fix: use JSON.parse for bracket-prefixed lines instead of blanket suppression 2026-06-24 20:35:04 +00:00
Rod Boev
4bf659e433 fix: harden test drivers against extractFunc brace-counter overrun 2026-06-24 20:35:04 +00:00
Rod Boev
32d171c1a1 fix: add _toolResultOneLiner to sibling test extractors and pin error-snippet behavior 2026-06-24 20:35:04 +00:00
Rod Boev
29604e5e7b fix: fall back to tc.snippet for cold-loaded tool results 2026-06-24 20:35:04 +00:00
Rod Boev
c19aaae27f fix(#4752): show tool result instead of call args in collapsed card preview 2026-06-24 20:35:04 +00:00
nesquena-hermes
159d362750
Release WM (v0.51.632): new conversations use configured default model (#4867, closes #4728)
Release WM (v0.51.632): new conversations use configured default model (#4867, closes #4728)
2026-06-24 13:32:08 -07:00
nesquena-hermes
7cd6cd7235 Release WM (v0.51.632): new conversations use configured default model (#4867, closes #4728) 2026-06-24 20:27:57 +00:00
nesquena-hermes
57a78e9284 fix(#4728): clear stale custom:* base_url + default wins without loaded session (gate findings)
Two gate-found CORE/SILENT edges fixed on-branch:
- api/config.py: switching the main default to a different custom:* provider kept
  the OLD provider's base_url, routing New Chat to the wrong endpoint. The
  base_url-clear on provider-change now covers custom:* too (was exempted).
- static/sessions.js: newSession() skipped the configured default when S.session
  was null but the picker held stale state (e.g. after deleting the last session),
  inheriting the stale model. Default now wins over legacy picker regardless of
  loaded-session state (explicit empty-composer override still takes priority).
- Updated 2 stale source-grep precedence assertions + widened a brittle 6000-char
  newSession() slice window to 7000 (assignment block grew; intent unchanged).
- 2 new non-vacuous regression tests (custom base_url clear; precedence).

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 20:17:29 +00:00
Rod Boev
897322eac3 fix(#4728): keep main default-model routes from persisting auto provider 2026-06-24 20:09:30 +00:00
Rod Boev
23b3206f83 fix(#4728): guard settings default-model capture when no option is selected 2026-06-24 20:09:30 +00:00
Rod Boev
c388d15f2b fix(#4728): clear stale base URLs when default provider changes 2026-06-24 20:09:30 +00:00
Rod Boev
bede035a5e fix(#4728): persist provider-only default-model changes end to end 2026-06-24 20:09:30 +00:00
Rod Boev
69d202b94a fix(#4728): treat provider-only default changes as settings edits 2026-06-24 20:09:30 +00:00
Rod Boev
eba089fd90 fix(#4728): preserve fallback-order guarantees for default-model routing 2026-06-24 20:09:30 +00:00
Rod Boev
cdb44fb7e0 fix(#4728): sync saved default model provider into new chat state 2026-06-24 20:09:30 +00:00
Rod Boev
dde3845171 fix(#4728): keep default-model requests on the configured provider 2026-06-24 20:09:30 +00:00
Rod Boev
d8b58da018 fix(#4728): use configured default for new conversations 2026-06-24 20:09:30 +00:00
nesquena-hermes
b553c2d084
Release WL (v0.51.631): reconnect chronology keeps prior content ordered (#4849, closes #4811)
Release WL (v0.51.631): reconnect chronology keeps prior content ordered (#4849, closes #4811)
2026-06-24 13:02:17 -07:00
nesquena-hermes
27e259660c Release WL (v0.51.631): reconnect chronology keeps prior content ordered (#4849, closes #4811) 2026-06-24 19:58:18 +00:00
nesquena-hermes
3c8cfdc589 fix(#4811): regenerate row_id/seq from final order index so anonymous tool rows don't collide (gate finding)
Codex gate found a SILENT drop: reconnect scene rows are built with orderIndex=0,
so two tools WITHOUT a tool id at the same message index both got row_id
'...:tool:<idx>:0'; _completeSettledAnchorSceneForTurn dedupes by row_id, silently
dropping the second. Now the emit loop rewrites order_index AND regenerates the
index-derived row_id + seq + identity.seq from the final per-bucket position
(tid-based tool row_ids, already unique, are left untouched). Regression test
added + proven non-vacuous.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 19:48:56 +00:00
Rod Boev
f330fa7f44 perf(reconnect): pre-index toolCalls and remove unreachable guard (#4811) 2026-06-24 19:39:40 +00:00
Rod Boev
e86ebb6379 fix: remove unused textwrap import 2026-06-24 19:39:40 +00:00
Rod Boev
173014ae0e fix: update stale string-snapshot assertions for refactored anchor loop 2026-06-24 19:39:40 +00:00
Rod Boev
057b878136 fix(#4811): sort reconnect scene rows by phase and started_at chronology 2026-06-24 19:39:40 +00:00
nesquena-hermes
9a8b353239
Release WK (v0.51.630): surface real git fetch errors on update failure (#4862, closes #4694)
Release WK (v0.51.630): surface real git fetch errors on update failure (#4862, closes #4694)
2026-06-24 12:34:57 -07:00
nesquena-hermes
4c1c7d8938 Release WK (v0.51.630): surface real git fetch errors on update failure (#4862, closes #4694) 2026-06-24 19:30:49 +00:00
nesquena-hermes
8d2689ccc0 harden(#4694): broaden query-secret redaction before surfacing fetch diagnostics (gate finding)
Codex gate: the apply path now surfaces sanitized non-network fetch stderr, but
_QUERY_SECRET_RE only redacted access_token/token/password/auth/key — leaving
client_secret, private_token, oauth_token, api_key in a remote URL exposed in
the user-facing error. Broadened the pattern to cover those + app_secret/secret
+ api[_-]?key. Regression test added + proven non-vacuous.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-24 19:29:06 +00:00
Rod Boev
e88e4ecefc fix(#4694): treat fetch timeout diagnostics as network failures 2026-06-24 19:29:06 +00:00
Rod Boev
a3eac6a538 fix(#4694): surface non-network git fetch failures in updates 2026-06-24 19:29:06 +00:00
nesquena-hermes
25dc1dcd2a
Release WJ (v0.51.629): macOS workspace drag-drop now lands (#4845, closes #4757)
Release WJ (v0.51.629): macOS workspace drag-drop now lands (#4845, closes #4757)
2026-06-24 12:27:36 -07:00
nesquena-hermes
d313a899fc Release WJ (v0.51.629): macOS workspace drag-drop now lands (#4845, closes #4757) 2026-06-24 19:23:32 +00:00