opencode-remote-control 0.1.0 → 0.1.3
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 +27 -19
- package/dist/cli.js +16 -13
- package/dist/telegram/bot.js +188 -158
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
# OpenCode Remote Control
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://github.com/ceociocto/opencode-remote-control/actions/workflows/publish.yml?query=branch%3Amain"><img src="https://img.shields.io/github/actions/workflow/status/ceociocto/opencode-remote-control/publish.yml?branch=main&style=for-the-badge" alt="CI status"></a>
|
|
5
|
+
<a href="https://www.npmjs.com/package/opencode-remote-control"><img src="https://img.shields.io/npm/v/opencode-remote-control?style=for-the-badge" alt="npm version"></a>
|
|
6
|
+
<a href="https://github.com/ceociocto/opencode-remote-control/releases"><img src="https://img.shields.io/github/v/release/ceociocto/opencode-remote-control?include_prereleases&style=for-the-badge" alt="GitHub release"></a>
|
|
7
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge" alt="MIT License"></a>
|
|
8
|
+
</p>
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="./README_CN.md">中文文档</a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
Control OpenCode from anywhere via Telegram.
|
|
16
|
+
</p>
|
|
6
17
|
|
|
7
18
|
## Installation
|
|
8
19
|
|
|
@@ -13,19 +24,6 @@ npm install -g opencode-remote-control
|
|
|
13
24
|
pnpm install -g opencode-remote-control
|
|
14
25
|
# or
|
|
15
26
|
bun install -g opencode-remote-control
|
|
16
|
-
|
|
17
|
-
# Run (will prompt for token on first run)
|
|
18
|
-
opencode-remote
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### Install from Source
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
git clone https://github.com/ceociocto/opencode-remote-control.git
|
|
25
|
-
cd opencode-remote-control
|
|
26
|
-
bun install
|
|
27
|
-
bun run build
|
|
28
|
-
node dist/cli.js
|
|
29
27
|
```
|
|
30
28
|
|
|
31
29
|
## Setup
|
|
@@ -38,16 +36,26 @@ On first run, you'll be prompted for a Telegram bot token:
|
|
|
38
36
|
|
|
39
37
|
Token is saved to `~/.opencode-remote/.env`
|
|
40
38
|
|
|
41
|
-
##
|
|
39
|
+
## Usage
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
```
|
|
41
|
+
```bash
|
|
45
42
|
opencode-remote # Start the bot
|
|
46
43
|
opencode-remote config # Reconfigure token
|
|
47
44
|
opencode-remote help # Show help
|
|
48
45
|
```
|
|
49
46
|
|
|
50
|
-
|
|
47
|
+
## Install from Source
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
git clone https://github.com/ceociocto/opencode-remote-control.git
|
|
51
|
+
cd opencode-remote-control
|
|
52
|
+
bun install
|
|
53
|
+
bun run build
|
|
54
|
+
node dist/cli.js
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Telegram Commands
|
|
58
|
+
|
|
51
59
|
| Command | Description |
|
|
52
60
|
|--------|-------------|
|
|
53
61
|
| `/start` | Start the bot |
|
package/dist/cli.js
CHANGED
|
@@ -48,16 +48,20 @@ async function promptToken() {
|
|
|
48
48
|
return token;
|
|
49
49
|
}
|
|
50
50
|
async function getConfig() {
|
|
51
|
-
// Check environment variable first
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
// Check environment variable first (must be non-empty)
|
|
52
|
+
const envToken = process.env.TELEGRAM_BOT_TOKEN;
|
|
53
|
+
if (envToken && envToken.trim()) {
|
|
54
|
+
return envToken.trim();
|
|
54
55
|
}
|
|
55
56
|
// Check config file
|
|
56
57
|
if (existsSync(CONFIG_FILE)) {
|
|
57
58
|
const content = readFileSync(CONFIG_FILE, 'utf-8');
|
|
58
59
|
const match = content.match(/TELEGRAM_BOT_TOKEN=(.+)/);
|
|
59
60
|
if (match) {
|
|
60
|
-
|
|
61
|
+
const token = match[1].trim();
|
|
62
|
+
if (token && token !== 'your_bot_token_here') {
|
|
63
|
+
return token;
|
|
64
|
+
}
|
|
61
65
|
}
|
|
62
66
|
}
|
|
63
67
|
// Check local .env
|
|
@@ -66,7 +70,10 @@ async function getConfig() {
|
|
|
66
70
|
const content = readFileSync(localEnv, 'utf-8');
|
|
67
71
|
const match = content.match(/TELEGRAM_BOT_TOKEN=(.+)/);
|
|
68
72
|
if (match) {
|
|
69
|
-
|
|
73
|
+
const token = match[1].trim();
|
|
74
|
+
if (token && token !== 'your_bot_token_here') {
|
|
75
|
+
return token;
|
|
76
|
+
}
|
|
70
77
|
}
|
|
71
78
|
}
|
|
72
79
|
return null;
|
|
@@ -88,18 +95,14 @@ async function runConfig() {
|
|
|
88
95
|
}
|
|
89
96
|
await saveConfig(token);
|
|
90
97
|
console.log('\n🚀 Ready! Run `opencode-remote` to start the bot.');
|
|
98
|
+
process.exit(0);
|
|
91
99
|
}
|
|
92
100
|
async function runStart() {
|
|
93
|
-
printBanner();
|
|
94
101
|
const token = await getConfig();
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return;
|
|
102
|
+
// Set token in environment for startBot to use
|
|
103
|
+
if (token) {
|
|
104
|
+
process.env.TELEGRAM_BOT_TOKEN = token;
|
|
99
105
|
}
|
|
100
|
-
// Set token in environment
|
|
101
|
-
process.env.TELEGRAM_BOT_TOKEN = token;
|
|
102
|
-
console.log('🚀 Starting bot...\n');
|
|
103
106
|
try {
|
|
104
107
|
await startBot();
|
|
105
108
|
}
|
package/dist/telegram/bot.js
CHANGED
|
@@ -4,24 +4,29 @@ import { loadConfig } from '../core/types.js';
|
|
|
4
4
|
import { initSessionManager, getOrCreateSession } from '../core/session.js';
|
|
5
5
|
import { splitMessage } from '../core/notifications.js';
|
|
6
6
|
import { initOpenCode, createSession, sendMessage, checkConnection } from '../opencode/client.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
// Lazy initialization - bot is only created when startBot() is called
|
|
8
|
+
let config = null;
|
|
9
|
+
let bot = null;
|
|
10
|
+
let openCodeSessions = null;
|
|
11
|
+
// Helper to get thread ID
|
|
12
|
+
function getThreadId(ctx) {
|
|
13
|
+
const chatId = ctx.chat?.id;
|
|
14
|
+
const threadId = ctx.message?.message_thread_id || ctx.message?.message_id;
|
|
15
|
+
return `${chatId}:${threadId}`;
|
|
16
|
+
}
|
|
17
|
+
// Setup bot commands
|
|
18
|
+
function setupBotCommands(bot, openCodeSessions) {
|
|
19
|
+
// Start command
|
|
20
|
+
bot.command('start', async (ctx) => {
|
|
21
|
+
await ctx.reply(`🚀 OpenCode Remote Control ready
|
|
17
22
|
|
|
18
23
|
💬 Send me a prompt to start coding
|
|
19
24
|
/help — see all commands
|
|
20
25
|
/status — check OpenCode connection`);
|
|
21
|
-
});
|
|
22
|
-
// Help command
|
|
23
|
-
bot.command('help', async (ctx) => {
|
|
24
|
-
|
|
26
|
+
});
|
|
27
|
+
// Help command
|
|
28
|
+
bot.command('help', async (ctx) => {
|
|
29
|
+
await ctx.reply(`📖 Commands
|
|
25
30
|
|
|
26
31
|
/start — Start bot
|
|
27
32
|
/status — Check connection
|
|
@@ -32,169 +37,194 @@ bot.command('help', async (ctx) => {
|
|
|
32
37
|
/files — List changed files
|
|
33
38
|
|
|
34
39
|
💬 Anything else is treated as a prompt for OpenCode!`);
|
|
35
|
-
});
|
|
36
|
-
// Status command
|
|
37
|
-
bot.command('status', async (ctx) => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
});
|
|
41
|
+
// Status command
|
|
42
|
+
bot.command('status', async (ctx) => {
|
|
43
|
+
const threadId = getThreadId(ctx);
|
|
44
|
+
const session = getOrCreateSession(threadId, 'telegram');
|
|
45
|
+
const openCodeSession = openCodeSessions.get(threadId);
|
|
46
|
+
// Check OpenCode connection
|
|
47
|
+
const connected = await checkConnection();
|
|
48
|
+
if (!connected) {
|
|
49
|
+
await ctx.reply(`❌ OpenCode is offline
|
|
45
50
|
|
|
46
51
|
Cannot connect to OpenCode server.
|
|
47
52
|
|
|
48
53
|
🔄 /retry — check again`);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const idleSeconds = Math.round((Date.now() - session.lastActivity) / 1000);
|
|
57
|
+
const pendingCount = session.pendingApprovals.length;
|
|
58
|
+
await ctx.reply(`✅ Connected
|
|
54
59
|
|
|
55
60
|
💬 Session: ${openCodeSession?.sessionId?.slice(0, 8) || 'none'}
|
|
56
61
|
⏰ Idle: ${idleSeconds}s
|
|
57
62
|
📝 Pending approvals: ${pendingCount}`);
|
|
58
|
-
});
|
|
59
|
-
// Approve command
|
|
60
|
-
bot.command('approve', async (ctx) => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
});
|
|
71
|
-
// Reject command
|
|
72
|
-
bot.command('reject', async (ctx) => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
});
|
|
82
|
-
// Reset command
|
|
83
|
-
bot.command('reset', async (ctx) => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
});
|
|
92
|
-
// Diff command
|
|
93
|
-
bot.command('diff', async (ctx) => {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
});
|
|
105
|
-
// Files command
|
|
106
|
-
bot.command('files', async (ctx) => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
});
|
|
117
|
-
// Retry command
|
|
118
|
-
bot.command('retry', async (ctx) => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
});
|
|
127
|
-
// Handle all other messages as prompts
|
|
128
|
-
bot.on('message:text', async (ctx) => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
63
|
+
});
|
|
64
|
+
// Approve command
|
|
65
|
+
bot.command('approve', async (ctx) => {
|
|
66
|
+
const threadId = getThreadId(ctx);
|
|
67
|
+
const session = getOrCreateSession(threadId, 'telegram');
|
|
68
|
+
if (session.pendingApprovals.length === 0) {
|
|
69
|
+
await ctx.reply('🤷 Nothing to approve right now');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Remove first pending approval
|
|
73
|
+
session.pendingApprovals.shift();
|
|
74
|
+
await ctx.reply('✅ Approved — changes applied');
|
|
75
|
+
});
|
|
76
|
+
// Reject command
|
|
77
|
+
bot.command('reject', async (ctx) => {
|
|
78
|
+
const threadId = getThreadId(ctx);
|
|
79
|
+
const session = getOrCreateSession(threadId, 'telegram');
|
|
80
|
+
if (session.pendingApprovals.length === 0) {
|
|
81
|
+
await ctx.reply('🤷 Nothing to reject right now');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
session.pendingApprovals.shift();
|
|
85
|
+
await ctx.reply('❌ Rejected — changes discarded');
|
|
86
|
+
});
|
|
87
|
+
// Reset command
|
|
88
|
+
bot.command('reset', async (ctx) => {
|
|
89
|
+
const threadId = getThreadId(ctx);
|
|
90
|
+
const session = getOrCreateSession(threadId, 'telegram');
|
|
91
|
+
session.pendingApprovals = [];
|
|
92
|
+
session.opencodeSessionId = undefined;
|
|
93
|
+
// Clear OpenCode session
|
|
94
|
+
openCodeSessions.delete(threadId);
|
|
95
|
+
await ctx.reply('🔄 Session reset. Start fresh!');
|
|
96
|
+
});
|
|
97
|
+
// Diff command
|
|
98
|
+
bot.command('diff', async (ctx) => {
|
|
99
|
+
const threadId = getThreadId(ctx);
|
|
100
|
+
const session = getOrCreateSession(threadId, 'telegram');
|
|
101
|
+
const pending = session.pendingApprovals[0];
|
|
102
|
+
if (!pending?.files?.length) {
|
|
103
|
+
await ctx.reply('📄 No pending changes to show');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// Show file list with changes
|
|
107
|
+
const fileList = pending.files.map(f => `• ${f.path} (+${f.additions}, -${f.deletions})`).join('\n');
|
|
108
|
+
await ctx.reply(`📄 Pending changes:\n\n${fileList}\n\n💬 /approve or /reject`);
|
|
109
|
+
});
|
|
110
|
+
// Files command
|
|
111
|
+
bot.command('files', async (ctx) => {
|
|
112
|
+
const threadId = getThreadId(ctx);
|
|
113
|
+
const session = getOrCreateSession(threadId, 'telegram');
|
|
114
|
+
const pending = session.pendingApprovals[0];
|
|
115
|
+
if (!pending?.files?.length) {
|
|
116
|
+
await ctx.reply('📄 No files changed in this session');
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const fileList = pending.files.map(f => `• ${f.path} (+${f.additions}, -${f.deletions})`).join('\n');
|
|
120
|
+
await ctx.reply(`📄 Changed files:\n\n${fileList}`);
|
|
121
|
+
});
|
|
122
|
+
// Retry command
|
|
123
|
+
bot.command('retry', async (ctx) => {
|
|
124
|
+
const connected = await checkConnection();
|
|
125
|
+
if (connected) {
|
|
126
|
+
await ctx.reply('✅ OpenCode is now online!');
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
await ctx.reply('❌ Still offline. Is OpenCode running?');
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// Handle all other messages as prompts
|
|
133
|
+
bot.on('message:text', async (ctx) => {
|
|
134
|
+
const text = ctx.message.text;
|
|
135
|
+
// Skip if it's a command (already handled)
|
|
136
|
+
if (text.startsWith('/'))
|
|
137
|
+
return;
|
|
138
|
+
const threadId = getThreadId(ctx);
|
|
139
|
+
// Send typing indicator
|
|
140
|
+
await ctx.api.sendChatAction(ctx.chat.id, 'typing');
|
|
141
|
+
// Get or create session
|
|
142
|
+
const session = getOrCreateSession(threadId, 'telegram');
|
|
143
|
+
// Check OpenCode connection
|
|
144
|
+
const connected = await checkConnection();
|
|
145
|
+
if (!connected) {
|
|
146
|
+
await ctx.reply(`❌ OpenCode is offline
|
|
142
147
|
|
|
143
148
|
Cannot connect to OpenCode server.
|
|
144
149
|
|
|
145
150
|
🔄 /retry — check again`);
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
// Get or create OpenCode session
|
|
149
|
-
let openCodeSession = openCodeSessions.get(threadId);
|
|
150
|
-
if (!openCodeSession) {
|
|
151
|
-
await ctx.reply('⏳ Creating session...');
|
|
152
|
-
const newSession = await createSession(threadId, `Telegram thread ${threadId}`);
|
|
153
|
-
if (!newSession) {
|
|
154
|
-
await ctx.reply('❌ Failed to create OpenCode session');
|
|
155
151
|
return;
|
|
156
152
|
}
|
|
157
|
-
|
|
158
|
-
openCodeSessions.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
153
|
+
// Get or create OpenCode session
|
|
154
|
+
let openCodeSession = openCodeSessions.get(threadId);
|
|
155
|
+
if (!openCodeSession) {
|
|
156
|
+
await ctx.reply('⏳ Creating session...');
|
|
157
|
+
const newSession = await createSession(threadId, `Telegram thread ${threadId}`);
|
|
158
|
+
if (!newSession) {
|
|
159
|
+
await ctx.reply('❌ Failed to create OpenCode session');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
openCodeSession = newSession;
|
|
163
|
+
openCodeSessions.set(threadId, openCodeSession);
|
|
164
|
+
session.opencodeSessionId = openCodeSession.sessionId;
|
|
165
|
+
// Share the session URL
|
|
166
|
+
if (openCodeSession.shareUrl) {
|
|
167
|
+
await ctx.reply(`🔗 Session: ${openCodeSession.shareUrl}`);
|
|
168
|
+
}
|
|
163
169
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
// Send prompt to OpenCode
|
|
171
|
+
await ctx.reply('⏳ Thinking...');
|
|
172
|
+
try {
|
|
173
|
+
const response = await sendMessage(openCodeSession, text);
|
|
174
|
+
// Split long messages
|
|
175
|
+
const messages = splitMessage(response);
|
|
176
|
+
for (const msg of messages) {
|
|
177
|
+
await ctx.reply(msg);
|
|
178
|
+
}
|
|
173
179
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
//
|
|
185
|
-
function getThreadId(ctx) {
|
|
186
|
-
const chatId = ctx.chat?.id;
|
|
187
|
-
const threadId = ctx.message?.message_thread_id || ctx.message?.message_id;
|
|
188
|
-
return `${chatId}:${threadId}`;
|
|
189
|
-
}
|
|
190
|
-
export { bot };
|
|
191
|
-
// Start bot function
|
|
180
|
+
catch (error) {
|
|
181
|
+
console.error('Error sending message:', error);
|
|
182
|
+
await ctx.reply(`❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
// Error handling
|
|
186
|
+
bot.catch((err) => {
|
|
187
|
+
console.error('Bot error:', err);
|
|
188
|
+
});
|
|
189
|
+
} // End of setupBotCommands
|
|
190
|
+
// Start bot function - initializes everything lazily
|
|
192
191
|
export async function startBot() {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
// Load config
|
|
193
|
+
config = loadConfig();
|
|
194
|
+
if (!config.telegramBotToken || config.telegramBotToken === 'your_bot_token_here') {
|
|
195
|
+
console.log('');
|
|
196
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
197
|
+
console.log(' ❌ Telegram Bot Token not configured');
|
|
198
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
199
|
+
console.log('');
|
|
200
|
+
console.log(' To get your bot token:');
|
|
201
|
+
console.log('');
|
|
202
|
+
console.log(' 1. Open Telegram app');
|
|
203
|
+
console.log(' 2. Search for @BotFather');
|
|
204
|
+
console.log(' 3. Send: /newbot');
|
|
205
|
+
console.log(' 4. Follow the instructions to create your bot');
|
|
206
|
+
console.log(' 5. Copy the token (looks like: 123456789:ABCdef...)');
|
|
207
|
+
console.log('');
|
|
208
|
+
console.log(' Then run: opencode-remote config');
|
|
209
|
+
console.log('');
|
|
210
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
196
211
|
process.exit(1);
|
|
197
212
|
}
|
|
213
|
+
// Show banner
|
|
214
|
+
console.log('');
|
|
215
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
216
|
+
console.log(' OpenCode Remote Control');
|
|
217
|
+
console.log(' Control OpenCode from Telegram');
|
|
218
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
219
|
+
console.log('');
|
|
220
|
+
// Create bot instance
|
|
221
|
+
bot = new Bot(config.telegramBotToken);
|
|
222
|
+
// Initialize session manager
|
|
223
|
+
initSessionManager(config);
|
|
224
|
+
// Initialize OpenCode sessions map
|
|
225
|
+
openCodeSessions = new Map();
|
|
226
|
+
// Setup bot commands
|
|
227
|
+
setupBotCommands(bot, openCodeSessions);
|
|
198
228
|
// Initialize OpenCode
|
|
199
229
|
console.log('🔧 Initializing OpenCode...');
|
|
200
230
|
try {
|