Simulate a 30-turn complex session (user → thinking → assistant →
tools) and assert the rail_prefix_widths vector stays under 1 MB even
in pathological sessions. The test reports exact memory figures via
eprintln! for diagnostic visibility.
Replace the hardcoded three-glyph TOOL_CARD_RAIL_PREFIXES set (only
covered tool-card rails) with iterative structural detection that
handles all TUI decoration glyphs:
- Iterates through consecutive leading decorative spans so tool headers
with multiple prefix spans (e.g. "• ▶ run issue") are fully stripped.
- Pattern A: "<glyph>[<glyph>…]<space>" where all non-space chars are
drawing characters — covers single-glyph (▏, ▶, ⌕) and multi-glyph
prefixes (⋮⋮).
- Pattern B: "<glyph>" + lone space span — covers assistant/user glyphs
(●, ▎).
- Covers Box Drawing, Block Elements, Geometric Shapes, and individual
chars used as TUI decoration (•, …, ·, ⌕, ⋮).
Store rail-prefix widths in TranscriptViewCache so the copy path reads
metadata rather than guessing from glyphs.
When the user holds the left mouse button and drags past the top or
bottom of the transcript rect, advance the viewport on a fixed cadence
so a long passage can be selected in one drag. Also strip the visual
tool-card left-rail glyph (`╭ │ ╰`) from copied text so it does not
leak into the clipboard.
Auto-scroll:
* New `SelectionAutoscroll` state on `ViewportState` records direction
and the last in-bounds column while a drag is held outside the rect.
* Armed/disarmed by the existing `Drag(Left)` handler; cleared on
`Up(Left)`, on a fresh `Down(Left)`, and when the cursor returns
inside the viewport.
* A new per-loop helper `tick_selection_autoscroll` advances
`pending_scroll_delta` by ±1 line every 30 ms (~33 lines/sec) and
extends the selection head to the matching edge row, so the visible
selection rect stays glued to the cursor edge.
* The main loop's `poll_timeout` is clamped to the next autoscroll
tick so the loop wakes up on cadence even with no input events.
Copy artifact:
* `line_to_plain_for_copy` returns `(plain_text, rail_prefix_width)`,
stripping a leading rail glyph span when present.
* `selection_to_text` shifts recorded selection columns left by the
rail width before slicing so visible selection bounds still match.
Tests:
* `drag_above/below_viewport_arms_autoscroll_*` — verify direction
and clamped column for vertical-out drags.
* `drag_back_inside_disarms_autoscroll` — re-entering clears state.
* `mouse_up_clears_selection_autoscroll` — release ends autoscroll.
* `tick_selection_autoscroll_advances_pending_scroll_when_due` —
cadence advances scroll and head; `_respects_cadence` blocks early
ticks; `_clears_when_drag_ended` self-heals if drag state is lost.
* `line_to_plain_for_copy_*` — rail glyph stripping for top/middle/
bottom rails plus negative tests for plain spans, OSC-8 wrappers,
and lines whose plain text legitimately starts with `│`.
* Strengthened `selection_to_text_copies_rendered_transcript_block`
to assert no `│ ` line-prefix leaks.
## Summary
- Prefer a writable named Docker volume for the container home data path.
- Document the non-root UID/GID ownership requirement for host bind mounts.
- Update README and Docker docs examples to avoid permission-denied first runs.
## Test plan
- git diff --check
- GitHub CI green: version drift, lint, ubuntu, macOS, Windows, npm wrapper smoke, GitGuardian
## Summary
- Move the pager exit hint to the front of the footer so q/Esc is immediately discoverable.
- Preserve the rest of the pager footer metadata and styling.
## Test plan
- cargo test -p deepseek-tui pager --locked
- cargo fmt --all -- --check
- git diff --check
- GitHub CI green: version drift, lint, ubuntu, macOS, Windows, npm wrapper smoke, GitGuardian
## Summary
- carry markdown render metadata through the message renderer so fenced code lines are identified explicitly
- keep normal conversational continuation rails for prose, but replace the rail with alignment spaces before fenced code lines
- add a regression test for assistant code blocks so the visible U+258F rail does not appear inside code output
## Test plan
- cargo test -p deepseek-tui assistant_code_block_lines_do_not_get_transcript_rail --locked
- cargo fmt --all -- --check
- git diff --check origin/main..HEAD
- GitHub CI: lint, version drift, ubuntu/macos/windows tests, npm wrapper smoke, GitGuardian
## Summary
- treat the macOS Option+V legacy glyph as the tool-details shortcut instead of inserting text
- show the platform-appropriate details shortcut label in active tool status/footer copy
- add regression coverage for macOS glyph handling and existing tool-details target behavior
## Test plan
- cargo test -p deepseek-tui macos_option_v_glyph_is_treated_as_details_shortcut_only_on_macos --locked
- cargo test -p deepseek-tui detail_target_prefers_visible_tool_card --locked
- cargo test -p deepseek-tui active_tool_status_label_summarizes_live_tool_group --locked
- cargo fmt --all -- --check
- git diff --check
- GitHub CI: Version drift, Lint, Test (ubuntu-latest), Test (macos-latest), Test (windows-latest), npm wrapper smoke, GitGuardian
## Summary
- normalize empty or missing tool-call names to unknown_tool in streaming and non-streaming responses
- include source/id context in fallback warnings
- add regression coverage for empty streaming names and missing non-streaming names
## Test plan
- cargo test -p deepseek-tui decoder_uses_fallback_name_for_empty_streaming_tool_name --locked
- cargo test -p deepseek-tui non_streaming_response_uses_fallback_name_for_missing_tool_name --locked
- cargo fmt --all -- --check
- git diff --check
- GitHub CI: Version drift, Lint, Test (ubuntu-latest), Test (macos-latest), Test (windows-latest), npm wrapper smoke, GitGuardian
## Summary
- Add explicit ID, Status, Time, and Title headers to /task list output.
- Align task rows without changing task storage or execution behavior.
## Verification
- GitHub CI passed: lint, version drift, ubuntu/macos/windows tests, npm wrapper smoke, GitGuardian.
## Summary
- Probe common Linux and macOS gh CLI paths when DEEPSEEK_GH_BIN is not set.
- Keep the existing /opt/homebrew/bin/gh fallback for compatibility.
- Improve the not-installed error message.
## Verification
- GitHub CI passed: lint, version drift, ubuntu/macos/windows tests, npm wrapper smoke, GitGuardian.
* test: add reproducer for /models 404 on beta base URL
* fix: route non-beta paths to /v1 when base URL ends with /beta
---------
Co-authored-by: Hanmiao Li <894876246@qq.com>
`libc` was declared only for macOS and Linux, causing a build failure on
FreeBSD (#1143). All call sites that use `libc` are already guarded with
`#[cfg(unix)]` or narrower OS-specific guards, so broadening the
dependency to `cfg(unix)` fixes FreeBSD (and other BSDs) with no
behavioural change on macOS or Linux.
Co-authored-by: Vince <liuwenchang.x@qq.com>
Update competitive analysis to reflect that LSP integration is now
implemented as automatic post-edit diagnostics injection, and adjust
the recommended implementation order accordingly.
Co-authored-by: Stephen Xu <wexu@expediagroup.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use a dedicated user_body_style() with a green (#4ADE80 / #15803D)
foreground color for user messages instead of sharing the
message_body_style() (TEXT_PRIMARY) used by assistant messages.
This makes user input visually distinguishable from assistant
responses in the transcript.
Changes:
- palette.rs: add USER_BODY and LIGHT_USER_BODY color constants
- palette.rs: adapt_fg_for_palette_mode entry for light-mode mapping
- history.rs: add user_body_style() function
- history.rs: replace message_body_style() with user_body_style()
in all three User render paths (lines / lines_with_options /
transcript_lines)
Co-authored-by: Assassin-D007 <ws1554410958@163.com>
Teach /skill install to recognize compatible skill directories such as .claude/skills/<name>/SKILL.md, nested packages/.../skills/<name>/SKILL.md, and single nested skill repos while still extracting only the selected subtree.
Also make /init treat an existing AGENTS.md as an idempotent no-op so the TUI matches the dispatcher behavior instead of surfacing a scary error for an already-initialized project.
Make plain Up/Down navigate composer input history instead of scrolling
the transcript from an empty composer.
Keep menu overlays in control of arrow keys, preserve existing transcript
scroll shortcuts, and support word-wise cursor movement with Ctrl or
Alt/Option Left/Right.
* 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
Sister fix to #1108 / #1121. The 6-hour facts-drift cron has its own
provider labelMap (lib/facts-drift.ts) that re-derives ApiProvider
from the live source on GitHub and writes to CURATED_KV under
"facts:current". Without this fix, every cron tick repopulates the
KV cache with deepseek-cn even though the published binary's
ProviderArg rejects it — undoing the static facts.generated.ts fix.
Mirror the labelMap that derive-facts.mjs uses (no DeepseekCN entry).
Stale "facts:current" KV entry was deleted manually so this takes
effect immediately rather than after the next 6h cron tick.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DeepSeek's official API has a single endpoint, https://api.deepseek.com,
with servers physically in China. There is no separate mainland endpoint,
and api.deepseeki.com is a typo grandfathered into the source.
The /zh/install "国内 API 访问" panel previously suggested users set a
custom base_url to a China endpoint, which doesn't exist. Replace with
the truth: the default works for mainland users; only override
DEEPSEEK_BASE_URL if you have a private mirror.
Also re-runs derive-facts to keep facts.generated.ts at 9 providers.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The current CLOUDFLARE_API_TOKEN secret authenticates but lacks
User -> User Details -> Read, which OpenNext needs to call the
/memberships endpoint during the KV populate step. Until that
permission is added (or the token is regenerated from Cloudflare's
"Edit Cloudflare Workers" template), every push to web/** fails CI.
Removing the workflow file until the token is ready. Re-add when
the secret has the right scopes; the workflow's previous content
is preserved in git history at 6483997480.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
wrangler 4 requires Node.js >=22; the deploy job was pinned to 20
and failed at `npx wrangler deploy` with "Wrangler requires at
least Node.js v22.0.0".
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First commit of the Next.js community site that powers
deepseek-tui.com, deployed via Cloudflare Workers / OpenNext.
This commit lands the scaffold and applies the visual + correctness
pass requested by community feedback:
- Palette: drop the cream/Anthropic-feel paper (#F4F1E8) for a
DeepSeek-aligned cool white + soft gray (#FFFFFF / #F4F6FB), with
indigo accents kept. Soften default hairlines so a pure-white
background reads clean instead of harsh.
- Mobile: add a hamburger menu (mobile-menu.tsx) so phones can reach
Install / Docs / Activity / Roadmap / Contribute — previously the
link list was hidden on phones with no replacement. Tighter hero,
flexible button row, viewport-safe code blocks, columnar grids
collapse cleanly under 768px, and the printed-almanac center rule
is desktop-only now (it sliced through narrow viewports).
- "How it works" diagram: replace the hand-rolled ASCII art (which
misaligned under CJK monospace because Han characters take 2
columns vs Latin's 1, per dhh's note in WeChat) with a real
mermaid diagram rendered client-side via dynamic import. Uses the
mermaid.live standard syntax 庄表伟 recommended.
- Issue #1104: the docs listed a `deepseek-cn` provider that the
v0.8.16 binary doesn't accept (`ProviderArg` in crates/cli only
has 9 variants; the 10th lives only in the legacy tui/config.rs).
derive-facts.mjs now omits `deepseek-cn` until that variant is
wired through the shared ProviderKind, and the install page's
China-network recipe uses `base_url` / `DEEPSEEK_BASE_URL` (which
actually works on v0.8.16) instead of the unsupported provider.
Auto-deploys via .github/workflows/deploy-web.yml on push to main.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>