@fonz/tgcc 0.0.1 → 0.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/LICENSE +21 -0
- package/README.md +266 -0
- package/dist/bridge.d.ts +32 -0
- package/dist/bridge.js +1193 -0
- package/dist/bridge.js.map +1 -0
- package/dist/cc-process.d.ts +75 -0
- package/dist/cc-process.js +426 -0
- package/dist/cc-process.js.map +1 -0
- package/dist/cc-protocol.d.ts +255 -0
- package/dist/cc-protocol.js +109 -0
- package/dist/cc-protocol.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +668 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +75 -0
- package/dist/config.js +268 -0
- package/dist/config.js.map +1 -0
- package/dist/ctl-server.d.ts +57 -0
- package/dist/ctl-server.js +98 -0
- package/dist/ctl-server.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-bridge.d.ts +45 -0
- package/dist/mcp-bridge.js +182 -0
- package/dist/mcp-bridge.js.map +1 -0
- package/dist/mcp-server.d.ts +1 -0
- package/dist/mcp-server.js +109 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/service.d.ts +1 -0
- package/dist/service.js +84 -0
- package/dist/service.js.map +1 -0
- package/dist/session.d.ts +71 -0
- package/dist/session.js +438 -0
- package/dist/session.js.map +1 -0
- package/dist/streaming.d.ts +178 -0
- package/dist/streaming.js +814 -0
- package/dist/streaming.js.map +1 -0
- package/dist/telegram-html.d.ts +5 -0
- package/dist/telegram-html.js +120 -0
- package/dist/telegram-html.js.map +1 -0
- package/dist/telegram.d.ts +71 -0
- package/dist/telegram.js +384 -0
- package/dist/telegram.js.map +1 -0
- package/package.json +95 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 fnz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# @fonz/tgcc
|
|
2
|
+
|
|
3
|
+
**Telegram ↔ Claude Code bridge** — run Claude Code sessions from Telegram with full streaming, inline editing, and multi-agent support.
|
|
4
|
+
|
|
5
|
+
## What is TGCC?
|
|
6
|
+
|
|
7
|
+
TGCC bridges the [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) to Telegram, turning any Telegram bot into a full Claude Code client.
|
|
8
|
+
|
|
9
|
+
- **Streaming output** — CC responses stream into a single Telegram message that updates in place (no message spam)
|
|
10
|
+
- **Multi-agent** — run one bot per project/repo, each with its own config, model, and permissions
|
|
11
|
+
- **Session management** — resume, switch, and list sessions with inline keyboard buttons
|
|
12
|
+
- **Permission relay** — CC permission prompts appear as inline buttons (Allow / Deny / Allow All)
|
|
13
|
+
- **Thinking display** — thinking content shown as expandable blockquotes (collapsible in Telegram)
|
|
14
|
+
- **Sub-agent threading** — sub-agent tool calls appear as threaded replies to the main message
|
|
15
|
+
- **Staleness detection** — detects when a session was modified externally (e.g. from VS Code) and reconnects
|
|
16
|
+
- **Usage stats** — per-turn token counts and cost shown as a subtle footer
|
|
17
|
+
- **CLI tool** — send messages from your terminal, manage agents and repos
|
|
18
|
+
- **HTML formatting** — code blocks with syntax highlighting, bold, italic, links
|
|
19
|
+
|
|
20
|
+
## Architecture
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
User ──► Telegram ──► TGCC ──► Claude Code CLI (stream-json)
|
|
24
|
+
│
|
|
25
|
+
config.json (agents, repos, permissions)
|
|
26
|
+
state.json (sessions, models, per-user overrides)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
TGCC runs as a persistent service. Each configured agent connects to its own Telegram bot. When a user sends a message, TGCC spawns (or reuses) a Claude Code process using the `stream-json` protocol, forwards the message, and streams the response back to Telegram with edit-in-place updates.
|
|
30
|
+
|
|
31
|
+
**Key design decisions:**
|
|
32
|
+
- **Config-driven** — everything in `~/.tgcc/config.json`, hot-reloaded on changes
|
|
33
|
+
- **Unix sockets** — CLI communicates with the running service via per-agent sockets in `/tmp/tgcc/ctl/`
|
|
34
|
+
- **MCP bridge** — CC can send files, images, and voice back to the user via a built-in MCP server
|
|
35
|
+
- **State-aware hang detection** — distinguishes between API waits, tool execution (checks child processes), and real hangs
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Install
|
|
41
|
+
npm install -g @fonz/tgcc
|
|
42
|
+
|
|
43
|
+
# Create a Telegram bot via @BotFather, get the token
|
|
44
|
+
|
|
45
|
+
# Register an agent
|
|
46
|
+
tgcc agent add mybot --bot-token 123456:ABC-DEF --repo ~/myproject
|
|
47
|
+
|
|
48
|
+
# Start the service
|
|
49
|
+
tgcc
|
|
50
|
+
|
|
51
|
+
# Send your bot a message on Telegram!
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
Config lives at `~/.tgcc/config.json`. TGCC creates it automatically when you run `tgcc agent add`.
|
|
57
|
+
|
|
58
|
+
```jsonc
|
|
59
|
+
{
|
|
60
|
+
"global": {
|
|
61
|
+
"ccBinaryPath": "claude", // Path to claude CLI binary
|
|
62
|
+
"logLevel": "info",
|
|
63
|
+
"mediaDir": "~/.tgcc/media",
|
|
64
|
+
"socketDir": "/tmp/tgcc",
|
|
65
|
+
"stateFile": "~/.tgcc/state.json"
|
|
66
|
+
},
|
|
67
|
+
"repos": {
|
|
68
|
+
"myproject": "/home/user/myproject",
|
|
69
|
+
"backend": "/home/user/backend"
|
|
70
|
+
},
|
|
71
|
+
"agents": {
|
|
72
|
+
"mybot": {
|
|
73
|
+
"botToken": "123456:ABC-DEF...",
|
|
74
|
+
"allowedUsers": ["123456789"], // Telegram user IDs
|
|
75
|
+
"defaults": {
|
|
76
|
+
"model": "claude-sonnet-4-20250514",
|
|
77
|
+
"repo": "myproject",
|
|
78
|
+
"permissionMode": "acceptEdits",
|
|
79
|
+
"maxTurns": 30,
|
|
80
|
+
"idleTimeoutMs": 600000,
|
|
81
|
+
"hangTimeoutMs": 300000
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Permission Modes
|
|
89
|
+
|
|
90
|
+
| Mode | Description |
|
|
91
|
+
|------|-------------|
|
|
92
|
+
| `dangerously-skip` | Skip all permission prompts (⚠️ use with care) |
|
|
93
|
+
| `acceptEdits` | Auto-accept file edits, prompt for everything else |
|
|
94
|
+
| `default` | CC's built-in permission flow — prompts appear as inline buttons in Telegram |
|
|
95
|
+
| `plan` | Plan-only mode, no tool execution |
|
|
96
|
+
|
|
97
|
+
### Repo Registry
|
|
98
|
+
|
|
99
|
+
Repos are named shortcuts for project paths. Register them once, use everywhere:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
tgcc repo add myproject ~/code/myproject
|
|
103
|
+
tgcc repo add backend ~/code/backend
|
|
104
|
+
tgcc repo assign mybot myproject # Set as agent's default
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
In Telegram, `/repo` shows an inline keyboard to switch repos on the fly.
|
|
108
|
+
|
|
109
|
+
## Telegram Commands
|
|
110
|
+
|
|
111
|
+
| Command | Description |
|
|
112
|
+
|---------|-------------|
|
|
113
|
+
| `/start` | Welcome message, register bot commands |
|
|
114
|
+
| `/help` | List all commands |
|
|
115
|
+
| `/new` | Start a fresh session |
|
|
116
|
+
| `/sessions` | List recent sessions with Resume/Delete buttons |
|
|
117
|
+
| `/resume <id>` | Resume a session by ID |
|
|
118
|
+
| `/session` | Current session info |
|
|
119
|
+
| `/status` | Process state, model, repo, uptime, cost |
|
|
120
|
+
| `/cost` | Show session cost |
|
|
121
|
+
| `/model <name>` | Switch model (takes effect on next spawn) |
|
|
122
|
+
| `/permissions` | Set permission mode with inline buttons |
|
|
123
|
+
| `/repo` | Switch repo with inline buttons |
|
|
124
|
+
| `/cancel` | Abort current CC turn (sends SIGINT) |
|
|
125
|
+
| `/catchup` | Summarize external CC activity on the same repo |
|
|
126
|
+
| `/ping` | Liveness check |
|
|
127
|
+
|
|
128
|
+
### Examples
|
|
129
|
+
|
|
130
|
+
**Start a conversation:**
|
|
131
|
+
> You: Fix the auth middleware to handle expired tokens
|
|
132
|
+
|
|
133
|
+
> Bot:
|
|
134
|
+
> <blockquote expandable>💭 Thinking<br>Looking at the auth middleware...</blockquote>
|
|
135
|
+
>
|
|
136
|
+
> I've updated `src/middleware/auth.ts` to handle expired tokens gracefully...
|
|
137
|
+
>
|
|
138
|
+
> *↩️ 1.2k in · 450 out · $0.0034*
|
|
139
|
+
|
|
140
|
+
**Permission prompt (when not using bypass mode):**
|
|
141
|
+
> 🔐 CC wants to use `Write`
|
|
142
|
+
> ```{"file_path": "src/auth.ts", ...}```
|
|
143
|
+
>
|
|
144
|
+
> `[✅ Allow]` `[❌ Deny]` `[✅ Allow All]`
|
|
145
|
+
|
|
146
|
+
**Switch repos:**
|
|
147
|
+
> `/repo`
|
|
148
|
+
>
|
|
149
|
+
> Current repo: `~/myproject`
|
|
150
|
+
>
|
|
151
|
+
> `[myproject]`
|
|
152
|
+
> `[backend]`
|
|
153
|
+
> `[➕ Add]` `[❓ Help]`
|
|
154
|
+
|
|
155
|
+
## CLI Commands
|
|
156
|
+
|
|
157
|
+
The `tgcc` CLI communicates with the running service via Unix sockets.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Start the service (foreground)
|
|
161
|
+
tgcc
|
|
162
|
+
|
|
163
|
+
# Send a message to a running agent
|
|
164
|
+
tgcc message "fix the login bug" --agent mybot
|
|
165
|
+
tgcc msg "deploy to staging" --agent mybot --session abc123
|
|
166
|
+
|
|
167
|
+
# Check status
|
|
168
|
+
tgcc status
|
|
169
|
+
tgcc status --agent mybot
|
|
170
|
+
|
|
171
|
+
# Agent management
|
|
172
|
+
tgcc agent add mybot --bot-token <token> --repo ~/project
|
|
173
|
+
tgcc agent remove mybot
|
|
174
|
+
tgcc agent rename mybot newname
|
|
175
|
+
tgcc agent list
|
|
176
|
+
tgcc agent repo mybot backend # Set default repo
|
|
177
|
+
|
|
178
|
+
# Repo management
|
|
179
|
+
tgcc repo add myproject ~/code/myproject
|
|
180
|
+
tgcc repo remove myproject
|
|
181
|
+
tgcc repo assign mybot myproject
|
|
182
|
+
tgcc repo clear mybot
|
|
183
|
+
tgcc repo list
|
|
184
|
+
|
|
185
|
+
# Permissions
|
|
186
|
+
tgcc permissions set mybot dangerously-skip
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Features in Detail
|
|
190
|
+
|
|
191
|
+
### Streaming with Edit-in-Place
|
|
192
|
+
|
|
193
|
+
CC output streams into a single Telegram message. As CC produces text, TGCC edits the same message with the accumulated content (throttled to ~1 edit/second to respect Telegram rate limits). When the message gets too long (~4000 chars), it splits into a new message.
|
|
194
|
+
|
|
195
|
+
### HTML Formatting
|
|
196
|
+
|
|
197
|
+
All output uses Telegram's HTML parse mode:
|
|
198
|
+
- Code blocks → `<pre><code class="language-python">...</code></pre>`
|
|
199
|
+
- Inline code → `<code>...</code>`
|
|
200
|
+
- Bold, italic, strikethrough, links — all converted from CC's markdown
|
|
201
|
+
|
|
202
|
+
### Thinking in Expandable Blockquotes
|
|
203
|
+
|
|
204
|
+
When CC thinks, the thinking content is captured and displayed as a collapsible blockquote:
|
|
205
|
+
|
|
206
|
+
```html
|
|
207
|
+
<blockquote expandable>💭 Thinking
|
|
208
|
+
Analyzing the auth middleware pattern...
|
|
209
|
+
</blockquote>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Users can tap to expand and see what CC was thinking.
|
|
213
|
+
|
|
214
|
+
### Sub-Agent Activity
|
|
215
|
+
|
|
216
|
+
When CC spawns sub-agents (via `dispatch_agent`, `Task`, etc.), TGCC sends a threaded reply:
|
|
217
|
+
|
|
218
|
+
> 🔄 Sub-agent spawned: `dispatch_agent`
|
|
219
|
+
> *(updates with input preview, then ✅ on completion)*
|
|
220
|
+
|
|
221
|
+
### Smart Hang Detection
|
|
222
|
+
|
|
223
|
+
TGCC tracks CC's activity state and checks for active child processes before declaring a hang:
|
|
224
|
+
- **Tool executing** with active children → extend timer
|
|
225
|
+
- **Waiting for API** → extend timer (API can be slow)
|
|
226
|
+
- **No activity** for hangTimeoutMs → truly hung, kill and notify
|
|
227
|
+
|
|
228
|
+
### Session Staleness Detection
|
|
229
|
+
|
|
230
|
+
If you use the same CC session from both Telegram and VS Code, TGCC detects the modification when you next message from Telegram. It shows a summary of what happened externally and reconnects cleanly.
|
|
231
|
+
|
|
232
|
+
## How It Works with Claude Code
|
|
233
|
+
|
|
234
|
+
TGCC uses CC's `stream-json` protocol:
|
|
235
|
+
|
|
236
|
+
1. **Spawn** — `claude -p --input-format stream-json --output-format stream-json --verbose --include-partial-messages`
|
|
237
|
+
2. **Initialize** — Send `control_request` with `subtype: "initialize"` (SDK handshake)
|
|
238
|
+
3. **Messages** — Write JSON user messages to stdin, parse NDJSON events from stdout
|
|
239
|
+
4. **Streaming** — `stream_event` wraps inner events: `message_start`, `content_block_start`, `content_block_delta` (text, thinking, image), `content_block_stop`, `message_stop`
|
|
240
|
+
5. **Permissions** — CC sends `control_request` with `subtype: "can_use_tool"`, TGCC relays to Telegram and sends `control_response` back
|
|
241
|
+
6. **Sessions** — `--resume <id>` reconnects to an existing session, same JSONL files as the VS Code extension
|
|
242
|
+
7. **Results** — `result` event with cost, token usage, success/error status
|
|
243
|
+
|
|
244
|
+
Sessions are fully interoperable with the VS Code Claude Code extension — the same `~/.claude/projects/` JSONL files are used by both.
|
|
245
|
+
|
|
246
|
+
## Project Structure
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
src/
|
|
250
|
+
├── cli.ts # CLI tool (tgcc command)
|
|
251
|
+
├── bridge.ts # Core orchestrator (TG ↔ CC)
|
|
252
|
+
├── cc-process.ts # CC process lifecycle management
|
|
253
|
+
├── cc-protocol.ts # CC stream-json protocol types & parser
|
|
254
|
+
├── streaming.ts # Stream accumulator (edit-in-place, splitting)
|
|
255
|
+
├── telegram.ts # Telegram bot (grammY)
|
|
256
|
+
├── config.ts # Config loading, validation, hot-reload
|
|
257
|
+
├── session.ts # Session store, staleness, catchup
|
|
258
|
+
├── ctl-server.ts # Unix socket server for CLI communication
|
|
259
|
+
├── mcp-bridge.ts # MCP server for CC → TG file/image/voice
|
|
260
|
+
├── mcp-server.ts # MCP tool definitions
|
|
261
|
+
└── index.ts # Entry point
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
MIT
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import pino from 'pino';
|
|
3
|
+
import type { TgccConfig, ConfigDiff } from './config.js';
|
|
4
|
+
import { type CtlHandler, type CtlAckResponse, type CtlStatusResponse } from './ctl-server.js';
|
|
5
|
+
export declare class Bridge extends EventEmitter implements CtlHandler {
|
|
6
|
+
private config;
|
|
7
|
+
private agents;
|
|
8
|
+
private mcpServer;
|
|
9
|
+
private ctlServer;
|
|
10
|
+
private sessionStore;
|
|
11
|
+
private logger;
|
|
12
|
+
constructor(config: TgccConfig, logger?: pino.Logger);
|
|
13
|
+
start(): Promise<void>;
|
|
14
|
+
private startAgent;
|
|
15
|
+
handleConfigChange(newConfig: TgccConfig, diff: ConfigDiff): Promise<void>;
|
|
16
|
+
private stopAgent;
|
|
17
|
+
private handleTelegramMessage;
|
|
18
|
+
private sendToCC;
|
|
19
|
+
/** Check if the session JSONL was modified externally since we last tracked it. */
|
|
20
|
+
private checkSessionStaleness;
|
|
21
|
+
/** Update JSONL tracking from the current file state. */
|
|
22
|
+
private updateJsonlTracking;
|
|
23
|
+
private spawnCCProcess;
|
|
24
|
+
private handleStreamEvent;
|
|
25
|
+
private handleResult;
|
|
26
|
+
private handleSlashCommand;
|
|
27
|
+
private handleCallbackQuery;
|
|
28
|
+
handleCtlMessage(agentId: string, text: string, sessionId?: string): CtlAckResponse;
|
|
29
|
+
handleCtlStatus(agentId?: string): CtlStatusResponse;
|
|
30
|
+
private handleMcpToolRequest;
|
|
31
|
+
stop(): Promise<void>;
|
|
32
|
+
}
|