WEIPING_WHALE

mcp
Security Audit
Fail
Health Pass
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Community trust — 131 GitHub stars
Code Fail
  • process.env — Environment variable access in scripts/demo.mjs
  • spawnSync — Synchronous process spawning in scripts/e2e-lsp.mjs
  • process.env — Environment variable access in scripts/e2e-lsp.mjs
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

A small terminal coding agent for DeepSeek models: it reads your repository, runs commands after asking, proposes edits as patches you apply, and checkpoints the workspace around every turn so any turn can be undone.

README.md

WEIPING_WHALE

A small terminal coding agent for DeepSeek models: it reads your repository, runs
commands after asking, proposes edits as patches you apply, and checkpoints the
workspace around every turn so any turn can be undone.

It is a TypeScript port of the design of
CodeWhale (formerly deepseek-tui,
MIT), a much larger and more mature Rust agent. The snapshot scheme, session
fork/backtrack, cost footer, auto-routing and prompt layout all come from CodeWhale;
see THIRD_PARTY_NOTICES.md. Not affiliated with DeepSeek.

$ npm run demo          # build output and startup banner left out
session: demo
path: ~/.weiping-whale/sessions/demo.json
━━ test.mjs fails, find the bug and fix it
thinking...
tool execute_bash {"command":"node test.mjs"}
  execute_bash failed in 3471ms
thinking round 2...
tool read_file {"path":"src/slugify.mjs"}
  read_file done in 12ms
thinking round 3...
tool edit_file {"path":"src/slugify.mjs","old_string":"    .replace(/[^a-z0-9]+/g, \"-\");","new_string":"    .replace(/[^a-z0-9]+/g...
  edit_file done in 174ms
thinking round 4...

WEIPING_WHALE
`node test.mjs` fails because slugify("Hello, World!") returns "hello-world-".
The regex turns every run of non-alphanumerics into a dash, including the
trailing "!", and nothing trims dashes at the ends.

I prepared patch 6f52149d, which strips leading and trailing dashes.
Review it with /patches, then /apply 6f52149d.

└ $0.0004 · 6.5k tok · cache 71%
━━ /apply 6f52149d
Applied patch 6f52149d to ~/slugify-demo/src/slugify.mjs
━━ run the tests again
thinking...
tool execute_bash {"command":"node test.mjs"}
  execute_bash done in 2452ms
thinking round 2...

WEIPING_WHALE
Ran `node test.mjs`: 2 tests passed

└ $0.0005 · 10.4k tok · cache 80%
━━ /snapshots
4e7b557da997  2026-10-22 04:59:01  post-turn:2
ecaf8c885847  2026-10-22 04:58:55  pre-turn:2
7f520501f32a  2026-10-22 04:58:51  post-turn:1
507aabc12156  2026-10-22 04:58:42  pre-turn:1

That session is real except for the model. npm run demo starts
scripts/mock-deepseek.mjs, a fake DeepSeek endpoint
whose replies are scripted, and points the built CLI at it. The shell command, the
file read, the patch preview, the snapshots and the session file are produced by the
actual tool code; the token counts are the mock's rough estimate (4 characters per
token) priced at the default flash rates. The same session as an image is in
docs/demo.png.

Why I built it

I wanted to understand how tools like Claude Code, Codex and CodeWhale work, not just
use them. Porting CodeWhale to a language I read every day, at a size I can hold in my
head, was the most direct way. If you just want a coding agent, use CodeWhale itself
(OS sandboxing, more language servers, more providers), Aider,
or one of the vendor CLIs. This repo is for reading and changing the loop.

Install

Requires Node.js 22.18 or newer and git. The package is not published on npm.

git clone https://github.com/appleweiping/WEIPING_WHALE.git
cd WEIPING_WHALE
npm ci
npm run demo            # builds, then replays the session above; no API key needed
npm link                # puts `wwhale` and `weiping-whale` on your PATH

With a DeepSeek key:

export DEEPSEEK_API_KEY=sk-...
wwhale --doctor         # checks config, key source and paths
wwhale                  # REPL in the current directory
wwhale -t "summarize the architecture of this repo"

Inside the REPL, /patches and /apply <id> review edits, /approve <id> runs a held
shell command, /undo rolls the workspace back one turn, and /cost shows spend.
The full list of commands, config keys and safety profiles is in
docs/usage.md.

How a coding agent works in ~8.5k lines

src/ is about 8,500 lines of TypeScript (wc -l src/*.ts src/*/*.ts). One turn
looks like this:

flowchart TD
    P["System prompt<br/>prompts/base.md + AGENTS.md/CLAUDE.md<br/>+ repo map + skills<br/>src/prompts/assemble.ts"] --> L
    U["You: REPL, -t task or HTTP API<br/>src/index.ts"] --> S1["pre-turn snapshot<br/>src/snapshot/"]
    S1 --> R{"--model auto?<br/>src/router.ts"}
    R --> L["Agent loop<br/>src/agent.ts"]
    L -->|"messages + tool schemas"| M["DeepSeek chat API<br/>src/llm/deepseek.ts"]
    M -->|"usage"| C["Cost and cache-hit tracker<br/>src/cost.ts"]
    M -->|"tool_calls"| T["Tool registry<br/>src/tools/registry.ts"]
    T --> B["Built-in tools<br/>read/write/edit, glob/grep, bash,<br/>todo, revert_turn, sub-agents"]
    T --> X["MCP servers<br/>src/mcp/"]
    B --> G["Approval queue and patch previews<br/>src/safety/"]
    G -->|"tool results"| L
    X -->|"tool results"| L
    M -->|"plain answer"| S2["post-turn snapshot<br/>save session JSON<br/>src/session.ts"]
  1. Prompt. src/prompts/assemble.ts builds one system
    message, most static part first so DeepSeek's prefix cache keeps hitting:
    prompts/base.md, the project's AGENTS.md/CLAUDE.md, a
    size-limited map of tracked files and their top-level symbols
    (src/context/repo-map.ts), and the list of skills.
  2. Checkpoint. Before the turn, src/snapshot/repo.ts
    commits the whole workspace into a separate git repository under
    ~/.weiping-whale/snapshots/, passing --git-dir and --work-tree explicitly so
    your own .git is never touched. /undo checks that tree back out.
  3. Routing. With --model auto, src/router.ts picks flash or
    pro and the thinking level from keywords in your message. No extra API call.
  4. The loop. Agent.complete() sends the messages plus every tool
    schema, executes each returned tool call, appends the results and asks again,
    until the model answers without tool calls or max_iterations is reached. The
    loop and its tool dispatcher are about 80 lines; most of the code is the tools
    and bookkeeping around it.
  5. Tools and safety. Built-in tools live in src/tools/. Shell
    commands are matched against two regex lists in
    src/safety/approval.ts: broad recursive deletes, disk
    and shutdown commands are always blocked; deletes, moves, redirections, package
    installs, force-pushes and ssh wait for /approve; everything else runs. In the
    default mode edit_file and write_file only create a preview
    (src/safety/patches.ts) until you /apply it. MCP
    tools come from the official SDK client in src/mcp/client.ts
    and are namespaced per server.
  6. Cost. Every response's usage goes to src/cost.ts, which
    prices cache-hit and cache-miss input tokens separately; the footer turns yellow
    or red when the cache-hit ratio drops, which usually means the context was
    reshuffled.
  7. Sessions. After the turn the message list is saved as JSON
    (src/session.ts). /fork copies it into a new session,
    /backtrack n cuts it just before the n-th last user message, and /compact
    (src/compaction.ts) folds old messages into a summary while
    keeping tool calls paired with their results.
  8. Sub-agents. agent_open starts another Agent with a copy of the config
    (src/tools/subagent.ts); the pool and nesting depth are
    capped.

The terminal UI (src/ui/terminal.ts), LSP diagnostics after
edits (src/lsp/) and the optional --serve HTTP/SSE API
(src/server/runtime-api.ts) sit around this core.

Tests

npm run typecheck
npm test

npm test builds the CLI and runs 18 end-to-end scripts in scripts/
(snapshots, sessions, cost, compaction, routing, MCP against a fake server, the HTTP
API, the full agent loop against the mock model, and more), then packs the tarball,
installs it in a temp directory and runs both binaries. Nothing calls the real
DeepSeek API. CI runs the same on Ubuntu and Windows.

Limitations

  • Shell safety is approval prompts plus pattern matching, not an OS sandbox. A
    command you approve runs with your permissions.
  • The client targets DeepSeek's OpenAI-compatible chat API; other endpoints set via
    base_url are untested. The default prices in src/cost.ts will drift; override
    them with [pricing] in the config.
  • LSP diagnostics cover TypeScript/JavaScript and Python, and only if the language
    servers are installed.
  • The demo and tests prove the plumbing, not the quality of the model's edits.

License

MIT, see LICENSE. CodeWhale's MIT notice is in
THIRD_PARTY_NOTICES.md.

Reviews (0)

No results found