The tests set \$HOME to drive `dirs::home_dir()`. On Unix that's the
contract dirs uses; on Windows dirs reads %USERPROFILE% first, so
setting HOME has no effect and the tests fail.
The `display_path` function itself is platform-identical — it
delegates to `dirs::home_dir()` for the home prefix and uses
`std::path::MAIN_SEPARATOR` for the separator after the tilde. The
contraction logic is exercised on macOS/Linux which is sufficient
coverage for an abstraction whose platform detail is delegated.
If we want Windows-specific assertion coverage in the future, it should
either set USERPROFILE alongside HOME or accept an injected home dir.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI on PR #256 flagged two minor lint hits in the privacy lane:
- skills/mod.rs: rustfmt wanted the new regression test's
`let rendered = …` line collapsed to one chain.
- main.rs:1614: `selected_skills_dir` is already `&PathBuf`, so
passing `&selected_skills_dir` is a `&&PathBuf` and clippy's
`needless_borrow` triggers under `-D warnings`.
No behavior change; same coverage and outputs. Re-runs locally:
cargo fmt --all -- --check → clean
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings → clean
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Anywhere the TUI, doctor stdout, setup stdout, or onboarding shows a
file path, it used to print the absolute form (e.g. /Users/<name>/...).
On macOS/Linux the home-directory segment reveals the OS account name,
which is often the same as a public handle — undesirable for users who
share screenshots, screencasts, or paste doctor output into a public
help request.
Adds `crate::utils::display_path` that contracts a leading $HOME to `~`
and falls through unchanged otherwise. Used at every viewer-visible site:
doctor: workspace, config.toml, MCP config, all skills dirs,
selected skills dir, tools dir, plugins dir
setup: workspace, skills/tools/plugins paths and status output
TUI: context inspector header, trust-directory onboarding,
shell-job cwd (sidebar + detail pager), subagent task header
Persisted state, audit log, session checkpoints, and LLM-bound system
prompts intentionally keep the absolute path — those need full fidelity
to resolve correctly across processes and the LLM provider sees
absolute paths anyway by virtue of the workspace summary.
`display_path` has 4 tests covering: home contraction, bare-`~` for
home itself, untouched-when-unrelated, and a username-prefix regression
guard (so `/Users/alice2/...` doesn't get rewritten when $HOME is
`/Users/alice`).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`render_available_skills_context` rendered each skill's file path as
`<skills_dir>/<frontmatter-name>/SKILL.md`. The directory name and the
frontmatter `name` can differ — community installs and manually-placed
skills routinely have this drift — and when they do, the model is told
the file lives at a path that does not exist, so it can't open the
SKILL.md it needs to actually use the skill.
`Skill` now carries a `path: PathBuf` populated by `discover()` from the
real directory entry. Renderer uses it directly. Adds a regression test
that creates a skill at `weird-dir-name/SKILL.md` with `name: friendly-name`
and asserts the rendered prompt contains the real path and not the
fabricated one.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Acceptance list called for tests of no-config / healthy / disabled /
failed servers. Healthy and failed already had a single dense
test (`command_palette_includes_mcp_discovery_and_failed_servers`);
no-config is implicit in the existing call sites that pass `None`
for the snapshot. Disabled was the actual gap — adds one focused
case asserting the `[disabled]` state tag appears in the rendered
description so users can see disabled servers in the palette
without opening the MCP manager.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surfaces the deepseek-tui-cli crates.io version next to the existing
CI and npm badges in both English and Simplified Chinese READMEs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The architecture promises that session_manager, runtime_threads, and
task_manager reject persisted state from a newer schema_version on
load, so a downgraded binary fails loud instead of silently truncating
or corrupting data. Existing tests covered:
- session_manager::test_checkpoint_rejects_newer_schema
- task_manager (newer task schema rejection)
- runtime_threads::store_load_thread_rejects_newer_schema_version
Adds the missing coverage for the other persistence paths:
- session_manager::test_load_session_rejects_newer_schema
- session_manager::test_load_offline_queue_rejects_newer_schema
- runtime_threads::store_load_turn_rejects_newer_schema_version
- runtime_threads::store_load_item_rejects_newer_schema_version
Each writes a JSON file with schema_version = CURRENT + 1 (or 999),
loads through the public API, and asserts the error message contains
"newer than supported".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The render-skills test asserted `rendered.contains("test-skill/SKILL.md")`
which only matched on Unix; Windows uses backslashes via Path::display(),
so the assertion failed only in CI on windows-latest.
Build the expected substring through PathBuf::display() so the assertion
matches the platform-correct separator.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps workspace, all internal path-deps, and npm wrapper (version +
deepseekBinaryVersion) from 0.8.1 → 0.8.2. Lockfile re-locked offline
to keep the registry index untouched.
Triggers auto-tag.yml on push, which creates v0.8.2 and fires
release.yml to build cross-platform binaries and draft the GitHub
Release. npm publish remains manual per CLAUDE.md release runbook.
Note: npm registry already has 0.8.2 published (with binaryVersion
0.8.1 from an earlier checkpoint). That release keeps working unchanged
because v0.8.1 binaries stay on GitHub. Repo state aligns to 0.8.2 so
the version-drift gate passes; next npm publish (which will need to be
0.8.3 since 0.8.2 is taken) will pick up binaryVersion=0.8.2 and pull
the new binaries.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5770a574 added crates/tui/src/bin/deepseek.rs as a shim that calls
deepseek_tui_cli::run_cli() so `cargo install deepseek-tui` would also
install the canonical `deepseek` command. But the cli crate already
declares an identically-named bin target, so workspace builds emit two
artifacts to target/release/deepseek(.exe) -- cargo prints `output
filename collision` and on Windows the second linker hits LNK1104:
cannot open file deepseek.exe (the first hold has not released).
The cli crate stays the single source of `deepseek`. Workspace default
members still produce both binaries (deepseek from cli, deepseek-tui
from tui), no collision. Cargo install path: `cargo install
deepseek-tui-cli` for the canonical `deepseek` command, `cargo install
deepseek-tui` for the TUI binary; npm wrapper unaffected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a model-visible skills block to the system prompt (progressive
disclosure: lists name/description/path, never inlines SKILL.md bodies)
with a 12k-char prompt budget and a 512-char per-description cap.
EngineConfig gains skills_dir, threaded through the three construction
sites (TUI app, exec agent, runtime thread manager).
README skills section is rewritten to document the discovery order,
the SKILL.md frontmatter contract, and the install/update/uninstall/
trust commands. Adds Simplified Chinese README cross-link and full
README.zh-CN.md translation (DeepSeek went viral in CN -- discoverability
matters).
Tests cover happy path, empty/missing dir → None, oversize description
truncation with U+2026 marker, internal-whitespace collapse, and the
overflow-budget omission notice.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The wrapper re-downloaded the SHA-256 manifest from the GitHub release on every
invocation of `deepseek` / `deepseek-tui`, so any GitHub flake, captive portal,
proxy, or offline state broke every command — not just install.
Now ensureBinary returns immediately when the binary exists and its `.version`
marker matches. The manifest fetch is lazy and only runs when a download is
actually needed (first install or DEEPSEEK_TUI_FORCE_DOWNLOAD=1).
Bumps wrapper to 0.8.2; deepseekBinaryVersion stays on 0.8.1 (no new Rust
release required).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps the workspace/npm wrapper to 0.8.0 and fixes completed background shell jobs retaining live process handles, which could cause Too many open files, checkpoint save failures, shell spawn failures, and lag around send/close/Esc. Also includes Windows REPL bootstrap timeout hardening and Cargo/TUNA mirror install docs.
Includes:
- Post-turn freeze fix (reorder maybe_advance_cycle before TurnComplete)
- Enter/steering fix (QueueFollowUp when model is streaming)
- Esc fanout hardening (idempotent finalize methods)
- cargo fmt pass on new code
- CHANGELOG, README, and version bump across workspace + npm
- fix(#234): reorder cycle advancement before TurnComplete so the engine
loop doesn't block the terminal after the turn signal. User sees the
'↻ context refreshing...' status chip during briefing generation
instead of a frozen terminal with no feedback.
- fix(#250): Enter during streaming queues a follow-up (visible queued
text) instead of claiming to 'steer' a message that never reaches the
model. During tool-execution phases Enter correctly steers the active
turn via rx_steer, which is already drained before each API call.
- fix(#243): hardened Esc during sub-agent fanout — added idempotency
test proving finalize_active_cell_as_interrupted is safe when
TurnComplete arrives after Esc.
- close(#249): unicode search panic fix confirmed in v0.7.8, closing.
- feat: both fixes implemented by live sub-agents (agent_spawn) —
proving the sub-agent system works end-to-end.
* wip(v0.7.7): handoff baseline of partial sub-agent stabilization
Captures uncommitted work-in-progress on the v0.7.7 stabilization lane
so subsequent fixes have a stable starting point. Subsequent commits
finish the canonical SubAgentJob/SwarmJob model, fix sidebar/transcript/
footer agreement, copy/paste/cancel contract, checklist rendering, shell
summary preservation, monotonic spend, and version provenance.
Refs #235#236#237#238#239#240#241#242#243#244#245
* release: bump workspace version to 0.7.7 (#245)
Refs #245
* fix(v0.7.7): canonical swarm card binding, monotonic spend, checklist + shell summary
- Add `swarm_card_index: HashMap<swarm_id, history_index>` so overlapping
fanouts each project to their own FanoutCard. Eliminates the screenshot
contradiction where a stale background swarm's progress clobbered a
newer card (#236, #238).
- Suppress fanout-class tools (`agent_swarm`, `spawn_agents_on_csv`,
`rlm`, `agent_spawn`) from `active_tool_status_label` so the footer no
longer reports "tool agent_swarm · 1 active" while sidebar+card show
the actual worker counts (#236, #238).
- Add `App::displayed_session_cost` + `displayed_cost_high_water` so the
visible session+sub-agent total is monotonic across reconciliation
events (cache discounts, provisional → final). New tests: monotonicity
under negative reconciliation; duplicate dedup keeps display steady (#244).
- Preserve high-signal summary lines from the truncated tail of shell
output: `test result:`, `failures:`, `error[E…]`, `Finished`,
`Compiling`, panic markers. Stops the agent re-running cargo gates
just to see pass/fail under truncation (#242).
- Render `checklist_write` / `todo_*` results as a purpose-built
checklist card with completed/total + percent header, per-item status
markers, and a collapsing affordance for long lists. Plumbed through
the existing `GenericToolCell` so no new variant threading is needed (#241).
Refs #236#238#241#242#244
* fix(v0.7.7): Esc clears active tool entries optimistically (#243)
When Esc cancels the foreground turn we now finalize the active cell
immediately rather than waiting for the engine's TurnComplete echo to
drain. This stops the footer "tool ... · X active" chip from briefly
contradicting the cancelled state, and frees the composer for the next
message.
Background `block:false` swarms are intentionally NOT killed here — they
remain durable, tracked through `swarm_jobs` and `swarm_card_index` so
their FanoutCard updates as workers land. Subsequent `swarm_status` /
`swarm_result` / `swarm_cancel` tool calls see the canonical store.
New focused test verifies: after Esc, `active_cell` is None, the
background swarm record is preserved, and `is_loading` is cleared so
the composer can submit immediately.
Refs #243
* fix(v0.7.7): Windows .exe lookup + post-turn snapshot detach (#247, #234)
#247 — npm-distributed Windows package failed at runtime because the
Rust dispatcher's `delegate_to_tui` / `delegate_simple_tui` looked for a
sibling named exactly "deepseek-tui", while the actual file shipped by
`scripts/install.js` is `deepseek-tui.exe`. Replace both lookups with
`locate_sibling_tui_binary`, which:
- Honours `DEEPSEEK_TUI_BIN` for explicit overrides
- Tries `deepseek-tui{EXE_SUFFIX}` first (`.exe` on Windows, "" elsewhere)
- Falls back to suffix-less `deepseek-tui` on Windows so users who
applied the issue's manual workaround still launch successfully
- Emits a platform-correct error path in the bail message
Tests: `sibling_tui_candidate_picks_platform_correct_name`,
`sibling_tui_candidate_windows_falls_back_to_suffixless` (windows-only),
`locate_sibling_tui_binary_honours_env_override`.
#234 — Detach the post-turn workspace snapshot so `git add -A && git
commit` no longer pins the engine loop after `Event::TurnComplete`.
The snapshot still runs on `tokio::task::spawn_blocking`, but the
engine no longer awaits its `JoinHandle`, so the UI accepts input
(text, copy, paste, selection) without waiting for the bookkeeping to
finish. Cycle advance and pre-turn snapshot remain awaited — they are
correctness-sensitive and the cycle path already emits a status chip
("↻ context refreshing…") so the user has visible feedback.
Refs #234#247
* chore(v0.7.7): bump npm package version 0.7.6 → 0.7.7
Required by `scripts/release/check-versions.sh` ("Version drift" CI
gate); the workspace was bumped to 0.7.7 but `npm/deepseek-tui/package.json`
still reported 0.7.6, blocking PR #246 from going green.
Refs #245
- Bump workspace version to 0.7.6 (Cargo.toml + all crate internal dep pins)
- Bump npm wrapper version and deepseekBinaryVersion to 0.7.6
- Add v0.7.6 changelog entry: localization, paste burst, history search,
pending input preview, grouped /config editor, searchable help overlay,
Alt+↑ edit-last-queued, composer attachment management
- Update README with v0.7.6 features (localization, paste, history search)
- Archive v0.7.5 implementation plan to docs/archive/
- Update Cargo.lock
Issues #202, #203, #204, #205:
- Cycle/seam triggers use active request input size + response
headroom reserve, not lifetime cumulative API usage.
- V4 hard-cycle headroom calibrated around fixed TURN_MAX_OUTPUT_TOKENS
plus CONTEXT_HEADROOM_TOKENS safety buffer.
- /tokens, /cost, footer/header labels, and docs now separate
active context, turn telemetry, cumulative usage, cache hit/miss,
context percent, and cost.
- Foreground exec_shell timeout output tells the model the process
was killed and suggests task_shell_start or background exec_shell
plus poll/wait.
- Added regression tests for active-token basis, V4 headroom,
seam trigger basis, footer label behavior, and shell timeout
recovery metadata.
- Preserved #200/#201 policy: V4 default is append-only,
prefix-cache preserving; replacement compaction, Flash seams,
and capacity intervention remain opt-in.
#167: Fix all 7 clippy warnings — annotated SeamMetadata dead fields,
removed unused should_cycle calls, collapsed nested ifs, fixed
useless_format and nonminimal_bool.
#168: Wire TokenUsage mailbox drain to subagent_cost accumulator.
handle_subagent_mailbox now intercepts TokenUsage before routing to
cards, computes cost via calculate_turn_cost, and increments
app.subagent_cost in real time. Footer reflects live sub-agent spend.
Restored ArchivedContext variant to HistoryCell (corrupted by prior
apply_patch). Version bump to 0.7.2.
Refs: #166, #167, #168
Adds the core SeamManager struct (#159) that uses V4 Flash to produce
append-only <archived_context> XML blocks at 192K/384K/576K thresholds.
No messages are deleted — soft seams are navigational summaries that
preserve the V4 prefix cache.
- seam_manager.rs: Flash-driven soft seam production, recompaction,
and cycle briefing replacement
- config.rs: [context] table with L1/L2/L3/cycle thresholds,
verbatim window, seam model, and per-model overrides
- compaction.rs: pub exports for plan_compaction, KEEP_RECENT_MESSAGES,
and CompactionPlan fields so SeamManager can reuse pinning heuristics
- cycle_manager.rs: pub CYCLE_HANDOFF_TEMPLATE for Flash briefing use
- main.rs: mod seam_manager registration
All 1,570 tests pass. Engine wiring follows in a subsequent commit.