@inetafrica/open-claudia 1.2.8 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +171 -31
- package/bin/cli.js +43 -14
- package/bot.js +5 -2
- package/package.json +1 -1
- package/setup.js +6 -9
package/README.md
CHANGED
|
@@ -7,92 +7,232 @@ Send text, voice notes, screenshots, and files from your phone. Claude Code work
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- **Multi-project sessions** — switch between workspace projects
|
|
10
|
+
- **Per-project conversation history** — auto-resumes last conversation, switch with `/sessions`
|
|
10
11
|
- **Voice notes** — speak instructions, transcribed locally via Whisper
|
|
11
|
-
- **Screenshots** — send UI mockups, errors, or code screenshots
|
|
12
|
-
- **File sharing** — send
|
|
12
|
+
- **Screenshots & images** — send UI mockups, errors, or code screenshots
|
|
13
|
+
- **File sharing** — send PDFs, code files, documents — saved and read by Claude
|
|
14
|
+
- **Reply context** — reply to any message (including files) for follow-up
|
|
13
15
|
- **Streaming output** — see Claude working in real-time
|
|
14
16
|
- **Cron jobs** — scheduled tasks (standups, git digests, health checks)
|
|
15
17
|
- **Encrypted vault** — store API keys and credentials securely
|
|
16
18
|
- **Customizable soul** — define your assistant's personality and knowledge
|
|
17
19
|
- **Model switching** — toggle between Opus, Sonnet, Haiku
|
|
18
20
|
- **Plan mode, effort levels, budgets** — full Claude Code control from Telegram
|
|
21
|
+
- **Auto-updates** — checks for new versions every 5 minutes, upgrade with `/upgrade`
|
|
22
|
+
- **Multi-user auth** — authorize additional users with code verification
|
|
23
|
+
- **Cross-platform** — works on macOS, Linux, and Windows
|
|
19
24
|
|
|
20
25
|
## Prerequisites
|
|
21
26
|
|
|
22
27
|
- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated
|
|
23
28
|
- [Node.js](https://nodejs.org/) 18+
|
|
24
29
|
- A Telegram bot token (from [@BotFather](https://t.me/BotFather))
|
|
25
|
-
- (Optional) whisper
|
|
30
|
+
- (Optional) [whisper.cpp](https://github.com/ggerganov/whisper.cpp) + ffmpeg for voice notes
|
|
26
31
|
|
|
27
32
|
## Install
|
|
28
33
|
|
|
29
34
|
```bash
|
|
30
|
-
|
|
31
|
-
npm install -g open-claudia
|
|
32
|
-
|
|
33
|
-
# Or from source
|
|
34
|
-
git clone https://git.coders.africa/agents/open-claudia.git
|
|
35
|
-
cd open-claudia
|
|
36
|
-
npm install
|
|
35
|
+
npm install -g @inetafrica/open-claudia
|
|
37
36
|
```
|
|
38
37
|
|
|
39
38
|
## Setup
|
|
40
39
|
|
|
41
40
|
```bash
|
|
42
41
|
open-claudia setup
|
|
43
|
-
# or: node setup.js
|
|
44
42
|
```
|
|
45
43
|
|
|
46
44
|
The setup wizard will:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
|
|
46
|
+
1. Detect Claude CLI, ffmpeg, and whisper on your system
|
|
47
|
+
2. Verify Claude is authenticated
|
|
48
|
+
3. Ask for your Telegram bot token and verify it
|
|
49
|
+
4. Generate a verification code — send it to your bot to prove your identity
|
|
50
|
+
5. Set your workspace path (default: `~/.open-claudia/Workspace`)
|
|
51
|
+
6. Create an encrypted vault for credentials
|
|
52
|
+
7. Optionally install as a background service (macOS launchd / Linux systemd)
|
|
53
|
+
|
|
54
|
+
If setup is interrupted, running it again resumes from the last completed step.
|
|
55
|
+
|
|
56
|
+
All configuration is stored in `~/.open-claudia/` — survives npm upgrades.
|
|
52
57
|
|
|
53
58
|
## Run
|
|
54
59
|
|
|
55
60
|
```bash
|
|
56
61
|
open-claudia start # Start the bot
|
|
57
62
|
open-claudia stop # Stop the bot
|
|
58
|
-
open-claudia status # Check if running
|
|
63
|
+
open-claudia status # Check if running (shows PID)
|
|
59
64
|
open-claudia logs # View recent logs
|
|
65
|
+
open-claudia auth # Manage chat authorizations
|
|
60
66
|
```
|
|
61
67
|
|
|
68
|
+
If installed as a background service, the bot starts automatically on login and restarts on crash.
|
|
69
|
+
|
|
62
70
|
## Telegram Commands
|
|
63
71
|
|
|
72
|
+
### Session Management
|
|
73
|
+
|
|
64
74
|
| Command | Description |
|
|
65
75
|
|---------|-------------|
|
|
66
76
|
| `/session` | Pick a project to work on |
|
|
77
|
+
| `/sessions` | List past conversations for current project |
|
|
67
78
|
| `/projects` | Browse all workspace projects |
|
|
68
|
-
| `/
|
|
69
|
-
| `/
|
|
70
|
-
|
|
79
|
+
| `/continue` | Resume last conversation explicitly |
|
|
80
|
+
| `/end` | End current session |
|
|
81
|
+
|
|
82
|
+
When you select a project, the last conversation is automatically resumed. Tap "New conversation" to start fresh.
|
|
83
|
+
|
|
84
|
+
### Settings
|
|
85
|
+
|
|
86
|
+
| Command | Description |
|
|
87
|
+
|---------|-------------|
|
|
88
|
+
| `/model` | Switch model (opus / sonnet / haiku) |
|
|
89
|
+
| `/effort` | Set effort level (low / medium / high / max) |
|
|
90
|
+
| `/budget` | Set max spend for next task (e.g. `/budget 0.50`) |
|
|
71
91
|
| `/plan` | Toggle plan mode |
|
|
72
|
-
| `/
|
|
92
|
+
| `/compact` | Summarize conversation context |
|
|
93
|
+
| `/worktree` | Toggle isolated git branch |
|
|
94
|
+
| `/status` | Show current session and settings |
|
|
95
|
+
|
|
96
|
+
### Automation
|
|
97
|
+
|
|
98
|
+
| Command | Description |
|
|
99
|
+
|---------|-------------|
|
|
73
100
|
| `/cron` | Manage scheduled tasks |
|
|
74
|
-
| `/vault` | Manage credentials (password
|
|
75
|
-
| `/soul` | View/edit assistant identity |
|
|
76
|
-
|
|
77
|
-
|
|
101
|
+
| `/vault` | Manage encrypted credentials (password required) |
|
|
102
|
+
| `/soul` | View/edit assistant identity and personality |
|
|
103
|
+
|
|
104
|
+
### System
|
|
105
|
+
|
|
106
|
+
| Command | Description |
|
|
107
|
+
|---------|-------------|
|
|
108
|
+
| `/version` | Show current running version |
|
|
109
|
+
| `/upgrade` | Upgrade to latest version and restart |
|
|
110
|
+
| `/restart` | Restart the bot |
|
|
111
|
+
| `/stop` | Cancel a running task |
|
|
112
|
+
| `/help` | Show all commands |
|
|
113
|
+
|
|
114
|
+
## Sending Files
|
|
115
|
+
|
|
116
|
+
Send any file to the bot — PDFs, code files, documents, images. Files are saved to `~/.open-claudia/files/` with their original names. Claude reads the file and responds based on content.
|
|
117
|
+
|
|
118
|
+
Add a caption to your file to give Claude specific instructions:
|
|
119
|
+
- Send a PDF with caption "summarize the key findings"
|
|
120
|
+
- Send a code file with caption "find bugs in this"
|
|
121
|
+
- Send a screenshot with caption "implement this design"
|
|
122
|
+
|
|
123
|
+
## Voice Notes
|
|
124
|
+
|
|
125
|
+
Requires [whisper.cpp](https://github.com/ggerganov/whisper.cpp) and ffmpeg:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# macOS
|
|
129
|
+
brew install whisper-cpp ffmpeg
|
|
130
|
+
|
|
131
|
+
# Linux (Ubuntu/Debian)
|
|
132
|
+
sudo apt install ffmpeg
|
|
133
|
+
# Build whisper.cpp from source: https://github.com/ggerganov/whisper.cpp
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Voice notes are transcribed locally — nothing sent to external services.
|
|
137
|
+
|
|
138
|
+
## Multi-User Authorization
|
|
139
|
+
|
|
140
|
+
The setup owner is automatically authorized. To add more users:
|
|
141
|
+
|
|
142
|
+
**From Telegram** (unauthorized users):
|
|
143
|
+
- Send `/auth` to the bot — the owner gets notified
|
|
144
|
+
|
|
145
|
+
**From the terminal** (owner):
|
|
146
|
+
```bash
|
|
147
|
+
open-claudia auth
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
This shows authorized chats, pending requests, and lets you approve/deny or add new users with code verification.
|
|
78
151
|
|
|
79
152
|
## How It Works
|
|
80
153
|
|
|
81
154
|
```
|
|
82
|
-
Phone (Telegram)
|
|
83
|
-
|
|
155
|
+
Phone (Telegram) --> Bot (Node.js) --> Claude Code CLI --> Your codebase
|
|
156
|
+
<-- <-- <--
|
|
84
157
|
```
|
|
85
158
|
|
|
86
|
-
The bot spawns `claude -p` for each message, streaming output back to Telegram. It maintains conversation context via `--resume` and passes a system prompt that gives Claude awareness of the Telegram environment, its
|
|
159
|
+
The bot spawns `claude -p` for each message, streaming output back to Telegram. It maintains conversation context via `--resume` and passes a system prompt that gives Claude awareness of the Telegram environment, its configuration files, and the ability to send files/images directly.
|
|
87
160
|
|
|
88
161
|
## Configuration Files
|
|
89
162
|
|
|
163
|
+
All stored in `~/.open-claudia/`:
|
|
164
|
+
|
|
90
165
|
| File | Purpose |
|
|
91
166
|
|------|---------|
|
|
92
|
-
| `.env` | Telegram token,
|
|
93
|
-
| `
|
|
94
|
-
| `crons.json` | Scheduled tasks |
|
|
167
|
+
| `.env` | Telegram token, workspace path, binary paths |
|
|
168
|
+
| `auth.json` | Authorized users and pending requests |
|
|
95
169
|
| `vault.enc` | Encrypted credential store |
|
|
170
|
+
| `soul.md` | Assistant identity and personality (editable via `/soul`) |
|
|
171
|
+
| `crons.json` | Scheduled tasks |
|
|
172
|
+
| `sessions.json` | Per-project conversation history |
|
|
173
|
+
| `state.json` | Current session state (survives restarts) |
|
|
174
|
+
| `bot.log` | Bot logs |
|
|
175
|
+
| `files/` | Files received from Telegram |
|
|
176
|
+
| `media/` | Temporary media (voice notes, photos) |
|
|
177
|
+
|
|
178
|
+
## Background Service
|
|
179
|
+
|
|
180
|
+
### macOS (launchd)
|
|
181
|
+
|
|
182
|
+
Set up during `open-claudia setup`, or manually:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# The setup wizard creates ~/Library/LaunchAgents/com.open-claudia.plist
|
|
186
|
+
# To manage:
|
|
187
|
+
launchctl load ~/Library/LaunchAgents/com.open-claudia.plist
|
|
188
|
+
launchctl unload ~/Library/LaunchAgents/com.open-claudia.plist
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Linux (systemd)
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# The setup wizard creates /etc/systemd/system/claude-telegram-bot.service
|
|
195
|
+
# To manage:
|
|
196
|
+
sudo systemctl enable claude-telegram-bot
|
|
197
|
+
sudo systemctl start claude-telegram-bot
|
|
198
|
+
sudo systemctl status claude-telegram-bot
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Auto-Updates
|
|
202
|
+
|
|
203
|
+
The bot checks npm for new versions every 5 minutes. When an update is available, you get a Telegram notification:
|
|
204
|
+
|
|
205
|
+
> "Hey! A new version is available (v1.3.0). You're on v1.2.9."
|
|
206
|
+
|
|
207
|
+
Send `/upgrade` to update. The bot will:
|
|
208
|
+
1. Download and install the new version
|
|
209
|
+
2. Go offline briefly
|
|
210
|
+
3. Restart and notify you it's back
|
|
211
|
+
|
|
212
|
+
## Cron Jobs
|
|
213
|
+
|
|
214
|
+
Schedule recurring tasks:
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
/cron add "0 9 * * 1-5" myproject "Morning standup: summarize git changes since yesterday"
|
|
218
|
+
/cron add "0 18 * * *" myproject "Git digest: what changed today?"
|
|
219
|
+
/cron add "*/30 * * * *" myproject "Health check: verify the API is responding"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Presets available via `/cron` menu.
|
|
223
|
+
|
|
224
|
+
## Vault
|
|
225
|
+
|
|
226
|
+
Store sensitive credentials encrypted:
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
/vault # Unlock vault (prompts for password)
|
|
230
|
+
/vault set AWS_KEY xxx # Store a credential
|
|
231
|
+
/vault remove AWS_KEY # Remove a credential
|
|
232
|
+
/vault lock # Lock vault
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Claude can read vault credentials when unlocked — useful for deployment scripts and API calls.
|
|
96
236
|
|
|
97
237
|
## License
|
|
98
238
|
|
package/bin/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const { execSync } = require("child_process");
|
|
4
|
+
const fs = require("fs");
|
|
4
5
|
const path = require("path");
|
|
5
6
|
|
|
6
7
|
const args = process.argv.slice(2);
|
|
@@ -8,6 +9,30 @@ const command = args[0] || "help";
|
|
|
8
9
|
|
|
9
10
|
const botDir = path.join(__dirname, "..");
|
|
10
11
|
|
|
12
|
+
function findBotProcesses() {
|
|
13
|
+
try {
|
|
14
|
+
if (process.platform === "win32") {
|
|
15
|
+
const out = execSync('tasklist /FI "IMAGENAME eq node.exe" /FO CSV /NH', { encoding: "utf-8" });
|
|
16
|
+
// Check if any node process has bot.js in its command line
|
|
17
|
+
const wmic = execSync('wmic process where "name=\'node.exe\'" get ProcessId,CommandLine /FORMAT:CSV 2>nul', { encoding: "utf-8" });
|
|
18
|
+
const pids = [];
|
|
19
|
+
for (const line of wmic.split("\n")) {
|
|
20
|
+
if (line.includes("bot.js") && line.includes("open-claudia")) {
|
|
21
|
+
const parts = line.trim().split(",");
|
|
22
|
+
const pid = parts[parts.length - 1];
|
|
23
|
+
if (pid) pids.push(pid.trim());
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return pids;
|
|
27
|
+
} else {
|
|
28
|
+
const out = execSync('ps -eo pid,command | grep "bot.js" | grep "open-claudia" | grep -v grep', { encoding: "utf-8" });
|
|
29
|
+
return out.trim().split("\n").map((l) => l.trim().split(/\s+/)[0]).filter(Boolean);
|
|
30
|
+
}
|
|
31
|
+
} catch (e) {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
11
36
|
switch (command) {
|
|
12
37
|
case "setup":
|
|
13
38
|
require(path.join(botDir, "setup.js"));
|
|
@@ -24,33 +49,37 @@ switch (command) {
|
|
|
24
49
|
require(path.join(botDir, "setup.js"));
|
|
25
50
|
break;
|
|
26
51
|
|
|
27
|
-
case "stop":
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
console.log("Stopped.");
|
|
31
|
-
} catch (e) {
|
|
52
|
+
case "stop": {
|
|
53
|
+
const pids = findBotProcesses();
|
|
54
|
+
if (pids.length === 0) {
|
|
32
55
|
console.log("Not running.");
|
|
56
|
+
} else {
|
|
57
|
+
for (const pid of pids) {
|
|
58
|
+
try { process.kill(parseInt(pid, 10), "SIGTERM"); } catch (e) {}
|
|
59
|
+
}
|
|
60
|
+
console.log("Stopped.");
|
|
33
61
|
}
|
|
34
62
|
break;
|
|
63
|
+
}
|
|
35
64
|
|
|
36
|
-
case "logs":
|
|
65
|
+
case "logs": {
|
|
37
66
|
const configDir = require(path.join(botDir, "config-dir"));
|
|
38
67
|
const logFile = path.join(configDir, "bot.log");
|
|
39
68
|
try {
|
|
40
|
-
|
|
69
|
+
const content = fs.readFileSync(logFile, "utf-8");
|
|
70
|
+
const lines = content.split("\n");
|
|
71
|
+
console.log(lines.slice(-50).join("\n"));
|
|
41
72
|
} catch (e) {
|
|
42
73
|
console.log("No logs found.");
|
|
43
74
|
}
|
|
44
75
|
break;
|
|
76
|
+
}
|
|
45
77
|
|
|
46
|
-
case "status":
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
console.log("Running.");
|
|
50
|
-
} catch (e) {
|
|
51
|
-
console.log("Not running.");
|
|
52
|
-
}
|
|
78
|
+
case "status": {
|
|
79
|
+
const pids = findBotProcesses();
|
|
80
|
+
console.log(pids.length > 0 ? `Running (PID: ${pids.join(", ")}).` : "Not running.");
|
|
53
81
|
break;
|
|
82
|
+
}
|
|
54
83
|
|
|
55
84
|
default:
|
|
56
85
|
console.log(`
|
package/bot.js
CHANGED
|
@@ -61,8 +61,11 @@ const FULL_PATH = [
|
|
|
61
61
|
path.dirname(process.execPath),
|
|
62
62
|
FFMPEG ? path.dirname(FFMPEG) : null,
|
|
63
63
|
WHISPER_CLI ? path.dirname(WHISPER_CLI) : null,
|
|
64
|
-
|
|
65
|
-
].filter(Boolean).join("
|
|
64
|
+
...(process.platform === "win32"
|
|
65
|
+
? [process.env.APPDATA, process.env.LOCALAPPDATA].filter(Boolean).map((p) => path.join(p, "npm"))
|
|
66
|
+
: ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"]
|
|
67
|
+
),
|
|
68
|
+
].filter(Boolean).join(path.delimiter);
|
|
66
69
|
|
|
67
70
|
const bot = new TelegramBot(TOKEN, {
|
|
68
71
|
polling: {
|
package/package.json
CHANGED
package/setup.js
CHANGED
|
@@ -138,20 +138,17 @@ function detectPlatform() {
|
|
|
138
138
|
return "other";
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
function
|
|
141
|
+
function findBinary(name) {
|
|
142
|
+
const cmd = process.platform === "win32" ? `where ${name} 2>nul` : `which ${name} 2>/dev/null`;
|
|
142
143
|
try {
|
|
143
|
-
const p = execSync(
|
|
144
|
+
const p = execSync(cmd, { encoding: "utf-8" }).trim().split("\n")[0];
|
|
144
145
|
return p || null;
|
|
145
146
|
} catch (e) { return null; }
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
function
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function findFfmpeg() {
|
|
153
|
-
try { return execSync("which ffmpeg 2>/dev/null", { encoding: "utf-8" }).trim() || null; } catch (e) { return null; }
|
|
154
|
-
}
|
|
149
|
+
function findClaude() { return findBinary("claude"); }
|
|
150
|
+
function findWhisper() { return findBinary("whisper-cli"); }
|
|
151
|
+
function findFfmpeg() { return findBinary("ffmpeg"); }
|
|
155
152
|
|
|
156
153
|
function findWhisperModel() {
|
|
157
154
|
const candidates = [
|