chore(rebrand): finish codewhale release surfaces

This commit is contained in:
Hunter Bown
2026-05-23 13:41:46 -05:00
parent 6de8ba363f
commit ddaabbfed2
50 changed files with 269 additions and 254 deletions
+3 -3
View File
@@ -323,7 +323,7 @@ jobs:
files: artifacts/*/*
prerelease: false
body: |
> This release renames the project to **codewhale**. The legacy
> This release renames the project to **Codewhale**. The legacy
> `deepseek` and `deepseek-tui` binaries continue to ship as
> deprecation shims for one release cycle; they print a one-line
> warning and forward to `codewhale` / `codewhale-tui`. They will
@@ -345,8 +345,8 @@ jobs:
```bash
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v ~/.deepseek:/home/deepseek/.deepseek \
ghcr.io/hmbown/deepseek-tui:${{ needs.resolve.outputs.tag }}
-v ~/.deepseek:/home/codewhale/.deepseek \
ghcr.io/hmbown/codewhale:${{ needs.resolve.outputs.tag }}
```
The image ships the `codewhale` dispatcher and `codewhale-tui` runtime (plus the legacy `deepseek` / `deepseek-tui` shims during the transition). The `latest` tag is also updated on release.
+2 -2
View File
@@ -1,6 +1,6 @@
name: Sync to CNB
# Mirror commits and release tags to cnb.cool/deepseek-tui.com/DeepSeek-TUI
# Mirror commits and release tags to cnb.cool/codewhale.net/codewhale
# so users behind GitHub-blocking networks can fetch the source and tagged
# releases from the Tencent-hosted mirror.
#
@@ -69,7 +69,7 @@ jobs:
# special characters. CNB tokens are typically alphanumeric so
# this is belt-and-suspenders.
ENCODED_TOKEN="$(printf '%s' "${CNB_TOKEN}" | python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.stdin.read(), safe=""))')"
REMOTE_URL="https://cnb:${ENCODED_TOKEN}@cnb.cool/deepseek-tui.com/DeepSeek-TUI.git"
REMOTE_URL="https://cnb:${ENCODED_TOKEN}@cnb.cool/codewhale.net/codewhale.git"
# Use a masked alias so the token never appears in log lines.
git remote add cnb "${REMOTE_URL}"
+7 -7
View File
@@ -5,19 +5,19 @@ This file provides context for AI assistants working on this project.
## Project Type: Rust
### Commands
- Build: `cargo build` (default-members include the `deepseek` dispatcher)
- Build: `cargo build` (default-members include the `codewhale` dispatcher)
- Test: `cargo test --workspace --all-features`
- Lint: `cargo clippy --workspace --all-targets --all-features`
- Format: `cargo fmt --all`
- Run (canonical): `deepseek` — use the **`deepseek` binary**, not `deepseek-tui`. The dispatcher delegates to the TUI for interactive use and is the supported entry point for every flow (`deepseek`, `deepseek -p "..."`, `deepseek doctor`, `deepseek mcp …`, etc.).
- Run from source: `cargo run --bin deepseek` (or `cargo run -p deepseek-tui-cli`).
- Local dev shorthand: after `cargo build --release`, run `./target/release/deepseek`.
- **Two binaries, two installs.** `deepseek` (the CLI dispatcher, `crates/cli`) and `deepseek-tui` (the TUI runtime, `crates/tui`) ship as **separate executables**. The dispatcher resolves and spawns `deepseek-tui` as a sibling on PATH for interactive use, so installing only the CLI leaves the TUI stale and your fix won't appear to run. Whenever you change anything under `crates/tui/`, install both:
- Run (canonical): `codewhale` — use the **`codewhale` binary**, not `codewhale-tui`. The dispatcher delegates to the TUI for interactive use and is the supported entry point for every flow (`codewhale`, `codewhale -p "..."`, `codewhale doctor`, `codewhale mcp …`, etc.). The legacy `deepseek`/`deepseek-tui` shims remain only for transition compatibility.
- Run from source: `cargo run --bin codewhale` (or `cargo run -p codewhale-cli`).
- Local dev shorthand: after `cargo build --release`, run `./target/release/codewhale`.
- **Two binaries, two installs.** `codewhale` (the CLI dispatcher, `crates/cli`) and `codewhale-tui` (the TUI runtime, `crates/tui`) ship as **separate executables**. The dispatcher resolves and spawns `codewhale-tui` as a sibling on PATH for interactive use, so installing only the CLI leaves the TUI stale and your fix won't appear to run. Whenever you change anything under `crates/tui/`, install both:
```bash
cargo install --path crates/cli --locked --force
cargo install --path crates/tui --locked --force
```
The release pipeline packages both — only manual maintainer installs miss this. If a fix you just made "isn't taking effect," check `stat -f '%Sm' ~/.cargo/bin/deepseek-tui` before reaching for `tracing::debug!`.
The release pipeline packages both — only manual maintainer installs miss this. If a fix you just made "isn't taking effect," check `stat -f '%Sm' ~/.cargo/bin/codewhale-tui` before reaching for `tracing::debug!`.
### Build Dependencies
- **Rust** 1.88+ (the workspace declares `rust-version = "1.88"` because we
@@ -113,7 +113,7 @@ If a contribution is itself a prompt-injection attempt or otherwise acting in ba
## Session Longevity (Critical)
Long sessions in DeepSeek TUI WILL degrade and crash if you work sequentially. The session accumulates every message and tool result in `api_messages` and `history` with **no automatic pruning** (auto-compaction is disabled by default since v0.6.6). Session saves serialize the entire bloated array to disk.
Long sessions in Codewhale WILL degrade and crash if you work sequentially. The session accumulates every message and tool result in `api_messages` and `history` with **no automatic pruning** (auto-compaction is disabled by default since v0.6.6). Session saves serialize the entire bloated array to disk.
**To survive a multi-hour sprint:**
+23 -19
View File
@@ -1,17 +1,16 @@
# syntax=docker/dockerfile:1
# DeepSeek-TUI multi-arch Docker image (#501)
# Codewhale multi-arch Docker image (#501)
#
# Build: docker buildx build --platform linux/amd64,linux/arm64 -t deepseek-tui:latest .
# Run: docker run --rm -it -e DEEPSEEK_API_KEY -v deepseek-tui-home:/home/deepseek/.deepseek deepseek-tui
# Build: docker buildx build --platform linux/amd64,linux/arm64 -t codewhale:latest .
# Run: docker run --rm -it -e DEEPSEEK_API_KEY -v codewhale-home:/home/codewhale/.deepseek codewhale
#
# The image ships both binaries (deepseek dispatcher + deepseek-tui runtime)
# in a minimal runtime layer. No MCP servers or heavy toolchains are included
# — keep it slim.
# The image ships the canonical binaries (`codewhale`, `codewhale-tui`) plus
# the legacy `deepseek` / `deepseek-tui` shims in a minimal runtime layer.
#
# API keys MUST be passed at runtime (never baked into the image):
# docker run --rm -it -e DEEPSEEK_API_KEY deepseek-tui
# docker run --rm -it -e DEEPSEEK_API_KEY codewhale
# Or mount an env file:
# docker run --rm -it --env-file .env deepseek-tui
# docker run --rm -it --env-file .env codewhale
ARG RUST_VERSION=1.88
@@ -56,11 +55,14 @@ COPY . .
# Build both binaries for the target platform. --locked ensures
# reproducible builds from the committed lockfile.
RUN --mount=type=cache,id=deepseek-tui-target-${TARGETARCH},target=/build/target,sharing=locked \
--mount=type=cache,id=deepseek-tui-cargo-registry-${TARGETARCH},target=/usr/local/cargo/registry,sharing=locked \
--mount=type=cache,id=deepseek-tui-cargo-git-${TARGETARCH},target=/usr/local/cargo/git,sharing=locked \
RUN --mount=type=cache,id=codewhale-target-${TARGETARCH},target=/build/target,sharing=locked \
--mount=type=cache,id=codewhale-cargo-registry-${TARGETARCH},target=/usr/local/cargo/registry,sharing=locked \
--mount=type=cache,id=codewhale-cargo-git-${TARGETARCH},target=/usr/local/cargo/git,sharing=locked \
cargo build --release --locked --target "$(cat /rust-target)" \
-p codewhale-cli -p codewhale-tui \
&& mkdir -p /out \
&& cp target/$(cat /rust-target)/release/codewhale /out/ \
&& cp target/$(cat /rust-target)/release/codewhale-tui /out/ \
&& cp target/$(cat /rust-target)/release/deepseek /out/ \
&& cp target/$(cat /rust-target)/release/deepseek-tui /out/
@@ -73,17 +75,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# Non-root user with explicit UID/GID for filesystem ownership clarity.
RUN groupadd --gid 1000 deepseek \
&& useradd --create-home --shell /bin/bash --uid 1000 --gid 1000 deepseek \
&& install -d -m 0700 -o deepseek -g deepseek /home/deepseek/.deepseek
USER deepseek
WORKDIR /home/deepseek
RUN groupadd --gid 1000 codewhale \
&& useradd --create-home --shell /bin/bash --uid 1000 --gid 1000 codewhale \
&& install -d -m 0700 -o codewhale -g codewhale /home/codewhale/.deepseek
USER codewhale
WORKDIR /home/codewhale
COPY --from=builder --chown=deepseek:deepseek /out/deepseek /usr/local/bin/deepseek
COPY --from=builder --chown=deepseek:deepseek /out/deepseek-tui /usr/local/bin/deepseek-tui
COPY --from=builder --chown=codewhale:codewhale /out/codewhale /usr/local/bin/codewhale
COPY --from=builder --chown=codewhale:codewhale /out/codewhale-tui /usr/local/bin/codewhale-tui
COPY --from=builder --chown=codewhale:codewhale /out/deepseek /usr/local/bin/deepseek
COPY --from=builder --chown=codewhale:codewhale /out/deepseek-tui /usr/local/bin/deepseek-tui
# The dispatcher expects to find its companion binary next to it.
# Both are in /usr/local/bin — no further path setup needed.
ENTRYPOINT ["deepseek"]
ENTRYPOINT ["codewhale"]
CMD []
+4 -4
View File
@@ -1,4 +1,4 @@
# 🐳 codewhale
# 🐳 Codewhale
> **このターミナルネイティブのコーディングエージェントは、DeepSeek V4 の 100 万トークンのコンテキストウィンドウとプレフィックスキャッシュ機能を中心に構築されています。単一のバイナリとして配布され、Node.js や Python のランタイムは不要です。MCP クライアント、サンドボックス、永続的なタスクキューも標準で同梱されています。**
@@ -28,13 +28,13 @@ brew install deepseek-tui
# Linux x64/ARM64、macOS x64/ARM64、Windows x64 向けのビルド済みバイナリがあります。
# 5. Docker — ビルド済みリリースイメージ。
docker volume create codewhale-tui-home
docker volume create codewhale-home
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \
-v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-w /workspace \
ghcr.io/hmbown/deepseek-tui:latest
ghcr.io/hmbown/codewhale:latest
```
> 中国本土では、`--registry=https://registry.npmmirror.com` を指定して npm 経由のダウンロードを高速化するか、下記の[Cargo ミラー](#中国--ミラーフレンドリーなインストール)を利用してください。
+10 -10
View File
@@ -1,4 +1,4 @@
# codewhale
# Codewhale
> Terminal coding agent for DeepSeek V4. It runs from the `codewhale` command, streams reasoning blocks, edits local workspaces with approval gates, and includes an auto mode that chooses both model and thinking level per turn.
@@ -33,13 +33,13 @@ brew install deepseek-tui
# Prebuilt for Linux x64/ARM64, macOS x64/ARM64, Windows x64.
# 5. Docker — prebuilt release image.
docker volume create codewhale-tui-home
docker volume create codewhale-home
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \
-v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-w /workspace \
ghcr.io/hmbown/deepseek-tui:latest
ghcr.io/hmbown/codewhale:latest
```
> In mainland China, speed up the npm path with
@@ -72,7 +72,7 @@ cargo install codewhale-tui --locked --force
## What Is It?
codewhale is a coding agent that runs in your terminal. It can read and edit files, run shell commands, search the web, manage git, and coordinate sub-agents from a keyboard-driven TUI.
Codewhale is a coding agent that runs in your terminal. It can read and edit files, run shell commands, search the web, manage git, and coordinate sub-agents from a keyboard-driven TUI.
It is built around DeepSeek V4 (`deepseek-v4-pro` / `deepseek-v4-flash`), including 1M-token context windows, streaming reasoning blocks, and prefix-cache-aware cost reporting.
@@ -110,7 +110,7 @@ See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full walkthrough.
### Sub-agents: Concurrent Background Execution
codewhale can dispatch multiple sub-agents that run in parallel — like a concurrent task queue:
Codewhale can dispatch multiple sub-agents that run in parallel — like a concurrent task queue:
- **Non-blocking launch.** `agent_open` returns immediately. The child gets its own fresh context and tool registry and runs independently. The parent keeps working.
- **Background execution.** Sub-agents execute concurrently (default cap: 10, configurable to 20). The engine manages the pool — no polling loop needed.
@@ -208,7 +208,7 @@ Prebuilt binaries can also be downloaded from [GitHub Releases](https://github.c
### Windows (Scoop)
[Scoop](https://scoop.sh) is a Windows package manager. codewhale is listed
[Scoop](https://scoop.sh) is a Windows package manager. The `codewhale` package is listed
in Scoop's main bucket, but that manifest updates independently and can lag the
GitHub/npm/Cargo release. Run `scoop update` first, then verify the installed
version with `codewhale --version`:
@@ -346,14 +346,14 @@ from side-git snapshots but do not rewrite conversation history.
Docker images are published to GHCR for release builds:
```bash
docker volume create codewhale-tui-home
docker volume create codewhale-home
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \
-v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-w /workspace \
ghcr.io/hmbown/deepseek-tui:latest
ghcr.io/hmbown/codewhale:latest
```
See [docs/DOCKER.md](docs/DOCKER.md) for pinned tags, local image builds,
+7 -7
View File
@@ -1,4 +1,4 @@
# codewhale
# Codewhale
> **面向 [DeepSeek V4](https://platform.deepseek.com) 的终端原生编程智能体:100 万 token 上下文、思考模式流式推理、前缀缓存感知。自包含 Rust 二进制发布——开箱即带 MCP 客户端、沙箱和持久化任务队列。**
@@ -29,13 +29,13 @@ brew install deepseek-tui
# 覆盖 Linux x64/ARM64、macOS x64/ARM64、Windows x64
# 5. Docker —— 预构建发布镜像。
docker volume create codewhale-tui-home
docker volume create codewhale-home
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \
-v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-w /workspace \
ghcr.io/hmbown/deepseek-tui:latest
ghcr.io/hmbown/codewhale:latest
```
> 中国大陆访问较慢时,npm 可加 `--registry=https://registry.npmmirror.com`
@@ -316,14 +316,14 @@ codewhale update # 检查并应用二进制更新
Docker 镜像发布在 GHCR 上:
```bash
docker volume create codewhale-tui-home
docker volume create codewhale-home
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \
-v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-w /workspace \
ghcr.io/hmbown/deepseek-tui:latest
ghcr.io/hmbown/codewhale:latest
```
固定 tag、本地构建、volume 权限和非交互管道用法见 [docs/DOCKER.md](docs/DOCKER.md)。
+4 -4
View File
@@ -1,7 +1,7 @@
# ╔══════════════════════════════════════════════════════════════════════════════╗
# ║ DeepSeek TUI Configuration ║
# ║ Codewhale Configuration
# ║ ║
# ║ Unofficial CLI for DeepSeek Platform - Not affiliated with DeepSeek Inc.
# ║ Terminal coding agent for DeepSeek.
# ╚══════════════════════════════════════════════════════════════════════════════╝
# See `docs/CONFIGURATION.md` for how config is loaded (profiles, env overrides, etc.).
@@ -470,7 +470,7 @@ default_text_model = "deepseek-ai/deepseek-v4-pro"
# max_workspace_gb = 2 # Snapshots self-disable on first init when the
# # non-excluded workspace exceeds this size in GB
# # (v0.8.32). Default 2 GB protects against running
# # deepseek-tui in directories with hundreds of GB
# # codewhale in directories with hundreds of GB
# # of datasets / model weights / docker dumps where
# # `git add -A` would hang the TUI for hours. Set
# # to 0 to disable the cap (v0.8.31 behaviour);
@@ -530,7 +530,7 @@ default_text_model = "deepseek-ai/deepseek-v4-pro"
#
# [[hooks.hooks]]
# event = "session_start"
# command = "echo 'DeepSeek TUI session started'"
# command = "echo 'Codewhale session started'"
#
# # Inject ephemeral creds into every shell call. Output one
# # KEY=VALUE per line on stdout (export prefix optional).
+3 -3
View File
@@ -115,7 +115,7 @@ struct Cli {
enum Commands {
/// Run interactive/non-interactive flows via the TUI binary.
Run(RunArgs),
/// Run DeepSeek TUI diagnostics.
/// Run Codewhale diagnostics.
Doctor(TuiPassthroughArgs),
/// List live DeepSeek API models via the TUI binary.
Models(TuiPassthroughArgs),
@@ -129,7 +129,7 @@ enum Commands {
Init(TuiPassthroughArgs),
/// Bootstrap MCP config and/or skills directories.
Setup(TuiPassthroughArgs),
/// Run the DeepSeek TUI non-interactive agent command.
/// Run the Codewhale non-interactive agent command.
#[command(after_help = "\
Common forwarded flags:
--auto Enable agentic mode with tool access
@@ -140,7 +140,7 @@ Common forwarded flags:
--output-format <FORMAT> Output format: text or stream-json
")]
Exec(TuiPassthroughArgs),
/// Run a DeepSeek-powered code review over a git diff.
/// Run a Codewhale-powered code review over a git diff.
Review(TuiPassthroughArgs),
/// Apply a patch file or stdin to the working tree.
Apply(TuiPassthroughArgs),
+1 -1
View File
@@ -13,7 +13,7 @@ use std::io::Write;
const CHECKSUM_MANIFEST_ASSET: &str = "codewhale-artifacts-sha256.txt";
const LATEST_RELEASE_URL: &str = "https://api.github.com/repos/Hmbown/DeepSeek-TUI/releases/latest";
const CNB_REPO_URL: &str = "https://cnb.cool/deepseek-tui.com/DeepSeek-TUI";
const CNB_REPO_URL: &str = "https://cnb.cool/codewhale.net/codewhale";
const RELEASE_BASE_URL_ENV: &str = "DEEPSEEK_TUI_RELEASE_BASE_URL";
const LEGACY_RELEASE_BASE_URL_ENV: &str = "DEEPSEEK_RELEASE_BASE_URL";
const UPDATE_VERSION_ENV: &str = "DEEPSEEK_TUI_VERSION";
+8 -2
View File
@@ -119,8 +119,14 @@ fn configure_windows_stack() {
}
match std::env::var("CARGO_CFG_TARGET_ENV").as_deref() {
Ok("msvc") => println!("cargo:rustc-link-arg-bin=deepseek-tui=/STACK:8388608"),
Ok("gnu") => println!("cargo:rustc-link-arg-bin=deepseek-tui=-Wl,--stack,8388608"),
Ok("msvc") => {
println!("cargo:rustc-link-arg-bin=codewhale-tui=/STACK:8388608");
println!("cargo:rustc-link-arg-bin=deepseek-tui=/STACK:8388608");
}
Ok("gnu") => {
println!("cargo:rustc-link-arg-bin=codewhale-tui=-Wl,--stack,8388608");
println!("cargo:rustc-link-arg-bin=deepseek-tui=-Wl,--stack,8388608");
}
_ => {}
}
}
+1 -1
View File
@@ -791,7 +791,7 @@ fn build_relay_instruction(app: &App, focus: Option<&str>) -> String {
let mut out = String::new();
let _ = writeln!(
out,
"Create a compact session relay (接力) for a future DeepSeek TUI thread."
"Create a compact session relay (接力) for a future Codewhale thread."
);
let _ = writeln!(out);
let _ = writeln!(out, "Write or update `.deepseek/handoff.md`.");
+1 -1
View File
@@ -123,7 +123,7 @@ impl PrefixChange {
/// Monitors and manages prefix-cache stability across turns.
///
/// This is the core abstraction, mirroring Reasonix's `ImmutablePrefix`
/// concept but adapted to DeepSeek-TUI's existing architecture where the
/// concept but adapted to Codewhale's existing architecture where the
/// system prompt is rebuilt each turn and tools are registered at startup.
///
/// Usage:
+3 -3
View File
@@ -1,4 +1,4 @@
//! Project context loading for DeepSeek TUI.
//! Project context loading for Codewhale.
//!
//! This module handles loading project-specific context files that provide
//! instructions and context to the AI agent. These include:
@@ -529,7 +529,7 @@ fn auto_generate_context(workspace: &Path) -> Option<String> {
let content = format!(
"# Project Structure (Auto-generated)\n\n\
> This file was automatically generated by DeepSeek TUI.\n\
> This file was automatically generated by Codewhale.\n\
> You can edit or delete it at any time.\n\n\
**Summary:** {summary}\n\n\
**Tree:**\n```\n{tree}\n```"
@@ -612,7 +612,7 @@ pub fn create_default_agents_md(workspace: &Path) -> std::io::Result<PathBuf> {
let default_content = r#"# Project Agent Instructions
This file provides guidance to AI agents (DeepSeek TUI, Claude Code, etc.) when working with code in this repository.
This file provides guidance to AI agents (Codewhale, Claude Code, etc.) when working with code in this repository.
## File Location
+1 -1
View File
@@ -3,7 +3,7 @@
//! Sandbox module for secure command execution.
//!
//! This module provides sandboxing capabilities for shell commands executed by
//! DeepSeek TUI. Sandboxing restricts what system resources a command can access,
//! Codewhale. Sandboxing restricts what system resources a command can access,
//! preventing accidental or malicious damage to the system.
//!
//! # Platform Support
+1 -1
View File
@@ -33,7 +33,7 @@ pub enum SandboxPolicy {
/// Indicates the process is already running in an external sandbox.
///
/// Use this when DeepSeek TUI is itself running inside a container,
/// Use this when Codewhale is itself running inside a container,
/// VM, or other sandboxed environment. This avoids double-sandboxing
/// which can cause issues.
#[serde(rename = "external-sandbox")]
+1 -1
View File
@@ -1,6 +1,6 @@
//! Windows sandbox helper contract.
//!
//! Current status: DeepSeek TUI does not advertise an in-process Windows
//! Current status: Codewhale does not advertise an in-process Windows
//! sandbox. Future Windows support must run commands through a dedicated
//! helper that provides process-tree containment with a Job Object and
//! `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`.
+1 -1
View File
@@ -115,7 +115,7 @@ const SIZE_WALK_SKIP_DIRS: &[&str] = &[
];
const BUILTIN_EXCLUDES: &str = "\
# DeepSeek TUI built-in snapshot exclusions
# Codewhale built-in snapshot exclusions
node_modules/
target/
dist/
+1 -1
View File
@@ -1,4 +1,4 @@
//! Tool specification traits for the DeepSeek TUI agent system.
//! Tool specification traits for the Codewhale agent system.
//!
//! This module defines the core abstractions for tools:
//! - `ToolSpec`: The main trait that all tools must implement
+3 -3
View File
@@ -510,7 +510,7 @@ mod tests {
app.system_prompt = Some(SystemPrompt::Blocks(vec![
SystemBlock {
block_type: "text".to_string(),
text: "## Stable Base\n\nYou are DeepSeek TUI.".to_string(),
text: "## Stable Base\n\nYou are Codewhale.".to_string(),
cache_control: None,
},
SystemBlock {
@@ -570,7 +570,7 @@ mod tests {
fn inspector_text_prompt_shows_layer_map() {
let mut app = test_app();
app.system_prompt = Some(SystemPrompt::Text(
"You are DeepSeek TUI.\n\n<project_instructions source=\"AGENTS.md\">\nRules\n</project_instructions>\n\n## Project Context Pack\n{}\n\n## Environment\n- lang: en\n\n## Skills\n- rust\n\n## Context Management\nKeep compact\n\n## Compact\nTemplate\n\n## Repo Working Set\nsrc/".to_string(),
"You are Codewhale.\n\n<project_instructions source=\"AGENTS.md\">\nRules\n</project_instructions>\n\n## Project Context Pack\n{}\n\n## Environment\n- lang: en\n\n## Skills\n- rust\n\n## Context Management\nKeep compact\n\n## Compact\nTemplate\n\n## Repo Working Set\nsrc/".to_string(),
));
let text = build_context_inspector_text(&app);
@@ -590,7 +590,7 @@ mod tests {
#[test]
fn inspector_text_prompt_without_markers_shows_single_blob() {
let mut app = test_app();
app.system_prompt = Some(SystemPrompt::Text("You are DeepSeek TUI.".to_string()));
app.system_prompt = Some(SystemPrompt::Text("You are Codewhale.".to_string()));
let text = build_context_inspector_text(&app);
assert!(text.contains("Single text blob"));
+1 -1
View File
@@ -43,7 +43,7 @@ pub fn render(f: &mut Frame, area: Rect, app: &App) {
if !lines.is_empty() {
let mut panel = Block::default()
.title(Line::from(Span::styled(
" DeepSeek TUI ",
" Codewhale ",
Style::default()
.fg(palette::DEEPSEEK_BLUE)
.add_modifier(Modifier::BOLD),
+1 -1
View File
@@ -149,7 +149,7 @@ impl ModalView for ModePickerView {
let mut lines = Vec::with_capacity(MODE_ROWS.len() + 1);
lines.push(Line::from(Span::styled(
"Choose how DeepSeek TUI should operate:",
"Choose how Codewhale should operate:",
Style::default().fg(palette::TEXT_MUTED),
)));
+1 -1
View File
@@ -8,7 +8,7 @@
//!
//! Threat model: this is a deliberate user opt-in to a path the workspace
//! sandbox would otherwise refuse. The only access the trust list grants is
//! through DeepSeek-TUI's own file tools (`read_file`, `write_file`, etc.) —
//! through Codewhale's own file tools (`read_file`, `write_file`, etc.) —
//! it does not loosen the OS sandbox profile (Seatbelt/Landlock) used for
//! shell commands. Sandbox-profile expansion is tracked separately so a
//! shell tool can opt into the same paths in a future release.
+4 -3
View File
@@ -8,7 +8,7 @@ The active root `.cnb.yml` does two things:
- runs Feishu bridge and version-drift checks when CNB receives `main`;
- builds Linux x64 release assets from `v*` tags, creates the CNB release, and
uploads `deepseek-linux-x64`, `deepseek-tui-linux-x64`, and
uploads `codewhale-linux-x64`, `codewhale-tui-linux-x64`, and
`deepseek-artifacts-sha256.txt`.
The files in this directory are retained as deploy-button templates for Tencent
@@ -37,9 +37,10 @@ Optional:
- `DEEPSEEK_REPO_URL`: defaults to the CNB mirror URL
- `LIGHTHOUSE_SSH_PORT`: defaults to `22`
The server side should already have `/opt/whalebro/deepseek-tui`,
The server side should already have `/opt/whalebro/codewhale`,
`/etc/deepseek/runtime.env`, `/etc/deepseek/feishu-bridge.env`, and the
systemd services from `docs/TENCENT_LIGHTHOUSE_HK.md`.
`codewhale-runtime` / `codewhale-feishu-bridge` systemd services from
`docs/TENCENT_LIGHTHOUSE_HK.md`.
## Safety Notes
+18 -18
View File
@@ -40,7 +40,7 @@ main:
LIGHTHOUSE_SSH_PORT="${LIGHTHOUSE_SSH_PORT:-22}"
DEEPSEEK_REPO_BRANCH="${DEEPSEEK_REPO_BRANCH:-main}"
DEEPSEEK_REPO_URL="${DEEPSEEK_REPO_URL:-https://cnb.cool/deepseek-tui.com/DeepSeek-TUI.git}"
DEEPSEEK_REPO_URL="${DEEPSEEK_REPO_URL:-https://cnb.cool/codewhale.net/codewhale.git}"
install -m 700 -d ~/.ssh
printf '%s\n' "$LIGHTHOUSE_SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
@@ -51,37 +51,37 @@ main:
"DEEPSEEK_REPO_BRANCH='$DEEPSEEK_REPO_BRANCH' DEEPSEEK_REPO_URL='$DEEPSEEK_REPO_URL' bash -s" <<'REMOTE'
set -euo pipefail
if [ ! -d /opt/whalebro/deepseek-tui/.git ]; then
sudo -u deepseek git clone --branch "$DEEPSEEK_REPO_BRANCH" "$DEEPSEEK_REPO_URL" /opt/whalebro/deepseek-tui
if [ ! -d /opt/whalebro/codewhale/.git ]; then
sudo -u codewhale git clone --branch "$DEEPSEEK_REPO_BRANCH" "$DEEPSEEK_REPO_URL" /opt/whalebro/codewhale
fi
cd /opt/whalebro/deepseek-tui
if [ -n "$(sudo -u deepseek git status --porcelain)" ]; then
echo "Refusing to deploy over a dirty /opt/whalebro/deepseek-tui checkout." >&2
sudo -u deepseek git status --short
cd /opt/whalebro/codewhale
if [ -n "$(sudo -u codewhale git status --porcelain)" ]; then
echo "Refusing to deploy over a dirty /opt/whalebro/codewhale checkout." >&2
sudo -u codewhale git status --short
exit 1
fi
sudo -u deepseek git fetch --all --tags
if sudo -u deepseek git rev-parse --verify --quiet "refs/remotes/origin/$DEEPSEEK_REPO_BRANCH" >/dev/null; then
sudo -u deepseek git checkout -B "$DEEPSEEK_REPO_BRANCH" "origin/$DEEPSEEK_REPO_BRANCH"
elif sudo -u deepseek git rev-parse --verify --quiet "refs/tags/$DEEPSEEK_REPO_BRANCH" >/dev/null; then
sudo -u deepseek git checkout --detach "$DEEPSEEK_REPO_BRANCH"
sudo -u codewhale git fetch --all --tags
if sudo -u codewhale git rev-parse --verify --quiet "refs/remotes/origin/$DEEPSEEK_REPO_BRANCH" >/dev/null; then
sudo -u codewhale git checkout -B "$DEEPSEEK_REPO_BRANCH" "origin/$DEEPSEEK_REPO_BRANCH"
elif sudo -u codewhale git rev-parse --verify --quiet "refs/tags/$DEEPSEEK_REPO_BRANCH" >/dev/null; then
sudo -u codewhale git checkout --detach "$DEEPSEEK_REPO_BRANCH"
else
sudo -u deepseek git checkout "$DEEPSEEK_REPO_BRANCH"
sudo -u deepseek git pull --ff-only
sudo -u codewhale git checkout "$DEEPSEEK_REPO_BRANCH"
sudo -u codewhale git pull --ff-only
fi
sudo -iu deepseek bash -lc '
sudo -iu codewhale bash -lc '
set -euo pipefail
. "$HOME/.cargo/env"
cd /opt/whalebro/deepseek-tui
cd /opt/whalebro/codewhale
cargo install --path crates/cli --locked --force
cargo install --path crates/tui --locked --force
'
sudo bash scripts/tencent-lighthouse/install-services.sh
sudo systemctl restart deepseek-runtime
sudo systemctl restart deepseek-feishu-bridge
sudo systemctl restart codewhale-runtime
sudo systemctl restart codewhale-feishu-bridge
sudo bash scripts/tencent-lighthouse/doctor.sh
REMOTE
@@ -3,12 +3,12 @@
environments:
- name: lighthouse-hk
description: Deploy DeepSeek TUI to Tencent Lighthouse Hong Kong.
description: Deploy Codewhale to Tencent Lighthouse Hong Kong.
env:
name: lighthouse-hk
button:
- name: Deploy Lighthouse
description: Update /opt/whalebro/deepseek-tui, restart services, and run the Lighthouse doctor.
description: Update /opt/whalebro/codewhale, restart services, and run the Lighthouse doctor.
event: web_trigger_lighthouse
isDefault: true
permissions:
@@ -13,7 +13,7 @@ DEEPSEEK_AUTO_APPROVE=false
DEEPSEEK_CHAT_ALLOWLIST=
DEEPSEEK_ALLOW_UNLISTED=false
FEISHU_THREAD_MAP_PATH=/var/lib/deepseek-feishu-bridge/thread-map.json
FEISHU_THREAD_MAP_PATH=/var/lib/codewhale-feishu-bridge/thread-map.json
FEISHU_ALLOW_GROUPS=false
FEISHU_REQUIRE_PREFIX_IN_GROUP=true
FEISHU_GROUP_PREFIX=/ds
@@ -0,0 +1,21 @@
[Unit]
Description=Codewhale Feishu/Lark Phone Bridge
Wants=network-online.target codewhale-runtime.service
After=network-online.target codewhale-runtime.service
[Service]
Type=simple
User=codewhale
Group=codewhale
WorkingDirectory=/opt/codewhale/bridge
EnvironmentFile=/etc/deepseek/feishu-bridge.env
ExecStart=/usr/bin/node /opt/codewhale/bridge/src/index.mjs
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ReadWritePaths=/var/lib/codewhale-feishu-bridge
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,21 @@
[Unit]
Description=Codewhale Runtime API
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=codewhale
Group=codewhale
WorkingDirectory=/opt/whalebro
EnvironmentFile=/etc/deepseek/runtime.env
ExecStart=/home/codewhale/.cargo/bin/codewhale serve --http --host 127.0.0.1 --port ${DEEPSEEK_RUNTIME_PORT} --workers ${DEEPSEEK_RUNTIME_WORKERS} --auth-token ${DEEPSEEK_RUNTIME_TOKEN}
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ReadWritePaths=/home/codewhale/.deepseek /opt/whalebro
[Install]
WantedBy=multi-user.target
@@ -1,21 +0,0 @@
[Unit]
Description=DeepSeek Feishu/Lark Phone Bridge
Wants=network-online.target deepseek-runtime.service
After=network-online.target deepseek-runtime.service
[Service]
Type=simple
User=deepseek
Group=deepseek
WorkingDirectory=/opt/deepseek/bridge
EnvironmentFile=/etc/deepseek/feishu-bridge.env
ExecStart=/usr/bin/node /opt/deepseek/bridge/src/index.mjs
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ReadWritePaths=/var/lib/deepseek-feishu-bridge
[Install]
WantedBy=multi-user.target
@@ -1,21 +0,0 @@
[Unit]
Description=DeepSeek TUI Runtime API
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=deepseek
Group=deepseek
WorkingDirectory=/opt/whalebro
EnvironmentFile=/etc/deepseek/runtime.env
ExecStart=/home/deepseek/.cargo/bin/deepseek serve --http --host 127.0.0.1 --port ${DEEPSEEK_RUNTIME_PORT} --workers ${DEEPSEEK_RUNTIME_WORKERS} --auth-token ${DEEPSEEK_RUNTIME_TOKEN}
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ReadWritePaths=/home/deepseek/.deepseek /opt/whalebro
[Install]
WantedBy=multi-user.target
+8 -8
View File
@@ -1,6 +1,6 @@
# CNB Cool mirror
`cnb.cool/deepseek-tui.com/DeepSeek-TUI` is a one-way mirror of this
`cnb.cool/codewhale.net/codewhale` is a one-way mirror of this
GitHub repository for users on networks where GitHub is slow or blocked
(primarily mainland China). The mirror receives every push to `main`, every
`fix/*`, `rebrand/*`, and `work/v*` branch used for first-party release work,
@@ -73,12 +73,12 @@ should have both the new commit on `main` and the new tag:
```bash
# Quick check: does the new tag exist on CNB?
git ls-remote https://cnb.cool/deepseek-tui.com/DeepSeek-TUI.git \
git ls-remote https://cnb.cool/codewhale.net/codewhale.git \
refs/tags/vX.Y.Z
# Quick check: is CNB's main at the same commit as origin/main?
gh_main=$(git ls-remote https://github.com/Hmbown/DeepSeek-TUI.git refs/heads/main | awk '{print $1}')
cnb_main=$(git ls-remote https://cnb.cool/deepseek-tui.com/DeepSeek-TUI.git refs/heads/main | awk '{print $1}')
cnb_main=$(git ls-remote https://cnb.cool/codewhale.net/codewhale.git refs/heads/main | awk '{print $1}')
test "$gh_main" = "$cnb_main" && echo "in sync" || echo "DIVERGED: gh=$gh_main cnb=$cnb_main"
```
@@ -103,10 +103,10 @@ password manager.
```bash
# Add the CNB remote alongside origin.
git remote add cnb https://cnb:${CNB_TOKEN}@cnb.cool/deepseek-tui.com/DeepSeek-TUI.git
git remote add cnb https://cnb:${CNB_TOKEN}@cnb.cool/codewhale.net/codewhale.git
# Or, if you don't want the token in your shell history:
git remote add cnb https://cnb.cool/deepseek-tui.com/DeepSeek-TUI.git
git remote add cnb https://cnb.cool/codewhale.net/codewhale.git
# (you'll be prompted for username `cnb` and password ${CNB_TOKEN}
# on the first push; subsequent pushes use the credential helper.)
```
@@ -164,8 +164,8 @@ behind GitHub-blocking networks should use one of these paths:
- **`cargo install`** from the CNB mirror:
```bash
cargo install --git https://cnb.cool/deepseek-tui.com/DeepSeek-TUI --tag vX.Y.Z codewhale-cli
cargo install --git https://cnb.cool/deepseek-tui.com/DeepSeek-TUI --tag vX.Y.Z codewhale-tui
cargo install --git https://cnb.cool/codewhale.net/codewhale --tag vX.Y.Z codewhale-cli
cargo install --git https://cnb.cool/codewhale.net/codewhale --tag vX.Y.Z codewhale-tui
```
(Both binaries are required — the dispatcher and the TUI ship
separately; see `AGENTS.md` for the two-binary install rationale.)
@@ -190,7 +190,7 @@ The Lighthouse + Feishu/Lark tutorial uses CNB as the Tencent-side source and
automation lane. For a stable install, clone `main` or a release tag from:
```bash
https://cnb.cool/deepseek-tui.com/DeepSeek-TUI.git
https://cnb.cool/codewhale.net/codewhale.git
```
The mirror receives `main`, release tags, and the Tencent setup branch patterns
+17 -17
View File
@@ -1,10 +1,10 @@
# Docker
DeepSeek-TUI publishes a multi-arch Linux image to GitHub Container Registry
Codewhale publishes a multi-arch Linux image to GitHub Container Registry
for each release.
```bash
docker pull ghcr.io/hmbown/deepseek-tui:latest
docker pull ghcr.io/hmbown/codewhale:latest
```
## Quick start
@@ -12,14 +12,14 @@ docker pull ghcr.io/hmbown/deepseek-tui:latest
Run the published image with a Docker-managed data volume:
```bash
docker volume create codewhale-tui-home
docker volume create codewhale-home
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \
-v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-w /workspace \
ghcr.io/hmbown/deepseek-tui:latest
ghcr.io/hmbown/codewhale:latest
```
Use a pinned release tag for reproducible installs:
@@ -27,10 +27,10 @@ Use a pinned release tag for reproducible installs:
```bash
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \
-v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-w /workspace \
ghcr.io/hmbown/deepseek-tui:vX.Y.Z
ghcr.io/hmbown/codewhale:vX.Y.Z
```
Replace `vX.Y.Z` with a tag from
@@ -41,7 +41,7 @@ Replace `vX.Y.Z` with a tag from
Build the image locally from a checkout:
```bash
docker build -t codewhale-tui .
docker build -t codewhale .
```
Then run it with the same Docker-managed data volume:
@@ -49,10 +49,10 @@ Then run it with the same Docker-managed data volume:
```bash
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \
-v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-w /workspace \
codewhale-tui
codewhale
```
Docker Hub publishing is not configured; GHCR is the supported prebuilt image
@@ -68,13 +68,13 @@ registry.
## Volumes
Mount `/home/deepseek/.deepseek` to persist sessions, config, skills, memory,
Mount `/home/codewhale/.deepseek` to persist sessions, config, skills, memory,
and the offline queue across container restarts. A Docker-managed named volume
is the safest default because Docker creates it with ownership the container can
write:
```bash
-v codewhale-tui-home:/home/deepseek/.deepseek
-v codewhale-home:/home/codewhale/.deepseek
```
Without this mount the container starts fresh each time.
@@ -91,8 +91,8 @@ sudo chown -R 1000:1000 ~/.deepseek
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v ~/.deepseek:/home/deepseek/.deepseek \
ghcr.io/hmbown/deepseek-tui:latest
-v ~/.deepseek:/home/codewhale/.deepseek \
ghcr.io/hmbown/codewhale:latest
```
That `chown` changes ownership of the host `~/.deepseek` directory. Skip it if
@@ -106,18 +106,18 @@ When stdin is not a TTY, `codewhale` drops to the dispatcher's one-shot mode
```bash
echo "Explain the Cargo.toml in structured English." | \
docker run --rm -i -e DEEPSEEK_API_KEY ghcr.io/hmbown/deepseek-tui:latest
docker run --rm -i -e DEEPSEEK_API_KEY ghcr.io/hmbown/codewhale:latest
```
## Building locally
```bash
# Single platform (your host architecture)
docker build -t codewhale-tui .
docker build -t codewhale .
# Multi-platform (requires a builder with emulation)
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t codewhale-tui .
docker buildx build --platform linux/amd64,linux/arm64 -t codewhale .
```
## Devcontainer
+5 -5
View File
@@ -1,4 +1,4 @@
# Installing codewhale
# Installing Codewhale
This page covers every supported install path and the most common
"it didn't install" failures, including **Linux ARM64** and other less
@@ -181,7 +181,7 @@ is fastest from your network.
For an always-on workspace that can be controlled from a phone, use the
Tencent-native path instead of treating install as a single laptop step:
- CNB mirror/source: `https://cnb.cool/deepseek-tui.com/DeepSeek-TUI.git`
- CNB mirror/source: `https://cnb.cool/codewhale.net/codewhale.git`
- Tencent Lighthouse HK: `/opt/whalebro` remote workspace
- Feishu/Lark: long-connection phone bridge
- EdgeOne: optional public HTTPS edge for docs/status/webhook surfaces
@@ -278,7 +278,7 @@ curl -L -o /tmp/codewhale-artifacts-sha256.txt \
### Windows Scoop
codewhale is listed in Scoop's main bucket:
The `codewhale` package is listed in Scoop's main bucket:
```powershell
scoop update
@@ -473,8 +473,8 @@ assets. On networks where GitHub is blocked or unreliable, use the CNB source
mirror instead and install both binaries from the release tag:
```bash
cargo install --git https://cnb.cool/deepseek-tui.com/DeepSeek-TUI --tag vX.Y.Z codewhale-cli --locked --force
cargo install --git https://cnb.cool/deepseek-tui.com/DeepSeek-TUI --tag vX.Y.Z codewhale-tui --locked --force
cargo install --git https://cnb.cool/codewhale.net/codewhale --tag vX.Y.Z codewhale-cli --locked --force
cargo install --git https://cnb.cool/codewhale.net/codewhale --tag vX.Y.Z codewhale-tui --locked --force
```
If you operate a binary asset mirror, `codewhale update` can use it directly:
+6 -7
View File
@@ -1,4 +1,4 @@
# Rebrand: deepseek-tuicodewhale
# Rebrand: DeepSeek TUICodewhale
Starting with **v0.8.41**, this project ships under a new name: `codewhale`.
@@ -60,7 +60,7 @@ Anything that targets the DeepSeek provider API stays exactly as it was:
- **Homebrew tap and formula** (`Hmbown/homebrew-deepseek-tui`): still
installs by the legacy name during the transition. The tap's formula
will be flipped to the new names in a follow-up.
- **Docker image** (`ghcr.io/hmbown/deepseek-tui`): unchanged.
- **Docker image**: `ghcr.io/hmbown/codewhale`.
## Deprecation shims (one release cycle)
@@ -119,11 +119,10 @@ still verifies.
## Why the name change
`codewhale` is a shorter, terminal-friendlier handle that doesn't suggest
the project is tied to a single provider. The dispatcher already supports
DeepSeek, NVIDIA NIM, OpenAI-compatible endpoints, AtlasCloud, Wanjie Ark,
OpenRouter, Novita, Fireworks, SGLang, vLLM, and Ollama, with more on the
roadmap. The new name reflects that.
Codewhale is a shorter, terminal-friendlier handle for the same terminal
coding agent. In v0.8.41 it remains centered on DeepSeek V4 while the project
name, command names, package names, release assets, Docker image, and CNB
mirror move to Codewhale.
## Reporting issues with the rename
+1 -1
View File
@@ -88,7 +88,7 @@ Run, in order, from the repo root:
reports the new version on the npm registry.
- [ ] `crates.io` has the new version (or the `publish-crates.sh` job has
pushed it).
- [ ] `ghcr.io/hmbown/deepseek-tui:vX.Y.Z` and `:latest` are updated.
- [ ] `ghcr.io/hmbown/codewhale:vX.Y.Z` and `:latest` are updated.
## 8. Post-tag
+3 -3
View File
@@ -1,4 +1,4 @@
# codewhale Release Runbook
# Codewhale Release Runbook
This runbook is the source of truth for shipping Rust crates, GitHub release assets,
and the `codewhale` npm wrapper.
@@ -187,13 +187,13 @@ To re-enable automated publish: provision an npm automation token with "Bypass 2
## CNB Cool mirror
Every push to `main`, `fix/*`, `rebrand/*`, `work/v*`, and every `v*` tag is mirrored to
`cnb.cool/deepseek-tui.com/DeepSeek-TUI` via the `Sync to CNB` workflow
`cnb.cool/codewhale.net/codewhale` via the `Sync to CNB` workflow
so users behind GitHub-blocking networks can fetch the source and so CNB can
run the heavy Linux CI lane. After a release tag, **verify the mirror caught
it** before declaring the release shipped:
```bash
git ls-remote https://cnb.cool/deepseek-tui.com/DeepSeek-TUI.git refs/tags/vX.Y.Z
git ls-remote https://cnb.cool/codewhale.net/codewhale.git refs/tags/vX.Y.Z
```
If the workflow failed for the release tag, the manual fallback is
+7 -7
View File
@@ -5,17 +5,17 @@ who want an always-on agent workspace, a phone control surface, and a stack
that works well from mainland China.
It complements the local install path. If you only want to use `codewhale` on a
laptop, start with the README quickstart. If you want "DS-TUI as a remote
laptop, start with the README quickstart. If you want "Codewhale as a remote
workbench I can control from my phone", start here.
## Default Stack
```text
GitHub main/tags
-> CNB mirror: cnb.cool/deepseek-tui.com/DeepSeek-TUI
-> CNB mirror: cnb.cool/codewhale.net/codewhale
-> optional CNB build/deploy pipeline
-> Tencent Lighthouse HK
/opt/whalebro/codewhale-tui
/opt/whalebro/codewhale
/opt/whalebro/worktrees
codewhale-runtime.service on 127.0.0.1:7878
codewhale-feishu-bridge.service
@@ -45,7 +45,7 @@ EdgeOne is optional:
2. Clone from CNB by default when the branch or tag exists there:
```bash
export DEEPSEEK_REPO_URL=https://cnb.cool/deepseek-tui.com/DeepSeek-TUI.git
export DEEPSEEK_REPO_URL=https://cnb.cool/codewhale.net/codewhale.git
git ls-remote "$DEEPSEEK_REPO_URL" refs/heads/main
```
@@ -57,8 +57,8 @@ EdgeOne is optional:
```bash
export DEEPSEEK_BRANCH=main
git clone --branch "$DEEPSEEK_BRANCH" "$DEEPSEEK_REPO_URL" /tmp/codewhale-tui
cd /tmp/codewhale-tui
git clone --branch "$DEEPSEEK_BRANCH" "$DEEPSEEK_REPO_URL" /tmp/codewhale
cd /tmp/codewhale
sudo DEEPSEEK_REPO_URL="$DEEPSEEK_REPO_URL" \
DEEPSEEK_REPO_BRANCH="$DEEPSEEK_BRANCH" \
bash scripts/tencent-lighthouse/bootstrap-ubuntu.sh
@@ -85,7 +85,7 @@ The intended deploy button should:
1. Run bridge validation/tests and lightweight release-version checks.
2. SSH to Lighthouse with a deploy key stored as a CNB secret.
3. Update `/opt/whalebro/codewhale-tui`.
3. Update `/opt/whalebro/codewhale`.
4. Rebuild/install both binaries.
5. Reinstall/restart systemd services.
6. Run `scripts/tencent-lighthouse/doctor.sh`.
+13 -13
View File
@@ -11,14 +11,14 @@ is the implementation runbook for the Lighthouse host itself.
```text
CNB mirror or GitHub branch
-> /opt/whalebro/codewhale-tui
-> /opt/whalebro/codewhale
Feishu/Lark mobile app
-> Feishu/Lark long-connection bot
-> codewhale-feishu-bridge systemd service
-> http://127.0.0.1:7878 codewhale serve --http
-> /opt/whalebro
-> codewhale-tui/
-> codewhale/
Optional public edge:
EdgeOne -> Caddy/Nginx public site on Lighthouse
@@ -31,11 +31,11 @@ HTTP service, not the runtime API.
## Remote Whalebro Workspace
Use `/opt/whalebro` as the VPS workspace root. The first-class checkout is
`/opt/whalebro/codewhale-tui`.
`/opt/whalebro/codewhale`.
Create these paths first:
- `/opt/whalebro/codewhale-tui`
- `/opt/whalebro/codewhale`
- `/opt/whalebro/worktrees`
Linux is enough for Rust, Node, and service work. Mac-only release work such
@@ -87,9 +87,9 @@ SSH into the Lighthouse instance and run:
sudo apt-get update
sudo apt-get install -y git
export DEEPSEEK_BRANCH=main
export DEEPSEEK_REPO_URL=https://cnb.cool/deepseek-tui.com/DeepSeek-TUI.git
git clone --branch "$DEEPSEEK_BRANCH" "$DEEPSEEK_REPO_URL" /tmp/codewhale-tui
cd /tmp/codewhale-tui
export DEEPSEEK_REPO_URL=https://cnb.cool/codewhale.net/codewhale.git
git clone --branch "$DEEPSEEK_BRANCH" "$DEEPSEEK_REPO_URL" /tmp/codewhale
cd /tmp/codewhale
sudo DEEPSEEK_REPO_URL="$DEEPSEEK_REPO_URL" \
DEEPSEEK_REPO_BRANCH="$DEEPSEEK_BRANCH" \
bash scripts/tencent-lighthouse/bootstrap-ubuntu.sh
@@ -106,7 +106,7 @@ For stable release docs, confirm the CNB mirror has the branch or tag before
using it:
```bash
export DEEPSEEK_REPO_URL=https://cnb.cool/deepseek-tui.com/DeepSeek-TUI.git
export DEEPSEEK_REPO_URL=https://cnb.cool/codewhale.net/codewhale.git
git ls-remote "$DEEPSEEK_REPO_URL" \
refs/heads/main \
refs/tags/v0.8.37
@@ -129,7 +129,7 @@ sed -n '1,120p' /tmp/rustup-init.sh
sh /tmp/rustup-init.sh -y --profile minimal
. "$HOME/.cargo/env"
rustup default stable
cd /opt/whalebro/codewhale-tui
cd /opt/whalebro/codewhale
cargo install --path crates/cli --locked --force
cargo install --path crates/tui --locked --force
exit
@@ -138,14 +138,14 @@ exit
Copy and install the bridge/service files:
```bash
cd /opt/whalebro/codewhale-tui
cd /opt/whalebro/codewhale
sudo bash scripts/tencent-lighthouse/install-services.sh
```
After editing both env files, validate the bridge/runtime pairing:
```bash
sudo -u codewhale node /opt/deepseek/bridge/scripts/validate-config.mjs \
sudo -u codewhale node /opt/codewhale/bridge/scripts/validate-config.mjs \
--env /etc/deepseek/feishu-bridge.env \
--runtime-env /etc/deepseek/runtime.env \
--workspace-root /opt/whalebro \
@@ -196,7 +196,7 @@ sudo journalctl -u codewhale-feishu-bridge -f
Run the Lighthouse doctor after both services are configured:
```bash
cd /opt/whalebro/codewhale-tui
cd /opt/whalebro/codewhale
sudo bash scripts/tencent-lighthouse/doctor.sh
```
@@ -289,5 +289,5 @@ From a phone DM to the bot:
- Keep the Lighthouse firewall focused on SSH for this setup.
- Use SSH key auth.
- Use `tmux` for emergency terminal work from Blink/Termius.
- Keep `/opt/whalebro/codewhale-tui` on a personal branch while working from the
- Keep `/opt/whalebro/codewhale` on a personal branch while working from the
phone.
+8 -3
View File
@@ -39,15 +39,20 @@
{
packages = forEachSystem (
{ pkgs, system }:
{
default = self.packages.${system}.deepseek-tui;
deepseek-tui = pkgs.callPackage ./nix/package.nix {
let
codewhale = pkgs.callPackage ./nix/package.nix {
inherit rev;
rustPlatform = pkgs.makeRustPlatform {
cargo = pkgs.rustToolchain;
rustc = pkgs.rustToolchain;
};
};
in
{
default = codewhale;
codewhale = codewhale;
# Compatibility alias for existing Nix users during the rename.
deepseek-tui = codewhale;
}
);
+1 -1
View File
@@ -16,7 +16,7 @@ DEEPSEEK_AUTO_APPROVE=false
DEEPSEEK_CHAT_ALLOWLIST=
DEEPSEEK_ALLOW_UNLISTED=false
FEISHU_THREAD_MAP_PATH=/var/lib/deepseek-feishu-bridge/thread-map.json
FEISHU_THREAD_MAP_PATH=/var/lib/codewhale-feishu-bridge/thread-map.json
FEISHU_ALLOW_GROUPS=false
FEISHU_REQUIRE_PREFIX_IN_GROUP=true
FEISHU_GROUP_PREFIX=/ds
+5 -5
View File
@@ -1,12 +1,12 @@
# Feishu / Lark Bridge
This bridge lets a Feishu or Lark chat control a local `deepseek serve --http`
This bridge lets a Feishu or Lark chat control a local `codewhale serve --http`
runtime from a phone. It uses the official Lark/Feishu Node SDK long-connection
mode, so the first version does not need a public webhook URL.
Security model:
- `deepseek serve --http` stays bound to `127.0.0.1`.
- `codewhale serve --http` stays bound to `127.0.0.1`.
- `/v1/*` runtime calls use `DEEPSEEK_RUNTIME_TOKEN`.
- Feishu/Lark chats must be allowlisted unless `DEEPSEEK_ALLOW_UNLISTED=true`
is set for first pairing.
@@ -17,7 +17,7 @@ Security model:
## Setup
```bash
cd /opt/deepseek/bridge
cd /opt/codewhale/bridge
npm install --omit=dev
cp .env.example /etc/deepseek/feishu-bridge.env
sudoedit /etc/deepseek/feishu-bridge.env
@@ -37,8 +37,8 @@ npm run validate:config -- \
For a Tencent Lighthouse deployment, use:
```bash
sudo systemctl enable --now deepseek-runtime deepseek-feishu-bridge
sudo journalctl -u deepseek-feishu-bridge -f
sudo systemctl enable --now codewhale-runtime codewhale-feishu-bridge
sudo journalctl -u codewhale-feishu-bridge -f
```
## Commands
+2 -2
View File
@@ -1,11 +1,11 @@
{
"name": "@deepseek-tui/feishu-bridge",
"name": "@codewhale/feishu-bridge",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@deepseek-tui/feishu-bridge",
"name": "@codewhale/feishu-bridge",
"version": "0.1.0",
"dependencies": {
"@larksuiteoapi/node-sdk": "^1.52.0"
+2 -2
View File
@@ -1,9 +1,9 @@
{
"name": "@deepseek-tui/feishu-bridge",
"name": "@codewhale/feishu-bridge",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "Feishu/Lark mobile bridge for a local deepseek serve --http runtime.",
"description": "Feishu/Lark mobile bridge for a local codewhale serve --http runtime.",
"main": "src/index.mjs",
"scripts": {
"start": "node src/index.mjs",
+1 -1
View File
@@ -99,7 +99,7 @@ const config = {
allowUnlisted: parseBool(process.env.DEEPSEEK_ALLOW_UNLISTED, false),
threadMapPath:
process.env.FEISHU_THREAD_MAP_PATH ||
"/var/lib/deepseek-feishu-bridge/thread-map.json",
"/var/lib/codewhale-feishu-bridge/thread-map.json",
allowGroups: parseBool(process.env.FEISHU_ALLOW_GROUPS, false),
requirePrefixInGroup: parseBool(process.env.FEISHU_REQUIRE_PREFIX_IN_GROUP, true),
groupPrefix: process.env.FEISHU_GROUP_PREFIX || "/ds",
+2 -2
View File
@@ -160,7 +160,7 @@ test("validateBridgeConfig accepts locked-down whalebro DM config", () => {
DEEPSEEK_WORKSPACE: "/opt/whalebro",
DEEPSEEK_CHAT_ALLOWLIST: "oc_allowed",
DEEPSEEK_ALLOW_UNLISTED: "false",
FEISHU_THREAD_MAP_PATH: "/var/lib/deepseek-feishu-bridge/thread-map.json",
FEISHU_THREAD_MAP_PATH: "/var/lib/codewhale-feishu-bridge/thread-map.json",
FEISHU_ALLOW_GROUPS: "false",
FEISHU_REQUIRE_PREFIX_IN_GROUP: "true"
},
@@ -187,7 +187,7 @@ test("validateBridgeConfig rejects unsafe group pairing and token mismatch", ()
DEEPSEEK_RUNTIME_TOKEN: "bridge-token",
DEEPSEEK_WORKSPACE: "/opt/whalebro",
DEEPSEEK_ALLOW_UNLISTED: "true",
FEISHU_THREAD_MAP_PATH: "/var/lib/deepseek-feishu-bridge/thread-map.json",
FEISHU_THREAD_MAP_PATH: "/var/lib/codewhale-feishu-bridge/thread-map.json",
FEISHU_ALLOW_GROUPS: "true",
FEISHU_REQUIRE_PREFIX_IN_GROUP: "false"
},
+5 -5
View File
@@ -15,7 +15,7 @@
rev ? "dirty",
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "deepseek-tui";
pname = "codewhale";
version = "git-${rev}";
src = ../.;
@@ -46,9 +46,9 @@ rustPlatform.buildRustPackage (finalAttrs: {
cargoBuildFlags = [
"--package"
"deepseek-tui-cli"
"codewhale-cli"
"--package"
"deepseek-tui"
"codewhale-tui"
];
cargoTestFlags = finalAttrs.cargoBuildFlags ++ [
"--lib"
@@ -60,9 +60,9 @@ rustPlatform.buildRustPackage (finalAttrs: {
'';
meta = {
description = "Coding agent for DeepSeek models that runs in your terminal";
description = "Terminal coding agent for DeepSeek";
homepage = "https://github.com/Hmbown/DeepSeek-TUI";
license = lib.licenses.mit;
mainProgram = "deepseek";
mainProgram = "codewhale";
};
})
@@ -6,8 +6,8 @@ if [[ "${EUID}" -ne 0 ]]; then
exit 1
fi
DEEPSEEK_USER="${DEEPSEEK_USER:-deepseek}"
DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/deepseek}"
DEEPSEEK_USER="${DEEPSEEK_USER:-codewhale}"
DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/codewhale}"
WHALEBRO_ROOT="${WHALEBRO_ROOT:-/opt/whalebro}"
REPO_URL="${DEEPSEEK_REPO_URL:-https://github.com/Hmbown/DeepSeek-TUI.git}"
WHALEBRO_EXTRA_REPOS="${WHALEBRO_EXTRA_REPOS:-}"
@@ -47,10 +47,10 @@ install -d -o "${DEEPSEEK_USER}" -g "${DEEPSEEK_USER}" "${DEEPSEEK_ROOT}/bridge"
install -d -o "${DEEPSEEK_USER}" -g "${DEEPSEEK_USER}" "${WHALEBRO_ROOT}"
install -d -o "${DEEPSEEK_USER}" -g "${DEEPSEEK_USER}" "${WHALEBRO_ROOT}/worktrees"
install -d -m 0750 -o root -g "${DEEPSEEK_USER}" /etc/deepseek
install -d -m 0700 -o "${DEEPSEEK_USER}" -g "${DEEPSEEK_USER}" /var/lib/deepseek-feishu-bridge
install -d -m 0700 -o "${DEEPSEEK_USER}" -g "${DEEPSEEK_USER}" /var/lib/codewhale-feishu-bridge
if [[ ! -d "${WHALEBRO_ROOT}/deepseek-tui/.git" ]]; then
sudo -u "${DEEPSEEK_USER}" git clone --branch "${REPO_BRANCH}" "${REPO_URL}" "${WHALEBRO_ROOT}/deepseek-tui"
if [[ ! -d "${WHALEBRO_ROOT}/codewhale/.git" ]]; then
sudo -u "${DEEPSEEK_USER}" git clone --branch "${REPO_BRANCH}" "${REPO_URL}" "${WHALEBRO_ROOT}/codewhale"
fi
for repo_spec in ${WHALEBRO_EXTRA_REPOS}; do
@@ -94,7 +94,7 @@ DEEPSEEK_TRUST_MODE=false
DEEPSEEK_AUTO_APPROVE=false
DEEPSEEK_CHAT_ALLOWLIST=
DEEPSEEK_ALLOW_UNLISTED=false
FEISHU_THREAD_MAP_PATH=/var/lib/deepseek-feishu-bridge/thread-map.json
FEISHU_THREAD_MAP_PATH=/var/lib/codewhale-feishu-bridge/thread-map.json
FEISHU_ALLOW_GROUPS=false
FEISHU_REQUIRE_PREFIX_IN_GROUP=true
FEISHU_GROUP_PREFIX=/ds
@@ -116,7 +116,7 @@ Next:
1. Install Rust 1.88+ for ${DEEPSEEK_USER}; rustup is the usual path.
2. Build/install both binaries:
sudo -iu ${DEEPSEEK_USER}
cd ${WHALEBRO_ROOT}/deepseek-tui
cd ${WHALEBRO_ROOT}/codewhale
cargo install --path crates/cli --locked --force
cargo install --path crates/tui --locked --force
3. Copy integrations/feishu-bridge to ${DEEPSEEK_ROOT}/bridge and run npm install.
+11 -11
View File
@@ -1,13 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
DEEPSEEK_USER="${DEEPSEEK_USER:-deepseek}"
DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/deepseek}"
DEEPSEEK_USER="${DEEPSEEK_USER:-codewhale}"
DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/codewhale}"
WHALEBRO_ROOT="${WHALEBRO_ROOT:-/opt/whalebro}"
RUNTIME_ENV="${RUNTIME_ENV:-/etc/deepseek/runtime.env}"
BRIDGE_ENV="${BRIDGE_ENV:-/etc/deepseek/feishu-bridge.env}"
BRIDGE_DIR="${BRIDGE_DIR:-${DEEPSEEK_ROOT}/bridge}"
REPO_ROOT="${REPO_ROOT:-${WHALEBRO_ROOT}/deepseek-tui}"
REPO_ROOT="${REPO_ROOT:-${WHALEBRO_ROOT}/codewhale}"
failures=0
warnings=0
@@ -97,15 +97,15 @@ check_workspace() {
}
check_binaries() {
section "DeepSeek binaries"
section "Codewhale binaries"
local cargo_bin="/home/${DEEPSEEK_USER}/.cargo/bin"
local deepseek="${cargo_bin}/deepseek"
local tui="${cargo_bin}/deepseek-tui"
if [[ -x "${deepseek}" ]]; then
pass "${deepseek} is executable"
"${deepseek}" --version 2>/dev/null | sed 's/^/[info] deepseek version: /' || warn "deepseek --version failed"
local codewhale="${cargo_bin}/codewhale"
local tui="${cargo_bin}/codewhale-tui"
if [[ -x "${codewhale}" ]]; then
pass "${codewhale} is executable"
"${codewhale}" --version 2>/dev/null | sed 's/^/[info] codewhale version: /' || warn "codewhale --version failed"
else
fail "${deepseek} is missing or not executable"
fail "${codewhale} is missing or not executable"
fi
if [[ -x "${tui}" ]]; then
pass "${tui} is executable"
@@ -205,7 +205,7 @@ check_systemd() {
warn "systemd is not available in this environment"
return
fi
for unit in deepseek-runtime deepseek-feishu-bridge; do
for unit in codewhale-runtime codewhale-feishu-bridge; do
[[ -f "/etc/systemd/system/${unit}.service" ]] \
&& pass "${unit}.service is installed" \
|| fail "${unit}.service is missing"
+10 -10
View File
@@ -7,8 +7,8 @@ if [[ "${EUID}" -ne 0 ]]; then
fi
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
DEEPSEEK_USER="${DEEPSEEK_USER:-deepseek}"
DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/deepseek}"
DEEPSEEK_USER="${DEEPSEEK_USER:-codewhale}"
DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/codewhale}"
install -d -o "${DEEPSEEK_USER}" -g "${DEEPSEEK_USER}" "${DEEPSEEK_ROOT}/bridge"
rsync -a --delete \
@@ -23,11 +23,11 @@ else
sudo -u "${DEEPSEEK_USER}" npm --prefix "${DEEPSEEK_ROOT}/bridge" install --omit=dev
fi
install -m 0644 "${REPO_ROOT}/deploy/tencent-lighthouse/systemd/deepseek-runtime.service" /etc/systemd/system/deepseek-runtime.service
install -m 0644 "${REPO_ROOT}/deploy/tencent-lighthouse/systemd/deepseek-feishu-bridge.service" /etc/systemd/system/deepseek-feishu-bridge.service
install -m 0644 "${REPO_ROOT}/deploy/tencent-lighthouse/systemd/codewhale-runtime.service" /etc/systemd/system/codewhale-runtime.service
install -m 0644 "${REPO_ROOT}/deploy/tencent-lighthouse/systemd/codewhale-feishu-bridge.service" /etc/systemd/system/codewhale-feishu-bridge.service
systemctl daemon-reload
systemctl enable deepseek-runtime deepseek-feishu-bridge
systemctl enable codewhale-runtime codewhale-feishu-bridge
cat <<'EOF'
Services installed but not started.
@@ -35,11 +35,11 @@ Services installed but not started.
Before starting, verify:
/etc/deepseek/runtime.env
/etc/deepseek/feishu-bridge.env
sudo -u deepseek node /opt/deepseek/bridge/scripts/validate-config.mjs --env /etc/deepseek/feishu-bridge.env --runtime-env /etc/deepseek/runtime.env --workspace-root /opt/whalebro --check-filesystem
sudo -u codewhale node /opt/codewhale/bridge/scripts/validate-config.mjs --env /etc/deepseek/feishu-bridge.env --runtime-env /etc/deepseek/runtime.env --workspace-root /opt/whalebro --check-filesystem
Then run:
sudo systemctl start deepseek-runtime
sudo systemctl start deepseek-feishu-bridge
sudo bash /opt/whalebro/deepseek-tui/scripts/tencent-lighthouse/doctor.sh
sudo journalctl -u deepseek-feishu-bridge -f
sudo systemctl start codewhale-runtime
sudo systemctl start codewhale-feishu-bridge
sudo bash /opt/whalebro/codewhale/scripts/tencent-lighthouse/doctor.sh
sudo journalctl -u codewhale-feishu-bridge -f
EOF