Commit Graph

29 Commits

Author SHA1 Message Date
Hunter Bown bf6d82e4ba chore: release v0.8.2 — Windows build fix, npm offline, model-visible skills, zh-CN README
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>
2026-05-01 01:41:47 -05:00
Hunter Bown 5770a5747b fix cargo install packaging for v0.8.1 2026-04-30 23:45:21 -05:00
Hunter Bown 3f24759966 release: stabilize shell handles for v0.8.0
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.
2026-04-30 21:34:00 -05:00
Hunter Bown 3e8da4b99b chore: bump version to 0.7.9
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
2026-04-30 20:53:10 -05:00
Hunter Bown d25783fe5b fix(v0.7.8): reconcile swarm state and unicode search 2026-04-30 19:50:01 -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 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 00c92e1c2a Implement v0.7.4 long-running agent tools 2026-04-29 00:50:43 -05:00
Hunter Bown 0f8c363012 fix: clean v0.7.2 release prep 2026-04-28 21:54:43 -05:00
Hunter Bown 64d1698bde Release 0.7.1 (#156) 2026-04-28 18:38:44 -05:00
Hunter Bown a02907b89d chore(release): v0.7.0 2026-04-28 16:08:33 -05:00
Hunter Bown 27527699db Merge branch 'feat/v070-lsp' (#136 LSP diagnostics)
# Conflicts:
#	config.example.toml
#	crates/config/src/lib.rs
#	crates/tui/src/config.rs
#	crates/tui/src/core/engine.rs
#	crates/tui/src/main.rs
#	crates/tui/src/runtime_threads.rs
#	crates/tui/src/tui/ui.rs
2026-04-28 01:03:36 -05:00
Hunter Bown 41daab3ca0 Merge branch 'feat/v070-snapshots' (#137 side-git snapshots)
# Conflicts:
#	crates/config/src/lib.rs
#	crates/tui/src/config.rs
2026-04-28 00:58:16 -05:00
Hunter Bown 3bc54b0bc0 fix(snapshot): harden side-git restore wiring 2026-04-28 00:46:24 -05:00
Hunter Bown de9a3b8b74 feat(skills): #140 wire /skill install/update/uninstall/trust + [skills] config
Slash-command surface for the community-skill installer:

- `/skill install <github:owner/repo|https://...|<registry-name>>` parses
  the spec via `InstallSource::parse`, calls `install_with_registry`, and
  surfaces `NeedsApproval`/`NetworkDenied` with actionable messages
  pointing at `[network]` config (we deliberately don't dispatch a modal
  from the sync slash-command path; the underlying installer returns the
  outcome so a future approval wiring can reuse it).
- `/skill update <name>` re-fetches and prints "no upstream change" when
  the checksum matches.
- `/skill uninstall <name>` and `/skill trust <name>` both refuse to
  touch system skills (no `.installed-from` marker).
- `/skills --remote` (or `/skills remote`) fetches the curated registry
  through the same network gate and prints `name — description (source)`.

Internals:
- Sub-command dispatch happens in `run_skill` before activation lookup,
  so a user can't accidentally activate a skill literally named
  `install`. Async install/update/uninstall plumbed through
  `tokio::task::block_in_place` + `Handle::current().block_on`, matching
  the existing pattern in `commands/cycle.rs`.
- `installer_settings` loads `Config` on demand — `App` doesn't carry a
  `Config` reference, and the cost of a single TOML parse is negligible
  next to the network round-trip the install will make.

Config:
- New `[skills]` section in both `crates/tui/src/config.rs::Config` and
  the workspace `crates/config/src/lib.rs::ConfigToml` with
  `registry_url` (default: bundled raw GitHub index) and
  `max_install_size_bytes` (default: 5 MiB).
- `merge_config` propagates the new field, default impls cover the
  unset case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:30:05 -05:00
Hunter Bown 05a1032e00 feat(lsp): #136 post-edit diagnostics injection
Inject LSP diagnostics as a synthetic user message after every successful
file edit (`edit_file`, `apply_patch`, `write_file`) so the agent sees
compile breaks before its next reasoning step. Largest agent-quality
lever in v0.7.0.

Pieces:
- `crates/tui/src/lsp/`: thin JSON-RPC stdio client (no `tower-lsp`),
  per-language registry, diagnostics renderer producing the
  `<diagnostics file="…">` block format. `LspManager` owns lazily
  spawned per-language transports keyed by `Language`.
- `core/engine.rs`: hook on the success branch of the tool-result loop
  derives the edited file path(s) per tool, queries the LspManager
  with a 5 s timeout, and collects rendered blocks into
  `pending_lsp_blocks`. The queue is flushed as a `text` content
  block on the next request iteration so the model sees the
  diagnostics before it streams its next turn.
- `[lsp]` config schema (`enabled`, `poll_after_edit_ms`,
  `max_diagnostics_per_file`, `include_warnings`, optional
  `servers` override) with built-in defaults for rust-analyzer,
  gopls, pyright, typescript-language-server, and clangd.
- Failure modes are non-blocking by design: a missing LSP binary
  logs a one-time warning and skips the hook; a crashed server or
  poll timeout simply drops that turn's diagnostics. The agent's
  work is never blocked.

Tests: 24 unit tests cover language detection, registry overrides,
filter/sort/truncate behavior, and the rendered block format. Three
engine-level tokio tests exercise the full path through a fake
transport (no real LSP server is ever spawned in CI).

Acceptance criteria (per #136):
- Edit introducing a type error -> next request body contains
  `<diagnostics file="…">` block at the right line/col.
- `[lsp] enabled = false` -> no diagnostics injected.
- Snapshot test exercises full path with mock transport.
- LSP binary not on PATH -> one-time warning, agent proceeds.
- 5 s timeout, errors-only by default.
- Transports spawn lazily on first edit per language.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:29:28 -05:00
Hunter Bown 87ac2e9bdc Merge branch 'feat/v070-network' (#135 egress network policy + audit)
- crates/tui/src/network_policy.rs (NEW, ~300 LOC) — NetworkPolicy/NetworkPolicyDecider/NetworkAuditor
- crates/tui/src/tools/{fetch_url,web_search,spec}.rs + mcp.rs — gate before egress
- crates/tui/src/core/engine.rs + runtime_threads.rs + tui/ui.rs — surface NetworkDenied
- crates/config/src/lib.rs + tui/src/config.rs + config.example.toml — [network] schema
- Subdomain-prefix matching with deny-wins precedence
- Audit format: <RFC3339> network <host> <tool> <decision>

# Conflicts:
#	crates/tui/src/config.rs
2026-04-28 00:07:42 -05:00
Hunter Bown abbb86cdd2 feat(network): #135 add [network] config schema for policy
Adds the `[network]` table to both the workspace config crate (`ConfigToml`)
and the live tui config (`Config`), plus a documented example block in
`config.example.toml`. Schema:

```toml
[network]
default = "prompt"      # allow | deny | prompt
allow = ["api.deepseek.com", "github.com"]
deny = []
audit = true
```

`NetworkPolicyToml::into_runtime()` builds a runtime `NetworkPolicy` so the
engine can construct a `NetworkPolicyDecider` without reaching across crate
boundaries. Defaults preserve pre-v0.7.0 behavior: when the section is
absent, no policy is enforced.
2026-04-28 00:02:34 -05:00
Hunter Bown a5cc9d5852 feat(config): #134 resolve api_key through OS keyring with env fallback
Routes `ConfigToml::resolve_runtime_options` through the new
`deepseek_secrets::Secrets` façade so API keys are read from the OS
keyring before any environment variable, with the existing
plaintext-config layer kept as a deprecated last resort. The
precedence is now:

  CLI flag -> keyring -> env -> config-file

Reads of an `api_key` value from `~/.deepseek/config.toml` now emit
a one-time `tracing::warn!` directing users to
`deepseek auth set` / `deepseek auth migrate`.

`resolve_runtime_options_with_secrets` is exposed for tests and
process-level injection (the `cfg(test)` default uses an in-memory
store so unit tests never touch the real OS keychain). The
nvidia-nim provider keeps its `DEEPSEEK_API_KEY` env fallback for
back-compat. New tests cover keyring > env > config-file precedence
end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:01:23 -05:00
Hunter Bown f118db8201 feat(providers): #52 OpenRouter + Novita as first-class providers
ProviderKind gains Openrouter + Novita variants; ModelRegistry registers
deepseek/deepseek-v4-{pro,flash} against both. /provider opens a picker
modal with inline API-key prompt for un-configured providers. Env
fallbacks: OPENROUTER_API_KEY, NOVITA_API_KEY.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:58:51 -05:00
Hunter Bown 1107b723b1 chore: simplify pass + clippy clean for v0.6.2
Cleanup pass after the issue fixes (#64, #71, #80, #63):

Simplifications:
- sidebar.rs: extract `push_agent_row` closure to remove the duplicated
  two-line agent rendering (cached + progress-only paths used the same
  shape with different summary text).
- engine.rs: replace `error_categories.iter().any(|c| c == X)` with
  `.contains(&X)` (clippy::manual_contains).
- widgets/mod.rs: replace `for idx in menu_top..menu_bottom` index loop
  with `.iter().enumerate().take(menu_bottom).skip(menu_top)`
  (clippy::needless_range_loop).

Build hygiene (CI runs `cargo clippy ... -- -D warnings`):
- error_taxonomy.rs: per-item `#[allow(dead_code)]` on `ErrorSeverity`,
  `ErrorEnvelope`, and `ErrorEnvelope::new` with TODO notes referencing
  #66. Keeps deepseek's removal of the file-wide allow but stops the
  scaffold from breaking the build until #66 follows up.
- app.rs: per-field `#[allow(dead_code)]` on `fancy_animations` (pending
  #61 footer animation consumer).
- config/lib.rs: complete the OpenRouter/Novita variant scaffolding so
  `match ProviderKind { ... }` is exhaustive — add api_key/base_url env
  loading (`OPENROUTER_API_KEY`, `NOVITA_API_KEY`, optional `*_BASE_URL`
  overrides), wire `api_key_for` / `base_url_for` arms with the documented
  defaults, and extend `normalize_model_for_provider` so generic V4 model
  names map to each provider's catalog ID. Full /provider picker UI still
  pending #52.

Verified: cargo fmt clean, cargo clippy --workspace --all-targets
--all-features --locked -- -D warnings clean, full test suite passes
(979 + adjacent crate tests).
2026-04-26 13:54:54 -05:00
Hunter Bown 38069700cc chore: wip capacity canonical state + tool alias deprecation 2026-04-26 13:11:57 -05:00
Hunter Bown 29141bc89b Add NIM env support and .env.example template 2026-04-25 07:21:43 -05:00
Hunter Bown 16f62f7abf Fix reasoning replay and context accounting for NIM 2026-04-24 18:42:18 -05:00
Hunter Bown d0dc26ce25 Add NVIDIA NIM provider support for DeepSeek 2026-04-24 18:29:19 -05:00
Hunter Bown 35595f8edc fix: normalize legacy DeepSeek aliases to V4 flash 2026-04-23 23:08:44 -05:00
Hunter Bown b7bd02d814 feat: DeepSeek V4 support with reasoning-effort control (0.4.0)
Adds first-class DeepSeek V4 Pro and Flash support, updates the default model to deepseek-v4-pro, aligns legacy aliases with the current V4 1M context behavior, and fixes thinking-mode request handling.

Key fixes:
- Send DeepSeek's raw Chat Completions `thinking` parameter at the top level instead of SDK-only `extra_body`.
- Preserve assistant `reasoning_content` for all prior thinking-mode tool-call turns so subsequent requests satisfy DeepSeek V4's replay requirement.
- Fix npm wrapper concurrent first-run downloads by using per-process temporary download paths.
- Add `.mailmap` so historical bot-attributed commits aggregate under Hunter Bown where mailmap is honored.

Verified with the full local Rust gate, live DeepSeek V4 smoke, npm wrapper temp-install smoke, and green PR CI across Linux, macOS, and Windows.
2026-04-23 22:53:20 -05:00
Hunter Bown 37186c3d95 Workspace migration: split into modular crates, parity CI, release updates
- Convert root to Cargo workspace with crates/ layout
- Add deepseek-* crates mirroring Codex architecture
- Add parity CI workflow with snapshot/protocol/state tests
- Update release workflow to build both deepseek and deepseek-tui binaries
- Bump version to 0.3.28
2026-03-02 17:52:46 -06:00