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/*/* files: artifacts/*/*
prerelease: false prerelease: false
body: | 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 > `deepseek` and `deepseek-tui` binaries continue to ship as
> deprecation shims for one release cycle; they print a one-line > deprecation shims for one release cycle; they print a one-line
> warning and forward to `codewhale` / `codewhale-tui`. They will > warning and forward to `codewhale` / `codewhale-tui`. They will
@@ -345,8 +345,8 @@ jobs:
```bash ```bash
docker run --rm -it \ docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \ -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v ~/.deepseek:/home/deepseek/.deepseek \ -v ~/.deepseek:/home/codewhale/.deepseek \
ghcr.io/hmbown/deepseek-tui:${{ needs.resolve.outputs.tag }} 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. 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 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 # so users behind GitHub-blocking networks can fetch the source and tagged
# releases from the Tencent-hosted mirror. # releases from the Tencent-hosted mirror.
# #
@@ -69,7 +69,7 @@ jobs:
# special characters. CNB tokens are typically alphanumeric so # special characters. CNB tokens are typically alphanumeric so
# this is belt-and-suspenders. # 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=""))')" 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. # Use a masked alias so the token never appears in log lines.
git remote add cnb "${REMOTE_URL}" 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 ## Project Type: Rust
### Commands ### 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` - Test: `cargo test --workspace --all-features`
- Lint: `cargo clippy --workspace --all-targets --all-features` - Lint: `cargo clippy --workspace --all-targets --all-features`
- Format: `cargo fmt --all` - 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 (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 deepseek` (or `cargo run -p deepseek-tui-cli`). - Run from source: `cargo run --bin codewhale` (or `cargo run -p codewhale-cli`).
- Local dev shorthand: after `cargo build --release`, run `./target/release/deepseek`. - Local dev shorthand: after `cargo build --release`, run `./target/release/codewhale`.
- **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: - **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 ```bash
cargo install --path crates/cli --locked --force cargo install --path crates/cli --locked --force
cargo install --path crates/tui --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 ### Build Dependencies
- **Rust** 1.88+ (the workspace declares `rust-version = "1.88"` because we - **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) ## 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:** **To survive a multi-hour sprint:**
+23 -19
View File
@@ -1,17 +1,16 @@
# syntax=docker/dockerfile:1 # 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 . # Build: docker buildx build --platform linux/amd64,linux/arm64 -t codewhale:latest .
# Run: docker run --rm -it -e DEEPSEEK_API_KEY -v deepseek-tui-home:/home/deepseek/.deepseek deepseek-tui # 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) # The image ships the canonical binaries (`codewhale`, `codewhale-tui`) plus
# in a minimal runtime layer. No MCP servers or heavy toolchains are included # the legacy `deepseek` / `deepseek-tui` shims in a minimal runtime layer.
# — keep it slim.
# #
# API keys MUST be passed at runtime (never baked into the image): # 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: # 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 ARG RUST_VERSION=1.88
@@ -56,11 +55,14 @@ COPY . .
# Build both binaries for the target platform. --locked ensures # Build both binaries for the target platform. --locked ensures
# reproducible builds from the committed lockfile. # reproducible builds from the committed lockfile.
RUN --mount=type=cache,id=deepseek-tui-target-${TARGETARCH},target=/build/target,sharing=locked \ RUN --mount=type=cache,id=codewhale-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=codewhale-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 \ --mount=type=cache,id=codewhale-cargo-git-${TARGETARCH},target=/usr/local/cargo/git,sharing=locked \
cargo build --release --locked --target "$(cat /rust-target)" \ cargo build --release --locked --target "$(cat /rust-target)" \
-p codewhale-cli -p codewhale-tui \
&& mkdir -p /out \ && 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 /out/ \
&& cp target/$(cat /rust-target)/release/deepseek-tui /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/* && rm -rf /var/lib/apt/lists/*
# Non-root user with explicit UID/GID for filesystem ownership clarity. # Non-root user with explicit UID/GID for filesystem ownership clarity.
RUN groupadd --gid 1000 deepseek \ RUN groupadd --gid 1000 codewhale \
&& useradd --create-home --shell /bin/bash --uid 1000 --gid 1000 deepseek \ && useradd --create-home --shell /bin/bash --uid 1000 --gid 1000 codewhale \
&& install -d -m 0700 -o deepseek -g deepseek /home/deepseek/.deepseek && install -d -m 0700 -o codewhale -g codewhale /home/codewhale/.deepseek
USER deepseek USER codewhale
WORKDIR /home/deepseek WORKDIR /home/codewhale
COPY --from=builder --chown=deepseek:deepseek /out/deepseek /usr/local/bin/deepseek COPY --from=builder --chown=codewhale:codewhale /out/codewhale /usr/local/bin/codewhale
COPY --from=builder --chown=deepseek:deepseek /out/deepseek-tui /usr/local/bin/deepseek-tui 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. # The dispatcher expects to find its companion binary next to it.
# Both are in /usr/local/bin — no further path setup needed. # Both are in /usr/local/bin — no further path setup needed.
ENTRYPOINT ["deepseek"] ENTRYPOINT ["codewhale"]
CMD [] CMD []
+4 -4
View File
@@ -1,4 +1,4 @@
# 🐳 codewhale # 🐳 Codewhale
> **このターミナルネイティブのコーディングエージェントは、DeepSeek V4 の 100 万トークンのコンテキストウィンドウとプレフィックスキャッシュ機能を中心に構築されています。単一のバイナリとして配布され、Node.js や Python のランタイムは不要です。MCP クライアント、サンドボックス、永続的なタスクキューも標準で同梱されています。** > **このターミナルネイティブのコーディングエージェントは、DeepSeek V4 の 100 万トークンのコンテキストウィンドウとプレフィックスキャッシュ機能を中心に構築されています。単一のバイナリとして配布され、Node.js や Python のランタイムは不要です。MCP クライアント、サンドボックス、永続的なタスクキューも標準で同梱されています。**
@@ -28,13 +28,13 @@ brew install deepseek-tui
# Linux x64/ARM64、macOS x64/ARM64、Windows x64 向けのビルド済みバイナリがあります。 # Linux x64/ARM64、macOS x64/ARM64、Windows x64 向けのビルド済みバイナリがあります。
# 5. Docker — ビルド済みリリースイメージ。 # 5. Docker — ビルド済みリリースイメージ。
docker volume create codewhale-tui-home docker volume create codewhale-home
docker run --rm -it \ docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \ -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \ -v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \ -v "$PWD:/workspace" \
-w /workspace \ -w /workspace \
ghcr.io/hmbown/deepseek-tui:latest ghcr.io/hmbown/codewhale:latest
``` ```
> 中国本土では、`--registry=https://registry.npmmirror.com` を指定して npm 経由のダウンロードを高速化するか、下記の[Cargo ミラー](#中国--ミラーフレンドリーなインストール)を利用してください。 > 中国本土では、`--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. > 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. # Prebuilt for Linux x64/ARM64, macOS x64/ARM64, Windows x64.
# 5. Docker — prebuilt release image. # 5. Docker — prebuilt release image.
docker volume create codewhale-tui-home docker volume create codewhale-home
docker run --rm -it \ docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \ -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \ -v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \ -v "$PWD:/workspace" \
-w /workspace \ -w /workspace \
ghcr.io/hmbown/deepseek-tui:latest ghcr.io/hmbown/codewhale:latest
``` ```
> In mainland China, speed up the npm path with > In mainland China, speed up the npm path with
@@ -72,7 +72,7 @@ cargo install codewhale-tui --locked --force
## What Is It? ## 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. 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 ### 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. - **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. - **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) ### 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 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 GitHub/npm/Cargo release. Run `scoop update` first, then verify the installed
version with `codewhale --version`: 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: Docker images are published to GHCR for release builds:
```bash ```bash
docker volume create codewhale-tui-home docker volume create codewhale-home
docker run --rm -it \ docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \ -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \ -v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \ -v "$PWD:/workspace" \
-w /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, 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 客户端、沙箱和持久化任务队列。** > **面向 [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 # 覆盖 Linux x64/ARM64、macOS x64/ARM64、Windows x64
# 5. Docker —— 预构建发布镜像。 # 5. Docker —— 预构建发布镜像。
docker volume create codewhale-tui-home docker volume create codewhale-home
docker run --rm -it \ docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \ -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \ -v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \ -v "$PWD:/workspace" \
-w /workspace \ -w /workspace \
ghcr.io/hmbown/deepseek-tui:latest ghcr.io/hmbown/codewhale:latest
``` ```
> 中国大陆访问较慢时,npm 可加 `--registry=https://registry.npmmirror.com` > 中国大陆访问较慢时,npm 可加 `--registry=https://registry.npmmirror.com`
@@ -316,14 +316,14 @@ codewhale update # 检查并应用二进制更新
Docker 镜像发布在 GHCR 上: Docker 镜像发布在 GHCR 上:
```bash ```bash
docker volume create codewhale-tui-home docker volume create codewhale-home
docker run --rm -it \ docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \ -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \ -v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \ -v "$PWD:/workspace" \
-w /workspace \ -w /workspace \
ghcr.io/hmbown/deepseek-tui:latest ghcr.io/hmbown/codewhale:latest
``` ```
固定 tag、本地构建、volume 权限和非交互管道用法见 [docs/DOCKER.md](docs/DOCKER.md)。 固定 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.). # 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 # max_workspace_gb = 2 # Snapshots self-disable on first init when the
# # non-excluded workspace exceeds this size in GB # # non-excluded workspace exceeds this size in GB
# # (v0.8.32). Default 2 GB protects against running # # (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 # # of datasets / model weights / docker dumps where
# # `git add -A` would hang the TUI for hours. Set # # `git add -A` would hang the TUI for hours. Set
# # to 0 to disable the cap (v0.8.31 behaviour); # # to 0 to disable the cap (v0.8.31 behaviour);
@@ -530,7 +530,7 @@ default_text_model = "deepseek-ai/deepseek-v4-pro"
# #
# [[hooks.hooks]] # [[hooks.hooks]]
# event = "session_start" # event = "session_start"
# command = "echo 'DeepSeek TUI session started'" # command = "echo 'Codewhale session started'"
# #
# # Inject ephemeral creds into every shell call. Output one # # Inject ephemeral creds into every shell call. Output one
# # KEY=VALUE per line on stdout (export prefix optional). # # KEY=VALUE per line on stdout (export prefix optional).
+3 -3
View File
@@ -115,7 +115,7 @@ struct Cli {
enum Commands { enum Commands {
/// Run interactive/non-interactive flows via the TUI binary. /// Run interactive/non-interactive flows via the TUI binary.
Run(RunArgs), Run(RunArgs),
/// Run DeepSeek TUI diagnostics. /// Run Codewhale diagnostics.
Doctor(TuiPassthroughArgs), Doctor(TuiPassthroughArgs),
/// List live DeepSeek API models via the TUI binary. /// List live DeepSeek API models via the TUI binary.
Models(TuiPassthroughArgs), Models(TuiPassthroughArgs),
@@ -129,7 +129,7 @@ enum Commands {
Init(TuiPassthroughArgs), Init(TuiPassthroughArgs),
/// Bootstrap MCP config and/or skills directories. /// Bootstrap MCP config and/or skills directories.
Setup(TuiPassthroughArgs), Setup(TuiPassthroughArgs),
/// Run the DeepSeek TUI non-interactive agent command. /// Run the Codewhale non-interactive agent command.
#[command(after_help = "\ #[command(after_help = "\
Common forwarded flags: Common forwarded flags:
--auto Enable agentic mode with tool access --auto Enable agentic mode with tool access
@@ -140,7 +140,7 @@ Common forwarded flags:
--output-format <FORMAT> Output format: text or stream-json --output-format <FORMAT> Output format: text or stream-json
")] ")]
Exec(TuiPassthroughArgs), Exec(TuiPassthroughArgs),
/// Run a DeepSeek-powered code review over a git diff. /// Run a Codewhale-powered code review over a git diff.
Review(TuiPassthroughArgs), Review(TuiPassthroughArgs),
/// Apply a patch file or stdin to the working tree. /// Apply a patch file or stdin to the working tree.
Apply(TuiPassthroughArgs), Apply(TuiPassthroughArgs),
+1 -1
View File
@@ -13,7 +13,7 @@ use std::io::Write;
const CHECKSUM_MANIFEST_ASSET: &str = "codewhale-artifacts-sha256.txt"; 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 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 RELEASE_BASE_URL_ENV: &str = "DEEPSEEK_TUI_RELEASE_BASE_URL";
const LEGACY_RELEASE_BASE_URL_ENV: &str = "DEEPSEEK_RELEASE_BASE_URL"; const LEGACY_RELEASE_BASE_URL_ENV: &str = "DEEPSEEK_RELEASE_BASE_URL";
const UPDATE_VERSION_ENV: &str = "DEEPSEEK_TUI_VERSION"; 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() { match std::env::var("CARGO_CFG_TARGET_ENV").as_deref() {
Ok("msvc") => println!("cargo:rustc-link-arg-bin=deepseek-tui=/STACK:8388608"), Ok("msvc") => {
Ok("gnu") => println!("cargo:rustc-link-arg-bin=deepseek-tui=-Wl,--stack,8388608"), 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 mut out = String::new();
let _ = writeln!( let _ = writeln!(
out, 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);
let _ = writeln!(out, "Write or update `.deepseek/handoff.md`."); 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. /// Monitors and manages prefix-cache stability across turns.
/// ///
/// This is the core abstraction, mirroring Reasonix's `ImmutablePrefix` /// 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. /// system prompt is rebuilt each turn and tools are registered at startup.
/// ///
/// Usage: /// 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 //! This module handles loading project-specific context files that provide
//! instructions and context to the AI agent. These include: //! instructions and context to the AI agent. These include:
@@ -529,7 +529,7 @@ fn auto_generate_context(workspace: &Path) -> Option<String> {
let content = format!( let content = format!(
"# Project Structure (Auto-generated)\n\n\ "# 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\ > You can edit or delete it at any time.\n\n\
**Summary:** {summary}\n\n\ **Summary:** {summary}\n\n\
**Tree:**\n```\n{tree}\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 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 ## File Location
+1 -1
View File
@@ -3,7 +3,7 @@
//! Sandbox module for secure command execution. //! Sandbox module for secure command execution.
//! //!
//! This module provides sandboxing capabilities for shell commands executed by //! 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. //! preventing accidental or malicious damage to the system.
//! //!
//! # Platform Support //! # Platform Support
+1 -1
View File
@@ -33,7 +33,7 @@ pub enum SandboxPolicy {
/// Indicates the process is already running in an external sandbox. /// 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 /// VM, or other sandboxed environment. This avoids double-sandboxing
/// which can cause issues. /// which can cause issues.
#[serde(rename = "external-sandbox")] #[serde(rename = "external-sandbox")]
+1 -1
View File
@@ -1,6 +1,6 @@
//! Windows sandbox helper contract. //! 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 //! sandbox. Future Windows support must run commands through a dedicated
//! helper that provides process-tree containment with a Job Object and //! helper that provides process-tree containment with a Job Object and
//! `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`. //! `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 = "\ const BUILTIN_EXCLUDES: &str = "\
# DeepSeek TUI built-in snapshot exclusions # Codewhale built-in snapshot exclusions
node_modules/ node_modules/
target/ target/
dist/ 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: //! This module defines the core abstractions for tools:
//! - `ToolSpec`: The main trait that all tools must implement //! - `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![ app.system_prompt = Some(SystemPrompt::Blocks(vec![
SystemBlock { SystemBlock {
block_type: "text".to_string(), 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, cache_control: None,
}, },
SystemBlock { SystemBlock {
@@ -570,7 +570,7 @@ mod tests {
fn inspector_text_prompt_shows_layer_map() { fn inspector_text_prompt_shows_layer_map() {
let mut app = test_app(); let mut app = test_app();
app.system_prompt = Some(SystemPrompt::Text( 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); let text = build_context_inspector_text(&app);
@@ -590,7 +590,7 @@ mod tests {
#[test] #[test]
fn inspector_text_prompt_without_markers_shows_single_blob() { fn inspector_text_prompt_without_markers_shows_single_blob() {
let mut app = test_app(); 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); let text = build_context_inspector_text(&app);
assert!(text.contains("Single text blob")); 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() { if !lines.is_empty() {
let mut panel = Block::default() let mut panel = Block::default()
.title(Line::from(Span::styled( .title(Line::from(Span::styled(
" DeepSeek TUI ", " Codewhale ",
Style::default() Style::default()
.fg(palette::DEEPSEEK_BLUE) .fg(palette::DEEPSEEK_BLUE)
.add_modifier(Modifier::BOLD), .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); let mut lines = Vec::with_capacity(MODE_ROWS.len() + 1);
lines.push(Line::from(Span::styled( lines.push(Line::from(Span::styled(
"Choose how DeepSeek TUI should operate:", "Choose how Codewhale should operate:",
Style::default().fg(palette::TEXT_MUTED), 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 //! 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 //! 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 //! it does not loosen the OS sandbox profile (Seatbelt/Landlock) used for
//! shell commands. Sandbox-profile expansion is tracked separately so a //! shell commands. Sandbox-profile expansion is tracked separately so a
//! shell tool can opt into the same paths in a future release. //! 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`; - runs Feishu bridge and version-drift checks when CNB receives `main`;
- builds Linux x64 release assets from `v*` tags, creates the CNB release, and - 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`. `deepseek-artifacts-sha256.txt`.
The files in this directory are retained as deploy-button templates for Tencent 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 - `DEEPSEEK_REPO_URL`: defaults to the CNB mirror URL
- `LIGHTHOUSE_SSH_PORT`: defaults to `22` - `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 `/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 ## Safety Notes
+18 -18
View File
@@ -40,7 +40,7 @@ main:
LIGHTHOUSE_SSH_PORT="${LIGHTHOUSE_SSH_PORT:-22}" LIGHTHOUSE_SSH_PORT="${LIGHTHOUSE_SSH_PORT:-22}"
DEEPSEEK_REPO_BRANCH="${DEEPSEEK_REPO_BRANCH:-main}" 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 install -m 700 -d ~/.ssh
printf '%s\n' "$LIGHTHOUSE_SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519 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' "DEEPSEEK_REPO_BRANCH='$DEEPSEEK_REPO_BRANCH' DEEPSEEK_REPO_URL='$DEEPSEEK_REPO_URL' bash -s" <<'REMOTE'
set -euo pipefail set -euo pipefail
if [ ! -d /opt/whalebro/deepseek-tui/.git ]; then if [ ! -d /opt/whalebro/codewhale/.git ]; then
sudo -u deepseek git clone --branch "$DEEPSEEK_REPO_BRANCH" "$DEEPSEEK_REPO_URL" /opt/whalebro/deepseek-tui sudo -u codewhale git clone --branch "$DEEPSEEK_REPO_BRANCH" "$DEEPSEEK_REPO_URL" /opt/whalebro/codewhale
fi fi
cd /opt/whalebro/deepseek-tui cd /opt/whalebro/codewhale
if [ -n "$(sudo -u deepseek git status --porcelain)" ]; then if [ -n "$(sudo -u codewhale git status --porcelain)" ]; then
echo "Refusing to deploy over a dirty /opt/whalebro/deepseek-tui checkout." >&2 echo "Refusing to deploy over a dirty /opt/whalebro/codewhale checkout." >&2
sudo -u deepseek git status --short sudo -u codewhale git status --short
exit 1 exit 1
fi fi
sudo -u deepseek git fetch --all --tags sudo -u codewhale git fetch --all --tags
if sudo -u deepseek git rev-parse --verify --quiet "refs/remotes/origin/$DEEPSEEK_REPO_BRANCH" >/dev/null; then if sudo -u codewhale 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" sudo -u codewhale 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 elif sudo -u codewhale 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 checkout --detach "$DEEPSEEK_REPO_BRANCH"
else else
sudo -u deepseek git checkout "$DEEPSEEK_REPO_BRANCH" sudo -u codewhale git checkout "$DEEPSEEK_REPO_BRANCH"
sudo -u deepseek git pull --ff-only sudo -u codewhale git pull --ff-only
fi fi
sudo -iu deepseek bash -lc ' sudo -iu codewhale bash -lc '
set -euo pipefail set -euo pipefail
. "$HOME/.cargo/env" . "$HOME/.cargo/env"
cd /opt/whalebro/deepseek-tui cd /opt/whalebro/codewhale
cargo install --path crates/cli --locked --force cargo install --path crates/cli --locked --force
cargo install --path crates/tui --locked --force cargo install --path crates/tui --locked --force
' '
sudo bash scripts/tencent-lighthouse/install-services.sh sudo bash scripts/tencent-lighthouse/install-services.sh
sudo systemctl restart deepseek-runtime sudo systemctl restart codewhale-runtime
sudo systemctl restart deepseek-feishu-bridge sudo systemctl restart codewhale-feishu-bridge
sudo bash scripts/tencent-lighthouse/doctor.sh sudo bash scripts/tencent-lighthouse/doctor.sh
REMOTE REMOTE
@@ -3,12 +3,12 @@
environments: environments:
- name: lighthouse-hk - name: lighthouse-hk
description: Deploy DeepSeek TUI to Tencent Lighthouse Hong Kong. description: Deploy Codewhale to Tencent Lighthouse Hong Kong.
env: env:
name: lighthouse-hk name: lighthouse-hk
button: button:
- name: Deploy Lighthouse - 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 event: web_trigger_lighthouse
isDefault: true isDefault: true
permissions: permissions:
@@ -13,7 +13,7 @@ DEEPSEEK_AUTO_APPROVE=false
DEEPSEEK_CHAT_ALLOWLIST= DEEPSEEK_CHAT_ALLOWLIST=
DEEPSEEK_ALLOW_UNLISTED=false 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_ALLOW_GROUPS=false
FEISHU_REQUIRE_PREFIX_IN_GROUP=true FEISHU_REQUIRE_PREFIX_IN_GROUP=true
FEISHU_GROUP_PREFIX=/ds 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 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 GitHub repository for users on networks where GitHub is slow or blocked
(primarily mainland China). The mirror receives every push to `main`, every (primarily mainland China). The mirror receives every push to `main`, every
`fix/*`, `rebrand/*`, and `work/v*` branch used for first-party release work, `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 ```bash
# Quick check: does the new tag exist on CNB? # 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 refs/tags/vX.Y.Z
# Quick check: is CNB's main at the same commit as origin/main? # 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}') 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" test "$gh_main" = "$cnb_main" && echo "in sync" || echo "DIVERGED: gh=$gh_main cnb=$cnb_main"
``` ```
@@ -103,10 +103,10 @@ password manager.
```bash ```bash
# Add the CNB remote alongside origin. # 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: # 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} # (you'll be prompted for username `cnb` and password ${CNB_TOKEN}
# on the first push; subsequent pushes use the credential helper.) # 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: - **`cargo install`** from the CNB mirror:
```bash ```bash
cargo install --git https://cnb.cool/deepseek-tui.com/DeepSeek-TUI --tag vX.Y.Z codewhale-cli cargo install --git https://cnb.cool/codewhale.net/codewhale --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-tui
``` ```
(Both binaries are required — the dispatcher and the TUI ship (Both binaries are required — the dispatcher and the TUI ship
separately; see `AGENTS.md` for the two-binary install rationale.) 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: automation lane. For a stable install, clone `main` or a release tag from:
```bash ```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 The mirror receives `main`, release tags, and the Tencent setup branch patterns
+17 -17
View File
@@ -1,10 +1,10 @@
# Docker # 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. for each release.
```bash ```bash
docker pull ghcr.io/hmbown/deepseek-tui:latest docker pull ghcr.io/hmbown/codewhale:latest
``` ```
## Quick start ## Quick start
@@ -12,14 +12,14 @@ docker pull ghcr.io/hmbown/deepseek-tui:latest
Run the published image with a Docker-managed data volume: Run the published image with a Docker-managed data volume:
```bash ```bash
docker volume create codewhale-tui-home docker volume create codewhale-home
docker run --rm -it \ docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \ -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \ -v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \ -v "$PWD:/workspace" \
-w /workspace \ -w /workspace \
ghcr.io/hmbown/deepseek-tui:latest ghcr.io/hmbown/codewhale:latest
``` ```
Use a pinned release tag for reproducible installs: Use a pinned release tag for reproducible installs:
@@ -27,10 +27,10 @@ Use a pinned release tag for reproducible installs:
```bash ```bash
docker run --rm -it \ docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \ -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \ -v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \ -v "$PWD:/workspace" \
-w /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 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: Build the image locally from a checkout:
```bash ```bash
docker build -t codewhale-tui . docker build -t codewhale .
``` ```
Then run it with the same Docker-managed data volume: 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 ```bash
docker run --rm -it \ docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \ -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-tui-home:/home/deepseek/.deepseek \ -v codewhale-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \ -v "$PWD:/workspace" \
-w /workspace \ -w /workspace \
codewhale-tui codewhale
``` ```
Docker Hub publishing is not configured; GHCR is the supported prebuilt image Docker Hub publishing is not configured; GHCR is the supported prebuilt image
@@ -68,13 +68,13 @@ registry.
## Volumes ## 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 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 is the safest default because Docker creates it with ownership the container can
write: write:
```bash ```bash
-v codewhale-tui-home:/home/deepseek/.deepseek -v codewhale-home:/home/codewhale/.deepseek
``` ```
Without this mount the container starts fresh each time. Without this mount the container starts fresh each time.
@@ -91,8 +91,8 @@ sudo chown -R 1000:1000 ~/.deepseek
docker run --rm -it \ docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \ -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v ~/.deepseek:/home/deepseek/.deepseek \ -v ~/.deepseek:/home/codewhale/.deepseek \
ghcr.io/hmbown/deepseek-tui:latest ghcr.io/hmbown/codewhale:latest
``` ```
That `chown` changes ownership of the host `~/.deepseek` directory. Skip it if 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 ```bash
echo "Explain the Cargo.toml in structured English." | \ 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 ## Building locally
```bash ```bash
# Single platform (your host architecture) # Single platform (your host architecture)
docker build -t codewhale-tui . docker build -t codewhale .
# Multi-platform (requires a builder with emulation) # Multi-platform (requires a builder with emulation)
docker buildx create --use 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 ## Devcontainer
+5 -5
View File
@@ -1,4 +1,4 @@
# Installing codewhale # Installing Codewhale
This page covers every supported install path and the most common This page covers every supported install path and the most common
"it didn't install" failures, including **Linux ARM64** and other less "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 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: 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 - Tencent Lighthouse HK: `/opt/whalebro` remote workspace
- Feishu/Lark: long-connection phone bridge - Feishu/Lark: long-connection phone bridge
- EdgeOne: optional public HTTPS edge for docs/status/webhook surfaces - EdgeOne: optional public HTTPS edge for docs/status/webhook surfaces
@@ -278,7 +278,7 @@ curl -L -o /tmp/codewhale-artifacts-sha256.txt \
### Windows Scoop ### Windows Scoop
codewhale is listed in Scoop's main bucket: The `codewhale` package is listed in Scoop's main bucket:
```powershell ```powershell
scoop update 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: mirror instead and install both binaries from the release tag:
```bash ```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/codewhale.net/codewhale --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-tui --locked --force
``` ```
If you operate a binary asset mirror, `codewhale update` can use it directly: 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`. 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 - **Homebrew tap and formula** (`Hmbown/homebrew-deepseek-tui`): still
installs by the legacy name during the transition. The tap's formula installs by the legacy name during the transition. The tap's formula
will be flipped to the new names in a follow-up. 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) ## Deprecation shims (one release cycle)
@@ -119,11 +119,10 @@ still verifies.
## Why the name change ## Why the name change
`codewhale` is a shorter, terminal-friendlier handle that doesn't suggest Codewhale is a shorter, terminal-friendlier handle for the same terminal
the project is tied to a single provider. The dispatcher already supports coding agent. In v0.8.41 it remains centered on DeepSeek V4 while the project
DeepSeek, NVIDIA NIM, OpenAI-compatible endpoints, AtlasCloud, Wanjie Ark, name, command names, package names, release assets, Docker image, and CNB
OpenRouter, Novita, Fireworks, SGLang, vLLM, and Ollama, with more on the mirror move to Codewhale.
roadmap. The new name reflects that.
## Reporting issues with the rename ## 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. reports the new version on the npm registry.
- [ ] `crates.io` has the new version (or the `publish-crates.sh` job has - [ ] `crates.io` has the new version (or the `publish-crates.sh` job has
pushed it). 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 ## 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, This runbook is the source of truth for shipping Rust crates, GitHub release assets,
and the `codewhale` npm wrapper. 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 ## CNB Cool mirror
Every push to `main`, `fix/*`, `rebrand/*`, `work/v*`, and every `v*` tag is mirrored to 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 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 run the heavy Linux CI lane. After a release tag, **verify the mirror caught
it** before declaring the release shipped: it** before declaring the release shipped:
```bash ```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 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. that works well from mainland China.
It complements the local install path. If you only want to use `codewhale` on a 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. workbench I can control from my phone", start here.
## Default Stack ## Default Stack
```text ```text
GitHub main/tags GitHub main/tags
-> CNB mirror: cnb.cool/deepseek-tui.com/DeepSeek-TUI -> CNB mirror: cnb.cool/codewhale.net/codewhale
-> optional CNB build/deploy pipeline -> optional CNB build/deploy pipeline
-> Tencent Lighthouse HK -> Tencent Lighthouse HK
/opt/whalebro/codewhale-tui /opt/whalebro/codewhale
/opt/whalebro/worktrees /opt/whalebro/worktrees
codewhale-runtime.service on 127.0.0.1:7878 codewhale-runtime.service on 127.0.0.1:7878
codewhale-feishu-bridge.service codewhale-feishu-bridge.service
@@ -45,7 +45,7 @@ EdgeOne is optional:
2. Clone from CNB by default when the branch or tag exists there: 2. Clone from CNB by default when the branch or tag exists there:
```bash ```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 git ls-remote "$DEEPSEEK_REPO_URL" refs/heads/main
``` ```
@@ -57,8 +57,8 @@ EdgeOne is optional:
```bash ```bash
export DEEPSEEK_BRANCH=main export DEEPSEEK_BRANCH=main
git clone --branch "$DEEPSEEK_BRANCH" "$DEEPSEEK_REPO_URL" /tmp/codewhale-tui git clone --branch "$DEEPSEEK_BRANCH" "$DEEPSEEK_REPO_URL" /tmp/codewhale
cd /tmp/codewhale-tui cd /tmp/codewhale
sudo DEEPSEEK_REPO_URL="$DEEPSEEK_REPO_URL" \ sudo DEEPSEEK_REPO_URL="$DEEPSEEK_REPO_URL" \
DEEPSEEK_REPO_BRANCH="$DEEPSEEK_BRANCH" \ DEEPSEEK_REPO_BRANCH="$DEEPSEEK_BRANCH" \
bash scripts/tencent-lighthouse/bootstrap-ubuntu.sh 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. 1. Run bridge validation/tests and lightweight release-version checks.
2. SSH to Lighthouse with a deploy key stored as a CNB secret. 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. 4. Rebuild/install both binaries.
5. Reinstall/restart systemd services. 5. Reinstall/restart systemd services.
6. Run `scripts/tencent-lighthouse/doctor.sh`. 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 ```text
CNB mirror or GitHub branch CNB mirror or GitHub branch
-> /opt/whalebro/codewhale-tui -> /opt/whalebro/codewhale
Feishu/Lark mobile app Feishu/Lark mobile app
-> Feishu/Lark long-connection bot -> Feishu/Lark long-connection bot
-> codewhale-feishu-bridge systemd service -> codewhale-feishu-bridge systemd service
-> http://127.0.0.1:7878 codewhale serve --http -> http://127.0.0.1:7878 codewhale serve --http
-> /opt/whalebro -> /opt/whalebro
-> codewhale-tui/ -> codewhale/
Optional public edge: Optional public edge:
EdgeOne -> Caddy/Nginx public site on Lighthouse EdgeOne -> Caddy/Nginx public site on Lighthouse
@@ -31,11 +31,11 @@ HTTP service, not the runtime API.
## Remote Whalebro Workspace ## Remote Whalebro Workspace
Use `/opt/whalebro` as the VPS workspace root. The first-class checkout is Use `/opt/whalebro` as the VPS workspace root. The first-class checkout is
`/opt/whalebro/codewhale-tui`. `/opt/whalebro/codewhale`.
Create these paths first: Create these paths first:
- `/opt/whalebro/codewhale-tui` - `/opt/whalebro/codewhale`
- `/opt/whalebro/worktrees` - `/opt/whalebro/worktrees`
Linux is enough for Rust, Node, and service work. Mac-only release work such 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 update
sudo apt-get install -y git sudo apt-get install -y git
export DEEPSEEK_BRANCH=main export DEEPSEEK_BRANCH=main
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 clone --branch "$DEEPSEEK_BRANCH" "$DEEPSEEK_REPO_URL" /tmp/codewhale-tui git clone --branch "$DEEPSEEK_BRANCH" "$DEEPSEEK_REPO_URL" /tmp/codewhale
cd /tmp/codewhale-tui cd /tmp/codewhale
sudo DEEPSEEK_REPO_URL="$DEEPSEEK_REPO_URL" \ sudo DEEPSEEK_REPO_URL="$DEEPSEEK_REPO_URL" \
DEEPSEEK_REPO_BRANCH="$DEEPSEEK_BRANCH" \ DEEPSEEK_REPO_BRANCH="$DEEPSEEK_BRANCH" \
bash scripts/tencent-lighthouse/bootstrap-ubuntu.sh 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: using it:
```bash ```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" \ git ls-remote "$DEEPSEEK_REPO_URL" \
refs/heads/main \ refs/heads/main \
refs/tags/v0.8.37 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 sh /tmp/rustup-init.sh -y --profile minimal
. "$HOME/.cargo/env" . "$HOME/.cargo/env"
rustup default stable rustup default stable
cd /opt/whalebro/codewhale-tui cd /opt/whalebro/codewhale
cargo install --path crates/cli --locked --force cargo install --path crates/cli --locked --force
cargo install --path crates/tui --locked --force cargo install --path crates/tui --locked --force
exit exit
@@ -138,14 +138,14 @@ exit
Copy and install the bridge/service files: Copy and install the bridge/service files:
```bash ```bash
cd /opt/whalebro/codewhale-tui cd /opt/whalebro/codewhale
sudo bash scripts/tencent-lighthouse/install-services.sh sudo bash scripts/tencent-lighthouse/install-services.sh
``` ```
After editing both env files, validate the bridge/runtime pairing: After editing both env files, validate the bridge/runtime pairing:
```bash ```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 \ --env /etc/deepseek/feishu-bridge.env \
--runtime-env /etc/deepseek/runtime.env \ --runtime-env /etc/deepseek/runtime.env \
--workspace-root /opt/whalebro \ --workspace-root /opt/whalebro \
@@ -196,7 +196,7 @@ sudo journalctl -u codewhale-feishu-bridge -f
Run the Lighthouse doctor after both services are configured: Run the Lighthouse doctor after both services are configured:
```bash ```bash
cd /opt/whalebro/codewhale-tui cd /opt/whalebro/codewhale
sudo bash scripts/tencent-lighthouse/doctor.sh 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. - Keep the Lighthouse firewall focused on SSH for this setup.
- Use SSH key auth. - Use SSH key auth.
- Use `tmux` for emergency terminal work from Blink/Termius. - 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. phone.
+8 -3
View File
@@ -39,15 +39,20 @@
{ {
packages = forEachSystem ( packages = forEachSystem (
{ pkgs, system }: { pkgs, system }:
{ let
default = self.packages.${system}.deepseek-tui; codewhale = pkgs.callPackage ./nix/package.nix {
deepseek-tui = pkgs.callPackage ./nix/package.nix {
inherit rev; inherit rev;
rustPlatform = pkgs.makeRustPlatform { rustPlatform = pkgs.makeRustPlatform {
cargo = pkgs.rustToolchain; cargo = pkgs.rustToolchain;
rustc = 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_CHAT_ALLOWLIST=
DEEPSEEK_ALLOW_UNLISTED=false 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_ALLOW_GROUPS=false
FEISHU_REQUIRE_PREFIX_IN_GROUP=true FEISHU_REQUIRE_PREFIX_IN_GROUP=true
FEISHU_GROUP_PREFIX=/ds FEISHU_GROUP_PREFIX=/ds
+5 -5
View File
@@ -1,12 +1,12 @@
# Feishu / Lark Bridge # 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 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. mode, so the first version does not need a public webhook URL.
Security model: 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`. - `/v1/*` runtime calls use `DEEPSEEK_RUNTIME_TOKEN`.
- Feishu/Lark chats must be allowlisted unless `DEEPSEEK_ALLOW_UNLISTED=true` - Feishu/Lark chats must be allowlisted unless `DEEPSEEK_ALLOW_UNLISTED=true`
is set for first pairing. is set for first pairing.
@@ -17,7 +17,7 @@ Security model:
## Setup ## Setup
```bash ```bash
cd /opt/deepseek/bridge cd /opt/codewhale/bridge
npm install --omit=dev npm install --omit=dev
cp .env.example /etc/deepseek/feishu-bridge.env cp .env.example /etc/deepseek/feishu-bridge.env
sudoedit /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: For a Tencent Lighthouse deployment, use:
```bash ```bash
sudo systemctl enable --now deepseek-runtime deepseek-feishu-bridge sudo systemctl enable --now codewhale-runtime codewhale-feishu-bridge
sudo journalctl -u deepseek-feishu-bridge -f sudo journalctl -u codewhale-feishu-bridge -f
``` ```
## Commands ## Commands
+2 -2
View File
@@ -1,11 +1,11 @@
{ {
"name": "@deepseek-tui/feishu-bridge", "name": "@codewhale/feishu-bridge",
"version": "0.1.0", "version": "0.1.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@deepseek-tui/feishu-bridge", "name": "@codewhale/feishu-bridge",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@larksuiteoapi/node-sdk": "^1.52.0" "@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", "version": "0.1.0",
"private": true, "private": true,
"type": "module", "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", "main": "src/index.mjs",
"scripts": { "scripts": {
"start": "node src/index.mjs", "start": "node src/index.mjs",
+1 -1
View File
@@ -99,7 +99,7 @@ const config = {
allowUnlisted: parseBool(process.env.DEEPSEEK_ALLOW_UNLISTED, false), allowUnlisted: parseBool(process.env.DEEPSEEK_ALLOW_UNLISTED, false),
threadMapPath: threadMapPath:
process.env.FEISHU_THREAD_MAP_PATH || 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), allowGroups: parseBool(process.env.FEISHU_ALLOW_GROUPS, false),
requirePrefixInGroup: parseBool(process.env.FEISHU_REQUIRE_PREFIX_IN_GROUP, true), requirePrefixInGroup: parseBool(process.env.FEISHU_REQUIRE_PREFIX_IN_GROUP, true),
groupPrefix: process.env.FEISHU_GROUP_PREFIX || "/ds", 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_WORKSPACE: "/opt/whalebro",
DEEPSEEK_CHAT_ALLOWLIST: "oc_allowed", DEEPSEEK_CHAT_ALLOWLIST: "oc_allowed",
DEEPSEEK_ALLOW_UNLISTED: "false", 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_ALLOW_GROUPS: "false",
FEISHU_REQUIRE_PREFIX_IN_GROUP: "true" 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_RUNTIME_TOKEN: "bridge-token",
DEEPSEEK_WORKSPACE: "/opt/whalebro", DEEPSEEK_WORKSPACE: "/opt/whalebro",
DEEPSEEK_ALLOW_UNLISTED: "true", 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_ALLOW_GROUPS: "true",
FEISHU_REQUIRE_PREFIX_IN_GROUP: "false" FEISHU_REQUIRE_PREFIX_IN_GROUP: "false"
}, },
+5 -5
View File
@@ -15,7 +15,7 @@
rev ? "dirty", rev ? "dirty",
}: }:
rustPlatform.buildRustPackage (finalAttrs: { rustPlatform.buildRustPackage (finalAttrs: {
pname = "deepseek-tui"; pname = "codewhale";
version = "git-${rev}"; version = "git-${rev}";
src = ../.; src = ../.;
@@ -46,9 +46,9 @@ rustPlatform.buildRustPackage (finalAttrs: {
cargoBuildFlags = [ cargoBuildFlags = [
"--package" "--package"
"deepseek-tui-cli" "codewhale-cli"
"--package" "--package"
"deepseek-tui" "codewhale-tui"
]; ];
cargoTestFlags = finalAttrs.cargoBuildFlags ++ [ cargoTestFlags = finalAttrs.cargoBuildFlags ++ [
"--lib" "--lib"
@@ -60,9 +60,9 @@ rustPlatform.buildRustPackage (finalAttrs: {
''; '';
meta = { 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"; homepage = "https://github.com/Hmbown/DeepSeek-TUI";
license = lib.licenses.mit; license = lib.licenses.mit;
mainProgram = "deepseek"; mainProgram = "codewhale";
}; };
}) })
@@ -6,8 +6,8 @@ if [[ "${EUID}" -ne 0 ]]; then
exit 1 exit 1
fi fi
DEEPSEEK_USER="${DEEPSEEK_USER:-deepseek}" DEEPSEEK_USER="${DEEPSEEK_USER:-codewhale}"
DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/deepseek}" DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/codewhale}"
WHALEBRO_ROOT="${WHALEBRO_ROOT:-/opt/whalebro}" WHALEBRO_ROOT="${WHALEBRO_ROOT:-/opt/whalebro}"
REPO_URL="${DEEPSEEK_REPO_URL:-https://github.com/Hmbown/DeepSeek-TUI.git}" REPO_URL="${DEEPSEEK_REPO_URL:-https://github.com/Hmbown/DeepSeek-TUI.git}"
WHALEBRO_EXTRA_REPOS="${WHALEBRO_EXTRA_REPOS:-}" 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}"
install -d -o "${DEEPSEEK_USER}" -g "${DEEPSEEK_USER}" "${WHALEBRO_ROOT}/worktrees" 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 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 if [[ ! -d "${WHALEBRO_ROOT}/codewhale/.git" ]]; then
sudo -u "${DEEPSEEK_USER}" git clone --branch "${REPO_BRANCH}" "${REPO_URL}" "${WHALEBRO_ROOT}/deepseek-tui" sudo -u "${DEEPSEEK_USER}" git clone --branch "${REPO_BRANCH}" "${REPO_URL}" "${WHALEBRO_ROOT}/codewhale"
fi fi
for repo_spec in ${WHALEBRO_EXTRA_REPOS}; do for repo_spec in ${WHALEBRO_EXTRA_REPOS}; do
@@ -94,7 +94,7 @@ DEEPSEEK_TRUST_MODE=false
DEEPSEEK_AUTO_APPROVE=false DEEPSEEK_AUTO_APPROVE=false
DEEPSEEK_CHAT_ALLOWLIST= DEEPSEEK_CHAT_ALLOWLIST=
DEEPSEEK_ALLOW_UNLISTED=false 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_ALLOW_GROUPS=false
FEISHU_REQUIRE_PREFIX_IN_GROUP=true FEISHU_REQUIRE_PREFIX_IN_GROUP=true
FEISHU_GROUP_PREFIX=/ds FEISHU_GROUP_PREFIX=/ds
@@ -116,7 +116,7 @@ Next:
1. Install Rust 1.88+ for ${DEEPSEEK_USER}; rustup is the usual path. 1. Install Rust 1.88+ for ${DEEPSEEK_USER}; rustup is the usual path.
2. Build/install both binaries: 2. Build/install both binaries:
sudo -iu ${DEEPSEEK_USER} sudo -iu ${DEEPSEEK_USER}
cd ${WHALEBRO_ROOT}/deepseek-tui cd ${WHALEBRO_ROOT}/codewhale
cargo install --path crates/cli --locked --force cargo install --path crates/cli --locked --force
cargo install --path crates/tui --locked --force cargo install --path crates/tui --locked --force
3. Copy integrations/feishu-bridge to ${DEEPSEEK_ROOT}/bridge and run npm install. 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 #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
DEEPSEEK_USER="${DEEPSEEK_USER:-deepseek}" DEEPSEEK_USER="${DEEPSEEK_USER:-codewhale}"
DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/deepseek}" DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/codewhale}"
WHALEBRO_ROOT="${WHALEBRO_ROOT:-/opt/whalebro}" WHALEBRO_ROOT="${WHALEBRO_ROOT:-/opt/whalebro}"
RUNTIME_ENV="${RUNTIME_ENV:-/etc/deepseek/runtime.env}" RUNTIME_ENV="${RUNTIME_ENV:-/etc/deepseek/runtime.env}"
BRIDGE_ENV="${BRIDGE_ENV:-/etc/deepseek/feishu-bridge.env}" BRIDGE_ENV="${BRIDGE_ENV:-/etc/deepseek/feishu-bridge.env}"
BRIDGE_DIR="${BRIDGE_DIR:-${DEEPSEEK_ROOT}/bridge}" BRIDGE_DIR="${BRIDGE_DIR:-${DEEPSEEK_ROOT}/bridge}"
REPO_ROOT="${REPO_ROOT:-${WHALEBRO_ROOT}/deepseek-tui}" REPO_ROOT="${REPO_ROOT:-${WHALEBRO_ROOT}/codewhale}"
failures=0 failures=0
warnings=0 warnings=0
@@ -97,15 +97,15 @@ check_workspace() {
} }
check_binaries() { check_binaries() {
section "DeepSeek binaries" section "Codewhale binaries"
local cargo_bin="/home/${DEEPSEEK_USER}/.cargo/bin" local cargo_bin="/home/${DEEPSEEK_USER}/.cargo/bin"
local deepseek="${cargo_bin}/deepseek" local codewhale="${cargo_bin}/codewhale"
local tui="${cargo_bin}/deepseek-tui" local tui="${cargo_bin}/codewhale-tui"
if [[ -x "${deepseek}" ]]; then if [[ -x "${codewhale}" ]]; then
pass "${deepseek} is executable" pass "${codewhale} is executable"
"${deepseek}" --version 2>/dev/null | sed 's/^/[info] deepseek version: /' || warn "deepseek --version failed" "${codewhale}" --version 2>/dev/null | sed 's/^/[info] codewhale version: /' || warn "codewhale --version failed"
else else
fail "${deepseek} is missing or not executable" fail "${codewhale} is missing or not executable"
fi fi
if [[ -x "${tui}" ]]; then if [[ -x "${tui}" ]]; then
pass "${tui} is executable" pass "${tui} is executable"
@@ -205,7 +205,7 @@ check_systemd() {
warn "systemd is not available in this environment" warn "systemd is not available in this environment"
return return
fi 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" ]] \ [[ -f "/etc/systemd/system/${unit}.service" ]] \
&& pass "${unit}.service is installed" \ && pass "${unit}.service is installed" \
|| fail "${unit}.service is missing" || fail "${unit}.service is missing"
+10 -10
View File
@@ -7,8 +7,8 @@ if [[ "${EUID}" -ne 0 ]]; then
fi fi
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
DEEPSEEK_USER="${DEEPSEEK_USER:-deepseek}" DEEPSEEK_USER="${DEEPSEEK_USER:-codewhale}"
DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/deepseek}" DEEPSEEK_ROOT="${DEEPSEEK_ROOT:-/opt/codewhale}"
install -d -o "${DEEPSEEK_USER}" -g "${DEEPSEEK_USER}" "${DEEPSEEK_ROOT}/bridge" install -d -o "${DEEPSEEK_USER}" -g "${DEEPSEEK_USER}" "${DEEPSEEK_ROOT}/bridge"
rsync -a --delete \ rsync -a --delete \
@@ -23,11 +23,11 @@ else
sudo -u "${DEEPSEEK_USER}" npm --prefix "${DEEPSEEK_ROOT}/bridge" install --omit=dev sudo -u "${DEEPSEEK_USER}" npm --prefix "${DEEPSEEK_ROOT}/bridge" install --omit=dev
fi 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/codewhale-runtime.service" /etc/systemd/system/codewhale-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-feishu-bridge.service" /etc/systemd/system/codewhale-feishu-bridge.service
systemctl daemon-reload systemctl daemon-reload
systemctl enable deepseek-runtime deepseek-feishu-bridge systemctl enable codewhale-runtime codewhale-feishu-bridge
cat <<'EOF' cat <<'EOF'
Services installed but not started. Services installed but not started.
@@ -35,11 +35,11 @@ Services installed but not started.
Before starting, verify: Before starting, verify:
/etc/deepseek/runtime.env /etc/deepseek/runtime.env
/etc/deepseek/feishu-bridge.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: Then run:
sudo systemctl start deepseek-runtime sudo systemctl start codewhale-runtime
sudo systemctl start deepseek-feishu-bridge sudo systemctl start codewhale-feishu-bridge
sudo bash /opt/whalebro/deepseek-tui/scripts/tencent-lighthouse/doctor.sh sudo bash /opt/whalebro/codewhale/scripts/tencent-lighthouse/doctor.sh
sudo journalctl -u deepseek-feishu-bridge -f sudo journalctl -u codewhale-feishu-bridge -f
EOF EOF