Commit Graph

73 Commits

Author SHA1 Message Date
Hunter Bown 1af37e3fab Add DeepSeek-native bundled workflow skills 2026-05-13 00:53:44 -05:00
Hunter Bown ccfece77e3 Merge remote-tracking branch 'origin/pr/1534' into work/v0.8.34
# Conflicts:
#	crates/tui/src/commands/config.rs
#	crates/tui/src/commands/mod.rs
#	crates/tui/src/palette.rs
#	crates/tui/src/settings.rs
#	crates/tui/src/tui/app.rs
#	crates/tui/src/tui/color_compat.rs
#	crates/tui/src/tui/widgets/footer.rs
2026-05-12 23:58:39 -05:00
Hunter Bown a4637fe7d1 fix(settings): reduce motion in VTE flicker terminals
Harvested from PR #1527 by @axobase001.

Co-authored-by: axobase001 <dengzhuoran9@gmail.com>
2026-05-12 23:39:44 -05:00
Hunter Bown 485ba7bbd4 chore(release): finish v0.8.33 polish 2026-05-12 22:03:47 -05:00
Hunter Bown 99c6b22e83 chore(release): v0.8.33 — sub-agent and RLM renovation with persistent sessions
- Persistent RLM sessions (rlm_open/rlm_eval/rlm_close) with bounded REPL helpers
- Fork-aware sub-agent sessions (agent_open/agent_eval/agent_close) with handle_read
- Shared handle_read storage with slice/range/count/JSONPath projections
- Slash-command routing: /rlm, /agent, /relay (/接力) for handoff prompts
- Sidebar renamed to "Work" tab, consistent across Plan/Agent/YOLO modes
- Tool papercuts: file_search excludes, grep_files strings, fetch_url JSON,
  edit_file fuzz, exec_shell merged stdout/stderr, revert_turn no-op reject
- CLI reasoning-effort honoured on non-auto exec routes (#1511 @h3c-hexin)
- Edit-file replacement boundaries clarified (#1516)
- Pandoc output validated before probing (#1523)
- Running turns steerable/repaintable (#1533, #1537)
- Tasks/Activity Detail calmer under load
- npm retry timeout hint (#1538 @reidliu41)
- Issue templates improved (#1525 @reidliu41)
- Shell: kill process group to prevent UI freeze (#828 @CrepuscularIRIS)
- TUI: ignore leaked SGR mouse reports in composer (#1421 @reidliu41)
- Footer: keep chips within available width (#1417 @Wenjunyun123)
- Session picker: scope Ctrl+R to current workspace (#1395 @LinQ)
- Removed stale competitive-analysis doc
- Prompts/docs teach only new tool names
2026-05-12 19:54:08 -05:00
Hunter Bown 8f33e4bd48 feat(providers): add AtlasCloud as a first-class provider
AtlasCloud (https://atlascloud.ai) hosts the V4 family on its own
DeepSeek-compatible endpoint at `https://api.atlascloud.ai/v1`, and
several contributors had been running it through the
OpenAI-compatible passthrough with manual `base_url` / model
overrides. Selecting `provider = "atlascloud"` in
`~/.deepseek/config.toml` (or via `DEEPSEEK_PROVIDER=atlascloud`)
now wires up:

- documented `DEFAULT_ATLASCLOUD_BASE_URL` /
  `DEFAULT_ATLASCLOUD_MODEL` defaults so a fresh install needs
  only the api_key
- a `[providers.atlascloud]` config block with the same fields
  every other named provider exposes (api_key / base_url / model
  / http_headers)
- `ATLASCLOUD_API_KEY` env var path, including the secrets test
  cleanup loop so per-test env hygiene continues to work
- the provider-picker / `/provider` slash command entries so the
  provider is reachable from the runtime UI, not just config
- the env-driven `*_BASE_URL` override branch so users who pin a
  proxy can still flip it without editing config.toml

Trust-boundary pins held: AtlasCloud is opt-in (default remains
DeepSeek), no API keys are hardcoded, the api_key resolution flows
through the same `secrets` crate path every other provider uses,
and the provider-config base_url stays settable per environment.

Resolved 3-way merge conflicts in `crates/secrets/src/lib.rs` (env
cleanup loop) and `crates/tui/src/config.rs` (per-provider
base_url match arm + `provider_passes_model_through` predicate)
so the contributor's AtlasCloud branch coexists with the v0.8.x
provider expansion already on `main`. Added the missing match arm
in `validate_provider_base_url` so the non-exhaustive-pattern
check passes after the new variant lands.

Harvested from PR #1436 by @lucaszhu-hue

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 00:40:43 -05:00
reidliu41 6d099d425c feat: add note management commands
Extend /note beyond append-only usage with list, show, edit, remove,
  clear, path, and explicit add subcommands.

  Keep existing /note <text> behavior compatible, preserve the existing
  --- separated file format, and number notes only at display time so the
  stored notes stay clean.

  Update command help, localization, docs, and tests.
2026-05-10 20:56:39 -05:00
reidliu41 4f8eff0c69 refactor: unify mode switching under /mode
Replace the separate /agent, /plan, and /yolo commands with a single
  /mode command that can either open a picker or switch directly by name
  or number.

  This keeps mode switching in one command surface and avoids duplicating
  similar commands for each mode.
2026-05-10 08:15:19 -05:00
Zhiping 39fd5379fd docs(tui): clarify Windows mouse capture behavior 2026-05-10 08:15:19 -05:00
Liu-Vince 66a20ded2e docs(config): document additional environment variables
## Summary
- Document DEEPSEEK_STREAM_OPEN_TIMEOUT_SECS.
- Document DEEPSEEK_FORCE_HTTP1.
- Document DEEPSEEK_HOME and DEEPSEEK_AUTOMATIONS_DIR.

## Verification
- GitHub CI passed: lint, version drift, ubuntu/macos/windows tests, npm wrapper smoke, GitGuardian.
2026-05-08 09:01:03 -05:00
Hunter Bown 724af9494a fix(tui): keep interactive sessions in alternate screen (#1158) 2026-05-08 02:30:57 -05:00
Hunter Bown f283e56bd1 fix(prompts): prioritize user language for reasoning (#1137) 2026-05-07 23:53:15 -05:00
Hunter Bown b31b93aaae v0.8.19: endpoint, release workflow, IME + viewport fixes (#1128)
* fix(config): keep DeepSeek beta endpoint for legacy cn alias

* fix(ci): filter download-artifact to deepseek* pattern

Prevents the release aggregation job from picking up non-binary
artifacts (e.g. Docker .dockerbuild cache layers) that cause the
checksum manifest to include spurious entries and the Release to
carry files it shouldn't.

* fix(tui): enable focus events to restore IME after app-switch

On macOS, switching away (Cmd+Tab) and back suspends the IME compositor.
Without focus-event handling, the TUI never signals readiness to the
terminal, so CJK input methods (Pinyin, Zhuyin, etc.) stop working.

- EnableFocusChange on startup so the terminal reports FocusGained/FocusLost
- Re-push KeyboardEnhancementFlags on FocusGained (some terminals reset
  the enhanced keyboard mode on focus-loss)
- DisableFocusChange on shutdown for clean terminal handoff

* chore: cargo fmt

* docs: add DataWhale and DeepSeek to acknowledgments

* docs: fix DeepSeek name etymology in acknowledgments

* fix(tui): recapture viewport on focus restore

* docs: thank DeepSeek and DataWhale bilingually
2026-05-07 23:05:39 -05:00
Zhuoran Deng 451d66ab0a docs(sandbox): define windows helper contract 2026-05-07 15:28:10 -05:00
THINKER_ONLY 4aee8a15c6 fix(config): preserve OpenRouter custom endpoint models
When OpenRouter is pointed at a custom base_url, keep explicit model values verbatim instead of remapping DeepSeek aliases to OpenRouter catalog IDs.

Add config coverage for both the dispatcher config crate and the TUI config loader, while preserving existing provider alias behavior such as NVIDIA NIM.

Closes #857
2026-05-07 12:45:37 -05:00
Jefsky Wong 5c112b40bf fix(config): default deepseek-cn to official api.deepseek.com (#1084)
Sets the `deepseek-cn` provider preset's default `base_url` to the official host (`https://api.deepseek.com`) per [api-docs.deepseek.com](https://api-docs.deepseek.com/). Keeps recognizing `api.deepseeki.com` in URL heuristics and chat-client normalization so existing configs continue to work, and updates the `doctor` strict-tool-mode endpoint hint, docs, and examples accordingly.

Closes #1079. Thanks to @Jefsky for the fix.
2026-05-07 12:01:07 -05:00
Hunter Bown 628fb3c4a8 feat(tui): support custom background color (#1034) 2026-05-07 06:15:58 -05:00
axobase001 9327167e1d fix(engine): align stream idle timeout guard (#1012) 2026-05-07 05:42:24 -05:00
Hunter Bown f97604c3f0 fix(provider): enable OpenAI-compatible TUI runtime (#1017) 2026-05-07 05:32:15 -05:00
Hunter Bown c270ef81ef fix(tui): harden terminal resume and runtime context
Summary:
- Keep default auto alternate-screen mode inside the TUI so transcript scrolling stays app-owned unless users explicitly opt out.
- Queue terminal resume events when the engine channel is full, avoiding stranded paused terminal state after interactive tool cancellation or bursts.
- Scope crash-checkpoint recovery to the resolved launch workspace instead of the shell cwd.
- Add runtime deepseek_version to the prompt environment block so agents can distinguish installed runtime identity from a stale checkout.

Test plan:
- cargo test -p deepseek-tui --locked on a simulated merge with current main
- cargo fmt --all -- --check
- git diff --check
- Existing PR CI was green for lint, version drift, Linux/macOS/Windows tests, npm wrapper smoke, and GitGuardian.
2026-05-07 03:48:09 -05:00
Hunter Bown 4369410df7 fix(auth): show credential source table
## Summary
- show config, keyring, and env credential sources in deepseek auth status
- point env-only auth failures at auth status and auth set recovery commands
- document auth status and provider key precedence

## Test plan
- cargo test -p deepseek-tui-cli auth_ --locked
- cargo test -p deepseek-tui-cli --locked
- cargo test -p deepseek-tui env_only_auth_error_gets_recovery_hint --locked
- cargo test -p deepseek-config api_key --locked
- cargo test -p deepseek-config config_file_resolves_above_env_and_keyring --locked
- cargo test -p deepseek-config keyring_resolves_when_config_file_empty_even_if_env_is_set --locked
- cargo test -p deepseek-secrets --locked
- cargo fmt --all -- --check
- git diff --check
- cargo clippy -p deepseek-tui-cli -p deepseek-tui -p deepseek-secrets --all-targets --all-features --locked -- -D warnings

Closes #907
2026-05-07 02:55:55 -05:00
Hunter Bown c7ed05a07c feat(api): default DeepSeek to beta endpoint
Closes #941.\n\nRefs #938, #939, #940.
2026-05-06 21:24:59 -05:00
Reid 78c415f40c feat(provider): add Ollama provider support (#921)
Source PR: #921 by @reidliu41.
Closes #908.

Local verification:
- cargo test --workspace --all-features ollama
- cargo fmt --all -- --check
- cargo build

Co-authored-by: reidliu41 <reid201711@gmail.com>
2026-05-06 20:16:46 -05:00
Hunter Bown 633092167c feat(config): support custom HTTP headers (#914)
Integrates the useful custom HTTP header support from #881 onto current main.

- support root, provider-specific, and DEEPSEEK_HTTP_HEADERS overrides
- apply validated extra headers to model API requests while preserving protected Authorization and Content-Type defaults
- document the config shape in README, config.example.toml, and docs/CONFIGURATION.md

Co-authored-by: Desheng <8596814+dst1213@users.noreply.github.com>
2026-05-06 18:13:18 -05:00
Hunter Bown 88c2a06024 fix(tui): default mouse capture off in JetBrains JediTerm (#878, #898)
JetBrains' JediTerm — the terminal embedded in PyCharm, IDEA, CLion,
WebStorm, GoLand, etc. — advertises mouse support but forwards SGR
mouse-event escape sequences as raw input characters rather than
interpreting them. Users see the composer auto-fill with garbled
characters when they move the mouse over the TUI window. The
workaround was already a one-flag fix (`--no-mouse-capture` or
`[tui] mouse_capture = false` in config) but discovering it required
finding a maintainer comment on a related issue.

Auto-detect via `TERMINAL_EMULATOR=JetBrains-JediTerm` (the env var
JediTerm sets) and default `mouse_capture` off for that environment,
mirroring the existing Windows handling. Explicit `--mouse-capture`
or `[tui] mouse_capture = true` still wins, so power users who don't
hit the issue can opt back in.

Implementation:
- `default_mouse_capture_enabled` now takes `terminal_emulator: Option<&str>`
  so the function is pure and trivially testable. The CLI entry point
  reads the env var once and passes it through.
- `should_use_mouse_capture` keeps the same public signature; tests
  call `should_use_mouse_capture_with` which takes the env explicitly,
  removing test sensitivity to the host's actual TERMINAL_EMULATOR.
- Match is `eq_ignore_ascii_case` because JetBrains has occasionally
  varied the casing across releases.

Tests:
- 4 new tests covering JetBrains default-off, case-insensitive match,
  CLI override, and config-file override.
- Existing 6 mouse-capture tests retained, all passing.
- `cargo test -p deepseek-tui --bin deepseek-tui --all-features
  terminal_mode_tests --locked` → 10/10 pass.
- `cargo clippy -p deepseek-tui --bins --all-features --locked --
  -D warnings` clean.
- `cargo fmt --all -- --check` clean.

Docs in `docs/MODES.md` and `docs/CONFIGURATION.md` updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 15:12:47 -05:00
Hunter Bown 58f52c7725 feat(skills): discover global ~/.claude/skills (#902)
The skill registry already walks workspace-local `.claude/skills` for
Claude Code interop, plus global `~/.agents/skills` and
`~/.deepseek/skills`. Picking up the global `~/.claude/skills` brings
DeepSeek TUI in line with the broader Claude-ecosystem convention so
users can inherit skills installed for other Claude-compatible tools
without re-authoring them in DeepSeek's native layout.

Adds `claude_global_skills_dir()` mirroring `agents_global_skills_dir()`
and inserts it into `skills_directories()` between the agentskills.io
global and the DeepSeek-native global. Workspace candidates still win
on name conflicts; first-match-wins is preserved.

Tests:
- claude_global_skills_dir_returns_home_relative_path
- existing_skill_dirs_orders_globals_agents_then_claude_then_deepseek
- All 55 pre-existing skills tests still pass

Docs synced (README publishing-skills section, CONFIGURATION).
docs/COMPETITIVE_ANALYSIS.md already advertised this lookup; this
brings the implementation in line with the documented contract.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 15:00:51 -05:00
Hunter Bown a1a96d1afc fix: discover global agents skills (#848) 2026-05-06 05:21:02 -05:00
Hunter Bown 77b6d43088 chore(doctor): show resolved API endpoint (#823)
* chore(doctor): show resolved API endpoint

* test(tui): serialize markdown OSC8 parity render
2026-05-06 03:17:58 -05:00
Hunter Bown a2ca64018e feat(cost): support yuan display (#806) 2026-05-06 01:36:46 -05:00
Hunter Bown 3af6ef6f69 fix(tui): default mouse capture off on Windows (#785) 2026-05-05 22:40:31 -05:00
Agent007 a335ff5e4c feat(provider): add vLLM provider support (#737)
Add vLLM as a first-class OpenAI-compatible self-hosted provider with VLLM_BASE_URL, VLLM_API_KEY, and VLLM_MODEL wiring.
2026-05-05 21:22:24 -05:00
Hunter Bown a68c8dc974 docs(notifications): only completed turns notify; add Key Reference + WezTerm-on-Windows test
Post-merge review feedback on #583 surfaced four small accuracy gaps:

1. The narrative docs in `docs/CONFIGURATION.md` and the inline comment
   in `config.example.toml` said the notification fires "when a turn
   takes longer than a threshold" — but the call site in
   `tui/ui.rs:928` is gated on `TurnOutcomeStatus::Completed`. Failed
   and cancelled turns are silent on purpose. Spell that out so users
   don't expect alerts on long failures.

2. The `notify_done` rustdoc still summarised `Auto` as "Osc9 for known
   terminals, Bel otherwise" — internally inconsistent with the new
   Windows-aware fallback documented one screen earlier on the
   `Method::Auto` enum and on `resolve_method`. Update the public
   rustdoc to point at the canonical resolution table on
   `resolve_method` and call out the `Off`-on-Windows branch.

3. The `## Key Reference` list in `docs/CONFIGURATION.md` had no entries
   for `[notifications].method`, `[notifications].threshold_secs`, or
   `[notifications].include_summary`. Other features with a dedicated
   subsection (e.g. `[memory].enabled`) are listed there too, so readers
   scanning the canonical key list could not discover the notification
   knobs. Added the three keys with cross-references to the
   Notifications subsection.

4. The Windows-only test only covered the unknown-`TERM_PROGRAM` →
   `Off` fallback. The positive path (known OSC-9 terminal still
   resolves to `Osc9`) was only tested via `iTerm.app`, which is a
   macOS-only program — Windows CI would still pass if the `WezTerm`
   arm of the match disappeared. Added
   `auto_detect_picks_osc9_for_wezterm_on_windows` so the
   WezTerm-on-Windows compatibility guarantee is exercised on the
   Windows runner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:38:21 -05:00
Hunter Bown 3636908bb9 fix(notifications): default Windows Auto fallback to Off, not BEL
On Windows, the audio stack maps BEL (`\x07`) to the
`SystemAsterisk` / `MB_OK` chime — the same sound applications use
for error popups. So with the previous `Method::Auto` fallback to
`Bel`, every successful turn-completion notification ended up
sounding identical to a software error.

Reported by a community user who described it as "the popup-error
sound from a CAD program I used to use" (#583).

resolve_method() now returns `Off` instead of `Bel` on Windows for
unknown TERM_PROGRAM values. Known OSC-9-capable terminals
(`iTerm.app`, `Ghostty`, `WezTerm`) still resolve to `Osc9` on
every platform, so users running WezTerm on Windows keep getting
real notifications. macOS and Linux behaviour is unchanged.

Windows users who actively want an audible cue can opt back in by
setting `[notifications].method = "bel"` in `~/.deepseek/config.toml`.

Also:
- Documents `[notifications]` in `docs/CONFIGURATION.md` with an
  explicit Windows note (the schema was previously undocumented).
- Updates the inline comment in `config.example.toml` so users
  reading the seed config see the platform-specific behaviour.
- Splits the existing `auto_detect_picks_bel_for_unknown` test
  into a Unix variant (`#[cfg(not(target_os = "windows"))]`) and
  adds a new Windows-gated test that asserts the `Off` fallback,
  so CI's Windows runner exercises the platform-specific path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 12:49:03 -05:00
20bytes 8aed1bb674 memory: polish help and docs (#569)
- add /memory help and clearer invalid-subcommand guidance
- register /memory in shared slash-command help
- align memory docs with current behavior and config
- add focused tests for help and discovery
2026-05-04 02:25:13 -05:00
Hunter Bown fc1970fa55 fix(auth): use config-backed setup without credential prompts 2026-05-03 23:02:11 -05:00
Hunter Bown bda30b0fd6 Merge main into feat/v0.8.8-tui-polish + gemini-code-assist feedback
Resolves the post-#514/#517/#518 conflicts:

- CHANGELOG.md: kept both polish-stack and Linux ARM64 entries under
  [Unreleased]; reordered so the ARM64/install-message Changed/Docs
  sections precede the Releases footer.
- config.example.toml: kept both the `instructions = [...]` example
  and the `[memory]` opt-in stanza in sequence.
- crates/tui/src/config.rs: kept both `instructions_paths()` (#454)
  and `memory_enabled()` (#489) on the Config impl.
- crates/tui/src/prompts.rs: extended
  `system_prompt_for_mode_with_context_and_skills` to take BOTH
  `instructions: Option<&[PathBuf]>` and `user_memory_block:
  Option<&str>`. Section 2.5a renders instructions; 2.5b renders the
  memory block — both above the skills block so KV prefix caching
  still wins.
- crates/tui/src/core/engine.rs: thread both args through the two
  call sites.
- crates/tui/src/prompts.rs: update the `system_prompt_for_mode_with_context`
  forwarder and the test caller to pass `None` for the new arg.
- .gitignore: ignore `.claude/*.local.md` and `*.local.json` so
  local ralph / Claude-Code notes can't leak into commits.

Folds in two valid suggestions from the gemini-code-assist review on #519:

- `client.rs`: collapse the duplicated `LlmError → label` match and the
  `human_retry_reason` body into a single
  `retry_reason_label_and_human(err) -> (&'static str, String)` helper.
- `widgets/footer.rs::retry_banner_spans`: merge the two separate
  `match &props.retry` blocks into one that returns both `(label, color)`.

Behavior is unchanged; refactor is a pure DRY win.
2026-05-03 08:29:59 -05:00
Hunter Bown 604edc9f83 feat(tls): honor SSL_CERT_FILE for corporate-CA / MITM proxies (#418)
Corporate users behind TLS-inspecting proxies (Zscaler, Netskope,
Palo Alto, in-house mitmproxy fleets) need to add the proxy's
intermediate CA to the trusted-roots set so the deepseek client
doesn't fail with `unable to get local issuer certificate`.

The reqwest builder already trusts the platform's system store
via native-tls. This adds opt-in support for the conventional
`SSL_CERT_FILE` env var so users can point at their own bundle:

* New `add_extra_root_certs(builder, path)` helper reads the
  file, tries `Certificate::from_pem_bundle` (covers single-cert
  files too), falls back to `from_der` for binary cert files.
* Wired into `build_http_client` when `SSL_CERT_FILE` is set
  and non-empty. Failures log a warning via the existing
  `logging::warn` channel and return the builder unchanged —
  the existing system trust still applies, so a malformed env
  var degrades gracefully instead of bricking the launch.
* Each successful load logs `info` with the cert count so
  operators can confirm their bundle was picked up.

Documented in `docs/CONFIGURATION.md`'s environment-variables
list alongside the existing TLS-related notes.

No new dependency — reqwest's `native-tls` feature already
exposes `Certificate::from_pem_bundle` / `from_der`.
2026-05-03 07:35:23 -05:00
Hunter Bown 5627d6535b docs: document NO_ANIMATIONS, instructions array, /hooks, /stash
Catches up `docs/CONFIGURATION.md` with the v0.8.8 polish stack so
operators have one source of truth for the new surfaces:

* `NO_ANIMATIONS` env override (#450) joins the existing
  environment-variable list, with a cross-reference to
  `docs/ACCESSIBILITY.md`.
* New `### Instruction sources` section documents the
  `instructions = [...]` config field (#454): expansion rules,
  100 KiB per-file cap with `[…elided]` marker, missing-file
  warning behavior, and the project-wholesale-replaces-user
  override semantics.
* New `### /hooks listing` section documents the read-only
  slash command (#460 MVP) so users know how to introspect
  configured lifecycle hooks without `cat`-ing config.toml.
* New `### Composer stash` section documents Ctrl+S +
  `/stash list|pop|clear` (#440) including the 200-entry cap
  and multiline preservation.

Pure documentation; no code changes. Existing prompt-stability
and config-loading tests are unaffected.
2026-05-03 06:39:29 -05:00
Hunter Bown 8071bce319 docs: MEMORY.md — user-facing memory documentation (#489)
The memory MVP shipped in PR #518 added three surfaces (\`# \` quick-add,
\`/memory\` slash command, \`remember\` model tool) plus the opt-in
toggle, but the only user-facing reference today is the one-line
mention of \`memory_path\` in CONFIGURATION.md and the \`#489\` cross-
reference in SUBAGENTS.md. This commit adds a dedicated user-facing
doc covering the whole feature.

Coverage:

- Why opt-in by default
- How to enable (env var + config.toml)
- What the system prompt block looks like
- Three ways to add to memory:
  1. \`# foo\` composer prefix (#492)
  2. \`/memory\` slash command (#491) — show / path / clear / edit
  3. \`remember\` tool (#489) — model-callable, auto-approved
- File format — timestamped Markdown bullets, hand-editable
- What stays out of memory — secrets / transient state / long
  instructions / conversation snippets
- Privacy and scope — per-user, never uploaded, provider-agnostic
- Configuration reference — settings table with defaults and overrides

Cross-link added in CONFIGURATION.md so the existing \`memory_path\`
mention now points at the full feature doc.

No Rust code changed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 04:10:55 -05:00
Hunter Bown 4d4a9b424c feat(config): expand per-project overlay to cover provider, sandbox, approval, mcp_path, max_subagents, allow_shell (#485)
The project-config overlay (`<workspace>/.deepseek/config.toml` merged
on top of the user's global `~/.deepseek/config.toml`) was already
wired but only carried four string fields: model, api_key, base_url,
reasoning_effort. The use cases users actually file under #485 — "this
repo wants a different sandbox / approval policy / MCP server set / hard
sub-agent cap" — weren't covered.

### What ships

Adds the following keys to the project overlay, all merged with
identical "non-empty wins" semantics for strings:

- `provider` — pick a different backend per repo (e.g. `nvidia-nim` for
  an enterprise repo, `deepseek-cn` for a CN-team repo).
- `approval_policy` — `never` / `on-request` / `untrusted` for repos
  with strict policies.
- `sandbox_mode` — `read-only` / `workspace-write` / `danger-full-access`.
- `mcp_config_path` — per-repo MCP server set without touching the
  user's global file.
- `notes_path` — keep notes in-repo for projects where the notes tool
  is part of the dev workflow.

Plus two non-string fields:

- `max_subagents` (positive integer; clamped to `1..=MAX_SUBAGENTS=20`).
- `allow_shell` (bool).

### What stays user-global

`skills_dir`, `hooks`, `[capacity]`, `[retry]`, `[memory]`, etc. — those
are user-shaped settings, not repo-shaped. If a future use case
demands per-project values for any of them, a follow-up PR can extend
the overlay rather than letting the boundary blur.

### Tests

- 8 new tests in `project_config_tests` covering: provider+model,
  approval+sandbox, max_subagents+allow_shell, max_subagents
  clamping, negative-max_subagents rejection, missing config file
  pass-through, malformed TOML pass-through, and empty-string
  no-op.

### Docs

- New "Per-project overlay (#485)" section in `docs/CONFIGURATION.md`
  with a table of supported keys and the rationale for which fields
  stay user-global.

### Verification

cargo fmt --all -- --check                                          ✓
cargo clippy --workspace --all-targets --all-features --locked --   -D warnings   ✓
cargo test --workspace --all-features --locked                      ✓ 1828 + supporting (was 1820)

Closes #485

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 03:25:43 -05:00
Hunter Bown 3013a54c78 feat(tui): emit OSC 8 hyperlinks so URLs are Cmd+click-openable (#498)
Modern terminals (iTerm2, Terminal.app 13+, Ghostty, Kitty, WezTerm,
Alacritty, recent gnome-terminal/konsole) make a URL clickable when it's
wrapped in:

    \x1b]8;;TARGET\x1b\\LABEL\x1b]8;;\x1b\\

Terminals that don't understand the sequence simply render the visible
LABEL and ignore the escape, so emitting OSC 8 is a strict UX upgrade
for supporting terminals and a no-op for the rest.

### What's wired

- New `crates/tui/src/tui/osc8.rs` module with `wrap_link(target, label)`,
  `strip_into(s, &mut out)`, and a process-wide `ENABLED` AtomicBool that
  defaults to `true`.
- `markdown_render::render_line_with_links` now wraps recognized URLs
  (`http(s)://…`) in OSC 8 when the runtime flag is on. Display width is
  computed from the bare URL — the escapes are zero-width on supporting
  terminals.
- `ui_text::line_to_string` and `line_to_plain` strip OSC 8 wrappers when
  the span content contains an escape, so selection / clipboard output
  carries clean URLs and not the raw escape codes.
- `[tui] osc8_links: bool` config (default `true`) added to `TuiConfig`,
  documented in `docs/CONFIGURATION.md`, and surfaced in
  `config.example.toml`. `run_tui` applies it at startup.

### Tests

- 7 unit tests in `osc8::tests` covering wrap, strip-with-ESC-terminator,
  strip-with-BEL-terminator, plain passthrough, mixed escapes, default
  state, and round-trip set/unset.
- 2 markdown_render tests proving URLs in paragraph blocks emit the OSC 8
  wrapper when enabled and emit plain text when disabled.
- 2 ui_text tests proving `line_to_plain` strips OSC 8 wrappers from spans
  and passes plain spans through unchanged.

Tests that touch the global ENABLED flag serialize through a static
Mutex inside the test module so cargo's parallel runner can't observe a
torn read.

### Verification

cargo fmt --all -- --check                                          ✓
cargo clippy --workspace --all-targets --all-features --locked --   -D warnings   ✓
cargo test --workspace --all-features --locked                      ✓ (1820 + supporting; was 1809)

Closes #498

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 02:13:14 -05:00
Hunter Bown ad8064b143 chore(v0.8.8): stabilization batch — sub-agent caps, mutex contention, RLM polish, CI cleanup
Bundles the v0.8.8 stabilization fixes that were already implemented in the
working tree, plus the workflow/doc reconciliation called out in #507.

### Sub-agent runtime fixes
- **#509** Default sub-agent cap raised to 10 (configurable via
  `[subagents].max_concurrent` in `config.toml`, hard ceiling 20). The
  running-count calculation now ignores non-running, no-handle, and finished
  handles so completed agents stop counting against the cap.
- **#510** `SharedSubAgentManager` is now `Arc<RwLock<...>>`; the read paths
  that previously held a `Mutex` for inspection now take a read lock,
  eliminating the multi-agent fan-out UI freeze.
- **#511** `compact_tool_result_for_context` summarizes `agent_result` /
  `agent_wait` payloads before they are folded into the parent context.
- **#512** RLM tool cards map to `ToolFamily::Rlm` and render `rlm`, not
  `swarm`. Stale "swarm" wording cleaned in docs/comments/tests.
- **#513** (foreground stopgap only) Foreground RLM work is visible in the
  Agents sidebar projection. Full async RLM lifecycle remains v0.8.9 — the
  issue stays open with a refined scope.

### TUI / UX fixes
- **#487** Offline composer queue is now session-scoped; legacy unscoped
  queues fail closed.
- **#488** Composer Option+Backspace deletes by word; cross-platform key
  routing helpers added.
- **#443/#444** Keyboard enhancement flags pop on normal AND panic exit; the
  raw-mode startup probe is now bounded by a configurable timeout.
- **#449** Production footer reads statusline colors from `app.ui_theme`
  rather than the bespoke palette.
- **#506** `display_path_with_home` no longer mutates `HOME` in tests; the
  flake on shared-env CI is gone.

### Self-update / packaging
- **#503** `update.rs` arch mapping uses release-asset naming (`arm64`/`x64`)
  instead of the raw Rust constants. The platform-asset selector also rejects
  `.sha256` siblings as primary binaries. Tests now live alongside the source
  in `mod tests` (the `#[path]`-based integration test was removed because it
  duplicated test runs and forced a `pub(crate)` helper that no real caller
  used).
- **`Max 5 in flight` wording updated** in `agent_spawn` description,
  `prompts/base.md`, and `docs/TOOL_SURFACE.md` so the model sees the real
  default cap (10) and the configuration knob name.

### CI / release docs (#507)
- Pruned three duplicated/dead workflows: `crates-publish.yml`, `parity.yml`,
  `publish-npm.yml`. Their gates already run in `ci.yml` for every push/PR.
- `release.yml` build job now allows `parity` to be skipped (it only runs on
  tag push), unblocking `workflow_dispatch` reruns. The job still fails
  closed on a real parity failure.
- `RELEASE_RUNBOOK.md` reconciled: crate publishing is documented as the
  manual `scripts/release/publish-crates.sh` flow (no automated workflow);
  references to the deleted workflows removed.
- `CLAUDE.md` notes the `RELEASE_TAG_PAT` requirement for the auto-tag →
  release.yml chain (without it, the tag is created but `release.yml` does
  not fire) and documents the `workflow_dispatch` parity-skip behavior.

### Docs
- `docs/COMPETITIVE_ANALYSIS.md` added — capability matrix vs OpenCode and
  Codex CLI, gap analysis, and recommended implementation order.

### Verification (this branch)
- `cargo fmt --all -- --check` ✓
- `cargo check --workspace --all-targets --locked` ✓
- `cargo clippy --workspace --all-targets --all-features --locked -- -D warnings` ✓
- `cargo test --workspace --all-features --locked` ✓ (1809 + supporting)
- Parity gates ✓ (snapshot, parity_protocol, parity_state)
- `cargo build --release --locked -p deepseek-tui-cli -p deepseek-tui` ✓
- Lockfile drift guard ✓
- `deepseek doctor --json` clean
- `deepseek eval` (offline harness) success=true, 0 tool errors

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:57:37 -05:00
Hunter Bown 7125172f67 fix(tui): tighten selection and live task panels 2026-05-02 21:05:15 -05:00
Hunter Bown 7f2f47edf8 v0.7.7: stabilize sub-agent / swarm / fanout lifecycle, Windows install, and TUI polish (#246)
* 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
2026-04-30 07:26:26 -05:00
Hunter Bown a47b28e5d5 Complete v0.7.6 TUI polish and localization lane (#222)
Squash-merge PR #222 after green CI and review cleanup.\n\nCloses #198, #199, #206, #207, #208, #209, #210, #212, #213, #214, #215, #216.
2026-04-29 13:06:51 -05:00
Hunter Bown c2b2c284f6 release: v0.7.5 — token-basis fixes, shell timeout recovery, context/cache policy
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.
2026-04-29 10:13:27 -05:00
Hunter Bown 0578eb701e Add shell jobs and MCP manager to the TUI 2026-04-29 09:38:04 -05:00
Hunter Bown 41e8f2b5b2 Disable default compaction and opt in context seams 2026-04-29 09:12:20 -05:00
Hunter Bown 6d8ab4c2b8 fix: close v0.7.2 issue cleanup 2026-04-28 23:09:19 -05:00
Hunter Bown 3bc54b0bc0 fix(snapshot): harden side-git restore wiring 2026-04-28 00:46:24 -05:00