diff --git a/.gitignore b/.gitignore
index 010508bd..88cb49a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,6 +55,7 @@ AI_HANDOFF.md
result.json
count_deps.py
project_overhaul_prompt.md
+prompt_for_release_agent.md
.codex/
docs/rlm-paper.txt
diff --git a/README.md b/README.md
index a35e0860..b12b6bbb 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,7 @@ A terminal-native TUI and CLI for [DeepSeek](https://platform.deepseek.com) mode
[](https://github.com/Hmbown/DeepSeek-TUI/actions/workflows/ci.yml)
[](https://crates.io/crates/deepseek-tui)
+[](https://www.npmjs.com/package/deepseek-tui)
@@ -25,17 +26,29 @@ Three modes:
## Install
+```bash
+# Recommended — no Rust toolchain needed
+npm install -g deepseek-tui
+```
+
+This downloads prebuilt binaries for your platform (macOS, Linux, Windows). After install, both `deepseek` and `deepseek-tui` commands are available.
+
+
+Other install methods
+
```bash
# From crates.io (requires Rust 1.85+)
cargo install deepseek-tui --locked
-# Or from source
+# From source
git clone https://github.com/Hmbown/DeepSeek-TUI.git
cd DeepSeek-TUI
cargo install --path crates/tui --locked # TUI (interactive terminal)
cargo install --path crates/cli --locked # CLI (dispatcher + server)
```
+
+
## Setup
Create `~/.deepseek/config.toml`:
diff --git a/npm/deepseek-tui/.gitignore b/npm/deepseek-tui/.gitignore
new file mode 100644
index 00000000..f98d9c9f
--- /dev/null
+++ b/npm/deepseek-tui/.gitignore
@@ -0,0 +1 @@
+bin/downloads/
diff --git a/npm/deepseek-tui/README.md b/npm/deepseek-tui/README.md
new file mode 100644
index 00000000..4bcc173c
--- /dev/null
+++ b/npm/deepseek-tui/README.md
@@ -0,0 +1,31 @@
+# deepseek-tui
+
+This package installs the `deepseek` and `deepseek-tui` binaries from the
+`DeepSeek-TUI` GitHub release artifacts and exposes them as Node-compatible
+console entry points.
+
+## Install
+
+```bash
+npm install deepseek-tui
+# or
+pnpm add deepseek-tui
+```
+
+This runs `postinstall`, downloads the platform-specific binaries for version
+`0.3.28`, and makes `deepseek` and `deepseek-tui` available on your PATH.
+
+## Supported platforms
+
+- Linux x64
+- macOS x64 / arm64
+- Windows x64
+
+## Notes
+
+- Binaries come directly from release assets in
+ `https://github.com/Hmbown/DeepSeek-TUI/releases`.
+- Set `DEEPSEEK_VERSION` to install a different release version (defaults to package version).
+- Set `DEEPSEEK_GITHUB_REPO` to override the repo source (defaults to `Hmbown/DeepSeek-TUI`).
+- Set `DEEPSEEK_TUI_FORCE_DOWNLOAD=1` to force download even when the cached binary is already present.
+- Set `DEEPSEEK_TUI_DISABLE_INSTALL=1` to skip install-time download.
diff --git a/npm/deepseek-tui/bin/deepseek-tui.js b/npm/deepseek-tui/bin/deepseek-tui.js
new file mode 100755
index 00000000..00d81883
--- /dev/null
+++ b/npm/deepseek-tui/bin/deepseek-tui.js
@@ -0,0 +1,8 @@
+#!/usr/bin/env node
+
+const { runDeepseekTui } = require("../scripts/run");
+
+runDeepseekTui().catch((error) => {
+ console.error("Failed to start deepseek-tui:", error.message);
+ process.exit(1);
+});
diff --git a/npm/deepseek-tui/bin/deepseek.js b/npm/deepseek-tui/bin/deepseek.js
new file mode 100755
index 00000000..c0aaf5a6
--- /dev/null
+++ b/npm/deepseek-tui/bin/deepseek.js
@@ -0,0 +1,8 @@
+#!/usr/bin/env node
+
+const { runDeepseek } = require("../scripts/run");
+
+runDeepseek().catch((error) => {
+ console.error("Failed to start deepseek:", error.message);
+ process.exit(1);
+});
diff --git a/npm/deepseek-tui/package.json b/npm/deepseek-tui/package.json
new file mode 100644
index 00000000..6fb07f71
--- /dev/null
+++ b/npm/deepseek-tui/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "deepseek-tui",
+ "version": "0.3.28",
+ "description": "Install and run deepseek and deepseek-tui binaries from GitHub release artifacts.",
+ "author": "Hmbown",
+ "license": "MIT",
+ "homepage": "https://github.com/Hmbown/DeepSeek-TUI",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/Hmbown/DeepSeek-TUI.git"
+ },
+ "bugs": {
+ "url": "https://github.com/Hmbown/DeepSeek-TUI/issues"
+ },
+ "keywords": [
+ "deepseek",
+ "cli",
+ "tui",
+ "rust",
+ "binary",
+ "terminal"
+ ],
+ "type": "commonjs",
+ "bin": {
+ "deepseek": "bin/deepseek.js",
+ "deepseek-tui": "bin/deepseek-tui.js"
+ },
+ "scripts": {
+ "postinstall": "node scripts/install.js",
+ "prepack": "node scripts/install.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "preferGlobal": true,
+ "files": [
+ "bin/*.js",
+ "scripts/*.js",
+ "README.md",
+ "package.json"
+ ]
+}
diff --git a/npm/deepseek-tui/scripts/artifacts.js b/npm/deepseek-tui/scripts/artifacts.js
new file mode 100644
index 00000000..c79ad352
--- /dev/null
+++ b/npm/deepseek-tui/scripts/artifacts.js
@@ -0,0 +1,53 @@
+const path = require("path");
+const os = require("os");
+
+const ASSET_MATRIX = {
+ linux: {
+ x64: ["deepseek-linux-x64", "deepseek-tui-linux-x64"],
+ default: ["deepseek-linux-x64", "deepseek-tui-linux-x64"],
+ },
+ darwin: {
+ x64: ["deepseek-macos-x64", "deepseek-tui-macos-x64"],
+ arm64: ["deepseek-macos-arm64", "deepseek-tui-macos-arm64"],
+ default: ["deepseek-macos-x64", "deepseek-tui-macos-x64"],
+ },
+ win32: {
+ x64: ["deepseek-windows-x64.exe", "deepseek-tui-windows-x64.exe"],
+ default: ["deepseek-windows-x64.exe", "deepseek-tui-windows-x64.exe"],
+ },
+};
+
+function detectBinaryNames() {
+ const platform = os.platform();
+ const arch = os.arch();
+ const defaults = ASSET_MATRIX[platform];
+ if (!defaults) {
+ throw new Error(`Unsupported platform: ${platform}`);
+ }
+ const pair = defaults[arch] || defaults.default;
+ return {
+ platform,
+ arch,
+ deepseek: pair[0],
+ tui: pair[1],
+ };
+}
+
+function executableName(base, platform) {
+ return platform === "win32" ? `${base}.exe` : base;
+}
+
+function releaseAssetUrl(baseName, version, repo = "Hmbown/DeepSeek-TUI") {
+ return `https://github.com/${repo}/releases/download/v${version}/${baseName}`;
+}
+
+function releaseBinaryDirectory() {
+ return path.join(__dirname, "..", "bin", "downloads");
+}
+
+module.exports = {
+ detectBinaryNames,
+ executableName,
+ releaseAssetUrl,
+ releaseBinaryDirectory,
+};
diff --git a/npm/deepseek-tui/scripts/install.js b/npm/deepseek-tui/scripts/install.js
new file mode 100644
index 00000000..2bd6a358
--- /dev/null
+++ b/npm/deepseek-tui/scripts/install.js
@@ -0,0 +1,142 @@
+const fs = require("fs");
+const https = require("https");
+const http = require("http");
+const { mkdir, chmod, stat, rename, readFile, writeFile } = fs.promises;
+const { createWriteStream } = fs;
+const { pipeline } = require("stream/promises");
+const path = require("path");
+
+const {
+ detectBinaryNames,
+ releaseAssetUrl,
+ releaseBinaryDirectory,
+} = require("./artifacts");
+
+function resolvePackageVersion() {
+ const pkg = require("../package.json");
+ return process.env.DEEPSEEK_TUI_VERSION || process.env.DEEPSEEK_VERSION || pkg.version;
+}
+
+function resolveRepo() {
+ return process.env.DEEPSEEK_TUI_GITHUB_REPO || process.env.DEEPSEEK_GITHUB_REPO || "Hmbown/DeepSeek-TUI";
+}
+
+function binaryPaths() {
+ const { deepseek, tui } = detectBinaryNames();
+ const releaseDir = releaseBinaryDirectory();
+ return {
+ deepseek: {
+ asset: deepseek,
+ target: path.join(releaseDir, process.platform === "win32" ? "deepseek.exe" : "deepseek"),
+ },
+ tui: {
+ asset: tui,
+ target: path.join(releaseDir, process.platform === "win32" ? "deepseek-tui.exe" : "deepseek-tui"),
+ },
+ };
+}
+
+async function httpGet(url) {
+ const client = url.startsWith("https:") ? https : http;
+ const response = await new Promise((resolve, reject) => {
+ client.get(url, (res) => {
+ const status = res.statusCode || 0;
+ if (status >= 300 && status < 400 && res.headers.location) {
+ resolve({ redirect: res.headers.location, response: null });
+ return;
+ }
+ if (status !== 200) {
+ reject(new Error(`Request failed with status ${status}: ${url}`));
+ return;
+ }
+ resolve({ redirect: null, response: res });
+ }).on("error", reject);
+ });
+ return response;
+}
+
+async function download(url, destination) {
+ const resolved = await httpGet(url);
+ if (resolved.redirect) {
+ return download(resolved.redirect, destination);
+ }
+ await mkdir(path.dirname(destination), { recursive: true });
+ await pipeline(resolved.response, createWriteStream(destination));
+}
+
+async function readLocalVersion(file) {
+ return readFile(file, "utf8").catch(() => "");
+}
+
+async function fileExists(file) {
+ try {
+ const result = await stat(file);
+ return result.isFile();
+ } catch {
+ return false;
+ }
+}
+
+async function ensureBinary(targetPath, assetName, version, repo) {
+ const marker = `${targetPath}.version`;
+ const downloadIfNeeded =
+ process.env.DEEPSEEK_TUI_FORCE_DOWNLOAD === "1" || process.env.DEEPSEEK_FORCE_DOWNLOAD === "1";
+ if (!downloadIfNeeded) {
+ const existing = await fileExists(targetPath);
+ if (existing) {
+ const markerVersion = await readLocalVersion(marker);
+ if (markerVersion === String(version)) {
+ return targetPath;
+ }
+ }
+ }
+ const url = releaseAssetUrl(assetName, version, repo);
+ const destination = `${targetPath}.download`;
+ await download(url, destination);
+ if (process.platform !== "win32") {
+ await chmod(destination, 0o755);
+ }
+ await rename(destination, targetPath);
+ await writeFile(marker, String(version), "utf8");
+ return targetPath;
+}
+
+async function run() {
+ if (process.env.DEEPSEEK_TUI_DISABLE_INSTALL === "1" || process.env.DEEPSEEK_DISABLE_INSTALL === "1") {
+ return;
+ }
+ const version = resolvePackageVersion();
+ const repo = resolveRepo();
+ const paths = binaryPaths();
+ const releaseDir = releaseBinaryDirectory();
+ await mkdir(releaseDir, { recursive: true });
+
+ await Promise.all([
+ ensureBinary(paths.deepseek.target, paths.deepseek.asset, version, repo),
+ ensureBinary(paths.tui.target, paths.tui.asset, version, repo),
+ ]);
+}
+
+async function getBinaryPath(name) {
+ await run();
+ const paths = binaryPaths();
+ if (name === "deepseek") {
+ return paths.deepseek.target;
+ }
+ if (name === "deepseek-tui") {
+ return paths.tui.target;
+ }
+ throw new Error(`Unknown binary: ${name}`);
+}
+
+module.exports = {
+ getBinaryPath,
+ run,
+};
+
+if (require.main === module) {
+ run().catch((error) => {
+ console.error("deepseek-tui install failed:", error.message);
+ process.exit(1);
+ });
+}
diff --git a/npm/deepseek-tui/scripts/run.js b/npm/deepseek-tui/scripts/run.js
new file mode 100644
index 00000000..07f18cb5
--- /dev/null
+++ b/npm/deepseek-tui/scripts/run.js
@@ -0,0 +1,36 @@
+const { spawnSync } = require("child_process");
+const { getBinaryPath } = require("./install");
+
+async function run(binaryName) {
+ const binaryPath = await getBinaryPath(binaryName);
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
+ stdio: "inherit",
+ });
+ if (result.error) {
+ throw result.error;
+ }
+ process.exit(result.status ?? 1);
+}
+
+async function runDeepseek() {
+ await run("deepseek");
+}
+
+async function runDeepseekTui() {
+ await run("deepseek-tui");
+}
+
+module.exports = {
+ run,
+ runDeepseek,
+ runDeepseekTui,
+};
+
+if (require.main === module) {
+ const command = process.argv[1] || "";
+ if (command.includes("tui")) {
+ runDeepseekTui();
+ } else {
+ runDeepseek();
+ }
+}