Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
node_modules/
dist/
.env
.env.*
.wacli_auth/
.wwebjs_auth/
.wwebjs_cache/
*.log
*.tsbuildinfo
coverage/
.DS_Store
Thumbs.db
8 changes: 8 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ tsconfig.json
.env.*

# Test files
test/
tests/
__tests__/
*.test.ts
Expand All @@ -20,6 +21,13 @@ __tests__/
.oxlintrc.json
.detect-secrets.cfg
.secrets.baseline
vitest.config.ts

# Assets (README images)
assets/

# Coverage
coverage/

# Git
.git/
Expand Down
149 changes: 75 additions & 74 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ Send a WhatsApp message. Watch your IDE write code.

---


## Why txtcode?

You're on the couch, on the train, or away from your desk but you need to fix a bug, run tests, or scaffold a feature. With **txtcode**, your phone becomes a remote control for your IDE:
Expand All @@ -49,24 +48,30 @@ No port forwarding. No VPN. Just message and code.
<td width="50%">

### Messaging-First

Connect via **6 platforms** : WhatsApp, Telegram, Discord, Slack, Microsoft Teams, and Signal. First user to message is auto-authorized.

### 9 AI Providers

Anthropic, OpenAI, Google Gemini, Mistral, Moonshot, MiniMax, xAI Grok, HuggingFace, and OpenRouter. Hot-switch between them with `/switch`.

### 7 Coding Adapters

Claude Code, Cursor CLI, OpenAI Codex, Gemini CLI, Kiro CLI, OpenCode, and Ollama (local/free). Full IDE control in `/code` mode.

</td>
<td width="50%">

### 9 Built-in Tools

Terminal, process manager, git, file search, HTTP client, environment variables, network diagnostics, cron jobs, and system info all callable by the LLM.

### 13 MCP Servers

Connect GitHub, Brave Search, Puppeteer, PostgreSQL, MongoDB, Redis, Elasticsearch, AWS, GCP, Cloudflare, Vercel, Atlassian, and Supabase as external tools via the Model Context Protocol.

### Session Logging

Per-session logs accessible from the TUI. Follow live, view by index, auto-pruned after 7 days.

</td>
Expand Down Expand Up @@ -99,32 +104,32 @@ That's it. The interactive menu guides you through everything authentication, co

## Supported Platforms

| Platform | Transport | Setup |
|:---|:---|:---|
| **WhatsApp** | QR code pairing | Scan QR in terminal on first run |
| **Telegram** | Bot API | Create bot via [@BotFather](https://t.me/BotFather), paste token |
| **Discord** | Bot gateway | Create app at [discord.com/developers](https://discord.com/developers), paste bot token |
| **Slack** | Socket Mode | Create app at [api.slack.com](https://api.slack.com/apps), enable Socket Mode |
| **Microsoft Teams** | Bot Framework | Register bot at [dev.teams.microsoft.com](https://dev.teams.microsoft.com/bots) |
| **Signal** | signal-cli REST | Run [signal-cli-rest-api](https://github.com/bbernhard/signal-cli-rest-api) via Docker |
| Platform | Transport | Setup |
| :------------------ | :-------------- | :-------------------------------------------------------------------------------------- |
| **WhatsApp** | QR code pairing | Scan QR in terminal on first run |
| **Telegram** | Bot API | Create bot via [@BotFather](https://t.me/BotFather), paste token |
| **Discord** | Bot gateway | Create app at [discord.com/developers](https://discord.com/developers), paste bot token |
| **Slack** | Socket Mode | Create app at [api.slack.com](https://api.slack.com/apps), enable Socket Mode |
| **Microsoft Teams** | Bot Framework | Register bot at [dev.teams.microsoft.com](https://dev.teams.microsoft.com/bots) |
| **Signal** | signal-cli REST | Run [signal-cli-rest-api](https://github.com/bbernhard/signal-cli-rest-api) via Docker |

---

## AI Providers

txtcode supports **9 LLM providers** for chat mode. Configure one or more during setup and hot-switch with `/switch`.

| Provider | Example Models | Notes |
|:---|:---|:---|
| **Anthropic** | `claude-sonnet-4-6`, `claude-opus-4-6` | Claude family |
| **OpenAI** | `gpt-5.2`, `o4-mini`, `gpt-4o` | GPT and o-series |
| **Google Gemini** | `gemini-2.5-pro`, `gemini-2.5-flash` | Gemini family |
| **Mistral** | `mistral-large-latest`, `codestral-latest` | Mistral + Codestral |
| **Moonshot (Kimi)** | `kimi-k2.5`, `moonshot-v1-128k` | Long-context models |
| **MiniMax** | `MiniMax-M2.5`, `MiniMax-M2.1` | MiniMax family |
| **xAI (Grok)** | `grok-4`, `grok-3-fast` | Grok family |
| **HuggingFace** | *Discovered at runtime* | Inference Providers API |
| **OpenRouter** | *Discovered at runtime* | Unified API for 100+ models |
| Provider | Example Models | Notes |
| :------------------ | :----------------------------------------- | :-------------------------- |
| **Anthropic** | `claude-sonnet-4-6`, `claude-opus-4-6` | Claude family |
| **OpenAI** | `gpt-5.2`, `o4-mini`, `gpt-4o` | GPT and o-series |
| **Google Gemini** | `gemini-2.5-pro`, `gemini-2.5-flash` | Gemini family |
| **Mistral** | `mistral-large-latest`, `codestral-latest` | Mistral + Codestral |
| **Moonshot (Kimi)** | `kimi-k2.5`, `moonshot-v1-128k` | Long-context models |
| **MiniMax** | `MiniMax-M2.5`, `MiniMax-M2.1` | MiniMax family |
| **xAI (Grok)** | `grok-4`, `grok-3-fast` | Grok family |
| **HuggingFace** | _Discovered at runtime_ | Inference Providers API |
| **OpenRouter** | _Discovered at runtime_ | Unified API for 100+ models |

All providers support tool calling and LLM can invoke any built-in tool or connected MCP server.

Expand All @@ -134,33 +139,33 @@ All providers support tool calling and LLM can invoke any built-in tool or conne

Use `/code` mode to route messages directly to a coding adapter with full IDE control.

| Adapter | Backend | CLI Required | Notes |
|:---|:---|:---|:---|
| **Claude Code** | Anthropic API | `claude` | Official Claude CLI |
| **Cursor CLI** | Cursor | `cursor` | Headless Cursor |
| **OpenAI Codex** | OpenAI API | `codex` | OpenAI's coding agent |
| **Gemini CLI** | Google AI API | `gemini` | Google's CLI |
| **Kiro CLI** | AWS | `kiro-cli` | AWS Kiro subscription |
| **OpenCode** | Multi-provider | `opencode` | Open-source, multi-provider |
| **Ollama Claude Code** | Local (Ollama) | `ollama` | Free, no API key needed |
| Adapter | Backend | CLI Required | Notes |
| :--------------------- | :------------- | :----------- | :-------------------------- |
| **Claude Code** | Anthropic API | `claude` | Official Claude CLI |
| **Cursor CLI** | Cursor | `cursor` | Headless Cursor |
| **OpenAI Codex** | OpenAI API | `codex` | OpenAI's coding agent |
| **Gemini CLI** | Google AI API | `gemini` | Google's CLI |
| **Kiro CLI** | AWS | `kiro-cli` | AWS Kiro subscription |
| **OpenCode** | Multi-provider | `opencode` | Open-source, multi-provider |
| **Ollama Claude Code** | Local (Ollama) | `ollama` | Free, no API key needed |

---

## Built-in Tools

The primary LLM in chat mode has access to **9 built-in tools** that it can call autonomously:

| Tool | Capabilities |
|:---|:---|
| **Terminal** | Execute shell commands with timeout and output capture |
| **Process** | Manage background processes: list, poll, stream logs, kill, send input |
| **Git** | Full git operations (blocks force-push and credential config for safety) |
| **Search** | File and content search across the project |
| **HTTP** | Make HTTP requests (GET, POST, PUT, DELETE, PATCH, HEAD). Blocks cloud metadata endpoints |
| **Env** | Get, set, list, and delete environment variables. Masks sensitive values |
| **Network** | Ping, DNS lookup, reachability checks, port scanning |
| **Cron** | Create, list, and manage cron jobs |
| **Sysinfo** | CPU, memory, disk, uptime, OS details |
| Tool | Capabilities |
| :----------- | :---------------------------------------------------------------------------------------- |
| **Terminal** | Execute shell commands with timeout and output capture |
| **Process** | Manage background processes: list, poll, stream logs, kill, send input |
| **Git** | Full git operations (blocks force-push and credential config for safety) |
| **Search** | File and content search across the project |
| **HTTP** | Make HTTP requests (GET, POST, PUT, DELETE, PATCH, HEAD). Blocks cloud metadata endpoints |
| **Env** | Get, set, list, and delete environment variables. Masks sensitive values |
| **Network** | Ping, DNS lookup, reachability checks, port scanning |
| **Cron** | Create, list, and manage cron jobs |
| **Sysinfo** | CPU, memory, disk, uptime, OS details |

---

Expand All @@ -170,36 +175,36 @@ txtcode integrates with the **Model Context Protocol** to connect external tool

### Developer Tools

| Server | Transport | Description |
|:---|:---|:---|
| **GitHub** | stdio | Repos, issues, PRs, code search, Actions |
| **Brave Search** | stdio | Web, image, video, and news search |
| **Puppeteer** | stdio | Browser automation, screenshots, form filling |
| Server | Transport | Description |
| :--------------- | :-------- | :-------------------------------------------- |
| **GitHub** | stdio | Repos, issues, PRs, code search, Actions |
| **Brave Search** | stdio | Web, image, video, and news search |
| **Puppeteer** | stdio | Browser automation, screenshots, form filling |

### Databases

| Server | Transport | Description |
|:---|:---|:---|
| **PostgreSQL** | stdio | Read-only SQL queries and schema inspection |
| **MongoDB** | stdio | CRUD, indexes, vector search, Atlas management |
| **Redis** | stdio | Data structures, caching, vectors, pub/sub |
| **Elasticsearch** | stdio | Index management, search queries, cluster ops |
| **Supabase** | HTTP | Postgres, Auth, Storage, Edge Functions |
| Server | Transport | Description |
| :---------------- | :-------- | :--------------------------------------------- |
| **PostgreSQL** | stdio | Read-only SQL queries and schema inspection |
| **MongoDB** | stdio | CRUD, indexes, vector search, Atlas management |
| **Redis** | stdio | Data structures, caching, vectors, pub/sub |
| **Elasticsearch** | stdio | Index management, search queries, cluster ops |
| **Supabase** | HTTP | Postgres, Auth, Storage, Edge Functions |

### Cloud

| Server | Transport | Description |
|:---|:---|:---|
| **AWS** | stdio | S3, Lambda, EKS, CDK, CloudFormation, 60+ services |
| **Google Cloud** | HTTP | BigQuery, GKE, Compute, Storage, Firebase |
| **Cloudflare** | HTTP | Workers, R2, DNS, Zero Trust, 2500+ endpoints |
| **Vercel** | HTTP | Deployments, domains, env vars, logs |
| Server | Transport | Description |
| :--------------- | :-------- | :------------------------------------------------- |
| **AWS** | stdio | S3, Lambda, EKS, CDK, CloudFormation, 60+ services |
| **Google Cloud** | HTTP | BigQuery, GKE, Compute, Storage, Firebase |
| **Cloudflare** | HTTP | Workers, R2, DNS, Zero Trust, 2500+ endpoints |
| **Vercel** | HTTP | Deployments, domains, env vars, logs |

### Productivity

| Server | Transport | Description |
|:---|:---|:---|
| **Atlassian** | HTTP | Jira issues, Confluence pages, Compass components |
| Server | Transport | Description |
| :------------ | :-------- | :------------------------------------------------ |
| **Atlassian** | HTTP | Jira issues, Confluence pages, Compass components |

> **stdio** = local process, **HTTP** = remote Streamable HTTP endpoint. You can also add custom MCP servers via **Configuration** &rarr; **Manage MCP Servers**.

Expand All @@ -209,19 +214,18 @@ txtcode integrates with the **Model Context Protocol** to connect external tool

Send these commands in any messaging app while connected:

| Command | Description |
|:---|:---|
| `/chat` | Switch to **Chat mode** to send messages to primary LLM with tools *(default)* |
| `/code` | Switch to **Code mode** to send messages to coding adapter (full IDE control) |
| `/switch` | Switch primary LLM provider or coding adapter on the fly |
| `/cli-model` | Change the model used by the current coding adapter |
| `/cancel` | Cancel the currently running command |
| `/status` | Show adapter connection and current configuration |
| `/help` | Show available commands |
| Command | Description |
| :----------- | :----------------------------------------------------------------------------- |
| `/chat` | Switch to **Chat mode** to send messages to primary LLM with tools _(default)_ |
| `/code` | Switch to **Code mode** to send messages to coding adapter (full IDE control) |
| `/switch` | Switch primary LLM provider or coding adapter on the fly |
| `/cli-model` | Change the model used by the current coding adapter |
| `/cancel` | Cancel the currently running command |
| `/status` | Show adapter connection and current configuration |
| `/help` | Show available commands |

---


## Configuration

Config is stored at **`~/.txtcode/config.json`**. API keys and tokens are stored in your OS keychain (via `keytar`), never in the config file.
Expand Down Expand Up @@ -298,9 +302,6 @@ Verbose and debug output goes to the log file; the terminal shows only key statu

---



## License

Apache-2.0

27 changes: 18 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,25 @@
"text-based-coding",
"whatsapp"
],
"license": "MIT",
"author": "",
"homepage": "https://github.com/IMvision12/txtcode#readme",
"bugs": {
"url": "https://github.com/IMvision12/txtcode/issues"
},
"license": "Apache-2.0",
"author": "Gitesh Chawda (IMvision12)",
"repository": {
"type": "git",
"url": "https://github.com/IMvision12/txtcode.git"
},
"bin": {
"txtcode": "dist/cli/index.js"
},
"main": "dist/index.js",
"files": [
"dist/",
"LICENSE",
"README.md"
],
"main": "dist/cli/index.js",
"scripts": {
"build": "tsc && npm run copy-data",
"copy-data": "node -e \"require('fs').cpSync('src/data', 'dist/data', {recursive: true})\"",
Expand All @@ -37,7 +50,7 @@
"lint": "oxlint",
"lint:fix": "oxlint --fix",
"prepublishOnly": "npm run build",
"start": "node dist/cli.js",
"start": "node dist/cli/index.js",
"test": "vitest run",
"test:watch": "vitest"
},
Expand All @@ -51,9 +64,7 @@
"chalk": "^4.1.2",
"discord.js": "^14.25.1",
"dotenv": "^16.3.1",
"gradient-string": "^3.0.0",
"keytar": "^7.9.0",
"link-preview-js": "^3.2.0",
"openai": "^6.19.0",
"qrcode-terminal": "^0.12.0",
"telegraf": "^4.15.0"
Expand All @@ -66,9 +77,7 @@
"typescript": "^5.3.3",
"vitest": "^4.0.18"
},
"preferGlobal": true,
"engines": {
"node": ">=20.0.0",
"npm": ">=10.0.0"
"node": ">=20.0.0"
}
}
10 changes: 8 additions & 2 deletions src/cli/commands/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -813,9 +813,15 @@ export async function authCommand() {
await setBotToken("signal-phone", signalPhoneNumber);
await setBotToken("signal-api-url", signalCliRestUrl);
}
} catch {
} catch (keychainError) {
console.log(chalk.red("\n[ERROR] Failed to store credentials in keychain"));
console.log(chalk.yellow("Falling back to encrypted file storage...\n"));
console.log(chalk.yellow("Credentials will be unavailable until keychain access is restored."));
console.log(
chalk.gray(
`Details: ${keychainError instanceof Error ? keychainError.message : String(keychainError)}`,
),
);
console.log(chalk.gray("Re-run 'txtcode' → 'Authenticate' to retry.\n"));
}

// Build providers object dynamically
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export async function startCommand(_options: { daemon?: boolean }) {
process.env.IDE_PORT = String(config.idePort);
process.env.AI_API_KEY = apiKey;
process.env.AI_PROVIDER = config.aiProvider;
process.env.AI_MODEL = config.aiModel;
process.env.AI_MODEL = config.aiModel || "";
process.env.PROJECT_PATH = config.projectPath || process.cwd();
process.env.OLLAMA_MODEL = config.ollamaModel || "gpt-oss:20b";
process.env.CLAUDE_MODEL = config.claudeModel || "sonnet";
Expand Down
8 changes: 4 additions & 4 deletions src/core/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ export class Router {
}

async shutdownMCP(): Promise<void> {
for (const serverId of this.mcpBridge.getConnectedServerIds()) {
this.toolRegistry.removeMCPTools(serverId);
}
await this.mcpBridge.disconnectAll();
}

Expand Down Expand Up @@ -313,10 +316,7 @@ export class Router {

return result;
} finally {
// Clear abort controller after command completes
if (this.currentAbortController && !signal.aborted) {
this.currentAbortController = null;
}
this.currentAbortController = null;
}
}

Expand Down
Loading