teleton 0.7.4 → 0.7.5
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 +36 -26
- package/dist/{chunk-XDYDA2KV.js → chunk-2GLHOJ5C.js} +268 -59
- package/dist/chunk-5UVXJMOX.js +292 -0
- package/dist/{chunk-BGC2IUM5.js → chunk-AVDWXYQ7.js} +65 -20
- package/dist/{chunk-RMLQS3X6.js → chunk-CB2Y45HA.js} +106 -1
- package/dist/{chunk-5PLZ3KSO.js → chunk-DMXTIRUW.js} +5 -6
- package/dist/{chunk-YFG2QHLA.js → chunk-G2LLMJXJ.js} +1578 -115
- package/dist/{chunk-EK7M5K26.js → chunk-LCCVZ4D2.js} +3 -3
- package/dist/{chunk-LAQOUFOJ.js → chunk-OGMVWDVU.js} +3517 -3620
- package/dist/{chunk-4DU3C27M.js → chunk-R4YSJ4EY.js} +5 -1
- package/dist/{chunk-XBKSS6DM.js → chunk-VFA7QMCZ.js} +5 -3
- package/dist/{chunk-VAUJSSD3.js → chunk-XQUHC3JZ.js} +1 -1
- package/dist/{chunk-RO62LO6Z.js → chunk-YP25WTQK.js} +2 -0
- package/dist/cli/index.js +92 -28
- package/dist/{client-RTNALK7W.js → client-O37XDCJB.js} +4 -5
- package/dist/index.js +12 -13
- package/dist/{memory-JQZ6MTRU.js → memory-KQALFUV3.js} +6 -7
- package/dist/{migrate-GS5ACQDA.js → migrate-UV3WEL5D.js} +6 -7
- package/dist/{server-TCJOBV3D.js → server-BHHJGUDF.js} +35 -9
- package/dist/{setup-server-YHYJLAMA.js → setup-server-G7UG2DI3.js} +21 -9
- package/dist/store-H4XPNGC2.js +34 -0
- package/dist/{task-dependency-resolver-WKZWJLLM.js → task-dependency-resolver-VMEVJRPO.js} +2 -2
- package/dist/{task-executor-PD3H4MLO.js → task-executor-WWSPBJ4V.js} +1 -1
- package/dist/{tool-index-6HBRVXVG.js → tool-index-2KH3OB6X.js} +5 -5
- package/dist/web/assets/index-BrVqauzj.css +1 -0
- package/dist/web/assets/index-Bx8JW3gV.js +72 -0
- package/dist/web/assets/{index.es-CqZHj0tz.js → index.es-Pet5-M13.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +2 -2
- package/dist/chunk-JQDLW7IE.js +0 -107
- package/dist/chunk-UCN6TI25.js +0 -143
- package/dist/web/assets/index-B6M9knfJ.css +0 -1
- package/dist/web/assets/index-DAGeQfVZ.js +0 -72
- package/scripts/patch-gramjs.sh +0 -46
- package/scripts/postinstall.mjs +0 -16
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getDatabase
|
|
3
|
+
} from "./chunk-2GLHOJ5C.js";
|
|
4
|
+
import {
|
|
5
|
+
createLogger
|
|
6
|
+
} from "./chunk-RCMD3U65.js";
|
|
7
|
+
|
|
8
|
+
// src/session/store.ts
|
|
9
|
+
import { randomUUID } from "crypto";
|
|
10
|
+
var log = createLogger("Session");
|
|
11
|
+
function getDb() {
|
|
12
|
+
return getDatabase().getDb();
|
|
13
|
+
}
|
|
14
|
+
function rowToSession(row) {
|
|
15
|
+
return {
|
|
16
|
+
sessionId: row.id,
|
|
17
|
+
chatId: row.chat_id,
|
|
18
|
+
createdAt: row.started_at,
|
|
19
|
+
updatedAt: row.updated_at,
|
|
20
|
+
messageCount: row.message_count || 0,
|
|
21
|
+
lastMessageId: row.last_message_id ?? void 0,
|
|
22
|
+
lastChannel: row.last_channel ?? void 0,
|
|
23
|
+
lastTo: row.last_to ?? void 0,
|
|
24
|
+
contextTokens: row.context_tokens ?? void 0,
|
|
25
|
+
model: row.model ?? void 0,
|
|
26
|
+
provider: row.provider ?? void 0,
|
|
27
|
+
lastResetDate: row.last_reset_date ?? void 0,
|
|
28
|
+
inputTokens: row.input_tokens ?? void 0,
|
|
29
|
+
outputTokens: row.output_tokens ?? void 0
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function loadSessionStore() {
|
|
33
|
+
try {
|
|
34
|
+
const db = getDb();
|
|
35
|
+
const rows = db.prepare("SELECT * FROM sessions").all();
|
|
36
|
+
const store = {};
|
|
37
|
+
for (const row of rows) {
|
|
38
|
+
const sessionKey = row.chat_id;
|
|
39
|
+
store[sessionKey] = rowToSession(row);
|
|
40
|
+
}
|
|
41
|
+
return store;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
log.warn({ err: error }, "Failed to load sessions from database");
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function saveSessionStore(store) {
|
|
48
|
+
try {
|
|
49
|
+
const db = getDb();
|
|
50
|
+
const insertStmt = db.prepare(`
|
|
51
|
+
INSERT INTO sessions (
|
|
52
|
+
id, chat_id, started_at, updated_at, message_count,
|
|
53
|
+
last_message_id, last_channel, last_to, context_tokens,
|
|
54
|
+
model, provider, last_reset_date, input_tokens, output_tokens
|
|
55
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
56
|
+
`);
|
|
57
|
+
db.transaction(() => {
|
|
58
|
+
db.prepare("DELETE FROM sessions").run();
|
|
59
|
+
for (const [chatId, session] of Object.entries(store)) {
|
|
60
|
+
insertStmt.run(
|
|
61
|
+
session.sessionId,
|
|
62
|
+
chatId,
|
|
63
|
+
session.createdAt,
|
|
64
|
+
session.updatedAt,
|
|
65
|
+
session.messageCount,
|
|
66
|
+
session.lastMessageId,
|
|
67
|
+
session.lastChannel,
|
|
68
|
+
session.lastTo,
|
|
69
|
+
session.contextTokens,
|
|
70
|
+
session.model,
|
|
71
|
+
session.provider,
|
|
72
|
+
session.lastResetDate,
|
|
73
|
+
session.inputTokens ?? 0,
|
|
74
|
+
session.outputTokens ?? 0
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
})();
|
|
78
|
+
} catch (error) {
|
|
79
|
+
log.error({ err: error }, "Failed to save sessions to database");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function getOrCreateSession(chatId) {
|
|
83
|
+
const db = getDb();
|
|
84
|
+
const sessionKey = `telegram:${chatId}`;
|
|
85
|
+
const row = db.prepare("SELECT * FROM sessions WHERE chat_id = ?").get(sessionKey);
|
|
86
|
+
if (row) {
|
|
87
|
+
return rowToSession(row);
|
|
88
|
+
}
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
const newSession = {
|
|
91
|
+
sessionId: randomUUID(),
|
|
92
|
+
chatId,
|
|
93
|
+
createdAt: now,
|
|
94
|
+
updatedAt: now,
|
|
95
|
+
messageCount: 0,
|
|
96
|
+
lastChannel: "telegram",
|
|
97
|
+
lastTo: chatId
|
|
98
|
+
};
|
|
99
|
+
db.prepare(
|
|
100
|
+
`
|
|
101
|
+
INSERT INTO sessions (
|
|
102
|
+
id, chat_id, started_at, updated_at, message_count, last_channel, last_to
|
|
103
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
104
|
+
`
|
|
105
|
+
).run(
|
|
106
|
+
newSession.sessionId,
|
|
107
|
+
sessionKey,
|
|
108
|
+
newSession.createdAt,
|
|
109
|
+
newSession.updatedAt,
|
|
110
|
+
newSession.messageCount,
|
|
111
|
+
newSession.lastChannel,
|
|
112
|
+
newSession.lastTo
|
|
113
|
+
);
|
|
114
|
+
log.info(`New session created: ${newSession.sessionId} for chat ${chatId}`);
|
|
115
|
+
return newSession;
|
|
116
|
+
}
|
|
117
|
+
function updateSession(chatId, update) {
|
|
118
|
+
const db = getDb();
|
|
119
|
+
const sessionKey = `telegram:${chatId}`;
|
|
120
|
+
const existing = db.prepare("SELECT * FROM sessions WHERE chat_id = ?").get(sessionKey);
|
|
121
|
+
if (!existing) {
|
|
122
|
+
return getOrCreateSession(chatId);
|
|
123
|
+
}
|
|
124
|
+
const updates = [];
|
|
125
|
+
const values = [];
|
|
126
|
+
if (update.sessionId !== void 0) {
|
|
127
|
+
updates.push("id = ?");
|
|
128
|
+
values.push(update.sessionId);
|
|
129
|
+
}
|
|
130
|
+
if (update.messageCount !== void 0) {
|
|
131
|
+
updates.push("message_count = ?");
|
|
132
|
+
values.push(update.messageCount);
|
|
133
|
+
}
|
|
134
|
+
if (update.lastMessageId !== void 0) {
|
|
135
|
+
updates.push("last_message_id = ?");
|
|
136
|
+
values.push(update.lastMessageId);
|
|
137
|
+
}
|
|
138
|
+
if (update.lastChannel !== void 0) {
|
|
139
|
+
updates.push("last_channel = ?");
|
|
140
|
+
values.push(update.lastChannel);
|
|
141
|
+
}
|
|
142
|
+
if (update.lastTo !== void 0) {
|
|
143
|
+
updates.push("last_to = ?");
|
|
144
|
+
values.push(update.lastTo);
|
|
145
|
+
}
|
|
146
|
+
if (update.contextTokens !== void 0) {
|
|
147
|
+
updates.push("context_tokens = ?");
|
|
148
|
+
values.push(update.contextTokens);
|
|
149
|
+
}
|
|
150
|
+
if (update.model !== void 0) {
|
|
151
|
+
updates.push("model = ?");
|
|
152
|
+
values.push(update.model);
|
|
153
|
+
}
|
|
154
|
+
if (update.provider !== void 0) {
|
|
155
|
+
updates.push("provider = ?");
|
|
156
|
+
values.push(update.provider);
|
|
157
|
+
}
|
|
158
|
+
if (update.lastResetDate !== void 0) {
|
|
159
|
+
updates.push("last_reset_date = ?");
|
|
160
|
+
values.push(update.lastResetDate);
|
|
161
|
+
}
|
|
162
|
+
if (update.inputTokens !== void 0) {
|
|
163
|
+
updates.push("input_tokens = ?");
|
|
164
|
+
values.push(update.inputTokens);
|
|
165
|
+
}
|
|
166
|
+
if (update.outputTokens !== void 0) {
|
|
167
|
+
updates.push("output_tokens = ?");
|
|
168
|
+
values.push(update.outputTokens);
|
|
169
|
+
}
|
|
170
|
+
updates.push("updated_at = ?");
|
|
171
|
+
values.push(Date.now());
|
|
172
|
+
values.push(sessionKey);
|
|
173
|
+
db.prepare(
|
|
174
|
+
`
|
|
175
|
+
UPDATE sessions
|
|
176
|
+
SET ${updates.join(", ")}
|
|
177
|
+
WHERE chat_id = ?
|
|
178
|
+
`
|
|
179
|
+
).run(...values);
|
|
180
|
+
const updated = db.prepare("SELECT * FROM sessions WHERE chat_id = ?").get(sessionKey);
|
|
181
|
+
return rowToSession(updated);
|
|
182
|
+
}
|
|
183
|
+
function incrementMessageCount(chatId) {
|
|
184
|
+
const db = getDb();
|
|
185
|
+
const sessionKey = `telegram:${chatId}`;
|
|
186
|
+
const result = db.prepare(
|
|
187
|
+
`UPDATE sessions SET message_count = message_count + 1, updated_at = ? WHERE chat_id = ?`
|
|
188
|
+
).run(Date.now(), sessionKey);
|
|
189
|
+
if (result.changes === 0) {
|
|
190
|
+
getOrCreateSession(chatId);
|
|
191
|
+
db.prepare(
|
|
192
|
+
`UPDATE sessions SET message_count = message_count + 1, updated_at = ? WHERE chat_id = ?`
|
|
193
|
+
).run(Date.now(), sessionKey);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function getSession(chatId) {
|
|
197
|
+
const db = getDb();
|
|
198
|
+
const sessionKey = `telegram:${chatId}`;
|
|
199
|
+
const row = db.prepare("SELECT * FROM sessions WHERE chat_id = ?").get(sessionKey);
|
|
200
|
+
return row ? rowToSession(row) : null;
|
|
201
|
+
}
|
|
202
|
+
function resetSession(chatId) {
|
|
203
|
+
const oldSession = getSession(chatId);
|
|
204
|
+
const now = Date.now();
|
|
205
|
+
const newSession = {
|
|
206
|
+
sessionId: randomUUID(),
|
|
207
|
+
chatId,
|
|
208
|
+
createdAt: now,
|
|
209
|
+
updatedAt: now,
|
|
210
|
+
messageCount: 0,
|
|
211
|
+
lastChannel: oldSession?.lastChannel || "telegram",
|
|
212
|
+
lastTo: oldSession?.lastTo || chatId,
|
|
213
|
+
contextTokens: oldSession?.contextTokens,
|
|
214
|
+
model: oldSession?.model,
|
|
215
|
+
provider: oldSession?.provider
|
|
216
|
+
};
|
|
217
|
+
const db = getDb();
|
|
218
|
+
const sessionKey = `telegram:${chatId}`;
|
|
219
|
+
db.prepare(
|
|
220
|
+
`
|
|
221
|
+
UPDATE sessions
|
|
222
|
+
SET id = ?, started_at = ?, updated_at = ?, message_count = 0
|
|
223
|
+
WHERE chat_id = ?
|
|
224
|
+
`
|
|
225
|
+
).run(newSession.sessionId, newSession.createdAt, newSession.updatedAt, sessionKey);
|
|
226
|
+
log.info(`Session reset: ${oldSession?.sessionId} \u2192 ${newSession.sessionId}`);
|
|
227
|
+
return newSession;
|
|
228
|
+
}
|
|
229
|
+
function shouldResetSession(session, policy) {
|
|
230
|
+
const now = Date.now();
|
|
231
|
+
if (policy.daily_reset_enabled) {
|
|
232
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
233
|
+
const lastReset = session.lastResetDate || new Date(session.createdAt).toISOString().split("T")[0];
|
|
234
|
+
if (lastReset !== today) {
|
|
235
|
+
const currentHour = (/* @__PURE__ */ new Date()).getHours();
|
|
236
|
+
const resetHour = policy.daily_reset_hour;
|
|
237
|
+
if (lastReset < today && currentHour >= resetHour) {
|
|
238
|
+
log.info(
|
|
239
|
+
`Daily reset triggered for session ${session.sessionId} (last reset: ${lastReset})`
|
|
240
|
+
);
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (policy.idle_expiry_enabled) {
|
|
246
|
+
const idleMs = now - session.updatedAt;
|
|
247
|
+
const idleMinutes = idleMs / (1e3 * 60);
|
|
248
|
+
const expiryMinutes = policy.idle_expiry_minutes;
|
|
249
|
+
if (idleMinutes >= expiryMinutes) {
|
|
250
|
+
log.info(
|
|
251
|
+
`Idle expiry triggered for session ${session.sessionId} (idle: ${Math.floor(idleMinutes)}m)`
|
|
252
|
+
);
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
function resetSessionWithPolicy(chatId, policy) {
|
|
259
|
+
const newSession = resetSession(chatId);
|
|
260
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
261
|
+
return updateSession(chatId, {
|
|
262
|
+
lastResetDate: today
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
function pruneOldSessions(maxAgeDays = 30) {
|
|
266
|
+
try {
|
|
267
|
+
const db = getDb();
|
|
268
|
+
const cutoffMs = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
269
|
+
const result = db.prepare(`DELETE FROM sessions WHERE updated_at < ? AND updated_at > 0`).run(cutoffMs);
|
|
270
|
+
const pruned = result.changes;
|
|
271
|
+
if (pruned > 0) {
|
|
272
|
+
log.info(`\u{1F5D1}\uFE0F Pruned ${pruned} session(s) older than ${maxAgeDays} days`);
|
|
273
|
+
}
|
|
274
|
+
return pruned;
|
|
275
|
+
} catch (error) {
|
|
276
|
+
log.warn({ err: error }, "Failed to prune old sessions");
|
|
277
|
+
return 0;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export {
|
|
282
|
+
loadSessionStore,
|
|
283
|
+
saveSessionStore,
|
|
284
|
+
getOrCreateSession,
|
|
285
|
+
updateSession,
|
|
286
|
+
incrementMessageCount,
|
|
287
|
+
getSession,
|
|
288
|
+
resetSession,
|
|
289
|
+
shouldResetSession,
|
|
290
|
+
resetSessionWithPolicy,
|
|
291
|
+
pruneOldSessions
|
|
292
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
COINGECKO_API_URL,
|
|
3
3
|
tonapiFetch
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VFA7QMCZ.js";
|
|
5
5
|
import {
|
|
6
6
|
TELEGRAM_MAX_MESSAGE_LENGTH
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-YP25WTQK.js";
|
|
8
8
|
import {
|
|
9
9
|
fetchWithTimeout
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-XQUHC3JZ.js";
|
|
11
11
|
import {
|
|
12
12
|
TELETON_ROOT,
|
|
13
13
|
WORKSPACE_PATHS,
|
|
@@ -17,20 +17,21 @@ import {
|
|
|
17
17
|
createLogger
|
|
18
18
|
} from "./chunk-RCMD3U65.js";
|
|
19
19
|
|
|
20
|
-
// src/ton/wallet-service.ts
|
|
21
|
-
import { mnemonicNew, mnemonicToPrivateKey, mnemonicValidate } from "@ton/crypto";
|
|
22
|
-
import { WalletContractV5R1, TonClient, fromNano } from "@ton/ton";
|
|
23
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
24
|
-
import { join, dirname } from "path";
|
|
25
|
-
|
|
26
20
|
// src/ton/endpoint.ts
|
|
27
21
|
var ENDPOINT_CACHE_TTL_MS = 6e4;
|
|
28
22
|
var ORBS_HOST = "ton.access.orbs.network";
|
|
29
23
|
var ORBS_TOPOLOGY_URL = `https://${ORBS_HOST}/mngr/nodes?npm_version=2.3.3`;
|
|
30
|
-
var
|
|
24
|
+
var TONCENTER_URL = `https://toncenter.com/api/v2/jsonRPC`;
|
|
31
25
|
var _cache = null;
|
|
26
|
+
var _toncenterApiKey;
|
|
27
|
+
function setToncenterApiKey(key) {
|
|
28
|
+
_toncenterApiKey = key;
|
|
29
|
+
}
|
|
30
|
+
function getToncenterApiKey() {
|
|
31
|
+
return _toncenterApiKey;
|
|
32
|
+
}
|
|
32
33
|
async function discoverOrbsEndpoint() {
|
|
33
|
-
const res = await fetch(ORBS_TOPOLOGY_URL);
|
|
34
|
+
const res = await fetch(ORBS_TOPOLOGY_URL, { signal: AbortSignal.timeout(5e3) });
|
|
34
35
|
const nodes = await res.json();
|
|
35
36
|
const healthy = nodes.filter(
|
|
36
37
|
(n) => n.Healthy === "1" && n.Weight > 0 && n.Mngr?.health?.["v2-mainnet"]
|
|
@@ -53,10 +54,28 @@ async function getCachedHttpEndpoint() {
|
|
|
53
54
|
return _cache.url;
|
|
54
55
|
}
|
|
55
56
|
let url;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
if (_toncenterApiKey) {
|
|
58
|
+
try {
|
|
59
|
+
const testUrl = `https://toncenter.com/api/v2/getAddressInformation?address=EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c`;
|
|
60
|
+
const res = await fetch(testUrl, {
|
|
61
|
+
headers: { "X-API-Key": _toncenterApiKey },
|
|
62
|
+
signal: AbortSignal.timeout(5e3)
|
|
63
|
+
});
|
|
64
|
+
if (!res.ok) throw new Error(`TonCenter ${res.status}`);
|
|
65
|
+
url = TONCENTER_URL;
|
|
66
|
+
} catch {
|
|
67
|
+
try {
|
|
68
|
+
url = await discoverOrbsEndpoint();
|
|
69
|
+
} catch {
|
|
70
|
+
url = TONCENTER_URL;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
try {
|
|
75
|
+
url = await discoverOrbsEndpoint();
|
|
76
|
+
} catch {
|
|
77
|
+
url = TONCENTER_URL;
|
|
78
|
+
}
|
|
60
79
|
}
|
|
61
80
|
_cache = { url, ts: Date.now() };
|
|
62
81
|
return url;
|
|
@@ -66,6 +85,10 @@ function invalidateEndpointCache() {
|
|
|
66
85
|
}
|
|
67
86
|
|
|
68
87
|
// src/ton/wallet-service.ts
|
|
88
|
+
import { mnemonicNew, mnemonicToPrivateKey, mnemonicValidate } from "@ton/crypto";
|
|
89
|
+
import { WalletContractV5R1, TonClient, fromNano } from "@ton/ton";
|
|
90
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
91
|
+
import { join, dirname } from "path";
|
|
69
92
|
var log = createLogger("TON");
|
|
70
93
|
var WALLET_FILE = join(TELETON_ROOT, "wallet.json");
|
|
71
94
|
var _walletCache;
|
|
@@ -147,7 +170,8 @@ async function getCachedTonClient() {
|
|
|
147
170
|
if (_tonClientCache && _tonClientCache.endpoint === endpoint) {
|
|
148
171
|
return _tonClientCache.client;
|
|
149
172
|
}
|
|
150
|
-
const
|
|
173
|
+
const apiKey = getToncenterApiKey();
|
|
174
|
+
const client = new TonClient({ endpoint, ...apiKey && { apiKey } });
|
|
151
175
|
_tonClientCache = { client, endpoint };
|
|
152
176
|
return client;
|
|
153
177
|
}
|
|
@@ -217,8 +241,8 @@ async function getTonPrice() {
|
|
|
217
241
|
|
|
218
242
|
// src/config/schema.ts
|
|
219
243
|
import { z } from "zod";
|
|
220
|
-
var DMPolicy = z.enum(["allowlist", "open", "disabled"]);
|
|
221
|
-
var GroupPolicy = z.enum(["open", "allowlist", "disabled"]);
|
|
244
|
+
var DMPolicy = z.enum(["allowlist", "open", "admin-only", "disabled"]);
|
|
245
|
+
var GroupPolicy = z.enum(["open", "allowlist", "admin-only", "disabled"]);
|
|
222
246
|
var SessionResetPolicySchema = z.object({
|
|
223
247
|
daily_reset_enabled: z.boolean().default(true).describe("Enable daily session reset"),
|
|
224
248
|
daily_reset_hour: z.number().min(0).max(23).default(4).describe("Hour of day (0-23) to reset sessions"),
|
|
@@ -332,7 +356,7 @@ var _McpObject = z.object({
|
|
|
332
356
|
});
|
|
333
357
|
var McpConfigSchema = _McpObject.default(_McpObject.parse({}));
|
|
334
358
|
var _ToolRagObject = z.object({
|
|
335
|
-
enabled: z.boolean().default(
|
|
359
|
+
enabled: z.boolean().default(true).describe("Enable semantic tool retrieval (Tool RAG)"),
|
|
336
360
|
top_k: z.number().default(25).describe("Max tools to retrieve per LLM call"),
|
|
337
361
|
always_include: z.array(z.string()).default([
|
|
338
362
|
"telegram_send_message",
|
|
@@ -346,6 +370,24 @@ var _ToolRagObject = z.object({
|
|
|
346
370
|
skip_unlimited_providers: z.boolean().default(false).describe("Skip Tool RAG for providers with no tool limit (e.g. Anthropic)")
|
|
347
371
|
});
|
|
348
372
|
var ToolRagConfigSchema = _ToolRagObject.default(_ToolRagObject.parse({}));
|
|
373
|
+
var _ExecLimitsObject = z.object({
|
|
374
|
+
timeout: z.number().min(1).max(3600).default(120).describe("Max seconds per command execution"),
|
|
375
|
+
max_output: z.number().min(1e3).max(5e5).default(5e4).describe("Max chars of stdout/stderr captured per command")
|
|
376
|
+
});
|
|
377
|
+
var _ExecAuditObject = z.object({
|
|
378
|
+
log_commands: z.boolean().default(true).describe("Log every command to SQLite audit table")
|
|
379
|
+
});
|
|
380
|
+
var _ExecObject = z.object({
|
|
381
|
+
mode: z.enum(["off", "yolo"]).default("off").describe("Exec mode: off (disabled) or yolo (full system access)"),
|
|
382
|
+
scope: z.enum(["admin-only", "allowlist", "all"]).default("admin-only").describe("Who can trigger exec tools"),
|
|
383
|
+
allowlist: z.array(z.number()).default([]).describe("Telegram user IDs allowed to use exec (when scope = allowlist)"),
|
|
384
|
+
limits: _ExecLimitsObject.default(_ExecLimitsObject.parse({})),
|
|
385
|
+
audit: _ExecAuditObject.default(_ExecAuditObject.parse({}))
|
|
386
|
+
});
|
|
387
|
+
var _CapabilitiesObject = z.object({
|
|
388
|
+
exec: _ExecObject.default(_ExecObject.parse({}))
|
|
389
|
+
});
|
|
390
|
+
var CapabilitiesConfigSchema = _CapabilitiesObject.default(_CapabilitiesObject.parse({}));
|
|
349
391
|
var ConfigSchema = z.object({
|
|
350
392
|
meta: MetaConfigSchema.default(MetaConfigSchema.parse({})),
|
|
351
393
|
agent: AgentConfigSchema,
|
|
@@ -357,12 +399,14 @@ var ConfigSchema = z.object({
|
|
|
357
399
|
logging: LoggingConfigSchema,
|
|
358
400
|
dev: DevConfigSchema,
|
|
359
401
|
tool_rag: ToolRagConfigSchema,
|
|
402
|
+
capabilities: CapabilitiesConfigSchema,
|
|
360
403
|
mcp: McpConfigSchema,
|
|
361
404
|
plugins: z.record(z.string(), z.unknown()).default({}).describe("Per-plugin config (key = plugin name with underscores)"),
|
|
362
405
|
cocoon: z.object({
|
|
363
406
|
port: z.number().min(1).max(65535).default(1e4).describe("HTTP port of the cocoon-cli proxy")
|
|
364
407
|
}).optional().describe("Cocoon Network \u2014 expects external cocoon-cli running on this port"),
|
|
365
408
|
tonapi_key: z.string().optional().describe("TonAPI key for higher rate limits (from @tonapi_bot)"),
|
|
409
|
+
toncenter_api_key: z.string().optional().describe("TonCenter API key for dedicated RPC endpoint (free at https://toncenter.com)"),
|
|
366
410
|
tavily_api_key: z.string().optional().describe("Tavily API key for web search & extract (free at https://tavily.com)")
|
|
367
411
|
});
|
|
368
412
|
|
|
@@ -464,7 +508,8 @@ export {
|
|
|
464
508
|
ensureWorkspace,
|
|
465
509
|
isNewWorkspace,
|
|
466
510
|
loadTemplate,
|
|
467
|
-
|
|
511
|
+
setToncenterApiKey,
|
|
512
|
+
invalidateEndpointCache,
|
|
468
513
|
generateWallet,
|
|
469
514
|
saveWallet,
|
|
470
515
|
loadWallet,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLogger
|
|
3
|
+
} from "./chunk-RCMD3U65.js";
|
|
4
|
+
|
|
1
5
|
// src/config/providers.ts
|
|
2
6
|
var PROVIDER_REGISTRY = {
|
|
3
7
|
anthropic: {
|
|
@@ -154,8 +158,109 @@ function validateApiKeyFormat(provider, key) {
|
|
|
154
158
|
return void 0;
|
|
155
159
|
}
|
|
156
160
|
|
|
161
|
+
// src/providers/claude-code-credentials.ts
|
|
162
|
+
import { readFileSync, existsSync } from "fs";
|
|
163
|
+
import { execSync } from "child_process";
|
|
164
|
+
import { homedir } from "os";
|
|
165
|
+
import { join } from "path";
|
|
166
|
+
var log = createLogger("ClaudeCodeCreds");
|
|
167
|
+
var cachedToken = null;
|
|
168
|
+
var cachedExpiresAt = 0;
|
|
169
|
+
function getClaudeConfigDir() {
|
|
170
|
+
return process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
|
|
171
|
+
}
|
|
172
|
+
function getCredentialsFilePath() {
|
|
173
|
+
return join(getClaudeConfigDir(), ".credentials.json");
|
|
174
|
+
}
|
|
175
|
+
function readCredentialsFile() {
|
|
176
|
+
const filePath = getCredentialsFilePath();
|
|
177
|
+
if (!existsSync(filePath)) return null;
|
|
178
|
+
try {
|
|
179
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
180
|
+
return JSON.parse(raw);
|
|
181
|
+
} catch (e) {
|
|
182
|
+
log.warn({ err: e, path: filePath }, "Failed to parse Claude Code credentials file");
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function readKeychainCredentials() {
|
|
187
|
+
const serviceNames = ["Claude Code-credentials", "Claude Code"];
|
|
188
|
+
for (const service of serviceNames) {
|
|
189
|
+
try {
|
|
190
|
+
const raw = execSync(`security find-generic-password -s "${service}" -w`, {
|
|
191
|
+
encoding: "utf-8",
|
|
192
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
193
|
+
}).trim();
|
|
194
|
+
return JSON.parse(raw);
|
|
195
|
+
} catch {
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
function readCredentials() {
|
|
201
|
+
if (process.platform === "darwin") {
|
|
202
|
+
const keychainCreds = readKeychainCredentials();
|
|
203
|
+
if (keychainCreds) return keychainCreds;
|
|
204
|
+
log.debug("Keychain read failed, falling back to credentials file");
|
|
205
|
+
}
|
|
206
|
+
return readCredentialsFile();
|
|
207
|
+
}
|
|
208
|
+
function extractToken(creds) {
|
|
209
|
+
const oauth = creds.claudeAiOauth;
|
|
210
|
+
if (!oauth?.accessToken) {
|
|
211
|
+
log.warn("Claude Code credentials found but missing accessToken");
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
token: oauth.accessToken,
|
|
216
|
+
expiresAt: oauth.expiresAt ?? 0
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function getClaudeCodeApiKey(fallbackKey) {
|
|
220
|
+
if (cachedToken && Date.now() < cachedExpiresAt) {
|
|
221
|
+
return cachedToken;
|
|
222
|
+
}
|
|
223
|
+
const creds = readCredentials();
|
|
224
|
+
if (creds) {
|
|
225
|
+
const extracted = extractToken(creds);
|
|
226
|
+
if (extracted) {
|
|
227
|
+
cachedToken = extracted.token;
|
|
228
|
+
cachedExpiresAt = extracted.expiresAt;
|
|
229
|
+
log.debug("Claude Code credentials loaded successfully");
|
|
230
|
+
return cachedToken;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (fallbackKey && fallbackKey.length > 0) {
|
|
234
|
+
log.warn("Claude Code credentials not found, using fallback api_key from config");
|
|
235
|
+
return fallbackKey;
|
|
236
|
+
}
|
|
237
|
+
throw new Error("No Claude Code credentials found. Run 'claude login' or set api_key in config.");
|
|
238
|
+
}
|
|
239
|
+
function refreshClaudeCodeApiKey() {
|
|
240
|
+
cachedToken = null;
|
|
241
|
+
cachedExpiresAt = 0;
|
|
242
|
+
const creds = readCredentials();
|
|
243
|
+
if (creds) {
|
|
244
|
+
const extracted = extractToken(creds);
|
|
245
|
+
if (extracted) {
|
|
246
|
+
cachedToken = extracted.token;
|
|
247
|
+
cachedExpiresAt = extracted.expiresAt;
|
|
248
|
+
log.info("Claude Code credentials refreshed from disk");
|
|
249
|
+
return cachedToken;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
log.warn("Failed to refresh Claude Code credentials from disk");
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
function isClaudeCodeTokenValid() {
|
|
256
|
+
return cachedToken !== null && Date.now() < cachedExpiresAt;
|
|
257
|
+
}
|
|
258
|
+
|
|
157
259
|
export {
|
|
158
260
|
getProviderMetadata,
|
|
159
261
|
getSupportedProviders,
|
|
160
|
-
validateApiKeyFormat
|
|
262
|
+
validateApiKeyFormat,
|
|
263
|
+
getClaudeCodeApiKey,
|
|
264
|
+
refreshClaudeCodeApiKey,
|
|
265
|
+
isClaudeCodeTokenValid
|
|
161
266
|
};
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getClaudeCodeApiKey,
|
|
3
|
+
getProviderMetadata,
|
|
3
4
|
refreshClaudeCodeApiKey
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
getProviderMetadata
|
|
7
|
-
} from "./chunk-RMLQS3X6.js";
|
|
5
|
+
} from "./chunk-CB2Y45HA.js";
|
|
8
6
|
import {
|
|
9
7
|
appendToTranscript,
|
|
10
8
|
readTranscript
|
|
11
9
|
} from "./chunk-OCLG5GKI.js";
|
|
12
10
|
import {
|
|
13
11
|
fetchWithTimeout
|
|
14
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-XQUHC3JZ.js";
|
|
15
13
|
import {
|
|
16
14
|
createLogger
|
|
17
15
|
} from "./chunk-RCMD3U65.js";
|
|
@@ -306,7 +304,8 @@ async function chatWithContext(config, options) {
|
|
|
306
304
|
apiKey: getEffectiveApiKey(provider, config.api_key),
|
|
307
305
|
maxTokens: options.maxTokens ?? config.max_tokens,
|
|
308
306
|
temperature,
|
|
309
|
-
sessionId: options.sessionId
|
|
307
|
+
sessionId: options.sessionId,
|
|
308
|
+
cacheRetention: "long"
|
|
310
309
|
};
|
|
311
310
|
if (isCocoon) {
|
|
312
311
|
const { stripCocoonPayload } = await import("./tool-adapter-Y3TCEQOC.js");
|