@coffer-org/plugin-telegram 1.1.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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/bot.d.ts +19 -0
- package/dist/runtime/bot.d.ts.map +1 -0
- package/dist/runtime/bot.js +229 -0
- package/dist/runtime/bot.js.map +1 -0
- package/dist/runtime/config.d.ts +33 -0
- package/dist/runtime/config.d.ts.map +1 -0
- package/dist/runtime/config.js +42 -0
- package/dist/runtime/config.js.map +1 -0
- package/dist/runtime/index.d.ts +30 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +22 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/threads.d.ts +41 -0
- package/dist/runtime/threads.d.ts.map +1 -0
- package/dist/runtime/threads.js +63 -0
- package/dist/runtime/threads.js.map +1 -0
- package/dist/runtime/workspace.d.ts +18 -0
- package/dist/runtime/workspace.d.ts.map +1 -0
- package/dist/runtime/workspace.js +59 -0
- package/dist/runtime/workspace.js.map +1 -0
- package/package.json +30 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,wBAiBG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Плагін telegram — воркер без vaults/modules. Маніфест ІЗОМОРФНИЙ: не імпортує
|
|
3
|
+
* node-рантайм (src/runtime/*), бо потрапляє у web-бандл через src/registry.ts.
|
|
4
|
+
* Запуск/зупинка бота — у серверних хуках (packages/server/src/plugin-hooks.ts).
|
|
5
|
+
*/
|
|
6
|
+
import { definePlugin } from '@coffer-org/sdk/plugin';
|
|
7
|
+
import { defineSettings } from '@coffer-org/sdk/settings';
|
|
8
|
+
import { field } from '@coffer-org/sdk/fields';
|
|
9
|
+
export default definePlugin({
|
|
10
|
+
id: 'telegram',
|
|
11
|
+
version: '1.0.0',
|
|
12
|
+
dependsOn: [],
|
|
13
|
+
settings: defineSettings({
|
|
14
|
+
label: 'telegram.settings.label',
|
|
15
|
+
fields: [
|
|
16
|
+
field.int({ key: 'api_id', label: 'telegram.settings.api_id' }),
|
|
17
|
+
field.password({ key: 'api_hash', label: 'telegram.settings.api_hash' }),
|
|
18
|
+
field.password({ key: 'bot_token', label: 'telegram.settings.bot_token' }),
|
|
19
|
+
field.tel({ key: 'phone', label: 'telegram.settings.phone' }),
|
|
20
|
+
field.string({ key: 'claude_model', label: 'telegram.settings.claude_model' }),
|
|
21
|
+
field.string({ key: 'trigger_prefix', label: 'telegram.settings.trigger_prefix' }),
|
|
22
|
+
field.int({ key: 'response_timeout', label: 'telegram.settings.response_timeout' }),
|
|
23
|
+
field.boolean({ key: 'skip_permissions', label: 'telegram.settings.skip_permissions' }),
|
|
24
|
+
],
|
|
25
|
+
}),
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAE/C,eAAe,YAAY,CAAC;IAC1B,EAAE,EAAE,UAAU;IACd,OAAO,EAAE,OAAO;IAChB,SAAS,EAAE,EAAE;IACb,QAAQ,EAAE,cAAc,CAAC;QACvB,KAAK,EAAE,yBAAyB;QAChC,MAAM,EAAE;YACN,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC;YAC/D,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC;YACxE,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAC;YAC1E,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;YAC7D,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC;YAC9E,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC;YAClF,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,kBAAkB,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAC;YACnF,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,kBAAkB,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAC;SACxF;KACF,CAAC;CACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Env-оверрайди для `claude`: ізольований конфіг-дім (auth — через symlink у claude-home). */
|
|
2
|
+
export function claudeEnv(cfg: any): {
|
|
3
|
+
CLAUDE_CONFIG_DIR: any;
|
|
4
|
+
};
|
|
5
|
+
/** Зібрати argv для `claude -p`. sessionId=null → нова сесія (json), інакше --resume. */
|
|
6
|
+
export function buildClaudeArgs(cfg: any, sessionId: any): any[];
|
|
7
|
+
/** Розпарсити stdout `claude --output-format json` → { text, sessionId }. */
|
|
8
|
+
export function parseClaudeResult(stdout: any): {
|
|
9
|
+
text: any;
|
|
10
|
+
sessionId: any;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Стартувати бота. Тихо не запускається, якщо немає креденшелів
|
|
14
|
+
* (сервер працює далі). Кидає лише на справжній збій підключення.
|
|
15
|
+
*/
|
|
16
|
+
export function startBot(opts?: {}): Promise<boolean>;
|
|
17
|
+
/** Зупинити бота (викликається з shutdown сервера). Безпечно за відсутності клієнта. */
|
|
18
|
+
export function stopBot(): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=bot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../src/runtime/bot.js"],"names":[],"mappings":"AAkCA,+FAA+F;AAC/F;;EAEC;AAED,yFAAyF;AACzF,iEAMC;AAED,6EAA6E;AAC7E;;;EAOC;AA0DD;;;GAGG;AACH,sDAiHC;AAED,wFAAwF;AACxF,yCASC"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import pkg from 'telegram';
|
|
6
|
+
import { StringSession } from 'telegram/sessions/index.js';
|
|
7
|
+
import { NewMessage } from 'telegram/events/index.js';
|
|
8
|
+
import { loadBotConfig, hasCredentials } from './config.js';
|
|
9
|
+
import { ensureWorkspace } from './workspace.js';
|
|
10
|
+
import { loadThreads, saveThreads, resolveParent, getSession, recordSession, pruneThreads } from './threads.js';
|
|
11
|
+
const { TelegramClient } = pkg;
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const MAX_MESSAGE_LENGTH = 4096;
|
|
14
|
+
const log = {
|
|
15
|
+
info: (m) => console.log(`[telegram-bot] ${new Date().toISOString().slice(0, 19)} ${m}`),
|
|
16
|
+
warn: (m) => console.warn(`[telegram-bot] ${new Date().toISOString().slice(0, 19)} WARN ${m}`),
|
|
17
|
+
error: (m) => console.error(`[telegram-bot] ${new Date().toISOString().slice(0, 19)} ERROR ${m}`),
|
|
18
|
+
};
|
|
19
|
+
function loadSessionString(file) {
|
|
20
|
+
try {
|
|
21
|
+
return fs.readFileSync(file, 'utf-8');
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function saveSessionString(file, s) {
|
|
28
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
29
|
+
fs.writeFileSync(file, s, 'utf-8');
|
|
30
|
+
}
|
|
31
|
+
/** Env-оверрайди для `claude`: ізольований конфіг-дім (auth — через symlink у claude-home). */
|
|
32
|
+
export function claudeEnv(cfg) {
|
|
33
|
+
return { CLAUDE_CONFIG_DIR: cfg.claudeHomeDir };
|
|
34
|
+
}
|
|
35
|
+
/** Зібрати argv для `claude -p`. sessionId=null → нова сесія (json), інакше --resume. */
|
|
36
|
+
export function buildClaudeArgs(cfg, sessionId) {
|
|
37
|
+
const args = ['-p', '--model', cfg.claudeModel, '--output-format', 'json'];
|
|
38
|
+
if (cfg.skipPermissions)
|
|
39
|
+
args.push('--dangerously-skip-permissions');
|
|
40
|
+
if (sessionId)
|
|
41
|
+
args.push('--resume', sessionId);
|
|
42
|
+
args.push('--mcp-config', path.join(cfg.workspaceDir, '.mcp.json'));
|
|
43
|
+
return args;
|
|
44
|
+
}
|
|
45
|
+
/** Розпарсити stdout `claude --output-format json` → { text, sessionId }. */
|
|
46
|
+
export function parseClaudeResult(stdout) {
|
|
47
|
+
try {
|
|
48
|
+
const obj = JSON.parse(stdout);
|
|
49
|
+
return { text: (obj.result ?? '').trim() || '(порожня відповідь)', sessionId: obj.session_id ?? null };
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return { text: stdout.trim() || '(порожня відповідь)', sessionId: null };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Запустити `claude` headless в ІЗОЛЬОВАНОМУ runtime: cwd=workspace,
|
|
57
|
+
* CLAUDE_CONFIG_DIR=claude-home (0 глобальних плагінів/скілів), тільки coffer MCP.
|
|
58
|
+
* @returns {Promise<{text:string|null, sessionId:string|null}>}
|
|
59
|
+
*/
|
|
60
|
+
function runClaude(prompt, cfg, sessionId) {
|
|
61
|
+
return new Promise((resolve) => {
|
|
62
|
+
const args = buildClaudeArgs(cfg, sessionId);
|
|
63
|
+
const proc = spawn('claude', args, {
|
|
64
|
+
cwd: cfg.workspaceDir,
|
|
65
|
+
env: { ...process.env, ...claudeEnv(cfg) },
|
|
66
|
+
});
|
|
67
|
+
let stdout = '';
|
|
68
|
+
let stderr = '';
|
|
69
|
+
const timer = setTimeout(() => {
|
|
70
|
+
log.warn(`claude таймаут ${cfg.responseTimeout}s — kill`);
|
|
71
|
+
proc.kill('SIGKILL');
|
|
72
|
+
}, cfg.responseTimeout * 1000);
|
|
73
|
+
proc.stdout.on('data', (d) => {
|
|
74
|
+
stdout += d.toString();
|
|
75
|
+
});
|
|
76
|
+
proc.stderr.on('data', (d) => {
|
|
77
|
+
stderr += d.toString();
|
|
78
|
+
});
|
|
79
|
+
proc.on('error', (e) => {
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
log.error(`claude spawn: ${e.message}`);
|
|
82
|
+
resolve({ text: `⚠️ не вдалося запустити claude: ${e.message}`, sessionId: null });
|
|
83
|
+
});
|
|
84
|
+
proc.on('close', (code) => {
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
if (code === 0) {
|
|
87
|
+
resolve(parseClaudeResult(stdout));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
log.error(`claude exit ${code}: ${stderr.slice(0, 800)}`);
|
|
91
|
+
resolve({ text: stderr.trim() ? `⚠️ ${stderr.slice(0, 400)}` : null, sessionId: null });
|
|
92
|
+
});
|
|
93
|
+
proc.stdin.write(prompt);
|
|
94
|
+
proc.stdin.end();
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async function sendLong(client, peer, text) {
|
|
98
|
+
let last;
|
|
99
|
+
for (let i = 0; i < text.length; i += MAX_MESSAGE_LENGTH) {
|
|
100
|
+
last = await client.sendMessage(peer, { message: text.slice(i, i + MAX_MESSAGE_LENGTH) });
|
|
101
|
+
if (i + MAX_MESSAGE_LENGTH < text.length)
|
|
102
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
103
|
+
}
|
|
104
|
+
return last;
|
|
105
|
+
}
|
|
106
|
+
let client; // активний клієнт (для stopBot)
|
|
107
|
+
/**
|
|
108
|
+
* Стартувати бота. Тихо не запускається, якщо немає креденшелів
|
|
109
|
+
* (сервер працює далі). Кидає лише на справжній збій підключення.
|
|
110
|
+
*/
|
|
111
|
+
export async function startBot(opts = {}) {
|
|
112
|
+
const cfg = loadBotConfig(opts);
|
|
113
|
+
if (!hasCredentials(cfg)) {
|
|
114
|
+
log.warn('немає креденшелів (api_id/api_hash + bot_token|phone) — не стартую. Заповни налаштування плагіна або встанови env-змінні TELEGRAM_*');
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
ensureWorkspace(cfg, log);
|
|
118
|
+
const sessionFile = path.join(cfg.stateDir, '.sessions', 'claude_bot.session');
|
|
119
|
+
const threadsFile = path.join(cfg.stateDir, 'threads.json');
|
|
120
|
+
client = new TelegramClient(new StringSession(loadSessionString(sessionFile)), cfg.apiId, cfg.apiHash, {
|
|
121
|
+
connectionRetries: 5,
|
|
122
|
+
});
|
|
123
|
+
// bot_token → неінтерактивний запуск; інакше phone (потрібен TTY).
|
|
124
|
+
await client.start(cfg.botToken
|
|
125
|
+
? { botAuthToken: cfg.botToken }
|
|
126
|
+
: { phoneNumber: async () => cfg.phone, onError: (e) => log.error(e.message) });
|
|
127
|
+
saveSessionString(sessionFile, client.session.save());
|
|
128
|
+
const me = await client.getMe();
|
|
129
|
+
const meId = me?.id?.toString();
|
|
130
|
+
log.info(`підключено як @${me?.username || me?.firstName || meId}`);
|
|
131
|
+
const prefix = cfg.triggerPrefix.toLowerCase();
|
|
132
|
+
client.addEventHandler(async (event) => {
|
|
133
|
+
try {
|
|
134
|
+
const message = event.message;
|
|
135
|
+
if (!message)
|
|
136
|
+
return;
|
|
137
|
+
if (message.out)
|
|
138
|
+
return; // власні повідомлення (анти-петля)
|
|
139
|
+
if (message.senderId && meId && message.senderId.toString() === meId)
|
|
140
|
+
return;
|
|
141
|
+
const text = (message.text || message.message || '').trim();
|
|
142
|
+
if (!text)
|
|
143
|
+
return;
|
|
144
|
+
// Діагностика: бачимо КОЖНЕ вхідне повідомлення в логах сервера.
|
|
145
|
+
let chatLabel = String(event.chatId ?? '?');
|
|
146
|
+
let peer = event.chatId;
|
|
147
|
+
try {
|
|
148
|
+
const chat = await event.getChat();
|
|
149
|
+
chatLabel = chat?.title || chat?.username || chatLabel;
|
|
150
|
+
peer = chat ?? peer;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
/* ignore */
|
|
154
|
+
}
|
|
155
|
+
log.info(`msg [${chatLabel}]: ${text.slice(0, 80)}`);
|
|
156
|
+
// Тригер: за замовч. (порожній префікс) — відповідаємо на все.
|
|
157
|
+
if (prefix && !text.toLowerCase().startsWith(prefix))
|
|
158
|
+
return;
|
|
159
|
+
const query = prefix ? text.slice(prefix.length).trim() : text;
|
|
160
|
+
if (!query)
|
|
161
|
+
return;
|
|
162
|
+
let placeholder;
|
|
163
|
+
try {
|
|
164
|
+
placeholder = await message.reply({ message: '⌛' });
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
/* ignore */
|
|
168
|
+
}
|
|
169
|
+
// Резолв гілки: explicit reply > implicit (вікно replyWindow) > нова сесія.
|
|
170
|
+
const now = Date.now();
|
|
171
|
+
let threads = loadThreads(threadsFile);
|
|
172
|
+
const replyToMsgId = message.replyTo?.replyToMsgId ?? null;
|
|
173
|
+
const parent = resolveParent(threads, { replyToMsgId, now }, cfg.replyWindow);
|
|
174
|
+
const parentSession = getSession(threads, parent);
|
|
175
|
+
let { text: responseText, sessionId } = await runClaude(query, cfg, parentSession);
|
|
176
|
+
// --resume з протухлим id → fallback на нову сесію.
|
|
177
|
+
if (responseText == null && parentSession) {
|
|
178
|
+
({ text: responseText, sessionId } = await runClaude(query, cfg, null));
|
|
179
|
+
}
|
|
180
|
+
// Прибрати плейсхолдер ⌛.
|
|
181
|
+
if (placeholder) {
|
|
182
|
+
try {
|
|
183
|
+
await client.deleteMessages(peer, [placeholder.id], { revoke: true });
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
/* ignore */
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
let botMsgId = null;
|
|
190
|
+
if (responseText) {
|
|
191
|
+
const sent = await sendLong(client, peer, responseText);
|
|
192
|
+
botMsgId = sent?.id ?? null;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
try {
|
|
196
|
+
await client.sendMessage(peer, { message: '⚠️ claude не повернув відповіді' });
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
/* ignore */
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// Зберегти мапінг лише якщо є sessionId (нова або продовжена сесія).
|
|
203
|
+
if (sessionId) {
|
|
204
|
+
threads = recordSession(threads, { msgId: message.id, botMsgId, sessionId, now });
|
|
205
|
+
threads = pruneThreads(threads, now, 7);
|
|
206
|
+
saveThreads(threadsFile, threads);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
log.error(`обробка повідомлення: ${err.message}`);
|
|
211
|
+
}
|
|
212
|
+
}, new NewMessage({}));
|
|
213
|
+
log.info(`слухаю повідомлення (тригер: ${prefix ? `'${prefix}'` : 'усі'})`);
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
/** Зупинити бота (викликається з shutdown сервера). Безпечно за відсутності клієнта. */
|
|
217
|
+
export async function stopBot() {
|
|
218
|
+
if (!client)
|
|
219
|
+
return;
|
|
220
|
+
try {
|
|
221
|
+
await client.disconnect();
|
|
222
|
+
log.info('зупинено');
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
/* ignore */
|
|
226
|
+
}
|
|
227
|
+
client = undefined;
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=bot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.js","sourceRoot":"","sources":["../../src/runtime/bot.js"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Звести конфіг бота: значення з DB-налаштувань, env має пріоритет.
|
|
3
|
+
* @param {{ env?: Record<string,string|undefined>, dbSettings?: Record<string,unknown> }} [opts]
|
|
4
|
+
*/
|
|
5
|
+
export function loadBotConfig(opts?: {
|
|
6
|
+
env?: Record<string, string | undefined>;
|
|
7
|
+
dbSettings?: Record<string, unknown>;
|
|
8
|
+
}): {
|
|
9
|
+
apiId: number;
|
|
10
|
+
apiHash: {};
|
|
11
|
+
botToken: {};
|
|
12
|
+
phone: {};
|
|
13
|
+
claudeModel: {};
|
|
14
|
+
appRoot: string;
|
|
15
|
+
cofferUrl: {};
|
|
16
|
+
globalCredentials: string;
|
|
17
|
+
replyWindow: number;
|
|
18
|
+
runtimeDir: string;
|
|
19
|
+
workspaceDir: string;
|
|
20
|
+
claudeHomeDir: string;
|
|
21
|
+
stateDir: string;
|
|
22
|
+
workingDir: string;
|
|
23
|
+
triggerPrefix: {};
|
|
24
|
+
skipPermissions: boolean;
|
|
25
|
+
responseTimeout: number;
|
|
26
|
+
};
|
|
27
|
+
/** Чи достатньо креденшелів для запуску: apiId+apiHash і (botToken або phone). */
|
|
28
|
+
export function hasCredentials(cfg: any): boolean;
|
|
29
|
+
/** Корінь app (packages/plugin-telegram/src/runtime → ../../../..). */
|
|
30
|
+
export const APP_ROOT: string;
|
|
31
|
+
/** Корінь plugin-telegram (src/runtime → ../..). */
|
|
32
|
+
export const PLUGIN_ROOT: string;
|
|
33
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/runtime/config.js"],"names":[],"mappings":"AAYA;;;GAGG;AACH,qCAFW;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAC,MAAM,GAAC,SAAS,CAAC,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAC,OAAO,CAAC,CAAA;CAAE;;;;;;;;;;;;;;;;;;EA2BxF;AAED,kFAAkF;AAClF,kDAEC;AAxCD,uEAAuE;AACvE,8BAA+D;AAE/D,oDAAoD;AACpD,iCAA4D"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
/** Корінь app (packages/plugin-telegram/src/runtime → ../../../..). */
|
|
6
|
+
export const APP_ROOT = path.resolve(__dirname, '../../../..');
|
|
7
|
+
/** Корінь plugin-telegram (src/runtime → ../..). */
|
|
8
|
+
export const PLUGIN_ROOT = path.resolve(__dirname, '../..');
|
|
9
|
+
/**
|
|
10
|
+
* Звести конфіг бота: значення з DB-налаштувань, env має пріоритет.
|
|
11
|
+
* @param {{ env?: Record<string,string|undefined>, dbSettings?: Record<string,unknown> }} [opts]
|
|
12
|
+
*/
|
|
13
|
+
export function loadBotConfig(opts = {}) {
|
|
14
|
+
const env = opts.env ?? process.env;
|
|
15
|
+
const db = opts.dbSettings ?? {};
|
|
16
|
+
return {
|
|
17
|
+
apiId: Number(env.TELEGRAM_API_ID ?? db.api_id ?? 0) || 0,
|
|
18
|
+
apiHash: env.TELEGRAM_API_HASH ?? db.api_hash ?? '',
|
|
19
|
+
botToken: env.TELEGRAM_BOT_TOKEN ?? db.bot_token ?? '',
|
|
20
|
+
phone: env.TELEGRAM_PHONE ?? db.phone ?? '',
|
|
21
|
+
claudeModel: env.TELEGRAM_CLAUDE_MODEL ?? db.claude_model ?? 'haiku',
|
|
22
|
+
appRoot: APP_ROOT,
|
|
23
|
+
cofferUrl: env.COFFER_URL ?? db.coffer_url ?? 'http://localhost:7023',
|
|
24
|
+
// Авторизація: symlink на глобальний логін claude (баланс підписки). Окремого
|
|
25
|
+
// api_key немає — бот свідомо шарить уже налаштовану сесію ~/.claude.
|
|
26
|
+
globalCredentials: env.CLAUDE_GLOBAL_CREDENTIALS ?? path.join(os.homedir(), '.claude', '.credentials.json'),
|
|
27
|
+
replyWindow: Number(env.TELEGRAM_REPLY_WINDOW ?? db.reply_window ?? 1800) || 1800,
|
|
28
|
+
runtimeDir: path.join(PLUGIN_ROOT, 'runtime'),
|
|
29
|
+
workspaceDir: path.join(PLUGIN_ROOT, 'runtime', 'workspace'),
|
|
30
|
+
claudeHomeDir: path.join(PLUGIN_ROOT, 'runtime', 'claude-home'),
|
|
31
|
+
stateDir: path.join(PLUGIN_ROOT, 'runtime', 'state'),
|
|
32
|
+
workingDir: path.join(PLUGIN_ROOT, 'runtime', 'workspace'),
|
|
33
|
+
triggerPrefix: env.TELEGRAM_TRIGGER_PREFIX ?? db.trigger_prefix ?? '',
|
|
34
|
+
skipPermissions: db.skip_permissions !== false,
|
|
35
|
+
responseTimeout: Number(env.TELEGRAM_RESPONSE_TIMEOUT ?? db.response_timeout ?? 600) || 600,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Чи достатньо креденшелів для запуску: apiId+apiHash і (botToken або phone). */
|
|
39
|
+
export function hasCredentials(cfg) {
|
|
40
|
+
return Boolean(cfg.apiId && cfg.apiHash && (cfg.botToken || cfg.phone));
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/runtime/config.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,uEAAuE;AACvE,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AAE/D,oDAAoD;AACpD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAE5D;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAI,GAAG,EAAE;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;IAEjC,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC;QACzD,OAAO,EAAE,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,QAAQ,IAAI,EAAE;QACnD,QAAQ,EAAE,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC,SAAS,IAAI,EAAE;QACtD,KAAK,EAAE,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,KAAK,IAAI,EAAE;QAC3C,WAAW,EAAE,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC,YAAY,IAAI,OAAO;QACpE,OAAO,EAAE,QAAQ;QACjB,SAAS,EAAE,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,UAAU,IAAI,uBAAuB;QACrE,8EAA8E;QAC9E,sEAAsE;QACtE,iBAAiB,EAAE,GAAG,CAAC,yBAAyB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,mBAAmB,CAAC;QAC3G,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,IAAI;QACjF,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC;QAC7C,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,WAAW,CAAC;QAC5D,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,aAAa,CAAC;QAC/D,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,OAAO,CAAC;QACpD,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,WAAW,CAAC;QAC1D,aAAa,EAAE,GAAG,CAAC,uBAAuB,IAAI,EAAE,CAAC,cAAc,IAAI,EAAE;QACrE,eAAe,EAAE,EAAE,CAAC,gBAAgB,KAAK,KAAK;QAC9C,eAAe,EAAE,MAAM,CAAC,GAAG,CAAC,yBAAyB,IAAI,EAAE,CAAC,gBAAgB,IAAI,GAAG,CAAC,IAAI,GAAG;KAC5F,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,GAAG;IAChC,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PluginHooks } from '@coffer-org/server/plugin-hooks';
|
|
2
|
+
import { startBot, stopBot } from './bot.js';
|
|
3
|
+
export interface BotConfig {
|
|
4
|
+
apiId: number;
|
|
5
|
+
apiHash: string;
|
|
6
|
+
botToken: string;
|
|
7
|
+
phone: string;
|
|
8
|
+
claudeModel: string;
|
|
9
|
+
globalCredentials: string;
|
|
10
|
+
cofferUrl: string;
|
|
11
|
+
replyWindow: number;
|
|
12
|
+
appRoot: string;
|
|
13
|
+
runtimeDir: string;
|
|
14
|
+
workspaceDir: string;
|
|
15
|
+
claudeHomeDir: string;
|
|
16
|
+
stateDir: string;
|
|
17
|
+
workingDir: string;
|
|
18
|
+
triggerPrefix: string;
|
|
19
|
+
skipPermissions: boolean;
|
|
20
|
+
responseTimeout: number;
|
|
21
|
+
}
|
|
22
|
+
export interface StartOpts {
|
|
23
|
+
env?: Record<string, string | undefined>;
|
|
24
|
+
dbSettings?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export { startBot, stopBot };
|
|
27
|
+
export { loadBotConfig, hasCredentials } from './config.js';
|
|
28
|
+
/** Серверні хуки telegram-бота (збирає loadServerHooks через discovery). */
|
|
29
|
+
export declare const serverHooks: PluginHooks;
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAInE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAG7B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5D,4EAA4E;AAC5E,eAAO,MAAM,WAAW,EAAE,WAWzB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// TypeScript entry-point для plugin-hooks.ts (server-only, динамічний import).
|
|
2
|
+
// Реалізація — в bot.js / config.js (чистий ESM без TS-компілятора).
|
|
3
|
+
import { getPluginSettings } from '@coffer-org/server/plugin-runtime';
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
5
|
+
// @ts-ignore — bot.js є чистим ESM без .d.ts; resolve різниться між root-typecheck і tsc -b.
|
|
6
|
+
import { startBot, stopBot } from './bot.js';
|
|
7
|
+
export { startBot, stopBot };
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
9
|
+
// @ts-ignore — config.js є чистим ESM без .d.ts.
|
|
10
|
+
export { loadBotConfig, hasCredentials } from './config.js';
|
|
11
|
+
/** Серверні хуки telegram-бота (збирає loadServerHooks через discovery). */
|
|
12
|
+
export const serverHooks = {
|
|
13
|
+
init: async () => {
|
|
14
|
+
const dbSettings = await getPluginSettings('telegram');
|
|
15
|
+
// fire-and-forget: мережеве підключення не блокує bootstrap і не валить старт.
|
|
16
|
+
void startBot({ dbSettings }).catch((e) => console.warn(`[telegram] не стартував: ${e.message}`));
|
|
17
|
+
},
|
|
18
|
+
teardown: async () => {
|
|
19
|
+
await stopBot();
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,qEAAqE;AAGrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,6DAA6D;AAC7D,6FAA6F;AAC7F,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AA2B7C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC7B,6DAA6D;AAC7D,iDAAiD;AACjD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5D,4EAA4E;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAgB;IACtC,IAAI,EAAE,KAAK,IAAI,EAAE;QACf,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC,UAAU,CAAC,CAAC;QACvD,+EAA+E;QAC/E,KAAK,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE,CACjD,OAAO,CAAC,IAAI,CAAC,4BAA6B,CAAW,CAAC,OAAO,EAAE,CAAC,CACjE,CAAC;IACJ,CAAC;IACD,QAAQ,EAAE,KAAK,IAAI,EAAE;QACnB,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Порожній стан гілок. */
|
|
2
|
+
export function emptyThreads(): {
|
|
3
|
+
map: {};
|
|
4
|
+
last: null;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Визначити parent-повідомлення для прив'язки сесії:
|
|
8
|
+
* - explicit reply → той msgId;
|
|
9
|
+
* - інакше, якщо last у вікні replyWindow (сек) → last.msgId (implicit reply);
|
|
10
|
+
* - інакше null (нова гілка → нова сесія).
|
|
11
|
+
*/
|
|
12
|
+
export function resolveParent(threads: any, { replyToMsgId, now }: {
|
|
13
|
+
replyToMsgId: any;
|
|
14
|
+
now: any;
|
|
15
|
+
}, replyWindowSec: any): any;
|
|
16
|
+
/** sessionId, прив'язаний до parent-повідомлення, або null. */
|
|
17
|
+
export function getSession(threads: any, parentId: any): any;
|
|
18
|
+
/**
|
|
19
|
+
* Записати: вхідне повідомлення і відповідь бота → та сама сесія
|
|
20
|
+
* (щоб reply на будь-яке з них продовжував гілку). Оновити last.
|
|
21
|
+
*/
|
|
22
|
+
export function recordSession(threads: any, { msgId, botMsgId, sessionId, now }: {
|
|
23
|
+
msgId: any;
|
|
24
|
+
botMsgId: any;
|
|
25
|
+
sessionId: any;
|
|
26
|
+
now: any;
|
|
27
|
+
}): {
|
|
28
|
+
map: any;
|
|
29
|
+
last: {
|
|
30
|
+
msgId: any;
|
|
31
|
+
ts: any;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
/** Прибрати записи старші за ttlDays (щоб файл не ріс безмежно). */
|
|
35
|
+
export function pruneThreads(threads: any, now: any, ttlDays: any): {
|
|
36
|
+
map: {};
|
|
37
|
+
last: any;
|
|
38
|
+
};
|
|
39
|
+
export function loadThreads(file: any): any;
|
|
40
|
+
export function saveThreads(file: any, threads: any): void;
|
|
41
|
+
//# sourceMappingURL=threads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../../src/runtime/threads.js"],"names":[],"mappings":"AAGA,2BAA2B;AAC3B;;;EAEC;AAED;;;;;GAKG;AACH;;;6BAKC;AAED,+DAA+D;AAC/D,6DAGC;AAED;;;GAGG;AACH;;;;;;;;;;;EAKC;AAED,oEAAoE;AACpE;;;EAOC;AAED,4CAQC;AAED,2DAGC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/** Порожній стан гілок. */
|
|
4
|
+
export function emptyThreads() {
|
|
5
|
+
return { map: {}, last: null };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Визначити parent-повідомлення для прив'язки сесії:
|
|
9
|
+
* - explicit reply → той msgId;
|
|
10
|
+
* - інакше, якщо last у вікні replyWindow (сек) → last.msgId (implicit reply);
|
|
11
|
+
* - інакше null (нова гілка → нова сесія).
|
|
12
|
+
*/
|
|
13
|
+
export function resolveParent(threads, { replyToMsgId, now }, replyWindowSec) {
|
|
14
|
+
if (replyToMsgId != null)
|
|
15
|
+
return replyToMsgId;
|
|
16
|
+
const last = threads.last;
|
|
17
|
+
if (last && now - last.ts < replyWindowSec * 1000)
|
|
18
|
+
return last.msgId;
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
/** sessionId, прив'язаний до parent-повідомлення, або null. */
|
|
22
|
+
export function getSession(threads, parentId) {
|
|
23
|
+
if (parentId == null)
|
|
24
|
+
return null;
|
|
25
|
+
return threads.map[parentId]?.sessionId ?? null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Записати: вхідне повідомлення і відповідь бота → та сама сесія
|
|
29
|
+
* (щоб reply на будь-яке з них продовжував гілку). Оновити last.
|
|
30
|
+
*/
|
|
31
|
+
export function recordSession(threads, { msgId, botMsgId, sessionId, now }) {
|
|
32
|
+
const map = { ...threads.map };
|
|
33
|
+
map[msgId] = { sessionId, ts: now };
|
|
34
|
+
if (botMsgId != null)
|
|
35
|
+
map[botMsgId] = { sessionId, ts: now };
|
|
36
|
+
return { map, last: { msgId: botMsgId ?? msgId, ts: now } };
|
|
37
|
+
}
|
|
38
|
+
/** Прибрати записи старші за ttlDays (щоб файл не ріс безмежно). */
|
|
39
|
+
export function pruneThreads(threads, now, ttlDays) {
|
|
40
|
+
const cutoff = now - ttlDays * 86_400_000;
|
|
41
|
+
const map = {};
|
|
42
|
+
for (const [k, v] of Object.entries(threads.map)) {
|
|
43
|
+
if (v.ts >= cutoff)
|
|
44
|
+
map[k] = v;
|
|
45
|
+
}
|
|
46
|
+
return { map, last: threads.last };
|
|
47
|
+
}
|
|
48
|
+
export function loadThreads(file) {
|
|
49
|
+
try {
|
|
50
|
+
const obj = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
51
|
+
if (obj && typeof obj === 'object' && obj.map)
|
|
52
|
+
return obj;
|
|
53
|
+
return emptyThreads();
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return emptyThreads();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function saveThreads(file, threads) {
|
|
60
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
61
|
+
fs.writeFileSync(file, JSON.stringify(threads), 'utf-8');
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=threads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threads.js","sourceRoot":"","sources":["../../src/runtime/threads.js"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Прив'язати auth: symlink claude-home/.credentials.json → глобальний логін
|
|
3
|
+
* (~/.claude/.credentials.json). Так бот шарить уже налаштовану сесію і витрачає
|
|
4
|
+
* баланс підписки, а не окремий рахунок. Перестворюється щоразу (ідемпотентно).
|
|
5
|
+
* Якщо глобального файлу нема (напр. macOS keychain) — пропускаємо з warn.
|
|
6
|
+
* Безпека: claude-home лежить під APP_ROOT, а в settings.json є deny Read(APP_ROOT/**),
|
|
7
|
+
* тому Read-tool бота не може прочитати цей токен; внутрішнє auth-завантаження claude
|
|
8
|
+
* працює повз tool-дозволи.
|
|
9
|
+
*/
|
|
10
|
+
export function linkCredentials(cfg: any, log?: Console): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Ідемпотентно підготувати ізольований runtime бота: створити папки, згенерувати
|
|
13
|
+
* конфіги з абсолютними шляхами (APP_ROOT) — .mcp.json (тільки coffer) та
|
|
14
|
+
* claude-home/settings.json (обмежені інструменти, deny на код app), і прив'язати
|
|
15
|
+
* auth (symlink на глобальний логін). CLAUDE.md і skills не чіпаємо — версіонуються в git.
|
|
16
|
+
*/
|
|
17
|
+
export function ensureWorkspace(cfg: any, log?: Console): void;
|
|
18
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/runtime/workspace.js"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,kEASC;AAED;;;;;GAKG;AACH,+DAiCC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Прив'язати auth: symlink claude-home/.credentials.json → глобальний логін
|
|
5
|
+
* (~/.claude/.credentials.json). Так бот шарить уже налаштовану сесію і витрачає
|
|
6
|
+
* баланс підписки, а не окремий рахунок. Перестворюється щоразу (ідемпотентно).
|
|
7
|
+
* Якщо глобального файлу нема (напр. macOS keychain) — пропускаємо з warn.
|
|
8
|
+
* Безпека: claude-home лежить під APP_ROOT, а в settings.json є deny Read(APP_ROOT/**),
|
|
9
|
+
* тому Read-tool бота не може прочитати цей токен; внутрішнє auth-завантаження claude
|
|
10
|
+
* працює повз tool-дозволи.
|
|
11
|
+
*/
|
|
12
|
+
export function linkCredentials(cfg, log = console) {
|
|
13
|
+
const target = path.join(cfg.claudeHomeDir, '.credentials.json');
|
|
14
|
+
fs.rmSync(target, { force: true });
|
|
15
|
+
if (fs.existsSync(cfg.globalCredentials)) {
|
|
16
|
+
fs.symlinkSync(cfg.globalCredentials, target);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
log.warn?.(`[telegram-bot] global credentials не знайдено (${cfg.globalCredentials}) — claude буде "Not logged in"`);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Ідемпотентно підготувати ізольований runtime бота: створити папки, згенерувати
|
|
24
|
+
* конфіги з абсолютними шляхами (APP_ROOT) — .mcp.json (тільки coffer) та
|
|
25
|
+
* claude-home/settings.json (обмежені інструменти, deny на код app), і прив'язати
|
|
26
|
+
* auth (symlink на глобальний логін). CLAUDE.md і skills не чіпаємо — версіонуються в git.
|
|
27
|
+
*/
|
|
28
|
+
export function ensureWorkspace(cfg, log = console) {
|
|
29
|
+
fs.mkdirSync(path.join(cfg.stateDir, '.sessions'), { recursive: true });
|
|
30
|
+
fs.mkdirSync(path.join(cfg.workspaceDir, '.claude', 'skills'), { recursive: true });
|
|
31
|
+
fs.mkdirSync(cfg.claudeHomeDir, { recursive: true });
|
|
32
|
+
const mcp = {
|
|
33
|
+
mcpServers: {
|
|
34
|
+
coffer: {
|
|
35
|
+
command: 'npx',
|
|
36
|
+
args: ['tsx', path.join(cfg.appRoot, 'packages', 'mcp', 'bin', 'stdio.ts')],
|
|
37
|
+
env: { COFFER_URL: cfg.cofferUrl },
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
fs.writeFileSync(path.join(cfg.workspaceDir, '.mcp.json'), JSON.stringify(mcp, null, 2) + '\n', 'utf-8');
|
|
42
|
+
// Абсолютний шлях у permission-патернах Claude Code анкериться ПОДВІЙНИМ слешем
|
|
43
|
+
// (//abs/path); одинарний `/` означає відносно проєкту і НЕ матчить. deny має
|
|
44
|
+
// пріоритет і застосовується навіть під --dangerously-skip-permissions.
|
|
45
|
+
// Read у default-режимі авто-дозволений, тож код app блокуємо явним deny.
|
|
46
|
+
// appRoot покриває і workspace, і claude-home (вони під ним) → Read-tool бота не
|
|
47
|
+
// дістане ні код, ні .credentials.json. Skills вантажаться через Skill-tool, не Read.
|
|
48
|
+
const appGlob = `//${cfg.appRoot.replace(/^\/+/, '')}/**`;
|
|
49
|
+
const settings = {
|
|
50
|
+
permissions: {
|
|
51
|
+
allow: ['mcp__coffer__*', 'WebSearch', 'WebFetch', 'Skill'],
|
|
52
|
+
deny: ['Bash', 'Edit', 'Write', `Read(${appGlob})`, `Glob(${appGlob})`, `Grep(${appGlob})`],
|
|
53
|
+
},
|
|
54
|
+
enableAllProjectMcpServers: false,
|
|
55
|
+
};
|
|
56
|
+
fs.writeFileSync(path.join(cfg.claudeHomeDir, 'settings.json'), JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
57
|
+
linkCredentials(cfg, log);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/runtime/workspace.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAC;IACjE,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACzC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,GAAG,CAAC,IAAI,EAAE,CAAC,kDAAkD,GAAG,CAAC,iBAAiB,iCAAiC,CAAC,CAAC;IACrH,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO;IAChD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpF,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAErD,MAAM,GAAG,GAAG;QACV,UAAU,EAAE;YACV,MAAM,EAAE;gBACN,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;gBAC3E,GAAG,EAAE,EAAE,UAAU,EAAE,GAAG,CAAC,SAAS,EAAE;aACnC;SACF;KACF,CAAC;IACF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAEzG,gFAAgF;IAChF,8EAA8E;IAC9E,wEAAwE;IACxE,0EAA0E;IAC1E,iFAAiF;IACjF,sFAAsF;IACtF,MAAM,OAAO,GAAG,KAAK,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC;IAC1D,MAAM,QAAQ,GAAG;QACf,WAAW,EAAE;YACX,KAAK,EAAE,CAAC,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC;YAC3D,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,CAAC;SAC5F;QACD,0BAA0B,EAAE,KAAK;KAClC,CAAC;IACF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAEnH,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAC5B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@coffer-org/plugin-telegram",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./runtime": {
|
|
14
|
+
"types": "./dist/runtime/index.d.ts",
|
|
15
|
+
"default": "./dist/runtime/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc -b tsconfig.build.json",
|
|
20
|
+
"prepack": "npm run build && node ../../scripts/swap-exports.mjs dist",
|
|
21
|
+
"postpack": "node ../../scripts/swap-exports.mjs src",
|
|
22
|
+
"test": "node --test \"src/runtime/*.test.js\""
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@coffer-org/sdk": "^1.1.0",
|
|
26
|
+
"@coffer-org/server": "^1.1.0",
|
|
27
|
+
"telegram": "^2.26.0",
|
|
28
|
+
"input": "^1.0.1"
|
|
29
|
+
}
|
|
30
|
+
}
|