telegram-claude-code 1.0.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.
Files changed (38) hide show
  1. package/README.md +134 -0
  2. package/dist/bin/claude-telegram.d.ts +3 -0
  3. package/dist/bin/claude-telegram.d.ts.map +1 -0
  4. package/dist/bin/claude-telegram.js +39 -0
  5. package/dist/bin/claude-telegram.js.map +1 -0
  6. package/dist/src/bot/bot.d.ts +5 -0
  7. package/dist/src/bot/bot.d.ts.map +1 -0
  8. package/dist/src/bot/bot.js +30 -0
  9. package/dist/src/bot/bot.js.map +1 -0
  10. package/dist/src/bot/handlers.d.ts +9 -0
  11. package/dist/src/bot/handlers.d.ts.map +1 -0
  12. package/dist/src/bot/handlers.js +108 -0
  13. package/dist/src/bot/handlers.js.map +1 -0
  14. package/dist/src/bot/middleware.d.ts +3 -0
  15. package/dist/src/bot/middleware.d.ts.map +1 -0
  16. package/dist/src/bot/middleware.js +11 -0
  17. package/dist/src/bot/middleware.js.map +1 -0
  18. package/dist/src/claude/session.d.ts +13 -0
  19. package/dist/src/claude/session.d.ts.map +1 -0
  20. package/dist/src/claude/session.js +81 -0
  21. package/dist/src/claude/session.js.map +1 -0
  22. package/dist/src/cli/config.d.ts +3 -0
  23. package/dist/src/cli/config.d.ts.map +1 -0
  24. package/dist/src/cli/config.js +36 -0
  25. package/dist/src/cli/config.js.map +1 -0
  26. package/dist/src/cli/init.d.ts +2 -0
  27. package/dist/src/cli/init.d.ts.map +1 -0
  28. package/dist/src/cli/init.js +65 -0
  29. package/dist/src/cli/init.js.map +1 -0
  30. package/dist/src/cli/start.d.ts +2 -0
  31. package/dist/src/cli/start.d.ts.map +1 -0
  32. package/dist/src/cli/start.js +7 -0
  33. package/dist/src/cli/start.js.map +1 -0
  34. package/dist/src/config/config.d.ts +24 -0
  35. package/dist/src/config/config.d.ts.map +1 -0
  36. package/dist/src/config/config.js +49 -0
  37. package/dist/src/config/config.js.map +1 -0
  38. package/package.json +48 -0
package/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # telegram-claude-code
2
+
3
+ Control [Claude Code](https://docs.anthropic.com/en/docs/claude-code) remotely via Telegram. Send messages from anywhere and let Claude Code edit files, run commands, and manage your projects — all through a Telegram bot.
4
+
5
+ ## How it works
6
+
7
+ ```
8
+ You (Telegram) → Bot (thin proxy) → Claude Agent SDK → Your machine
9
+ ```
10
+
11
+ The bot is a **thin proxy** — it just routes messages between Telegram and the Claude Agent SDK. All the heavy lifting (conversation context, file editing, code execution) is handled by Claude Code itself.
12
+
13
+ ## Features
14
+
15
+ - **Remote Claude Code access** — interact with Claude Code from your phone or any device with Telegram
16
+ - **Session persistence** — conversations are maintained between messages and survive bot restarts
17
+ - **File sharing** — files created or edited by Claude Code are sent as Telegram documents
18
+ - **Whitelist auth** — only authorized Telegram users can interact with the bot
19
+ - **Cross-platform** — works on Linux, macOS, and Windows
20
+ - **Simple CLI** — interactive setup wizard, one command to start
21
+
22
+ ## Prerequisites
23
+
24
+ - [Node.js](https://nodejs.org/) >= 18
25
+ - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated (`ANTHROPIC_API_KEY` set)
26
+ - A Telegram bot token (create one via [@BotFather](https://t.me/BotFather))
27
+ - Your Telegram chat ID (get it from [@userinfobot](https://t.me/userinfobot))
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install -g telegram-claude-code
33
+ ```
34
+
35
+ Or run directly with npx:
36
+
37
+ ```bash
38
+ npx telegram-claude-code init
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ### 1. Setup
44
+
45
+ ```bash
46
+ telegram-claude-code init
47
+ ```
48
+
49
+ The wizard will ask for:
50
+ - **Telegram bot token** — from BotFather
51
+ - **Your chat ID** — who can use the bot
52
+ - **Working directory** — where Claude Code will operate
53
+
54
+ ### 2. Start the bot
55
+
56
+ ```bash
57
+ telegram-claude-code start
58
+ ```
59
+
60
+ ### 3. Chat
61
+
62
+ Open your bot on Telegram and start sending messages. Claude Code will respond just like it does in the terminal.
63
+
64
+ ## Telegram Commands
65
+
66
+ | Command | Description |
67
+ |---------|-------------|
68
+ | `/start` | Show welcome message and usage info |
69
+ | `/new` | Start a new conversation (clear session) |
70
+ | `/cwd <path>` | Change the working directory |
71
+
72
+ Any other text message is sent directly to Claude Code.
73
+
74
+ ## CLI Commands
75
+
76
+ ```bash
77
+ # Interactive setup
78
+ telegram-claude-code init
79
+
80
+ # Start the bot
81
+ telegram-claude-code start
82
+
83
+ # Show current config
84
+ telegram-claude-code config show
85
+
86
+ # Update a config value
87
+ telegram-claude-code config set telegram.whitelist 123456789,987654321
88
+ telegram-claude-code config set claude.workingDirectory /path/to/project
89
+ ```
90
+
91
+ ## Configuration
92
+
93
+ Config is stored at `~/.telegram-claude-code/config.json`:
94
+
95
+ ```json
96
+ {
97
+ "telegram": {
98
+ "token": "YOUR_BOT_TOKEN",
99
+ "whitelist": [123456789]
100
+ },
101
+ "claude": {
102
+ "workingDirectory": "/home/user/projects",
103
+ "permissionMode": "acceptEdits",
104
+ "allowedTools": ["Read", "Edit", "Write", "Bash", "Glob", "Grep"]
105
+ }
106
+ }
107
+ ```
108
+
109
+ ### Options
110
+
111
+ | Key | Description | Default |
112
+ |-----|-------------|---------|
113
+ | `telegram.token` | Telegram bot token | — |
114
+ | `telegram.whitelist` | Array of allowed chat IDs | — |
115
+ | `claude.workingDirectory` | Directory Claude Code operates in | `cwd` |
116
+ | `claude.permissionMode` | Permission mode (`default`, `acceptEdits`, `bypassPermissions`) | `acceptEdits` |
117
+ | `claude.allowedTools` | Tools Claude Code can use | `Read, Edit, Write, Bash, Glob, Grep` |
118
+
119
+ ## Security
120
+
121
+ - Config file is created with `600` permissions (owner read/write only)
122
+ - Only whitelisted chat IDs can interact with the bot
123
+ - Messages from unauthorized users are silently ignored
124
+ - The bot runs locally on your machine — no data is sent to third-party servers (only Telegram API and Anthropic API)
125
+
126
+ ## How Sessions Work
127
+
128
+ Each Telegram chat gets its own Claude Code session. The conversation context is maintained between messages, so you can have multi-turn interactions just like in the terminal. Sessions persist across bot restarts.
129
+
130
+ Use `/new` to start a fresh conversation when you want to change topics.
131
+
132
+ ## License
133
+
134
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=claude-telegram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-telegram.d.ts","sourceRoot":"","sources":["../../bin/claude-telegram.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { runInit } from "../src/cli/init.js";
4
+ import { runStart } from "../src/cli/start.js";
5
+ import { runConfigShow, runConfigSet } from "../src/cli/config.js";
6
+ const program = new Command();
7
+ program
8
+ .name("claude-telegram")
9
+ .description("Control Claude Code remotely via Telegram")
10
+ .version("1.0.0");
11
+ program
12
+ .command("init")
13
+ .description("Interactive setup wizard")
14
+ .action(async () => {
15
+ await runInit();
16
+ });
17
+ program
18
+ .command("start")
19
+ .description("Start the Telegram bot")
20
+ .action(async () => {
21
+ await runStart();
22
+ });
23
+ const configCmd = program
24
+ .command("config")
25
+ .description("Manage configuration");
26
+ configCmd
27
+ .command("show")
28
+ .description("Show current configuration")
29
+ .action(() => {
30
+ runConfigShow();
31
+ });
32
+ configCmd
33
+ .command("set <key> <value>")
34
+ .description("Set a configuration value")
35
+ .action((key, value) => {
36
+ runConfigSet(key, value);
37
+ });
38
+ program.parse();
39
+ //# sourceMappingURL=claude-telegram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-telegram.js","sourceRoot":"","sources":["../../bin/claude-telegram.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEnE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,iBAAiB,CAAC;KACvB,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,0BAA0B,CAAC;KACvC,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,OAAO,EAAE,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,wBAAwB,CAAC;KACrC,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,QAAQ,EAAE,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,MAAM,SAAS,GAAG,OAAO;KACtB,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,sBAAsB,CAAC,CAAC;AAEvC,SAAS;KACN,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4BAA4B,CAAC;KACzC,MAAM,CAAC,GAAG,EAAE;IACX,aAAa,EAAE,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL,SAAS;KACN,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,2BAA2B,CAAC;KACxC,MAAM,CAAC,CAAC,GAAW,EAAE,KAAa,EAAE,EAAE;IACrC,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Telegraf } from "telegraf";
2
+ import type { AppConfig } from "../config/config.js";
3
+ export declare function createBot(config: AppConfig): Telegraf;
4
+ export declare function startBot(config: AppConfig): Promise<void>;
5
+ //# sourceMappingURL=bot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../../src/bot/bot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKrD,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAerD;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/D"}
@@ -0,0 +1,30 @@
1
+ import { Telegraf } from "telegraf";
2
+ import { whitelist } from "./middleware.js";
3
+ import { createHandlers } from "./handlers.js";
4
+ import { initSessions } from "../claude/session.js";
5
+ export function createBot(config) {
6
+ const bot = new Telegraf(config.telegram.token);
7
+ bot.use(whitelist(config.telegram.whitelist));
8
+ initSessions();
9
+ const handlers = createHandlers(config);
10
+ bot.command("start", handlers.handleStart);
11
+ bot.command("new", handlers.handleNew);
12
+ bot.command("cwd", handlers.handleCwd);
13
+ bot.on("text", handlers.handleMessage);
14
+ return bot;
15
+ }
16
+ export async function startBot(config) {
17
+ const bot = createBot(config);
18
+ const shutdown = () => {
19
+ console.log("Shutting down...");
20
+ bot.stop("SIGINT");
21
+ process.exit(0);
22
+ };
23
+ process.on("SIGINT", shutdown);
24
+ process.on("SIGTERM", shutdown);
25
+ console.log("Bot started. Listening for messages...");
26
+ console.log(`Working directory: ${config.claude.workingDirectory}`);
27
+ console.log(`Whitelisted users: ${config.telegram.whitelist.join(", ")}`);
28
+ await bot.launch();
29
+ }
30
+ //# sourceMappingURL=bot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../../src/bot/bot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,MAAM,UAAU,SAAS,CAAC,MAAiB;IACzC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEhD,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IAE9C,YAAY,EAAE,CAAC;IAEf,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAExC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC3C,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IACvC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IACvC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;IAEvC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAiB;IAC9C,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAE9B,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAChC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhC,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAE1E,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;AACrB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Context } from "telegraf";
2
+ import type { AppConfig } from "../config/config.js";
3
+ export declare function createHandlers(config: AppConfig): {
4
+ handleStart: (ctx: Context) => Promise<void>;
5
+ handleNew: (ctx: Context) => Promise<void>;
6
+ handleCwd: (ctx: Context) => Promise<void>;
7
+ handleMessage: (ctx: Context) => Promise<void>;
8
+ };
9
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/bot/handlers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAyBrD,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS;uBAGd,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC;qBAUzB,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC;qBAMvB,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC;yBAmBnB,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC;EAgE1D"}
@@ -0,0 +1,108 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { sendMessage, clearSession } from "../claude/session.js";
4
+ const MAX_MESSAGE_LENGTH = 4096;
5
+ function splitMessage(text) {
6
+ if (text.length <= MAX_MESSAGE_LENGTH) {
7
+ return [text];
8
+ }
9
+ const chunks = [];
10
+ let remaining = text;
11
+ while (remaining.length > 0) {
12
+ if (remaining.length <= MAX_MESSAGE_LENGTH) {
13
+ chunks.push(remaining);
14
+ break;
15
+ }
16
+ let splitAt = remaining.lastIndexOf("\n", MAX_MESSAGE_LENGTH);
17
+ if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH / 2) {
18
+ splitAt = MAX_MESSAGE_LENGTH;
19
+ }
20
+ chunks.push(remaining.slice(0, splitAt));
21
+ remaining = remaining.slice(splitAt);
22
+ }
23
+ return chunks;
24
+ }
25
+ export function createHandlers(config) {
26
+ const activeRequests = new Set();
27
+ async function handleStart(ctx) {
28
+ await ctx.reply("Claude Code Bot connected.\n\n" +
29
+ "Commands:\n" +
30
+ "/new — Start new conversation\n" +
31
+ `/cwd — Change working directory (current: ${config.claude.workingDirectory})\n` +
32
+ "\nSend any message to interact with Claude Code.");
33
+ }
34
+ async function handleNew(ctx) {
35
+ const chatId = String(ctx.chat.id);
36
+ clearSession(chatId);
37
+ await ctx.reply("Session cleared. Next message starts a new conversation.");
38
+ }
39
+ async function handleCwd(ctx) {
40
+ const text = ctx.message?.text ?? "";
41
+ const newPath = text.replace(/^\/cwd\s*/, "").trim();
42
+ if (!newPath) {
43
+ await ctx.reply(`Current directory: ${config.claude.workingDirectory}`);
44
+ return;
45
+ }
46
+ const resolved = path.resolve(newPath);
47
+ if (!fs.existsSync(resolved) || !fs.statSync(resolved).isDirectory()) {
48
+ await ctx.reply(`Directory not found: ${resolved}`);
49
+ return;
50
+ }
51
+ config.claude.workingDirectory = resolved;
52
+ await ctx.reply(`Working directory changed to: ${resolved}`);
53
+ }
54
+ async function handleMessage(ctx) {
55
+ const chatId = ctx.chat.id;
56
+ const text = ctx.message?.text;
57
+ if (!text)
58
+ return;
59
+ if (activeRequests.has(chatId)) {
60
+ await ctx.reply("Please wait for the current request to finish.");
61
+ return;
62
+ }
63
+ activeRequests.add(chatId);
64
+ const typingInterval = setInterval(() => {
65
+ ctx.sendChatAction("typing").catch(() => { });
66
+ }, 4000);
67
+ try {
68
+ await ctx.sendChatAction("typing");
69
+ const response = await sendMessage(String(chatId), text, config.claude);
70
+ clearInterval(typingInterval);
71
+ if (response.text) {
72
+ const chunks = splitMessage(response.text);
73
+ for (const chunk of chunks) {
74
+ await ctx.reply(chunk);
75
+ }
76
+ }
77
+ for (const filePath of response.files) {
78
+ try {
79
+ if (fs.existsSync(filePath)) {
80
+ const stat = fs.statSync(filePath);
81
+ if (stat.size < 50 * 1024 * 1024) {
82
+ await ctx.replyWithDocument({
83
+ source: fs.createReadStream(filePath),
84
+ filename: path.basename(filePath),
85
+ });
86
+ }
87
+ }
88
+ }
89
+ catch {
90
+ // skip files that can't be sent
91
+ }
92
+ }
93
+ if (response.cost > 0) {
94
+ await ctx.reply(`💰 Cost: $${response.cost.toFixed(4)}`);
95
+ }
96
+ }
97
+ catch (err) {
98
+ clearInterval(typingInterval);
99
+ const msg = err instanceof Error ? err.message : String(err);
100
+ await ctx.reply(`Error: ${msg}`);
101
+ }
102
+ finally {
103
+ activeRequests.delete(chatId);
104
+ }
105
+ }
106
+ return { handleStart, handleNew, handleCwd, handleMessage };
107
+ }
108
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../../src/bot/handlers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Context, MiddlewareFn } from "telegraf";
2
+ export declare function whitelist(allowedIds: number[]): MiddlewareFn<Context>;
3
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/bot/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEtD,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CASrE"}
@@ -0,0 +1,11 @@
1
+ export function whitelist(allowedIds) {
2
+ const allowed = new Set(allowedIds);
3
+ return (ctx, next) => {
4
+ const chatId = ctx.chat?.id;
5
+ if (chatId === undefined || !allowed.has(chatId)) {
6
+ return;
7
+ }
8
+ return next();
9
+ };
10
+ }
11
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/bot/middleware.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CAAC,UAAoB;IAC5C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QACnB,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5B,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACjD,OAAO;QACT,CAAC;QACD,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type ClaudeConfig } from "../config/config.js";
2
+ interface ClaudeResponse {
3
+ text: string;
4
+ sessionId: string;
5
+ files: string[];
6
+ cost: number;
7
+ error?: string;
8
+ }
9
+ export declare function initSessions(): void;
10
+ export declare function clearSession(chatId: string): void;
11
+ export declare function sendMessage(chatId: string, message: string, config: ClaudeConfig): Promise<ClaudeResponse>;
12
+ export {};
13
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/claude/session.ts"],"names":[],"mappings":"AAEA,OAAO,EAA8B,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEpF,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,wBAAgB,YAAY,IAAI,IAAI,CAKnC;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGjD;AAUD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,cAAc,CAAC,CAoEzB"}
@@ -0,0 +1,81 @@
1
+ import { query } from "@anthropic-ai/claude-code";
2
+ import { loadSessions, saveSessions } from "../config/config.js";
3
+ const sessionMap = new Map();
4
+ export function initSessions() {
5
+ const saved = loadSessions();
6
+ for (const [chatId, sessionId] of Object.entries(saved)) {
7
+ sessionMap.set(chatId, sessionId);
8
+ }
9
+ }
10
+ export function clearSession(chatId) {
11
+ sessionMap.delete(chatId);
12
+ persistSessions();
13
+ }
14
+ function persistSessions() {
15
+ const obj = {};
16
+ for (const [k, v] of sessionMap) {
17
+ obj[k] = v;
18
+ }
19
+ saveSessions(obj);
20
+ }
21
+ export async function sendMessage(chatId, message, config) {
22
+ const existingSession = sessionMap.get(chatId);
23
+ const options = {
24
+ cwd: config.workingDirectory,
25
+ allowedTools: config.allowedTools,
26
+ permissionMode: config.permissionMode,
27
+ };
28
+ if (existingSession) {
29
+ options.resume = existingSession;
30
+ }
31
+ const files = [];
32
+ let resultText = "";
33
+ let sessionId = existingSession ?? "";
34
+ let cost = 0;
35
+ try {
36
+ const conversation = query({ prompt: message, options });
37
+ for await (const msg of conversation) {
38
+ if (msg.type === "system" && "session_id" in msg) {
39
+ sessionId = msg.session_id;
40
+ }
41
+ if (msg.type === "assistant") {
42
+ const assistant = msg;
43
+ if (assistant.message?.content) {
44
+ for (const block of assistant.message.content) {
45
+ if ("type" in block && block.type === "tool_use") {
46
+ const input = block.input;
47
+ if (["Write", "Edit"].includes(block.name) &&
48
+ typeof input.file_path === "string") {
49
+ files.push(input.file_path);
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ if (msg.type === "result") {
56
+ const result = msg;
57
+ if (result.subtype === "success") {
58
+ resultText = result.result;
59
+ cost = result.total_cost_usd;
60
+ }
61
+ else {
62
+ resultText = `Error: ${result.subtype}`;
63
+ }
64
+ }
65
+ }
66
+ sessionMap.set(chatId, sessionId);
67
+ persistSessions();
68
+ return { text: resultText, sessionId, files: [...new Set(files)], cost };
69
+ }
70
+ catch (err) {
71
+ const errorMsg = err instanceof Error ? err.message : String(err);
72
+ return {
73
+ text: `Error: ${errorMsg}`,
74
+ sessionId,
75
+ files: [],
76
+ cost: 0,
77
+ error: errorMsg,
78
+ };
79
+ }
80
+ }
81
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/claude/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAqB,MAAM,qBAAqB,CAAC;AAUpF,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE7C,MAAM,UAAU,YAAY;IAC1B,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxD,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACpC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1B,eAAe,EAAE,CAAC;AACpB,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,UAAU,EAAE,CAAC;QAChC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACb,CAAC;IACD,YAAY,CAAC,GAAG,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,OAAe,EACf,MAAoB;IAEpB,MAAM,eAAe,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAE/C,MAAM,OAAO,GAAY;QACvB,GAAG,EAAE,MAAM,CAAC,gBAAgB;QAC5B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,cAAc,EAAE,MAAM,CAAC,cAA2C;KACnE,CAAC;IAEF,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,GAAG,eAAe,CAAC;IACnC,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,IAAI,SAAS,GAAG,eAAe,IAAI,EAAE,CAAC;IACtC,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAEzD,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;YACrC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,YAAY,IAAI,GAAG,EAAE,CAAC;gBACjD,SAAS,GAAG,GAAG,CAAC,UAAoB,CAAC;YACvC,CAAC;YAED,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC7B,MAAM,SAAS,GAAG,GAA0B,CAAC;gBAC7C,IAAI,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;oBAC/B,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;wBAC9C,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;4BACjD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAgC,CAAC;4BACrD,IACE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;gCACtC,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,EACnC,CAAC;gCACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;4BAC9B,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,MAAM,MAAM,GAAG,GAAuB,CAAC;gBACvC,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;oBACjC,UAAU,GAAI,MAA4D,CAAC,MAAM,CAAC;oBAClF,IAAI,GAAI,MAA4D,CAAC,cAAc,CAAC;gBACtF,CAAC;qBAAM,CAAC;oBACN,UAAU,GAAG,UAAU,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC1C,CAAC;YACH,CAAC;QACH,CAAC;QAED,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAClC,eAAe,EAAE,CAAC;QAElB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAC3E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAClE,OAAO;YACL,IAAI,EAAE,UAAU,QAAQ,EAAE;YAC1B,SAAS;YACT,KAAK,EAAE,EAAE;YACT,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,QAAQ;SAChB,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function runConfigShow(): void;
2
+ export declare function runConfigSet(key: string, value: string): void;
3
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/cli/config.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,IAAI,IAAI,CAIpC;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CA+B7D"}
@@ -0,0 +1,36 @@
1
+ import { loadConfig, saveConfig, getConfigPath } from "../config/config.js";
2
+ export function runConfigShow() {
3
+ const config = loadConfig();
4
+ console.log(`Config file: ${getConfigPath()}\n`);
5
+ console.log(JSON.stringify(config, null, 2));
6
+ }
7
+ export function runConfigSet(key, value) {
8
+ const config = loadConfig();
9
+ const keys = key.split(".");
10
+ let target = config;
11
+ for (let i = 0; i < keys.length - 1; i++) {
12
+ const k = keys[i];
13
+ if (typeof target[k] !== "object" || target[k] === null) {
14
+ console.error(`Invalid config key: ${key}`);
15
+ process.exit(1);
16
+ }
17
+ target = target[k];
18
+ }
19
+ const lastKey = keys[keys.length - 1];
20
+ const currentValue = target[lastKey];
21
+ if (Array.isArray(currentValue)) {
22
+ target[lastKey] = value.split(",").map((v) => {
23
+ const num = Number(v.trim());
24
+ return isNaN(num) ? v.trim() : num;
25
+ });
26
+ }
27
+ else if (typeof currentValue === "number") {
28
+ target[lastKey] = Number(value);
29
+ }
30
+ else {
31
+ target[lastKey] = value;
32
+ }
33
+ saveConfig(config);
34
+ console.log(`Updated ${key} = ${JSON.stringify(target[lastKey])}`);
35
+ }
36
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE5E,MAAM,UAAU,aAAa;IAC3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,gBAAgB,aAAa,EAAE,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,KAAa;IACrD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,MAAM,GAA4B,MAA4C,CAAC;IAEnF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACnB,IAAI,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACxD,OAAO,CAAC,KAAK,CAAC,uBAAuB,GAAG,EAAE,CAAC,CAAC;YAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,MAAM,CAAC,CAAC,CAA4B,CAAC;IAChD,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;IACvC,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAErC,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7B,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;IAC1B,CAAC;IAED,UAAU,CAAC,MAAM,CAAC,CAAC;IACnB,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runInit(): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"AAKA,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CA+D7C"}
@@ -0,0 +1,65 @@
1
+ import inquirer from "inquirer";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { saveConfig, getConfigPath, configExists } from "../config/config.js";
5
+ export async function runInit() {
6
+ console.log("Claude Telegram — Setup\n");
7
+ if (configExists()) {
8
+ const { overwrite } = await inquirer.prompt([
9
+ {
10
+ type: "confirm",
11
+ name: "overwrite",
12
+ message: `Config already exists at ${getConfigPath()}. Overwrite?`,
13
+ default: false,
14
+ },
15
+ ]);
16
+ if (!overwrite) {
17
+ console.log("Setup cancelled.");
18
+ return;
19
+ }
20
+ }
21
+ const answers = await inquirer.prompt([
22
+ {
23
+ type: "input",
24
+ name: "token",
25
+ message: "Telegram bot token (from BotFather):",
26
+ validate: (v) => (v.trim().length > 0 ? true : "Token is required"),
27
+ },
28
+ {
29
+ type: "input",
30
+ name: "chatId",
31
+ message: "Your Telegram chat ID:",
32
+ validate: (v) => {
33
+ const n = Number(v);
34
+ return !isNaN(n) && n > 0 ? true : "Must be a valid number";
35
+ },
36
+ },
37
+ {
38
+ type: "input",
39
+ name: "workingDirectory",
40
+ message: "Working directory for Claude Code:",
41
+ default: process.cwd(),
42
+ validate: (v) => {
43
+ const resolved = path.resolve(v);
44
+ return fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()
45
+ ? true
46
+ : "Directory does not exist";
47
+ },
48
+ },
49
+ ]);
50
+ const config = {
51
+ telegram: {
52
+ token: answers.token.trim(),
53
+ whitelist: [Number(answers.chatId)],
54
+ },
55
+ claude: {
56
+ workingDirectory: path.resolve(answers.workingDirectory),
57
+ permissionMode: "acceptEdits",
58
+ allowedTools: ["Read", "Edit", "Write", "Bash", "Glob", "Grep"],
59
+ },
60
+ };
61
+ saveConfig(config);
62
+ console.log(`\nConfig saved to ${getConfigPath()}`);
63
+ console.log('Run "claude-telegram start" to launch the bot.');
64
+ }
65
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAkB,MAAM,qBAAqB,CAAC;AAE9F,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IAEzC,IAAI,YAAY,EAAE,EAAE,CAAC;QACnB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YAC1C;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,4BAA4B,aAAa,EAAE,cAAc;gBAClE,OAAO,EAAE,KAAK;aACf;SACF,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;YAChC,OAAO;QACT,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QACpC;YACE,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,sCAAsC;YAC/C,QAAQ,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC;SAC5E;QACD;YACE,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,wBAAwB;YACjC,QAAQ,EAAE,CAAC,CAAS,EAAE,EAAE;gBACtB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBACpB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,wBAAwB,CAAC;YAC9D,CAAC;SACF;QACD;YACE,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,kBAAkB;YACxB,OAAO,EAAE,oCAAoC;YAC7C,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE;YACtB,QAAQ,EAAE,CAAC,CAAS,EAAE,EAAE;gBACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACjC,OAAO,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;oBACnE,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,0BAA0B,CAAC;YACjC,CAAC;SACF;KACF,CAAC,CAAC;IAEH,MAAM,MAAM,GAAc;QACxB,QAAQ,EAAE;YACR,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE;YAC3B,SAAS,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;SACpC;QACD,MAAM,EAAE;YACN,gBAAgB,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC;YACxD,cAAc,EAAE,aAAa;YAC7B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChE;KACF,CAAC;IAEF,UAAU,CAAC,MAAM,CAAC,CAAC;IACnB,OAAO,CAAC,GAAG,CAAC,qBAAqB,aAAa,EAAE,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runStart(): Promise<void>;
2
+ //# sourceMappingURL=start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/cli/start.ts"],"names":[],"mappings":"AAGA,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAG9C"}
@@ -0,0 +1,7 @@
1
+ import { loadConfig } from "../config/config.js";
2
+ import { startBot } from "../bot/bot.js";
3
+ export async function runStart() {
4
+ const config = loadConfig();
5
+ await startBot(config);
6
+ }
7
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/cli/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,24 @@
1
+ export interface TelegramConfig {
2
+ token: string;
3
+ whitelist: number[];
4
+ }
5
+ export interface ClaudeConfig {
6
+ workingDirectory: string;
7
+ permissionMode: string;
8
+ allowedTools: string[];
9
+ }
10
+ export interface AppConfig {
11
+ telegram: TelegramConfig;
12
+ claude: ClaudeConfig;
13
+ }
14
+ export interface SessionMap {
15
+ [chatId: string]: string;
16
+ }
17
+ export declare function getConfigDir(): string;
18
+ export declare function getConfigPath(): string;
19
+ export declare function configExists(): boolean;
20
+ export declare function loadConfig(): AppConfig;
21
+ export declare function saveConfig(config: AppConfig): void;
22
+ export declare function loadSessions(): SessionMap;
23
+ export declare function saveSessions(sessions: SessionMap): void;
24
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/config/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAMD,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAQD,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED,wBAAgB,UAAU,IAAI,SAAS,CAQtC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAMlD;AAED,wBAAgB,YAAY,IAAI,UAAU,CAMzC;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI,CAMvD"}
@@ -0,0 +1,49 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ const CONFIG_DIR = path.join(os.homedir(), ".claude-telegram");
5
+ const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
6
+ const SESSIONS_FILE = path.join(CONFIG_DIR, "sessions.json");
7
+ export function getConfigDir() {
8
+ return CONFIG_DIR;
9
+ }
10
+ export function getConfigPath() {
11
+ return CONFIG_FILE;
12
+ }
13
+ function ensureConfigDir() {
14
+ if (!fs.existsSync(CONFIG_DIR)) {
15
+ fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
16
+ }
17
+ }
18
+ export function configExists() {
19
+ return fs.existsSync(CONFIG_FILE);
20
+ }
21
+ export function loadConfig() {
22
+ if (!configExists()) {
23
+ throw new Error(`Config not found. Run "claude-telegram init" first.`);
24
+ }
25
+ const raw = fs.readFileSync(CONFIG_FILE, "utf-8");
26
+ return JSON.parse(raw);
27
+ }
28
+ export function saveConfig(config) {
29
+ ensureConfigDir();
30
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), {
31
+ encoding: "utf-8",
32
+ mode: 0o600,
33
+ });
34
+ }
35
+ export function loadSessions() {
36
+ if (!fs.existsSync(SESSIONS_FILE)) {
37
+ return {};
38
+ }
39
+ const raw = fs.readFileSync(SESSIONS_FILE, "utf-8");
40
+ return JSON.parse(raw);
41
+ }
42
+ export function saveSessions(sessions) {
43
+ ensureConfigDir();
44
+ fs.writeFileSync(SESSIONS_FILE, JSON.stringify(sessions, null, 2), {
45
+ encoding: "utf-8",
46
+ mode: 0o600,
47
+ });
48
+ }
49
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAsBzB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AACzD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;AAE7D,MAAM,UAAU,YAAY;IAC1B,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,qDAAqD,CACtD,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,eAAe,EAAE,CAAC;IAClB,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAC7D,QAAQ,EAAE,OAAO;QACjB,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACpD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAoB;IAC/C,eAAe,EAAE,CAAC;IAClB,EAAE,CAAC,aAAa,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QACjE,QAAQ,EAAE,OAAO;QACjB,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "telegram-claude-code",
3
+ "version": "1.0.0",
4
+ "description": "Control Claude Code remotely via Telegram",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "telegram-claude-code": "dist/bin/claude-telegram.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "start": "node dist/bin/claude-telegram.js start",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": [
17
+ "claude",
18
+ "telegram",
19
+ "bot",
20
+ "claude-code",
21
+ "ai",
22
+ "cli"
23
+ ],
24
+ "type": "module",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/lucashcaraujo/cloude-telegram.git"
29
+ },
30
+ "homepage": "https://github.com/lucashcaraujo/cloude-telegram#readme",
31
+ "files": [
32
+ "dist",
33
+ "README.md"
34
+ ],
35
+ "engines": {
36
+ "node": ">=18.0.0"
37
+ },
38
+ "dependencies": {
39
+ "@anthropic-ai/claude-code": "^1.0.0",
40
+ "commander": "^13.0.0",
41
+ "inquirer": "^12.0.0",
42
+ "telegraf": "^4.16.0"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^22.0.0",
46
+ "typescript": "^5.7.0"
47
+ }
48
+ }