Commit Graph

78 Commits

Author SHA1 Message Date
Hunter Bown f738f0175a docs(keybindings): fix Ctrl-S (stash not history search), add Alt-R, audit to v0.8.13
- Fix Ctrl-S: stash current draft, not reverse history search
- Add Alt-R: search prompt history
- Note bare Up/Down arrows now scroll transcript when composer is empty (v0.8.13)
- Remove phantom Alt+Up from audit notes
- Note tui.toml wiring still deferred
- Remove dated 'v0.8.11 follow-up' reference in header
2026-05-05 18:03:45 -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
Hunter Bown 64cf0d8e46 Merge remote-tracking branch 'origin/main' into feat/v0.8.10-features 2026-05-04 10:03:06 -05:00
loongmiaow-pixel 65fb815cd2 docs(install): add Windows build guide, AV troubleshooting, and China mirror details 2026-05-04 20:17:27 +08:00
Hunter Bown 351ca4f3e6 docs(tui): keybindings audit + source-of-truth catalog (#559)
Walks every key handler in `crates/tui/src/tui/ui.rs` and
`crates/tui/src/tui/app.rs`, confirms each chord resolves to a live
action, and groups them by context (global, composer, transcript,
sidebar, palette, approval modal, onboarding) so users have a single
page to point at instead of guessing from the help overlay.

Audit findings inline at the bottom of the doc:
* No broken bindings: every chord resolves to a live handler.
* `Ctrl-P` was previously double-bound (history + palette); that's
  reconciled — the palette opens via `Ctrl-K`, `Ctrl-P` keeps history.
* The `?` help overlay entries all correspond to bindings in the
  catalog; aspirational ones were either implemented this release or
  dropped.

Deferral note for #436 (configurable keymap) and #437 (separate
`tui.toml`): both need a named-binding registry that names every chord
on this page and lets a user file override individual entries with
conflict detection. Half-implementing that in a patch release is worse
than landing the spec first; v0.8.10 ships the spec, the registry
follows in v0.8.11.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 03:07:24 -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 0047b3225b feat(runtime-api): daemon API quartet for whalescale (#561 #562 #563 #564) (#567)
Bridge work to unblock whalescale-desktop's Settings/Composer/Archived-chats
flows without requiring a daemon recompile per dev-port or client-side
aggregation.

#561 / whalescale#255 — CORS allow-list configurable
* Add `[runtime_api] cors_origins` config field, `--cors-origin URL`
  (repeatable) flag on `deepseek serve --http`, and `DEEPSEEK_CORS_ORIGINS`
  env var. User entries stack on top of the built-in defaults
  (localhost:3000, localhost:1420, tauri://localhost). Resolution preserves
  first-seen order and drops empty/duplicate values; invalid HeaderValues
  log a warning and are skipped.
* Refactor `cors_layer()` to read merged origins from `RuntimeApiState`.

#562 / whalescale#256 — `PATCH /v1/threads/{id}` accepts the full editable
field set
* Extend `UpdateThreadRequest` with `allow_shell`, `trust_mode`,
  `auto_approve`, `model`, `mode`, `title`, `system_prompt`. Each is
  optional; missing means no change. Empty-string clears `title`/
  `system_prompt`. Empty `model`/`mode` rejected with 400.
* Add `title: Option<String>` to `ThreadRecord` (additive, no schema bump
  per documented criteria — old readers ignore the field without
  misinterpretation). `list_threads_summary` now returns the user-set title
  when present, falling back to the derived input-summary title.
* `thread.updated` event payload now carries a `changes` map with only the
  fields that actually changed.

#563 / whalescale#260 — list-archived-only filter
* New `archived_only=true` query param on `GET /v1/threads` and
  `GET /v1/threads/summary`. Backed by a new `ThreadListFilter` enum
  (`ActiveOnly` | `IncludeArchived` | `ArchivedOnly`). `archived_only`
  takes precedence over `include_archived`. Default behavior unchanged.

#564 / whalescale#261 — `GET /v1/usage` aggregation
* New `RuntimeThreadManager::aggregate_usage` walks all threads/turns,
  filters by inclusive `since`/`until` RFC 3339 bounds, accumulates token
  totals + cost (via `pricing::calculate_turn_cost_from_usage`), and
  groups by `day` (default), `model`, `provider`, or `thread`.
* New `GET /v1/usage` route. `since`/`until`/`group_by` query params,
  `since > until` and unknown `group_by` rejected with 400. Empty time
  ranges yield empty `buckets` (never 404).

5 new tests cover preflight Allow-Origin echoing for both default and
extra origins, the extended PATCH field set + clear-by-empty + 400 paths,
the archived_only filter on list + summary endpoints, and the
/v1/usage envelope + validation errors. Existing 13 runtime_api tests
continue to pass; the parity gates and full workspace test suite are clean.

`docs/RUNTIME_API.md` and `config.example.toml` updated to document the
new params, body shape, endpoint, and CORS knob.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 02:18:19 -05:00
Hunter Bown 6ff4db5ba0 feat(v0.8.9): address all issues labeled v0.8.9
#551 — sidebar filters prior-session agents (from_prior_session)
#552 — status messages prioritise ↑ affordance over /queue
#553 — oversized paste consolidation to @mention file (+uuid suffix)
#523 — release.yml: add if: guard so release job doesn't skip on dispatch
#526 — verify cost_status side-channel is fully wired (already in place)
#554 — mouse/trackpad scroll now sets user_scrolled_during_stream
#522 — set RELEASE_TAG_PAT secret for auto-tag → release trigger
#504 — session-context panel (SidebarFocus::Context, config toggle, default off)
#501 — multi-arch Dockerfile (+BUILDPLATFORM pin) + devcontainer + release CI
#484 — docs/RUNTIME_API.md rewritten against actual runtime_api.rs endpoints
#482 — close v0.8.8 planning tracker

Fixes from review:
- RUNTIME_API.md: corrected endpoints (/v1/...), port (7878), doctor JSON schema (flat)
- Dockerfile: added --platform=$BUILDPLATFORM for native multi-arch builds
- docs/DOCKER.md: removed Docker Hub references (GHCR only)
- sidebar.rs: dropped unused _theme variable
- settings.rs: context_panel default changed to false
- app.rs: paste filename now includes 8-char uuid suffix to avoid collision
2026-05-04 00:33:08 -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 91dda88317 Merge pull request #508 from Hmbown/claude/improve-0.8.8-docs-BMhHj
feat(v0.8.8): linux ARM64 prebuilts + install docs overhaul
2026-05-03 08:19:07 -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 6dfb10f321 feat(a11y): NO_ANIMATIONS env override + accessibility docs (#450)
`fancy_animations: false` and `low_motion: true` already exist on
the settings struct, but the flag was undocumented and the only
ways to opt in were the `/settings` slash command or hand-editing
`~/.config/deepseek/settings.toml` — there was no environment-
level signal that platform a11y tooling could carry forward.

* `NO_ANIMATIONS=1` env var now forces `low_motion = true` and
  `fancy_animations = false` at startup, regardless of what's on
  disk. Recognises `1`, `true`, `yes`, `on` (case-insensitive);
  any other value is treated as unset.
* `Settings::apply_env_overrides()` is now called at the end of
  `Settings::load()`, so every consumer (App::new, /config, the
  doctor surface) sees the override applied uniformly. The
  override is a startup-time overlay — changing the env var
  mid-session has no effect.
* New `docs/ACCESSIBILITY.md` documents the existing `low_motion`,
  `fancy_animations`, `calm_mode`, `show_thinking`, and
  `show_tool_details` toggles plus the `NO_ANIMATIONS` startup
  override. Includes guidance for screen-reader users and a link
  back to this issue for follow-up motion regressions.

Tests:
  3 new tests in `settings.rs` (force-low-motion-on, override-
  user-opt-in, truthy-spelling-recognition). All three serialise
  through a static Mutex so the cargo parallel runner doesn't
  observe interleaved env mutations.
2026-05-03 05:09:17 -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 d129ab4150 docs: SUBAGENTS.md — role taxonomy, lifecycle, output contract (#404)
The role taxonomy expansion in #404 added Implementer + Verifier as
distinct postures alongside General / Explore / Plan / Review /
Custom. The issue body explicitly lists \`docs/AGENTS.md or
docs/SUBAGENTS.md\` as a target file; this commit creates that file.

Coverage:

- Role taxonomy table — stance, write/shell access, typical use per
  role.
- "When to pick which role" — narrative guidance the model can read
  if the role choice isn't obvious.
- Alias map — every accepted spelling routed to a canonical role,
  matching what \`SubAgentType::from_str\` accepts.
- Concurrency cap — the 10-by-default value, the
  \`[subagents].max_concurrent\` knob, and the running-only
  semantics (#509).
- Lifecycle — Pending → Running → terminal states, plus
  \`Interrupted\` after a process restart.
- Session boundaries (#405) — \`session_boot_id\` mechanics,
  default current-session filter, \`include_archived=true\` escape
  hatch, pre-#405 record handling.
- Output contract — the SUMMARY/CHANGES/EVIDENCE/RISKS/BLOCKERS
  format every sub-agent must produce.
- Memory + \`remember\` integration (#489) — sub-agents inherit the
  parent's memory file when memory is enabled and can append durable
  notes.
- Implementation notes — source path, persisted state file,
  is_running semantics, RwLock pattern.

Cross-link added in \`docs/TOOL_SURFACE.md\` so the sub-agent section
points to this doc.

No Rust code changed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 04:09:27 -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
Claude 0e5afe0b01 feat(v0.8.8): linux ARM64 prebuilts + install docs overhaul
Triggered by a Telegram report from a Chinese user trying to deploy
DeepSeek TUI on a HarmonyOS ARM64 thin-and-light: `npm i -g deepseek-tui`
exited with `Unsupported architecture: arm64 on platform linux` because
v0.8.7 only published x64 Linux artifacts. They worked around it with
`cargo install`, but the README never documented that path for ARM users.

This PR closes that gap on three layers:

- **Release workflow** — add `aarch64-unknown-linux-gnu` to the build
  matrix using GitHub's `ubuntu-24.04-arm` runner. v0.8.8 will publish
  `deepseek-linux-arm64` and `deepseek-tui-linux-arm64` alongside the
  existing x64/macOS/Windows assets, plus add the row to the Release
  body's manual-download table.

- **npm wrapper** — uncomment the linux/arm64 row in `ASSET_MATRIX`,
  rewrite the `Unsupported architecture/platform` error to print the
  full `cargo install deepseek-tui-cli deepseek-tui --locked` recipe
  and link to docs/INSTALL.md, and add `DEEPSEEK_TUI_OPTIONAL_INSTALL=1`
  so CI matrices that include unsupported platforms can keep running
  without a binary.

- **Docs** — new docs/INSTALL.md covering every supported platform,
  prebuilt vs. cargo install vs. manual download, cross-compiling x64
  -> ARM64 with `cross` or `gcc-aarch64-linux-gnu`, China mirror setup,
  and a troubleshooting section for the common arm64, MISSING_COMPANION_BINARY,
  and self-update arch-mapping (#503) errors. README and README.zh-CN
  now have an explicit Linux ARM64 quickstart pointing at `cargo install`
  for v0.8.7 today and `npm i -g` for v0.8.8+; the v0.8.7 known-issue
  block is updated to mention both #503 and the missing arm64 prebuilt.

https://claude.ai/code/session_01Fg1FKMtDxVnC4pp6bNBRCS
2026-05-03 04:42:53 +00:00
Hunter Bown e0b6a1b967 feat(v0.8.8): Don't auto-approve git -C ... (fixes #416) 2026-05-02 22:32:13 -05:00
Hunter Bown 7125172f67 fix(tui): tighten selection and live task panels 2026-05-02 21:05:15 -05:00
Hunter Bown 5bfc1feb62 v0.8.6: survivability, UX polish, and release hardening
Merge the v0.8.6 feature batch and release hardening.\n\nIncludes the full #373-#380/#382-#402 milestone scope, version bump to 0.8.6, secure /share temp-file handling, Windows-safe self-update replacement, and CI portability fixes.\n\nRemote PR checks passed on the final head before merge.
2026-05-02 20:11:33 -05:00
Hunter Bown aa23182674 chore(tools): remove /swarm command + agent_swarm/spawn_agents_on_csv tool surface; park swarm.rs pending #357 cascade (#336)
Surface removed: /swarm slash command, agent_swarm, spawn_agents_on_csv, swarm_status, swarm_result, swarm_cancel tools, report_agent_job_result. Prompts/docs/tests updated. swarm.rs parked with #![allow(dead_code)] pending the full cascade in #357. RLM prompt audit tracked in #358.
2026-05-02 01:30:23 -05:00
Hunter Bown 997c7f4bcd chore(release): verify dual registry publish state 2026-05-01 11:06:45 -05:00
Hunter Bown f00bae3bfb ci: smoke npm wrapper on windows 2026-05-01 02:37:37 -05:00
Hunter Bown 66a3aed528 feat(#248): foreground shell backgrounding, cancel tool, and Ctrl+B TUI shell control
- Add exec_shell_cancel tool to cancel one or all running background shell tasks
- Add foreground-to-background detach path via ShellManager request_foreground_background()
- Add wait_for_shell_delta_cancellable() so exec_shell_wait observes turn cancellation
- Add ShellControlView (Ctrl+B) with Background/Cancel options for active foreground commands
- Add 'Ctrl+B opens shell controls' hint in transcript for running exec cells
- Register exec_shell_cancel in ToolRegistryBuilder::with_shell_tools()
- Cancel-token checks in ShellInteractTool poll loop
- Update keybinding registry and OPERATIONS_RUNBOOK with Ctrl+B documentation
- Update TOOL_SURFACE.md with exec_shell_cancel entry
- Update prompts (rlm first-class guidance, AGENTS.md issue-closure policy)
- Tests: foreground_background, wait_cancel_leaves_running, cancel_tool_single, cancel_tool_all

Closes #248
2026-04-30 18:12: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 8ba8600155 release: v0.7.6
- 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
2026-04-29 17:00:36 -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 00c92e1c2a Implement v0.7.4 long-running agent tools 2026-04-29 00:50:43 -05:00
Hunter Bown 6d8ab4c2b8 fix: close v0.7.2 issue cleanup 2026-04-28 23:09:19 -05:00
Hunter Bown 97846cd63a release: include secrets crate in publish order 2026-04-28 16:39:22 -05:00
Hunter Bown 49d2be9e5c refactor(tools): share tool result primitives from crate 2026-04-28 01:23:21 -05:00
Hunter Bown 4fb8372c1c refactor(engine): split turn loop and capacity flow 2026-04-28 01:12:25 -05:00
Hunter Bown 3bc54b0bc0 fix(snapshot): harden side-git restore wiring 2026-04-28 00:46:24 -05:00
Hunter Bown 1f00ac6311 chore(release): drop auto npm publish, document manual flow, trim research PDF
- Remove the `publish-npm` job from `release.yml`. It has been failing on
  every release with `npm error code EOTP` because the configured `NPM_TOKEN`
  doesn't bypass 2FA. Manual publish from a developer machine is the actual
  ship path; codify that.
- Update `docs/RELEASE_RUNBOOK.md` "npm Wrapper Release" to describe the
  manual flow (`npm publish --access public` + OTP) and explain why the auto
  path is gone, with a recovery note for future Trusted-Publishing migration.
- Refresh stale cross-reference comment in `publish-npm.yml` (the workflow
  remains as inert plumbing for an eventual Trusted Publishing setup).
- Stop tracking `docs/DeepSeek_V4.pdf` (4.4 MB). It was never referenced
  outside test fixture filenames; the tests synthesize their own fake PDF.
  Add to `.gitignore` so a local copy can sit there without nagging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:26:10 -05:00
Hunter Bown feb3cf1e0c feat: explain parallel fan-out caps in tool descriptions and error messages (fixes #81) 2026-04-26 13:16:12 -05:00
Hunter Bown c58d10ded1 feat(tools): mark alias tools with deprecation metadata
Add `wrap_with_deprecation_notice` helper in the subagent module that
merges a `_deprecation` block into a ToolResult's metadata. Applied
exclusively on alias invocations:

- `spawn_agent` → use `agent_spawn` (removed in v0.8.0)
- `delegate_to_agent` → use `agent_spawn` (removed in v0.8.0)
- `close_agent` → use `agent_cancel` (removed in v0.8.0)
- `send_input` → use `agent_send_input` (removed in v0.8.0)

Canonical names are unaffected. Each alias invocation also emits a
`tracing::warn` so the deprecation appears in audit logs. Documents
the deprecation schedule in `docs/TOOL_SURFACE.md`. Four unit tests
verify the notice shape and that canonical tools stay clean.

Refs #72

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 12:32:26 -05:00
Hunter Bown ca7ca9f75f docs: drop stale handoff/migration/parity docs
Removed:

- `.claude/next-agent-prompt.md` (111 lines) — v0.4.6-era session prompt
  describing slices A/B/C that have all shipped. Successive sessions use
  fresh prompts (e.g. .deepseek/v0.6.0-overnight-review.md); this one is
  pure history.

- `docs/archive/workspace_migration_status.md` (92 lines) — explicitly
  archived (April 11), describes a one-time migration that's complete.
  Removed enclosing `docs/archive/` directory too (was the only file).
  CHANGELOG entry from v0.4.x still narrates the archival as history.

- `docs/parity_release_and_ci.md` (38 lines) — duplicates what
  `.github/workflows/parity.yml` and CONTRIBUTING.md already say
  authoritatively. Single source of truth wins.

- `AI_HANDOFF.md` + `todo.md` (untracked, no commit needed) — `todo.md`
  was a 7-line pointer to AI_HANDOFF.md, which itself was an April 11
  snapshot listing "remaining work" that's mostly delivered. CLAUDE.md
  is the live developer guide now.

1004/1004 tests still green; no doc/code references broken.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 00:27:58 -05:00
Hunter Bown 5f223adea6 v0.6.0: native rlm_query tool + scroll fix + cleanup
Adds a structured rlm_query tool for parallel/batched LLM fan-out.
The model calls it with one prompt or up to 16 concurrent prompts;
children dispatch via tokio::join_all against the existing DeepSeek
client. Default child model is deepseek-v4-flash; override per-call
via the model field. Available in Plan / Agent / YOLO. Cost folds
into the session's running total automatically.

Fixes scroll-stuck regression (#56): TranscriptScroll::resolve_top
and scrolled_by now use a three-level fallback chain (same line →
same cell line 0 → nearest cell at-or-before) instead of teleporting
to ToBottom when an anchor cell vanishes.

Loosens command-safety chains (#57): cargo build && cargo test and
similar chains of known-safe commands now escalate to RequiresApproval
instead of being hard-blocked as Dangerous. Chains containing unknown
commands still block.

Suppresses the GettingCrowded footer chip — context-percent header
already covers conversation pressure.

Refactors:
- Extracts file_mention parsing/completion/expansion (~450 LOC) from
  the 5,500-line ui.rs into crates/tui/src/tui/file_mention.rs.
- Deletes truly unused helpers (write_bytes, timestamped_filename,
  extension_from_url, output_path, has_project_doc, primary_doc_path).

Tests: 853 pass. cargo clippy --workspace -D warnings clean.
cargo fmt --all -- --check clean.

Closes #46 #47 #48 #49 #50 #53 #54 #55 #56 #57 #58.
2026-04-25 21:48:17 -05:00
Hunter Bown 027d6d19b6 docs(rlm): land Hetun design + helper layer + Sakana research methodology
Captures the full RLM-fundamental story across the design doc, MODES.md,
and the Hetun prompt. Tracking issues are now #46–#55 (helper layer
filed as #53, Hetun as #54, vendoring as #55).

What this nails down:

- **Hetun mode** is added at the END of the Tab cycle (Plan → Agent →
  YOLO → Hetun → Plan), not as a Plan replacement. Default landing mode
  is unchanged so people don't accidentally start there. Plan stays as
  it is.

- **Mission-level approval, not block-level.** Hetun runs a research
  phase, presents one mission card, and only executes after explicit
  user approval. Inside the execution turn the repl block runs straight
  through with no per-block prompts — that's the whole point of the
  mode.

- **The user's configured model is left alone on enter/exit.** Pro/max
  users stay on Pro/max. The flash-as-coordinator behaviour is internal
  to the runtime (ZIGRLM_RLM_CMD always points to flash regardless of
  mode). No global model swap.

- **No /hetun slash command.** Tab cycles into the mode; /plan keeps
  switching to Plan as today.

- **The helper layer (#53) is fundamental, not aleph-derived.** A
  curated ~20-function ctx-helper module + AST-validated Python sandbox
  baked into the repl runtime so a single block can load → slice → fan
  out flash queries → aggregate without crossing tool boundaries.
  Inspired by aleph's pattern but our own native primitive — not a port.

- **Hetun research methodology adopts Sakana's Fugu patterns.** The
  research phase is recursive novelty sampling + hierarchical narrative
  tree synthesis + multi-detector cross-verification (flash for
  breadth, Pro for depth) + hypothesis-verification loop. Not "fan out
  8 fixed queries". This is what makes "Plan + Recursive Agents"
  meaningful versus a flash-coordinator wrapper.

- **No version-number framing anywhere.** The plan ships as one cohesive
  RLM landing across #46/#48/#49/#50/#53/#54/#55 — order is dependency,
  not release schedule. We keep shipping.

- **Auto-compaction stays automatic.** Removed a manual /compact nag
  from the Hetun prompt; the existing coherence + capacity system
  already handles this.

Files:
  docs/rlm-design.md          new — full design doc with Hetun details
  docs/research-react-vs-rlm.md  new — supporting research treatment
  docs/MODES.md               4-mode cycle, Hetun added at end, Plan kept
  crates/tui/src/prompts/hetun.txt  prompt teaching the recursive-novelty
                              + hierarchical-synthesis + verification-loop
                              rhythm, mission-card structure, two-step gate
  .gitignore                  ignore .claude/scheduled_tasks.lock runtime

Closes nothing yet — implementation lands across the tracking issues.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 15:37:25 -05:00
Hunter Bown 82e4a564aa refactor(#35): tighten agent prompt tool descriptions, drop alias dupes
Tool-surface audit pass:

- FILE OPERATIONS rewritten so each line states the niche, not just the
  verb. read_file mentions PDF auto-extraction + `pages` slicing.
- New SEARCH section consolidates grep_files / file_search / web_search /
  fetch_url so the model sees them next to each other and picks the
  right one. fetch_url (#33) added; previously absent from the prompt.
- request_user_input pulled out of FILE OPERATIONS into its own USER
  section — it never belonged there.
- SUB-AGENTS list shrinks by 3: drops `spawn_agent` (use `agent_spawn`),
  `close_agent` (use `agent_cancel`), and the `agent_assign /
  assign_agent` dual-name. The underlying dispatchers still resolve those
  names, so existing sessions don't break — they just no longer
  pollute the model's tool list.

Adds `docs/TOOL_SURFACE.md` with the rationale, the v0.5.1 final
surface, and the dropped aliases. Calls out that grep_files is pure-Rust
(no rg/grep shell-out, so the "fall back to grep" AC from #35 is
vacuously satisfied — the tool has no shell dependency to fall back from).

Closes #35.
2026-04-25 13:44:43 -05:00
Hunter Bown 0a394e1587 fix(#31): catch version drift in CI, not at release time
Adds scripts/release/check-versions.sh and a `versions` CI job that runs
on every push/PR. Verifies:
- no per-crate Cargo.toml carries a literal version (must inherit the
  workspace version)
- npm/deepseek-tui/package.json matches the workspace version
- Cargo.lock is in sync with the manifests

Closes #31.
2026-04-25 13:25:55 -05:00
Hunter Bown 29141bc89b Add NIM env support and .env.example template 2026-04-25 07:21:43 -05:00
Hunter Bown 298f5c6c51 Merge branch 'claude/improve-deepseek-v4-harness-NxBpS' into main 2026-04-25 01:55:44 -05:00