teleton 0.7.3 → 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.
Files changed (36) hide show
  1. package/README.md +64 -35
  2. package/dist/{chunk-RBU6JXD3.js → chunk-2GLHOJ5C.js} +268 -59
  3. package/dist/chunk-5UVXJMOX.js +292 -0
  4. package/dist/{chunk-DAMCNMYL.js → chunk-AVDWXYQ7.js} +73 -28
  5. package/dist/{chunk-RMLQS3X6.js → chunk-CB2Y45HA.js} +106 -1
  6. package/dist/{chunk-5PLZ3KSO.js → chunk-DMXTIRUW.js} +5 -6
  7. package/dist/{chunk-A4GCOHCE.js → chunk-G2LLMJXJ.js} +1751 -116
  8. package/dist/{chunk-FNV5FF35.js → chunk-LCCVZ4D2.js} +32 -16
  9. package/dist/{chunk-BU453WX4.js → chunk-OGMVWDVU.js} +4172 -3792
  10. package/dist/chunk-QOQWUUA4.js +158 -0
  11. package/dist/{chunk-4DU3C27M.js → chunk-R4YSJ4EY.js} +5 -1
  12. package/dist/{chunk-XBKSS6DM.js → chunk-VFA7QMCZ.js} +5 -3
  13. package/dist/{chunk-VAUJSSD3.js → chunk-XQUHC3JZ.js} +1 -1
  14. package/dist/{chunk-RO62LO6Z.js → chunk-YP25WTQK.js} +2 -0
  15. package/dist/cli/index.js +234 -289
  16. package/dist/{client-RTNALK7W.js → client-O37XDCJB.js} +4 -5
  17. package/dist/index.js +12 -13
  18. package/dist/{memory-5SS3Q5EA.js → memory-KQALFUV3.js} +6 -7
  19. package/dist/{migrate-M7SJMDOL.js → migrate-UV3WEL5D.js} +6 -7
  20. package/dist/{server-FOC5P7U6.js → server-BHHJGUDF.js} +324 -16
  21. package/dist/{setup-server-BVVD2PR6.js → setup-server-G7UG2DI3.js} +26 -118
  22. package/dist/store-H4XPNGC2.js +34 -0
  23. package/dist/{task-dependency-resolver-WKZWJLLM.js → task-dependency-resolver-VMEVJRPO.js} +2 -2
  24. package/dist/{task-executor-PD3H4MLO.js → task-executor-WWSPBJ4V.js} +1 -1
  25. package/dist/{tool-index-MIVK3D7H.js → tool-index-2KH3OB6X.js} +5 -5
  26. package/dist/web/assets/index-BrVqauzj.css +1 -0
  27. package/dist/web/assets/index-Bx8JW3gV.js +72 -0
  28. package/dist/web/assets/{index.es-7MTSV5SL.js → index.es-Pet5-M13.js} +1 -1
  29. package/dist/web/index.html +2 -2
  30. package/package.json +3 -3
  31. package/dist/chunk-JQDLW7IE.js +0 -107
  32. package/dist/chunk-UCN6TI25.js +0 -143
  33. package/dist/web/assets/index-By_fs4Jl.js +0 -72
  34. package/dist/web/assets/index-CRDIf07k.css +0 -1
  35. package/scripts/patch-gramjs.sh +0 -46
  36. 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-XBKSS6DM.js";
4
+ } from "./chunk-VFA7QMCZ.js";
5
5
  import {
6
6
  TELEGRAM_MAX_MESSAGE_LENGTH
7
- } from "./chunk-RO62LO6Z.js";
7
+ } from "./chunk-YP25WTQK.js";
8
8
  import {
9
9
  fetchWithTimeout
10
- } from "./chunk-VAUJSSD3.js";
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 TONCENTER_FALLBACK = `https://toncenter.com/api/v2/jsonRPC`;
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
- try {
57
- url = await discoverOrbsEndpoint();
58
- } catch {
59
- url = TONCENTER_FALLBACK;
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 client = new TonClient({ endpoint });
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(["pairing", "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"),
@@ -255,7 +279,7 @@ var TelegramConfigSchema = z.object({
255
279
  phone: z.string(),
256
280
  session_name: z.string().default("teleton_session"),
257
281
  session_path: z.string().default("~/.teleton"),
258
- dm_policy: DMPolicy.default("pairing"),
282
+ dm_policy: DMPolicy.default("allowlist"),
259
283
  allow_from: z.array(z.number()).default([]),
260
284
  group_policy: GroupPolicy.default("open"),
261
285
  group_allow_from: z.array(z.number()).default([]),
@@ -275,7 +299,6 @@ var TelegramConfigSchema = z.object({
275
299
  });
276
300
  var StorageConfigSchema = z.object({
277
301
  sessions_file: z.string().default("~/.teleton/sessions.json"),
278
- pairing_file: z.string().default("~/.teleton/pairing.json"),
279
302
  memory_file: z.string().default("~/.teleton/memory.json"),
280
303
  history_limit: z.number().default(100)
281
304
  });
@@ -288,7 +311,7 @@ var MetaConfigSchema = z.object({
288
311
  var _DealsObject = z.object({
289
312
  enabled: z.boolean().default(true),
290
313
  expiry_seconds: z.number().default(120),
291
- buy_max_floor_percent: z.number().default(100),
314
+ buy_max_floor_percent: z.number().default(95),
292
315
  sell_min_floor_percent: z.number().default(105),
293
316
  poll_interval_ms: z.number().default(5e3),
294
317
  max_verification_retries: z.number().default(12),
@@ -333,7 +356,7 @@ var _McpObject = z.object({
333
356
  });
334
357
  var McpConfigSchema = _McpObject.default(_McpObject.parse({}));
335
358
  var _ToolRagObject = z.object({
336
- enabled: z.boolean().default(false).describe("Enable semantic tool retrieval (Tool RAG)"),
359
+ enabled: z.boolean().default(true).describe("Enable semantic tool retrieval (Tool RAG)"),
337
360
  top_k: z.number().default(25).describe("Max tools to retrieve per LLM call"),
338
361
  always_include: z.array(z.string()).default([
339
362
  "telegram_send_message",
@@ -347,6 +370,24 @@ var _ToolRagObject = z.object({
347
370
  skip_unlimited_providers: z.boolean().default(false).describe("Skip Tool RAG for providers with no tool limit (e.g. Anthropic)")
348
371
  });
349
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({}));
350
391
  var ConfigSchema = z.object({
351
392
  meta: MetaConfigSchema.default(MetaConfigSchema.parse({})),
352
393
  agent: AgentConfigSchema,
@@ -358,12 +399,14 @@ var ConfigSchema = z.object({
358
399
  logging: LoggingConfigSchema,
359
400
  dev: DevConfigSchema,
360
401
  tool_rag: ToolRagConfigSchema,
402
+ capabilities: CapabilitiesConfigSchema,
361
403
  mcp: McpConfigSchema,
362
404
  plugins: z.record(z.string(), z.unknown()).default({}).describe("Per-plugin config (key = plugin name with underscores)"),
363
405
  cocoon: z.object({
364
406
  port: z.number().min(1).max(65535).default(1e4).describe("HTTP port of the cocoon-cli proxy")
365
407
  }).optional().describe("Cocoon Network \u2014 expects external cocoon-cli running on this port"),
366
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)"),
367
410
  tavily_api_key: z.string().optional().describe("Tavily API key for web search & extract (free at https://tavily.com)")
368
411
  });
369
412
 
@@ -382,13 +425,14 @@ function findPackageRoot() {
382
425
  }
383
426
  var TEMPLATES_DIR = join2(findPackageRoot(), "src", "templates");
384
427
  async function ensureWorkspace(config) {
428
+ const silent = config?.silent ?? false;
385
429
  if (!existsSync2(TELETON_ROOT)) {
386
430
  mkdirSync2(TELETON_ROOT, { recursive: true });
387
- log2.info(`Created Teleton root at ${TELETON_ROOT}`);
431
+ if (!silent) log2.info(`Created Teleton root at ${TELETON_ROOT}`);
388
432
  }
389
433
  if (!existsSync2(WORKSPACE_ROOT)) {
390
434
  mkdirSync2(WORKSPACE_ROOT, { recursive: true });
391
- log2.info(`Created workspace at ${WORKSPACE_ROOT}`);
435
+ if (!silent) log2.info(`Created workspace at ${WORKSPACE_ROOT}`);
392
436
  }
393
437
  const directories = [
394
438
  WORKSPACE_PATHS.MEMORY_DIR,
@@ -424,11 +468,11 @@ async function ensureWorkspace(config) {
424
468
  walletPath: join2(TELETON_ROOT, "wallet.json")
425
469
  };
426
470
  if (config?.ensureTemplates) {
427
- await bootstrapTemplates(workspace);
471
+ await bootstrapTemplates(workspace, silent);
428
472
  }
429
473
  return workspace;
430
474
  }
431
- async function bootstrapTemplates(workspace) {
475
+ async function bootstrapTemplates(workspace, silent = false) {
432
476
  const templates = [
433
477
  { name: "SOUL.md", path: workspace.soulPath },
434
478
  { name: "MEMORY.md", path: workspace.memoryPath },
@@ -442,7 +486,7 @@ async function bootstrapTemplates(workspace) {
442
486
  const templateSource = join2(TEMPLATES_DIR, template.name);
443
487
  if (existsSync2(templateSource)) {
444
488
  copyFileSync(templateSource, template.path);
445
- log2.info(`Created ${template.name}`);
489
+ if (!silent) log2.info(`Created ${template.name}`);
446
490
  }
447
491
  }
448
492
  }
@@ -464,7 +508,8 @@ export {
464
508
  ensureWorkspace,
465
509
  isNewWorkspace,
466
510
  loadTemplate,
467
- getCachedHttpEndpoint,
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-JQDLW7IE.js";
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-VAUJSSD3.js";
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");