teleton 0.2.4 → 0.2.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.
@@ -29,6 +29,8 @@ var KNOWLEDGE_CHUNK_OVERLAP = 50;
29
29
  var PAYMENT_TOLERANCE_RATIO = 0.99;
30
30
  var TELEGRAM_CONNECTION_RETRIES = 5;
31
31
  var TELEGRAM_FLOOD_SLEEP_THRESHOLD = 60;
32
+ var MAX_DEPENDENTS_PER_TASK = 10;
33
+ var MAX_WRITE_SIZE = 50 * 1024 * 1024;
32
34
 
33
35
  export {
34
36
  MAX_TOOL_RESULT_SIZE,
@@ -60,5 +62,7 @@ export {
60
62
  KNOWLEDGE_CHUNK_OVERLAP,
61
63
  PAYMENT_TOLERANCE_RATIO,
62
64
  TELEGRAM_CONNECTION_RETRIES,
63
- TELEGRAM_FLOOD_SLEEP_THRESHOLD
65
+ TELEGRAM_FLOOD_SLEEP_THRESHOLD,
66
+ MAX_DEPENDENTS_PER_TASK,
67
+ MAX_WRITE_SIZE
64
68
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DEFAULT_FETCH_TIMEOUT_MS
3
- } from "./chunk-LJXYESJJ.js";
3
+ } from "./chunk-LCMHAUNK.js";
4
4
 
5
5
  // src/utils/fetch.ts
6
6
  var DEFAULT_TIMEOUT_MS = DEFAULT_FETCH_TIMEOUT_MS;
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  VOYAGE_API_URL,
3
3
  fetchWithTimeout
4
- } from "./chunk-WMIN6AGX.js";
4
+ } from "./chunk-DAMFGHXV.js";
5
5
  import {
6
6
  KNOWLEDGE_CHUNK_OVERLAP,
7
7
  KNOWLEDGE_CHUNK_SIZE,
8
8
  SQLITE_CACHE_SIZE_KB,
9
9
  SQLITE_MMAP_SIZE,
10
10
  VOYAGE_BATCH_SIZE
11
- } from "./chunk-QMN6ZOA5.js";
11
+ } from "./chunk-2X4PCE7V.js";
12
12
  import {
13
13
  TELETON_ROOT
14
14
  } from "./chunk-EYWNOHMJ.js";
@@ -1,3 +1,13 @@
1
+ import {
2
+ Mi,
3
+ Mn,
4
+ br,
5
+ dt,
6
+ le,
7
+ qn,
8
+ ut,
9
+ ye
10
+ } from "./chunk-U7FQYCBQ.js";
1
11
  import {
2
12
  initScraperDb
3
13
  } from "./chunk-DUW5VBAZ.js";
@@ -20,7 +30,7 @@ import {
20
30
  initializeMemory,
21
31
  migrateFromMainDb,
22
32
  openModuleDb
23
- } from "./chunk-TBIMVWQZ.js";
33
+ } from "./chunk-DR6WM6B5.js";
24
34
  import {
25
35
  COINGECKO_API_URL,
26
36
  ELEVENLABS_TTS_URL,
@@ -30,7 +40,7 @@ import {
30
40
  fetchWithTimeout,
31
41
  setTonapiKey,
32
42
  tonapiFetch
33
- } from "./chunk-WMIN6AGX.js";
43
+ } from "./chunk-DAMFGHXV.js";
34
44
  import {
35
45
  COMPACTION_KEEP_RECENT,
36
46
  COMPACTION_MAX_MESSAGES,
@@ -43,8 +53,10 @@ import {
43
53
  DEBOUNCE_MAX_BUFFER_SIZE,
44
54
  DEBOUNCE_MAX_MULTIPLIER,
45
55
  DEFAULT_GIFTS_QUERY_LIMIT,
56
+ MAX_DEPENDENTS_PER_TASK,
46
57
  MAX_POLL_QUESTION_LENGTH,
47
58
  MAX_TOOL_RESULT_SIZE,
59
+ MAX_WRITE_SIZE,
48
60
  PAYMENT_TOLERANCE_RATIO,
49
61
  PENDING_HISTORY_MAX_AGE_MS,
50
62
  PENDING_HISTORY_MAX_PER_CHAT,
@@ -53,7 +65,14 @@ import {
53
65
  TELEGRAM_CONNECTION_RETRIES,
54
66
  TELEGRAM_FLOOD_SLEEP_THRESHOLD,
55
67
  TELEGRAM_MAX_MESSAGE_LENGTH
56
- } from "./chunk-QMN6ZOA5.js";
68
+ } from "./chunk-2X4PCE7V.js";
69
+ import {
70
+ ALLOWED_EXTENSIONS,
71
+ MAX_FILE_SIZES,
72
+ TELETON_ROOT,
73
+ WORKSPACE_PATHS,
74
+ WORKSPACE_ROOT
75
+ } from "./chunk-EYWNOHMJ.js";
57
76
  import {
58
77
  GRAMJS_RETRY_DELAY_MS,
59
78
  MESSAGE_HANDLER_LOCK_TIMEOUT_MS,
@@ -64,29 +83,13 @@ import {
64
83
  RETRY_DEFAULT_MAX_ATTEMPTS,
65
84
  RETRY_DEFAULT_MAX_DELAY_MS,
66
85
  RETRY_DEFAULT_TIMEOUT_MS,
86
+ TOOL_EXECUTION_TIMEOUT_MS,
67
87
  TTS_TIMEOUT_MS
68
- } from "./chunk-LJXYESJJ.js";
69
- import {
70
- ALLOWED_EXTENSIONS,
71
- MAX_FILE_SIZES,
72
- TELETON_ROOT,
73
- WORKSPACE_PATHS,
74
- WORKSPACE_ROOT
75
- } from "./chunk-EYWNOHMJ.js";
88
+ } from "./chunk-LCMHAUNK.js";
76
89
  import {
77
90
  telegramGetMyGiftsExecutor,
78
91
  telegramGetMyGiftsTool
79
92
  } from "./chunk-B2PRMXOH.js";
80
- import {
81
- Mi,
82
- Mn,
83
- br,
84
- dt,
85
- le,
86
- qn,
87
- ut,
88
- ye
89
- } from "./chunk-U7FQYCBQ.js";
90
93
  import {
91
94
  __commonJS,
92
95
  __toESM
@@ -3409,7 +3412,13 @@ ${statsContext}`;
3409
3412
  const providerMeta = getProviderMetadata(
3410
3413
  this.config.agent.provider || "anthropic"
3411
3414
  );
3412
- const tools23 = this.toolRegistry?.getForContext(isGroup ?? false, providerMeta.toolLimit);
3415
+ const isAdmin = toolContext?.config?.telegram.admin_ids.includes(toolContext.senderId) ?? false;
3416
+ const tools23 = this.toolRegistry?.getForContext(
3417
+ isGroup ?? false,
3418
+ providerMeta.toolLimit,
3419
+ chatId,
3420
+ isAdmin
3421
+ );
3413
3422
  const maxIterations = this.config.agent.max_agentic_iterations || 5;
3414
3423
  let iteration = 0;
3415
3424
  let overflowResets = 0;
@@ -3624,22 +3633,6 @@ ${statsContext}`;
3624
3633
  */
3625
3634
  clearHistory(chatId) {
3626
3635
  const db3 = getDatabase().getDb();
3627
- db3.prepare(
3628
- `
3629
- DELETE FROM tg_messages_fts
3630
- WHERE rowid IN (
3631
- SELECT rowid FROM tg_messages WHERE chat_id = ?
3632
- )
3633
- `
3634
- ).run(chatId);
3635
- db3.prepare(
3636
- `
3637
- DELETE FROM tg_messages_vec
3638
- WHERE id IN (
3639
- SELECT id FROM tg_messages WHERE chat_id = ?
3640
- )
3641
- `
3642
- ).run(chatId);
3643
3636
  db3.prepare(`DELETE FROM tg_messages WHERE chat_id = ?`).run(chatId);
3644
3637
  resetSession(chatId);
3645
3638
  console.log(`\u{1F5D1}\uFE0F Cleared history for chat ${chatId}`);
@@ -4840,7 +4833,21 @@ import { mnemonicNew, mnemonicToPrivateKey, mnemonicValidate } from "@ton/crypto
4840
4833
  import { WalletContractV5R1, TonClient, fromNano } from "@ton/ton";
4841
4834
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync8, mkdirSync as mkdirSync6, chmodSync as chmodSync2 } from "fs";
4842
4835
  import { join as join6, dirname as dirname5 } from "path";
4836
+
4837
+ // src/ton/endpoint.ts
4843
4838
  import { getHttpEndpoint } from "@orbs-network/ton-access";
4839
+ var ENDPOINT_CACHE_TTL_MS = 6e4;
4840
+ var _cache = null;
4841
+ async function getCachedHttpEndpoint() {
4842
+ if (_cache && Date.now() - _cache.ts < ENDPOINT_CACHE_TTL_MS) {
4843
+ return _cache.url;
4844
+ }
4845
+ const url = await getHttpEndpoint({ network: "mainnet" });
4846
+ _cache = { url, ts: Date.now() };
4847
+ return url;
4848
+ }
4849
+
4850
+ // src/ton/wallet-service.ts
4844
4851
  var WALLET_FILE = join6(TELETON_ROOT, "wallet.json");
4845
4852
  async function generateWallet() {
4846
4853
  const mnemonic = await mnemonicNew(24);
@@ -4906,7 +4913,7 @@ function getWalletAddress() {
4906
4913
  }
4907
4914
  async function getWalletBalance(address4) {
4908
4915
  try {
4909
- const endpoint = await getHttpEndpoint({ network: "mainnet" });
4916
+ const endpoint = await getCachedHttpEndpoint();
4910
4917
  const client = new TonClient({ endpoint });
4911
4918
  const { Address: Address19 } = await import("@ton/core");
4912
4919
  const addressObj = Address19.parse(address4);
@@ -5000,15 +5007,20 @@ function initDealsConfig(yaml) {
5000
5007
  // src/telegram/admin.ts
5001
5008
  var VALID_DM_POLICIES = ["open", "allowlist", "pairing", "disabled"];
5002
5009
  var VALID_GROUP_POLICIES = ["open", "allowlist", "disabled"];
5010
+ var VALID_MODULE_LEVELS = ["open", "admin", "disabled"];
5003
5011
  var AdminHandler = class {
5004
5012
  bridge;
5005
5013
  config;
5006
5014
  agent;
5007
5015
  paused = false;
5008
- constructor(bridge, config, agent) {
5016
+ permissions;
5017
+ registry;
5018
+ constructor(bridge, config, agent, permissions, registry) {
5009
5019
  this.bridge = bridge;
5010
5020
  this.config = config;
5011
5021
  this.agent = agent;
5022
+ this.permissions = permissions ?? null;
5023
+ this.registry = registry ?? null;
5012
5024
  }
5013
5025
  /**
5014
5026
  * Check if user is admin
@@ -5043,7 +5055,7 @@ var AdminHandler = class {
5043
5055
  /**
5044
5056
  * Handle admin command
5045
5057
  */
5046
- async handleCommand(command, chatId, senderId) {
5058
+ async handleCommand(command, chatId, senderId, isGroup) {
5047
5059
  if (!this.isAdmin(senderId)) {
5048
5060
  return "\u26D4 Admin access required";
5049
5061
  }
@@ -5074,6 +5086,8 @@ var AdminHandler = class {
5074
5086
  return await this.handleStopCommand();
5075
5087
  case "verbose":
5076
5088
  return this.handleVerboseCommand();
5089
+ case "modules":
5090
+ return this.handleModulesCommand(command, isGroup ?? false);
5077
5091
  case "help":
5078
5092
  return this.handleHelpCommand();
5079
5093
  case "ping":
@@ -5286,6 +5300,124 @@ Usage:
5286
5300
  setVerbose(next);
5287
5301
  return next ? "\u{1F50A} Verbose logging **ON**" : "\u{1F507} Verbose logging **OFF**";
5288
5302
  }
5303
+ /**
5304
+ * /modules - Manage per-group module permissions
5305
+ */
5306
+ handleModulesCommand(command, isGroup) {
5307
+ if (!this.permissions || !this.registry) {
5308
+ return "\u274C Module permissions non disponible";
5309
+ }
5310
+ if (!isGroup) {
5311
+ return "\u274C /modules est uniquement disponible dans les groupes";
5312
+ }
5313
+ const chatId = command.chatId;
5314
+ const sub = command.args[0]?.toLowerCase();
5315
+ if (!sub) {
5316
+ return this.listModules(chatId);
5317
+ }
5318
+ switch (sub) {
5319
+ case "set":
5320
+ return this.setModuleLevel(chatId, command.args[1], command.args[2], command.senderId);
5321
+ case "info":
5322
+ return this.showModuleInfo(command.args[1], chatId);
5323
+ case "reset":
5324
+ return this.resetModules(chatId, command.args[1]);
5325
+ default:
5326
+ return `\u274C Sous-commande inconnue: "${sub}"
5327
+
5328
+ Usage: /modules | /modules set <module> <level> | /modules info <module> | /modules reset [module]`;
5329
+ }
5330
+ }
5331
+ listModules(chatId) {
5332
+ const modules = this.registry.getAvailableModules();
5333
+ const overrides = this.permissions.getOverrides(chatId);
5334
+ const lines = ["\u{1F9E9} **Modules** (ce groupe)\n"];
5335
+ for (const mod of modules) {
5336
+ const count = this.registry.getModuleToolCount(mod);
5337
+ const level = overrides.get(mod) ?? "open";
5338
+ const isProtected = this.permissions.isProtected(mod);
5339
+ let icon;
5340
+ switch (level) {
5341
+ case "open":
5342
+ icon = "\u2705";
5343
+ break;
5344
+ case "admin":
5345
+ icon = "\u{1F510}";
5346
+ break;
5347
+ case "disabled":
5348
+ icon = "\u274C";
5349
+ break;
5350
+ }
5351
+ const toolWord = count === 1 ? "tool" : "tools";
5352
+ const protectedMark = isProtected ? " \u{1F512}" : "";
5353
+ lines.push(` ${icon} **${mod}** ${count} ${toolWord} ${level}${protectedMark}`);
5354
+ }
5355
+ lines.push("");
5356
+ lines.push("Niveaux: `open` | `admin` | `disabled`");
5357
+ lines.push("Usage: `/modules set <module> <level>`");
5358
+ return lines.join("\n");
5359
+ }
5360
+ setModuleLevel(chatId, module, level, senderId) {
5361
+ if (!module || !level) {
5362
+ return "\u274C Usage: /modules set <module> <level>";
5363
+ }
5364
+ module = module.toLowerCase();
5365
+ level = level.toLowerCase();
5366
+ const available = this.registry.getAvailableModules();
5367
+ if (!available.includes(module)) {
5368
+ return `\u274C Module inconnu: "${module}"`;
5369
+ }
5370
+ if (this.permissions.isProtected(module)) {
5371
+ return `\u26D4 Module "${module}" est prot\xE9g\xE9`;
5372
+ }
5373
+ if (!VALID_MODULE_LEVELS.includes(level)) {
5374
+ return `\u274C Niveau invalide: "${level}". Valide: ${VALID_MODULE_LEVELS.join(", ")}`;
5375
+ }
5376
+ const oldLevel = this.permissions.getLevel(chatId, module);
5377
+ this.permissions.setLevel(chatId, module, level, senderId);
5378
+ const icons = { open: "\u2705", admin: "\u{1F510}", disabled: "\u274C" };
5379
+ return `${icons[level]} **${module}**: ${oldLevel} \u2192 ${level}`;
5380
+ }
5381
+ showModuleInfo(module, chatId) {
5382
+ if (!module) {
5383
+ return "\u274C Usage: /modules info <module>";
5384
+ }
5385
+ module = module.toLowerCase();
5386
+ const available = this.registry.getAvailableModules();
5387
+ if (!available.includes(module)) {
5388
+ return `\u274C Module inconnu: "${module}"`;
5389
+ }
5390
+ const tools23 = this.registry.getModuleTools(module);
5391
+ const count = tools23.length;
5392
+ const toolWord = count === 1 ? "tool" : "tools";
5393
+ const level = this.permissions.getLevel(chatId, module);
5394
+ const isProtected = this.permissions.isProtected(module);
5395
+ const protectedMark = isProtected ? " \u{1F512}" : "";
5396
+ const lines = [
5397
+ `\u{1F4E6} Module "**${module}**" \u2014 ${level}${protectedMark} (${count} ${toolWord})
5398
+ `
5399
+ ];
5400
+ for (const t of tools23) {
5401
+ lines.push(` ${t.name} ${t.scope}`);
5402
+ }
5403
+ return lines.join("\n");
5404
+ }
5405
+ resetModules(chatId, module) {
5406
+ if (module) {
5407
+ module = module.toLowerCase();
5408
+ const available = this.registry.getAvailableModules();
5409
+ if (!available.includes(module)) {
5410
+ return `\u274C Module inconnu: "${module}"`;
5411
+ }
5412
+ if (this.permissions.isProtected(module)) {
5413
+ return `\u26D4 Module "${module}" est prot\xE9g\xE9 (d\xE9j\xE0 open)`;
5414
+ }
5415
+ this.permissions.resetModule(chatId, module);
5416
+ return `\u2705 **${module}** \u2192 open`;
5417
+ }
5418
+ this.permissions.resetAll(chatId);
5419
+ return "\u2705 Tous les modules remis \xE0 **open**";
5420
+ }
5289
5421
  /**
5290
5422
  * /help - Show available commands
5291
5423
  */
@@ -5307,6 +5439,9 @@ Change access policy
5307
5439
  **/strategy** [buy|sell <percent>]
5308
5440
  View or change trading thresholds
5309
5441
 
5442
+ **/modules** [set|info|reset]
5443
+ Manage per-group module permissions
5444
+
5310
5445
  **/wallet**
5311
5446
  Check TON wallet balance
5312
5447
 
@@ -5458,6 +5593,8 @@ import { validateToolCall } from "@mariozechner/pi-ai";
5458
5593
  var ToolRegistry = class {
5459
5594
  tools = /* @__PURE__ */ new Map();
5460
5595
  scopes = /* @__PURE__ */ new Map();
5596
+ toolModules = /* @__PURE__ */ new Map();
5597
+ permissions = null;
5461
5598
  /**
5462
5599
  * Register a new tool with optional scope
5463
5600
  */
@@ -5469,6 +5606,42 @@ var ToolRegistry = class {
5469
5606
  if (scope && scope !== "always") {
5470
5607
  this.scopes.set(tool.name, scope);
5471
5608
  }
5609
+ this.toolModules.set(tool.name, tool.name.split("_")[0]);
5610
+ }
5611
+ /**
5612
+ * Set the module permissions manager
5613
+ */
5614
+ setPermissions(mp) {
5615
+ this.permissions = mp;
5616
+ }
5617
+ /**
5618
+ * Get sorted unique module names derived from registered tools
5619
+ */
5620
+ getAvailableModules() {
5621
+ const modules = new Set(this.toolModules.values());
5622
+ return Array.from(modules).sort();
5623
+ }
5624
+ /**
5625
+ * Get the number of tools in a module
5626
+ */
5627
+ getModuleToolCount(module) {
5628
+ let count = 0;
5629
+ for (const mod of this.toolModules.values()) {
5630
+ if (mod === module) count++;
5631
+ }
5632
+ return count;
5633
+ }
5634
+ /**
5635
+ * Get tools belonging to a module with their scope
5636
+ */
5637
+ getModuleTools(module) {
5638
+ const result = [];
5639
+ for (const [name, mod] of this.toolModules) {
5640
+ if (mod === module) {
5641
+ result.push({ name, scope: this.scopes.get(name) ?? "always" });
5642
+ }
5643
+ }
5644
+ return result.sort((a, b) => a.name.localeCompare(b.name));
5472
5645
  }
5473
5646
  /**
5474
5647
  * Get all registered tools for pi-ai
@@ -5500,9 +5673,43 @@ var ToolRegistry = class {
5500
5673
  error: `Tool "${toolCall.name}" is only available in group chats`
5501
5674
  };
5502
5675
  }
5676
+ if (context.isGroup && this.permissions) {
5677
+ const module = this.toolModules.get(toolCall.name);
5678
+ if (module) {
5679
+ const level = this.permissions.getLevel(context.chatId, module);
5680
+ if (level === "disabled") {
5681
+ return {
5682
+ success: false,
5683
+ error: `Module "${module}" is disabled in this group`
5684
+ };
5685
+ }
5686
+ if (level === "admin") {
5687
+ const isAdmin = context.config?.telegram.admin_ids.includes(context.senderId) ?? false;
5688
+ if (!isAdmin) {
5689
+ return {
5690
+ success: false,
5691
+ error: `Module "${module}" is restricted to admins in this group`
5692
+ };
5693
+ }
5694
+ }
5695
+ }
5696
+ }
5503
5697
  try {
5504
5698
  const validatedArgs = validateToolCall(this.getAll(), toolCall);
5505
- const result = await registered.executor(validatedArgs, context);
5699
+ let timeoutHandle;
5700
+ const result = await Promise.race([
5701
+ registered.executor(validatedArgs, context),
5702
+ new Promise((_, reject) => {
5703
+ timeoutHandle = setTimeout(
5704
+ () => reject(
5705
+ new Error(
5706
+ `Tool "${toolCall.name}" timed out after ${TOOL_EXECUTION_TIMEOUT_MS / 1e3}s`
5707
+ )
5708
+ ),
5709
+ TOOL_EXECUTION_TIMEOUT_MS
5710
+ );
5711
+ })
5712
+ ]).finally(() => clearTimeout(timeoutHandle));
5506
5713
  return result;
5507
5714
  } catch (error) {
5508
5715
  console.error(`Error executing tool ${toolCall.name}:`, error);
@@ -5526,13 +5733,25 @@ var ToolRegistry = class {
5526
5733
  return all.slice(0, toolLimit);
5527
5734
  }
5528
5735
  /**
5529
- * Get tools filtered by chat context (DM vs group) and provider limit.
5736
+ * Get tools filtered by chat context (DM vs group), module permissions, and provider limit.
5530
5737
  * - In groups: excludes "dm-only" tools (financial, private)
5531
5738
  * - In DMs: excludes "group-only" tools (moderation)
5739
+ * - In groups with permissions: excludes disabled modules, admin-only modules for non-admins
5532
5740
  */
5533
- getForContext(isGroup, toolLimit) {
5741
+ getForContext(isGroup, toolLimit, chatId, isAdmin) {
5534
5742
  const excluded = isGroup ? "dm-only" : "group-only";
5535
- const filtered = Array.from(this.tools.values()).filter((rt) => this.scopes.get(rt.tool.name) !== excluded).map((rt) => rt.tool);
5743
+ const filtered = Array.from(this.tools.values()).filter((rt) => {
5744
+ if (this.scopes.get(rt.tool.name) === excluded) return false;
5745
+ if (isGroup && chatId && this.permissions) {
5746
+ const module = this.toolModules.get(rt.tool.name);
5747
+ if (module) {
5748
+ const level = this.permissions.getLevel(chatId, module);
5749
+ if (level === "disabled") return false;
5750
+ if (level === "admin" && !isAdmin) return false;
5751
+ }
5752
+ }
5753
+ return true;
5754
+ }).map((rt) => rt.tool);
5536
5755
  if (toolLimit !== null && filtered.length > toolLimit) {
5537
5756
  console.warn(
5538
5757
  `\u26A0\uFE0F Provider tool limit: ${toolLimit}, after scope filter: ${filtered.length}. Truncating to ${toolLimit} tools.`
@@ -10526,19 +10745,6 @@ var GramJSBotClient = class {
10526
10745
  import { TonClient as TonClient2, fromNano as fromNano2 } from "@ton/ton";
10527
10746
  import { Address } from "@ton/core";
10528
10747
 
10529
- // src/ton/endpoint.ts
10530
- import { getHttpEndpoint as getHttpEndpoint2 } from "@orbs-network/ton-access";
10531
- var ENDPOINT_CACHE_TTL_MS = 6e4;
10532
- var _cache = null;
10533
- async function getCachedHttpEndpoint() {
10534
- if (_cache && Date.now() - _cache.ts < ENDPOINT_CACHE_TTL_MS) {
10535
- return _cache.url;
10536
- }
10537
- const url = await getHttpEndpoint2({ network: "mainnet" });
10538
- _cache = { url, ts: Date.now() };
10539
- return url;
10540
- }
10541
-
10542
10748
  // src/casino/retry.ts
10543
10749
  var DEFAULT_OPTIONS = {
10544
10750
  maxAttempts: RETRY_DEFAULT_MAX_ATTEMPTS,
@@ -10773,7 +10979,6 @@ If you already sent, wait a moment and try again.`
10773
10979
  import { mnemonicToPrivateKey as mnemonicToPrivateKey2 } from "@ton/crypto";
10774
10980
  import { WalletContractV5R1 as WalletContractV5R12, TonClient as TonClient3, toNano, internal } from "@ton/ton";
10775
10981
  import { Address as Address2, SendMode } from "@ton/core";
10776
- import { getHttpEndpoint as getHttpEndpoint3 } from "@orbs-network/ton-access";
10777
10982
  async function sendTon(params) {
10778
10983
  try {
10779
10984
  const { toAddress: toAddress2, amount, comment = "", bounce = false } = params;
@@ -10794,7 +10999,7 @@ async function sendTon(params) {
10794
10999
  workchain: 0,
10795
11000
  publicKey: keyPair.publicKey
10796
11001
  });
10797
- const endpoint = await getHttpEndpoint3({ network: "mainnet" });
11002
+ const endpoint = await getCachedHttpEndpoint();
10798
11003
  const client = new TonClient3({ endpoint });
10799
11004
  const contract = client.open(wallet);
10800
11005
  const seqno = await contract.getSeqno();
@@ -11954,6 +12159,7 @@ function openDealsDb() {
11954
12159
  CREATE INDEX IF NOT EXISTS idx_deals_chat ON deals(chat_id);
11955
12160
  CREATE INDEX IF NOT EXISTS idx_deals_inline_msg ON deals(inline_message_id) WHERE inline_message_id IS NOT NULL;
11956
12161
  CREATE INDEX IF NOT EXISTS idx_deals_payment_claimed ON deals(payment_claimed_at) WHERE payment_claimed_at IS NOT NULL;
12162
+ CREATE INDEX IF NOT EXISTS idx_deals_expires ON deals(expires_at) WHERE status IN ('proposed', 'accepted');
11957
12163
 
11958
12164
  CREATE TABLE IF NOT EXISTS user_trade_stats (
11959
12165
  telegram_id INTEGER PRIMARY KEY,
@@ -14374,7 +14580,6 @@ var telegramCreateScheduledTaskExecutor = async (params, context) => {
14374
14580
  }
14375
14581
  const { getTaskStore } = await import("./tasks-M3QDPTGY.js");
14376
14582
  const taskStore = getTaskStore(context.db);
14377
- const MAX_DEPENDENTS_PER_TASK = 10;
14378
14583
  if (dependsOn && dependsOn.length > 0) {
14379
14584
  for (const parentId of dependsOn) {
14380
14585
  const existingDependents = taskStore.getDependents(parentId);
@@ -14877,7 +15082,6 @@ import { Type as Type75 } from "@sinclair/typebox";
14877
15082
  import { mnemonicToPrivateKey as mnemonicToPrivateKey3 } from "@ton/crypto";
14878
15083
  import { WalletContractV5R1 as WalletContractV5R13, TonClient as TonClient4, toNano as toNano2, internal as internal2 } from "@ton/ton";
14879
15084
  import { Address as Address3, SendMode as SendMode2 } from "@ton/core";
14880
- import { getHttpEndpoint as getHttpEndpoint4 } from "@orbs-network/ton-access";
14881
15085
  var tonSendTool = {
14882
15086
  name: "ton_send",
14883
15087
  description: "Send TON cryptocurrency to an address. Requires wallet to be initialized. Amount is in TON (not nanoTON). Example: amount 1.5 = 1.5 TON. Always confirm the transaction details before sending.",
@@ -14919,7 +15123,7 @@ var tonSendExecutor = async (params, context) => {
14919
15123
  workchain: 0,
14920
15124
  publicKey: keyPair.publicKey
14921
15125
  });
14922
- const endpoint = await getHttpEndpoint4({ network: "mainnet" });
15126
+ const endpoint = await getCachedHttpEndpoint();
14923
15127
  const client = new TonClient4({ endpoint });
14924
15128
  const contract = client.open(wallet);
14925
15129
  const seqno = await contract.getSeqno();
@@ -14959,7 +15163,6 @@ var tonSendExecutor = async (params, context) => {
14959
15163
  import { Type as Type76 } from "@sinclair/typebox";
14960
15164
  import { TonClient as TonClient5, fromNano as fromNano3 } from "@ton/ton";
14961
15165
  import { Address as Address4 } from "@ton/core";
14962
- import { getHttpEndpoint as getHttpEndpoint5 } from "@orbs-network/ton-access";
14963
15166
  var OP_CODES = {
14964
15167
  COMMENT: 0,
14965
15168
  JETTON_TRANSFER: 260734629,
@@ -15035,7 +15238,7 @@ var tonGetTransactionsExecutor = async (params, context) => {
15035
15238
  error: `Invalid address: ${address4}`
15036
15239
  };
15037
15240
  }
15038
- const endpoint = await getHttpEndpoint5({ network: "mainnet" });
15241
+ const endpoint = await getCachedHttpEndpoint();
15039
15242
  const client = new TonClient5({ endpoint });
15040
15243
  const transactions = await client.getTransactions(addressObj, {
15041
15244
  limit: Math.min(limit, 50)
@@ -15179,7 +15382,6 @@ var tonGetTransactionsExecutor = async (params, context) => {
15179
15382
  import { Type as Type77 } from "@sinclair/typebox";
15180
15383
  import { TonClient as TonClient6, fromNano as fromNano4 } from "@ton/ton";
15181
15384
  import { Address as Address5 } from "@ton/core";
15182
- import { getHttpEndpoint as getHttpEndpoint6 } from "@orbs-network/ton-access";
15183
15385
  var OP_CODES2 = {
15184
15386
  COMMENT: 0,
15185
15387
  JETTON_TRANSFER: 260734629,
@@ -15251,7 +15453,7 @@ var tonMyTransactionsExecutor = async (params, context) => {
15251
15453
  };
15252
15454
  }
15253
15455
  const addressObj = Address5.parse(walletData.address);
15254
- const endpoint = await getHttpEndpoint6({ network: "mainnet" });
15456
+ const endpoint = await getCachedHttpEndpoint();
15255
15457
  const client = new TonClient6({ endpoint });
15256
15458
  const transactions = await client.getTransactions(addressObj, {
15257
15459
  limit: Math.min(limit, 50)
@@ -15657,7 +15859,6 @@ import { Type as Type81 } from "@sinclair/typebox";
15657
15859
  import { mnemonicToPrivateKey as mnemonicToPrivateKey4 } from "@ton/crypto";
15658
15860
  import { WalletContractV5R1 as WalletContractV5R14, TonClient as TonClient7, toNano as toNano3, internal as internal3, beginCell } from "@ton/ton";
15659
15861
  import { Address as Address6, SendMode as SendMode3 } from "@ton/core";
15660
- import { getHttpEndpoint as getHttpEndpoint7 } from "@orbs-network/ton-access";
15661
15862
  var DNS_COLLECTION = "EQC3dNlesgVD8YbAazcauIrXBPfiVhMMr5YYk2in0Mtsz0Bz";
15662
15863
  var dnsStartAuctionTool = {
15663
15864
  name: "dns_start_auction",
@@ -15700,7 +15901,7 @@ var dnsStartAuctionExecutor = async (params, context) => {
15700
15901
  workchain: 0,
15701
15902
  publicKey: keyPair.publicKey
15702
15903
  });
15703
- const endpoint = await getHttpEndpoint7({ network: "mainnet" });
15904
+ const endpoint = await getCachedHttpEndpoint();
15704
15905
  const client = new TonClient7({ endpoint });
15705
15906
  const contract = client.open(wallet);
15706
15907
  const seqno = await contract.getSeqno();
@@ -15745,7 +15946,6 @@ import { Type as Type82 } from "@sinclair/typebox";
15745
15946
  import { mnemonicToPrivateKey as mnemonicToPrivateKey5 } from "@ton/crypto";
15746
15947
  import { WalletContractV5R1 as WalletContractV5R15, TonClient as TonClient8, toNano as toNano4, internal as internal4 } from "@ton/ton";
15747
15948
  import { Address as Address7, SendMode as SendMode4 } from "@ton/core";
15748
- import { getHttpEndpoint as getHttpEndpoint8 } from "@orbs-network/ton-access";
15749
15949
  var dnsBidTool = {
15750
15950
  name: "dns_bid",
15751
15951
  description: "Place a bid on an existing .ton domain auction. Bid must be at least 5% higher than current bid. The domain must already be in auction (use dns_check first to verify status and get current bid).",
@@ -15818,7 +16018,7 @@ var dnsBidExecutor = async (params, context) => {
15818
16018
  workchain: 0,
15819
16019
  publicKey: keyPair.publicKey
15820
16020
  });
15821
- const endpoint = await getHttpEndpoint8({ network: "mainnet" });
16021
+ const endpoint = await getCachedHttpEndpoint();
15822
16022
  const client = new TonClient8({ endpoint });
15823
16023
  const contract = client.open(wallet);
15824
16024
  const seqno = await contract.getSeqno();
@@ -15863,7 +16063,6 @@ import { Type as Type83 } from "@sinclair/typebox";
15863
16063
  import { mnemonicToPrivateKey as mnemonicToPrivateKey6 } from "@ton/crypto";
15864
16064
  import { WalletContractV5R1 as WalletContractV5R16, TonClient as TonClient9, toNano as toNano5, internal as internal5, beginCell as beginCell2 } from "@ton/ton";
15865
16065
  import { Address as Address8, SendMode as SendMode5 } from "@ton/core";
15866
- import { getHttpEndpoint as getHttpEndpoint9 } from "@orbs-network/ton-access";
15867
16066
  var DNS_CHANGE_RECORD_OP = 1320284409;
15868
16067
  var DNS_SMC_ADDRESS_PREFIX = 40915;
15869
16068
  var WALLET_RECORD_KEY = BigInt(
@@ -15945,7 +16144,7 @@ var dnsLinkExecutor = async (params, context) => {
15945
16144
  workchain: 0,
15946
16145
  publicKey: keyPair.publicKey
15947
16146
  });
15948
- const endpoint = await getHttpEndpoint9({ network: "mainnet" });
16147
+ const endpoint = await getCachedHttpEndpoint();
15949
16148
  const client = new TonClient9({ endpoint });
15950
16149
  const contract = client.open(wallet);
15951
16150
  const seqno = await contract.getSeqno();
@@ -15991,7 +16190,6 @@ import { Type as Type84 } from "@sinclair/typebox";
15991
16190
  import { mnemonicToPrivateKey as mnemonicToPrivateKey7 } from "@ton/crypto";
15992
16191
  import { WalletContractV5R1 as WalletContractV5R17, TonClient as TonClient10, toNano as toNano6, internal as internal6, beginCell as beginCell3 } from "@ton/ton";
15993
16192
  import { Address as Address9, SendMode as SendMode6 } from "@ton/core";
15994
- import { getHttpEndpoint as getHttpEndpoint10 } from "@orbs-network/ton-access";
15995
16193
  var DNS_CHANGE_RECORD_OP2 = 1320284409;
15996
16194
  var WALLET_RECORD_KEY2 = BigInt(
15997
16195
  "0xe8d44050873dba865aa7c170ab4cce64d90839a34dcfd6cf71d14e0205443b1b"
@@ -16058,7 +16256,7 @@ var dnsUnlinkExecutor = async (params, context) => {
16058
16256
  workchain: 0,
16059
16257
  publicKey: keyPair.publicKey
16060
16258
  });
16061
- const endpoint = await getHttpEndpoint10({ network: "mainnet" });
16259
+ const endpoint = await getCachedHttpEndpoint();
16062
16260
  const client = new TonClient10({ endpoint });
16063
16261
  const contract = client.open(wallet);
16064
16262
  const seqno = await contract.getSeqno();
@@ -16218,7 +16416,6 @@ import { Type as Type86 } from "@sinclair/typebox";
16218
16416
  import { mnemonicToPrivateKey as mnemonicToPrivateKey8 } from "@ton/crypto";
16219
16417
  import { WalletContractV5R1 as WalletContractV5R18, TonClient as TonClient11, toNano as toNano19, internal as internal7 } from "@ton/ton";
16220
16418
  import { SendMode as SendMode7 } from "@ton/core";
16221
- import { getHttpEndpoint as getHttpEndpoint11 } from "@orbs-network/ton-access";
16222
16419
 
16223
16420
  // node_modules/@ston-fi/sdk/dist/chunk-HNMPFVZW.js
16224
16421
  import { Address as Address10, address } from "@ton/ton";
@@ -19589,7 +19786,7 @@ var jettonSwapExecutor = async (params, context) => {
19589
19786
  error: `Invalid to_asset address: ${toAddress2}`
19590
19787
  };
19591
19788
  }
19592
- const endpoint = await getHttpEndpoint11({ network: "mainnet" });
19789
+ const endpoint = await getCachedHttpEndpoint();
19593
19790
  const tonClient = new TonClient11({ endpoint });
19594
19791
  const stonApiClient = new StonApiClient();
19595
19792
  console.log(`Simulating swap: ${amount} ${fromAddress} \u2192 ${toAddress2}`);
@@ -19678,7 +19875,6 @@ import { Type as Type87 } from "@sinclair/typebox";
19678
19875
  import { mnemonicToPrivateKey as mnemonicToPrivateKey9 } from "@ton/crypto";
19679
19876
  import { WalletContractV5R1 as WalletContractV5R19, TonClient as TonClient12, toNano as toNano20, internal as internal8 } from "@ton/ton";
19680
19877
  import { Address as Address13, SendMode as SendMode8, beginCell as beginCell15 } from "@ton/core";
19681
- import { getHttpEndpoint as getHttpEndpoint12 } from "@orbs-network/ton-access";
19682
19878
  var JETTON_TRANSFER_OP = 260734629;
19683
19879
  var jettonSendTool = {
19684
19880
  name: "jetton_send",
@@ -19758,7 +19954,7 @@ var jettonSendExecutor = async (params, context) => {
19758
19954
  workchain: 0,
19759
19955
  publicKey: keyPair.publicKey
19760
19956
  });
19761
- const endpoint = await getHttpEndpoint12({ network: "mainnet" });
19957
+ const endpoint = await getCachedHttpEndpoint();
19762
19958
  const client = new TonClient12({ endpoint });
19763
19959
  const walletContract = client.open(wallet);
19764
19960
  const seqno = await walletContract.getSeqno();
@@ -20620,7 +20816,7 @@ var jettonPoolsExecutor = async (params, context) => {
20620
20816
 
20621
20817
  // src/agent/tools/jetton/index.ts
20622
20818
  var tools18 = [
20623
- { tool: jettonSwapTool, executor: jettonSwapExecutor, scope: "dm-only" },
20819
+ { tool: jettonSwapTool, executor: jettonSwapExecutor },
20624
20820
  { tool: jettonSendTool, executor: jettonSendExecutor, scope: "dm-only" },
20625
20821
  { tool: jettonBalancesTool, executor: jettonBalancesExecutor },
20626
20822
  { tool: jettonInfoTool, executor: jettonInfoExecutor },
@@ -20637,7 +20833,6 @@ var tools18 = [
20637
20833
  import { Type as Type96 } from "@sinclair/typebox";
20638
20834
  import { TonClient as TonClient13, toNano as toNano22, fromNano as fromNano5 } from "@ton/ton";
20639
20835
  import { Address as Address14 } from "@ton/core";
20640
- import { getHttpEndpoint as getHttpEndpoint13 } from "@orbs-network/ton-access";
20641
20836
  import { Factory, Asset, PoolType, ReadinessStatus } from "@dedust/sdk";
20642
20837
 
20643
20838
  // src/agent/tools/dedust/constants.ts
@@ -20711,7 +20906,7 @@ var dedustQuoteExecutor = async (params, context) => {
20711
20906
  };
20712
20907
  }
20713
20908
  }
20714
- const endpoint = await getHttpEndpoint13({ network: "mainnet" });
20909
+ const endpoint = await getCachedHttpEndpoint();
20715
20910
  const tonClient = new TonClient13({ endpoint });
20716
20911
  const factory = tonClient.open(
20717
20912
  Factory.createFromAddress(Address14.parse(DEDUST_FACTORY_MAINNET))
@@ -20795,7 +20990,6 @@ import { Type as Type97 } from "@sinclair/typebox";
20795
20990
  import { mnemonicToPrivateKey as mnemonicToPrivateKey10 } from "@ton/crypto";
20796
20991
  import { WalletContractV5R1 as WalletContractV5R110, TonClient as TonClient14, toNano as toNano23, fromNano as fromNano6 } from "@ton/ton";
20797
20992
  import { Address as Address15 } from "@ton/core";
20798
- import { getHttpEndpoint as getHttpEndpoint14 } from "@orbs-network/ton-access";
20799
20993
  import { Factory as Factory2, Asset as Asset2, PoolType as PoolType2, ReadinessStatus as ReadinessStatus2, JettonRoot, VaultJetton } from "@dedust/sdk";
20800
20994
  var dedustSwapTool = {
20801
20995
  name: "dedust_swap",
@@ -20859,7 +21053,7 @@ var dedustSwapExecutor = async (params, context) => {
20859
21053
  };
20860
21054
  }
20861
21055
  }
20862
- const endpoint = await getHttpEndpoint14({ network: "mainnet" });
21056
+ const endpoint = await getCachedHttpEndpoint();
20863
21057
  const tonClient = new TonClient14({ endpoint });
20864
21058
  const factory = tonClient.open(
20865
21059
  Factory2.createFromAddress(Address15.parse(DEDUST_FACTORY_MAINNET))
@@ -21089,7 +21283,7 @@ var dedustPoolsExecutor = async (params, context) => {
21089
21283
 
21090
21284
  // src/agent/tools/dedust/index.ts
21091
21285
  var tools19 = [
21092
- { tool: dedustSwapTool, executor: dedustSwapExecutor, scope: "dm-only" },
21286
+ { tool: dedustSwapTool, executor: dedustSwapExecutor },
21093
21287
  { tool: dedustQuoteTool, executor: dedustQuoteExecutor },
21094
21288
  { tool: dedustPoolsTool, executor: dedustPoolsExecutor }
21095
21289
  ];
@@ -21098,7 +21292,6 @@ var tools19 = [
21098
21292
  import { Type as Type99 } from "@sinclair/typebox";
21099
21293
  import { TonClient as TonClient15, toNano as toNano24, fromNano as fromNano7 } from "@ton/ton";
21100
21294
  import { Address as Address16 } from "@ton/core";
21101
- import { getHttpEndpoint as getHttpEndpoint15 } from "@orbs-network/ton-access";
21102
21295
  import { Factory as Factory3, Asset as Asset3, PoolType as PoolType3, ReadinessStatus as ReadinessStatus3 } from "@dedust/sdk";
21103
21296
  var dexQuoteTool = {
21104
21297
  name: "dex_quote",
@@ -21245,7 +21438,7 @@ async function getDedustQuote(fromAsset, toAsset, amount, slippage, tonClient) {
21245
21438
  var dexQuoteExecutor = async (params, context) => {
21246
21439
  try {
21247
21440
  const { from_asset, to_asset, amount, slippage = 0.01 } = params;
21248
- const endpoint = await getHttpEndpoint15({ network: "mainnet" });
21441
+ const endpoint = await getCachedHttpEndpoint();
21249
21442
  const tonClient = new TonClient15({ endpoint });
21250
21443
  const [stonfiQuote, dedustQuote] = await Promise.all([
21251
21444
  getStonfiQuote(from_asset, to_asset, amount, slippage),
@@ -21357,7 +21550,6 @@ import { Type as Type100 } from "@sinclair/typebox";
21357
21550
  import { mnemonicToPrivateKey as mnemonicToPrivateKey11 } from "@ton/crypto";
21358
21551
  import { WalletContractV5R1 as WalletContractV5R111, TonClient as TonClient16, toNano as toNano25, fromNano as fromNano8 } from "@ton/ton";
21359
21552
  import { Address as Address17, SendMode as SendMode9, internal as internal9 } from "@ton/core";
21360
- import { getHttpEndpoint as getHttpEndpoint16 } from "@orbs-network/ton-access";
21361
21553
  import { Factory as Factory4, Asset as Asset4, PoolType as PoolType4, ReadinessStatus as ReadinessStatus4, JettonRoot as JettonRoot2, VaultJetton as VaultJetton2 } from "@dedust/sdk";
21362
21554
  var dexSwapTool = {
21363
21555
  name: "dex_swap",
@@ -21579,7 +21771,7 @@ var dexSwapExecutor = async (params, context) => {
21579
21771
  if (!isTonOutput && !to_asset.match(/^[EUe][Qq][A-Za-z0-9_-]{46}$/)) {
21580
21772
  return { success: false, error: `Invalid to_asset address: ${to_asset}` };
21581
21773
  }
21582
- const endpoint = await getHttpEndpoint16({ network: "mainnet" });
21774
+ const endpoint = await getCachedHttpEndpoint();
21583
21775
  const tonClient = new TonClient16({ endpoint });
21584
21776
  let stonfiQuote = null;
21585
21777
  let dedustQuote = null;
@@ -21693,7 +21885,7 @@ var dexSwapExecutor = async (params, context) => {
21693
21885
 
21694
21886
  // src/agent/tools/dex/index.ts
21695
21887
  var tools20 = [
21696
- { tool: dexSwapTool, executor: dexSwapExecutor, scope: "dm-only" },
21888
+ { tool: dexSwapTool, executor: dexSwapExecutor },
21697
21889
  { tool: dexQuoteTool, executor: dexQuoteExecutor }
21698
21890
  ];
21699
21891
 
@@ -22312,7 +22504,6 @@ var workspaceWriteExecutor = async (params, _context) => {
22312
22504
  writeContent = content;
22313
22505
  }
22314
22506
  const contentSize = Buffer.byteLength(writeContent);
22315
- const MAX_WRITE_SIZE = 50 * 1024 * 1024;
22316
22507
  if (contentSize > MAX_WRITE_SIZE) {
22317
22508
  return {
22318
22509
  success: false,
@@ -22928,10 +23119,10 @@ async function sendPayout(playerAddress, amount, message) {
22928
23119
  const endpoint = await getCachedHttpEndpoint();
22929
23120
  const client = new TonClient17({ endpoint });
22930
23121
  const contract = client.open(wallet);
22931
- const seqno = await withBlockchainRetry(() => contract.getSeqno(), "getSeqno");
22932
- await withBlockchainRetry(
22933
- () => contract.sendTransfer({
22934
- seqno,
23122
+ const seqno = await withBlockchainRetry(async () => {
23123
+ const seq = await contract.getSeqno();
23124
+ await contract.sendTransfer({
23125
+ seqno: seq,
22935
23126
  secretKey: keyPair.secretKey,
22936
23127
  sendMode: SendMode10.PAY_GAS_SEPARATELY,
22937
23128
  messages: [
@@ -22942,9 +23133,9 @@ async function sendPayout(playerAddress, amount, message) {
22942
23133
  bounce: false
22943
23134
  })
22944
23135
  ]
22945
- }),
22946
- "sendTransfer"
22947
- );
23136
+ });
23137
+ return seq;
23138
+ }, "payout");
22948
23139
  const walletAddr = wallet.address.toString({ bounceable: false });
22949
23140
  const walletShort = walletAddr.slice(-8);
22950
23141
  const timestamp = Date.now();
@@ -23596,7 +23787,7 @@ var MarketScraperService = class {
23596
23787
  this.isScrapingInProgress = true;
23597
23788
  console.log("\u{1F504} Starting full market scrape...");
23598
23789
  try {
23599
- const { runScraper } = await import("./scraper-DSAYK6QJ.js");
23790
+ const { runScraper } = await import("./scraper-2O6Z3ZHT.js");
23600
23791
  const result = await runScraper({
23601
23792
  workers: 4,
23602
23793
  limit: 0
@@ -23940,6 +24131,85 @@ function loadModules(registry, config, db3) {
23940
24131
  return loaded;
23941
24132
  }
23942
24133
 
24134
+ // src/agent/tools/module-permissions.ts
24135
+ var PROTECTED_MODULES = /* @__PURE__ */ new Set(["telegram", "memory"]);
24136
+ var ModulePermissions = class {
24137
+ db;
24138
+ /** chatId → module → level */
24139
+ cache = /* @__PURE__ */ new Map();
24140
+ constructor(db3) {
24141
+ this.db = db3;
24142
+ this.ensureTable();
24143
+ this.loadAll();
24144
+ }
24145
+ ensureTable() {
24146
+ this.db.exec(`
24147
+ CREATE TABLE IF NOT EXISTS group_modules (
24148
+ chat_id TEXT NOT NULL,
24149
+ module TEXT NOT NULL,
24150
+ level TEXT NOT NULL CHECK(level IN ('open', 'admin', 'disabled')),
24151
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
24152
+ updated_by INTEGER,
24153
+ PRIMARY KEY (chat_id, module)
24154
+ )
24155
+ `);
24156
+ }
24157
+ loadAll() {
24158
+ const rows = this.db.prepare("SELECT chat_id, module, level FROM group_modules").all();
24159
+ for (const row of rows) {
24160
+ let chatMap = this.cache.get(row.chat_id);
24161
+ if (!chatMap) {
24162
+ chatMap = /* @__PURE__ */ new Map();
24163
+ this.cache.set(row.chat_id, chatMap);
24164
+ }
24165
+ chatMap.set(row.module, row.level);
24166
+ }
24167
+ }
24168
+ /** Get the effective level for a module in a chat. Default: "open". */
24169
+ getLevel(chatId, module) {
24170
+ return this.cache.get(chatId)?.get(module) ?? "open";
24171
+ }
24172
+ /** Set the level for a module in a chat. Throws if module is protected. */
24173
+ setLevel(chatId, module, level, userId) {
24174
+ if (PROTECTED_MODULES.has(module)) {
24175
+ throw new Error(`Module "${module}" est prot\xE9g\xE9`);
24176
+ }
24177
+ if (level === "open") {
24178
+ this.db.prepare("DELETE FROM group_modules WHERE chat_id = ? AND module = ?").run(chatId, module);
24179
+ this.cache.get(chatId)?.delete(module);
24180
+ } else {
24181
+ this.db.prepare(
24182
+ `INSERT OR REPLACE INTO group_modules (chat_id, module, level, updated_at, updated_by)
24183
+ VALUES (?, ?, ?, unixepoch(), ?)`
24184
+ ).run(chatId, module, level, userId ?? null);
24185
+ let chatMap = this.cache.get(chatId);
24186
+ if (!chatMap) {
24187
+ chatMap = /* @__PURE__ */ new Map();
24188
+ this.cache.set(chatId, chatMap);
24189
+ }
24190
+ chatMap.set(module, level);
24191
+ }
24192
+ }
24193
+ /** Reset a single module to default ("open"). */
24194
+ resetModule(chatId, module) {
24195
+ this.db.prepare("DELETE FROM group_modules WHERE chat_id = ? AND module = ?").run(chatId, module);
24196
+ this.cache.get(chatId)?.delete(module);
24197
+ }
24198
+ /** Reset all modules for a chat to default ("open"). */
24199
+ resetAll(chatId) {
24200
+ this.db.prepare("DELETE FROM group_modules WHERE chat_id = ?").run(chatId);
24201
+ this.cache.delete(chatId);
24202
+ }
24203
+ /** Get all non-default overrides for a chat. */
24204
+ getOverrides(chatId) {
24205
+ return this.cache.get(chatId) ?? /* @__PURE__ */ new Map();
24206
+ }
24207
+ /** Check if a module is protected (always open, cannot be changed). */
24208
+ isProtected(module) {
24209
+ return PROTECTED_MODULES.has(module);
24210
+ }
24211
+ };
24212
+
23943
24213
  // src/index.ts
23944
24214
  var TonnetApp = class {
23945
24215
  config;
@@ -23987,6 +24257,8 @@ var TonnetApp = class {
23987
24257
  });
23988
24258
  const db3 = getDatabase().getDb();
23989
24259
  this.modules = loadModules(this.toolRegistry, this.config, db3);
24260
+ const modulePermissions = new ModulePermissions(db3);
24261
+ this.toolRegistry.setPermissions(modulePermissions);
23990
24262
  this.toolCount = this.toolRegistry.count;
23991
24263
  this.messageHandler = new MessageHandler(
23992
24264
  this.bridge,
@@ -23999,7 +24271,13 @@ var TonnetApp = class {
23999
24271
  this.config
24000
24272
  // Pass full config for vision tool API key access
24001
24273
  );
24002
- this.adminHandler = new AdminHandler(this.bridge, this.config.telegram, this.agent);
24274
+ this.adminHandler = new AdminHandler(
24275
+ this.bridge,
24276
+ this.config.telegram,
24277
+ this.agent,
24278
+ modulePermissions,
24279
+ this.toolRegistry
24280
+ );
24003
24281
  }
24004
24282
  /**
24005
24283
  * Start the agent
@@ -24038,7 +24316,7 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
24038
24316
  `\u26A0\uFE0F Tool count (${this.toolCount}) exceeds ${providerMeta.displayName} limit (${providerMeta.toolLimit})`
24039
24317
  );
24040
24318
  }
24041
- const { migrateSessionsToDb } = await import("./migrate-7XOO67O5.js");
24319
+ const { migrateSessionsToDb } = await import("./migrate-6BQZVOBN.js");
24042
24320
  migrateSessionsToDb();
24043
24321
  const { cleanupOldTranscripts } = await import("./transcript-DF2Y6CFY.js");
24044
24322
  cleanupOldTranscripts(30);
@@ -24159,7 +24437,8 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
24159
24437
  const response = await this.adminHandler.handleCommand(
24160
24438
  adminCmd,
24161
24439
  message.chatId,
24162
- message.senderId
24440
+ message.senderId,
24441
+ message.isGroup
24163
24442
  );
24164
24443
  await this.bridge.sendMessage({
24165
24444
  chatId: message.chatId,
@@ -24187,8 +24466,8 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
24187
24466
  }
24188
24467
  const taskId = match[1];
24189
24468
  const { getTaskStore } = await import("./tasks-M3QDPTGY.js");
24190
- const { executeScheduledTask } = await import("./task-executor-MNI4VIZL.js");
24191
- const { getDatabase: getDatabase2 } = await import("./memory-OEOLPEXP.js");
24469
+ const { executeScheduledTask } = await import("./task-executor-4SVB72GR.js");
24470
+ const { getDatabase: getDatabase2 } = await import("./memory-PDEJIPK6.js");
24192
24471
  const db3 = getDatabase2().getDb();
24193
24472
  const taskStore = getTaskStore(db3);
24194
24473
  const task = taskStore.getTask(taskId);
@@ -24254,7 +24533,7 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
24254
24533
  taskStore.completeTask(taskId, response.content);
24255
24534
  console.log(`\u2705 Executed scheduled task ${taskId}: ${task.description}`);
24256
24535
  if (!this.dependencyResolver) {
24257
- const { TaskDependencyResolver } = await import("./task-dependency-resolver-CWG6DTU4.js");
24536
+ const { TaskDependencyResolver } = await import("./task-dependency-resolver-WNYOTWWM.js");
24258
24537
  this.dependencyResolver = new TaskDependencyResolver(taskStore, this.bridge);
24259
24538
  }
24260
24539
  await this.dependencyResolver.onTaskComplete(taskId);
@@ -24262,8 +24541,8 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
24262
24541
  console.error("Error handling scheduled task:", error);
24263
24542
  try {
24264
24543
  const { getTaskStore } = await import("./tasks-M3QDPTGY.js");
24265
- const { TaskDependencyResolver } = await import("./task-dependency-resolver-CWG6DTU4.js");
24266
- const { getDatabase: getDatabase2 } = await import("./memory-OEOLPEXP.js");
24544
+ const { TaskDependencyResolver } = await import("./task-dependency-resolver-WNYOTWWM.js");
24545
+ const { getDatabase: getDatabase2 } = await import("./memory-PDEJIPK6.js");
24267
24546
  const db3 = getDatabase2().getDb();
24268
24547
  const taskStore = getTaskStore(db3);
24269
24548
  const match = message.text.match(/^\[TASK:([^\]]+)\]/);
@@ -24303,14 +24582,19 @@ async function main(configPath) {
24303
24582
  console.error("\u{1F4A5} Uncaught exception:", error);
24304
24583
  process.exit(1);
24305
24584
  });
24306
- process.on("SIGINT", async () => {
24307
- await app.stop();
24308
- process.exit(0);
24309
- });
24310
- process.on("SIGTERM", async () => {
24585
+ const gracefulShutdown = async () => {
24586
+ const { SHUTDOWN_TIMEOUT_MS } = await import("./timeouts-ZAK6NELA.js");
24587
+ const forceExit = setTimeout(() => {
24588
+ console.error("\u26A0\uFE0F Shutdown timed out, forcing exit");
24589
+ process.exit(1);
24590
+ }, SHUTDOWN_TIMEOUT_MS);
24591
+ forceExit.unref();
24311
24592
  await app.stop();
24593
+ clearTimeout(forceExit);
24312
24594
  process.exit(0);
24313
- });
24595
+ };
24596
+ process.on("SIGINT", gracefulShutdown);
24597
+ process.on("SIGTERM", gracefulShutdown);
24314
24598
  await app.start();
24315
24599
  }
24316
24600
  if (import.meta.url === `file://${process.argv[1]}`) {
@@ -15,6 +15,7 @@ var SCRAPER_PRE_SCROLL_MS = 4e3;
15
15
  var SCRAPER_COLLECTION_SCROLL_MS = 200;
16
16
  var SCRAPER_SCROLL_INCREMENT_PX = 250;
17
17
  var SCRAPER_SCROLL_PADDING_PX = 500;
18
+ var SCRAPER_WINDOW_SCROLL_PX = 2e3;
18
19
  var SCRAPER_MAX_SCROLL_ITERATIONS = 15;
19
20
  var SCRAPER_COLLECTION_NAV_MS = 6e4;
20
21
  var RETRY_DEFAULT_MAX_ATTEMPTS = 3;
@@ -25,6 +26,8 @@ var RETRY_BLOCKCHAIN_BASE_DELAY_MS = 2e3;
25
26
  var RETRY_BLOCKCHAIN_MAX_DELAY_MS = 15e3;
26
27
  var RETRY_BLOCKCHAIN_TIMEOUT_MS = 3e4;
27
28
  var GRAMJS_RETRY_DELAY_MS = 1e3;
29
+ var TOOL_EXECUTION_TIMEOUT_MS = 9e4;
30
+ var SHUTDOWN_TIMEOUT_MS = 1e4;
28
31
 
29
32
  export {
30
33
  TTS_TIMEOUT_MS,
@@ -43,6 +46,7 @@ export {
43
46
  SCRAPER_COLLECTION_SCROLL_MS,
44
47
  SCRAPER_SCROLL_INCREMENT_PX,
45
48
  SCRAPER_SCROLL_PADDING_PX,
49
+ SCRAPER_WINDOW_SCROLL_PX,
46
50
  SCRAPER_MAX_SCROLL_ITERATIONS,
47
51
  SCRAPER_COLLECTION_NAV_MS,
48
52
  RETRY_DEFAULT_MAX_ATTEMPTS,
@@ -52,5 +56,7 @@ export {
52
56
  RETRY_BLOCKCHAIN_BASE_DELAY_MS,
53
57
  RETRY_BLOCKCHAIN_MAX_DELAY_MS,
54
58
  RETRY_BLOCKCHAIN_TIMEOUT_MS,
55
- GRAMJS_RETRY_DELAY_MS
59
+ GRAMJS_RETRY_DELAY_MS,
60
+ TOOL_EXECUTION_TIMEOUT_MS,
61
+ SHUTDOWN_TIMEOUT_MS
56
62
  };
package/dist/cli/index.js CHANGED
@@ -17,25 +17,25 @@ import {
17
17
  saveWallet,
18
18
  validateApiKeyFormat,
19
19
  walletExists
20
- } from "../chunk-74MTM3AB.js";
20
+ } from "../chunk-KS7B2CVM.js";
21
+ import "../chunk-U7FQYCBQ.js";
21
22
  import "../chunk-DUW5VBAZ.js";
22
23
  import "../chunk-OQGNS2FV.js";
23
- import "../chunk-TBIMVWQZ.js";
24
+ import "../chunk-DR6WM6B5.js";
24
25
  import {
25
26
  fetchWithTimeout
26
- } from "../chunk-WMIN6AGX.js";
27
+ } from "../chunk-DAMFGHXV.js";
27
28
  import {
28
29
  TELEGRAM_MAX_MESSAGE_LENGTH
29
- } from "../chunk-QMN6ZOA5.js";
30
- import {
31
- ONBOARDING_PROMPT_TIMEOUT_MS
32
- } from "../chunk-LJXYESJJ.js";
30
+ } from "../chunk-2X4PCE7V.js";
33
31
  import {
34
32
  TELETON_ROOT
35
33
  } from "../chunk-EYWNOHMJ.js";
34
+ import {
35
+ ONBOARDING_PROMPT_TIMEOUT_MS
36
+ } from "../chunk-LCMHAUNK.js";
36
37
  import "../chunk-E2NXSWOS.js";
37
38
  import "../chunk-B2PRMXOH.js";
38
- import "../chunk-U7FQYCBQ.js";
39
39
  import "../chunk-QGM4M3NI.js";
40
40
 
41
41
  // src/cli/index.ts
@@ -523,11 +523,7 @@ Get it at: ${providerMeta.consoleUrl}`,
523
523
  sellMinFloorPercent = parseInt(sellInput, 10);
524
524
  }
525
525
  }
526
- const setupBot = dealsEnabled ? await prompter.confirm({
527
- message: "Set up a Telegram bot for deal confirmations? (inline buttons)",
528
- initialValue: true
529
- }) : false;
530
- if (setupBot) {
526
+ if (dealsEnabled) {
531
527
  prompter.note(
532
528
  "Create a bot with @BotFather on Telegram:\n1. Send /newbot and follow the instructions\n2. Copy the bot token\n3. Enable inline mode: /setinline on the bot",
533
529
  "Deals Bot"
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  TonnetApp,
3
3
  main
4
- } from "./chunk-74MTM3AB.js";
4
+ } from "./chunk-KS7B2CVM.js";
5
+ import "./chunk-U7FQYCBQ.js";
5
6
  import "./chunk-DUW5VBAZ.js";
6
7
  import "./chunk-OQGNS2FV.js";
7
- import "./chunk-TBIMVWQZ.js";
8
- import "./chunk-WMIN6AGX.js";
9
- import "./chunk-QMN6ZOA5.js";
10
- import "./chunk-LJXYESJJ.js";
8
+ import "./chunk-DR6WM6B5.js";
9
+ import "./chunk-DAMFGHXV.js";
10
+ import "./chunk-2X4PCE7V.js";
11
11
  import "./chunk-EYWNOHMJ.js";
12
+ import "./chunk-LCMHAUNK.js";
12
13
  import "./chunk-E2NXSWOS.js";
13
14
  import "./chunk-B2PRMXOH.js";
14
- import "./chunk-U7FQYCBQ.js";
15
15
  import "./chunk-QGM4M3NI.js";
16
16
  export {
17
17
  TonnetApp,
@@ -24,11 +24,11 @@ import {
24
24
  runMigrations,
25
25
  serializeEmbedding,
26
26
  setSchemaVersion
27
- } from "./chunk-TBIMVWQZ.js";
28
- import "./chunk-WMIN6AGX.js";
29
- import "./chunk-QMN6ZOA5.js";
30
- import "./chunk-LJXYESJJ.js";
27
+ } from "./chunk-DR6WM6B5.js";
28
+ import "./chunk-DAMFGHXV.js";
29
+ import "./chunk-2X4PCE7V.js";
31
30
  import "./chunk-EYWNOHMJ.js";
31
+ import "./chunk-LCMHAUNK.js";
32
32
  import {
33
33
  TaskStore,
34
34
  getTaskStore
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  getDatabase
3
- } from "./chunk-TBIMVWQZ.js";
4
- import "./chunk-WMIN6AGX.js";
5
- import "./chunk-QMN6ZOA5.js";
6
- import "./chunk-LJXYESJJ.js";
3
+ } from "./chunk-DR6WM6B5.js";
4
+ import "./chunk-DAMFGHXV.js";
5
+ import "./chunk-2X4PCE7V.js";
7
6
  import {
8
7
  TELETON_ROOT
9
8
  } from "./chunk-EYWNOHMJ.js";
9
+ import "./chunk-LCMHAUNK.js";
10
10
  import "./chunk-E2NXSWOS.js";
11
11
  import "./chunk-QGM4M3NI.js";
12
12
 
@@ -8,10 +8,11 @@ import {
8
8
  } from "./chunk-DUW5VBAZ.js";
9
9
  import {
10
10
  MARKETAPP_BASE_URL
11
- } from "./chunk-WMIN6AGX.js";
11
+ } from "./chunk-DAMFGHXV.js";
12
12
  import {
13
13
  SCRAPER_PARALLEL_WORKERS
14
- } from "./chunk-QMN6ZOA5.js";
14
+ } from "./chunk-2X4PCE7V.js";
15
+ import "./chunk-EYWNOHMJ.js";
15
16
  import {
16
17
  BROWSER_NAVIGATION_TIMEOUT_MS,
17
18
  SCRAPER_COLLECTION_NAV_MS,
@@ -26,8 +27,7 @@ import {
26
27
  SCRAPER_SCROLL_INCREMENT_PX,
27
28
  SCRAPER_SCROLL_PADDING_PX,
28
29
  SCRAPER_SCROLL_STEP_MS
29
- } from "./chunk-LJXYESJJ.js";
30
- import "./chunk-EYWNOHMJ.js";
30
+ } from "./chunk-LCMHAUNK.js";
31
31
  import "./chunk-QGM4M3NI.js";
32
32
 
33
33
  // src/market/scraper.ts
@@ -1,10 +1,12 @@
1
+ import {
2
+ MAX_DEPENDENTS_PER_TASK
3
+ } from "./chunk-2X4PCE7V.js";
1
4
  import {
2
5
  BATCH_TRIGGER_DELAY_MS
3
- } from "./chunk-LJXYESJJ.js";
6
+ } from "./chunk-LCMHAUNK.js";
4
7
  import "./chunk-QGM4M3NI.js";
5
8
 
6
9
  // src/telegram/task-dependency-resolver.ts
7
- var MAX_DEPENDENTS_PER_TASK = 10;
8
10
  var TaskDependencyResolver = class {
9
11
  constructor(taskStore, bridge) {
10
12
  this.taskStore = taskStore;
@@ -3,7 +3,7 @@ import {
3
3
  MAX_TOTAL_PROMPT_CHARS,
4
4
  SECONDS_PER_DAY,
5
5
  SECONDS_PER_HOUR
6
- } from "./chunk-QMN6ZOA5.js";
6
+ } from "./chunk-2X4PCE7V.js";
7
7
  import "./chunk-QGM4M3NI.js";
8
8
 
9
9
  // src/telegram/task-executor.ts
@@ -0,0 +1,63 @@
1
+ import {
2
+ BATCH_TRIGGER_DELAY_MS,
3
+ BROWSER_NAVIGATION_TIMEOUT_MS,
4
+ DEFAULT_FETCH_TIMEOUT_MS,
5
+ GRAMJS_RETRY_DELAY_MS,
6
+ MESSAGE_HANDLER_LOCK_TIMEOUT_MS,
7
+ ONBOARDING_PROMPT_TIMEOUT_MS,
8
+ RETRY_BLOCKCHAIN_BASE_DELAY_MS,
9
+ RETRY_BLOCKCHAIN_MAX_DELAY_MS,
10
+ RETRY_BLOCKCHAIN_TIMEOUT_MS,
11
+ RETRY_DEFAULT_BASE_DELAY_MS,
12
+ RETRY_DEFAULT_MAX_ATTEMPTS,
13
+ RETRY_DEFAULT_MAX_DELAY_MS,
14
+ RETRY_DEFAULT_TIMEOUT_MS,
15
+ SCRAPER_COLLECTION_NAV_MS,
16
+ SCRAPER_COLLECTION_SCROLL_MS,
17
+ SCRAPER_FILTER_CLICK_MS,
18
+ SCRAPER_FILTER_OPEN_MS,
19
+ SCRAPER_MAX_SCROLL_ITERATIONS,
20
+ SCRAPER_MODEL_CLICK_MS,
21
+ SCRAPER_MODEL_OPEN_MS,
22
+ SCRAPER_PAGE_LOAD_MS,
23
+ SCRAPER_PRE_SCROLL_MS,
24
+ SCRAPER_SCROLL_INCREMENT_PX,
25
+ SCRAPER_SCROLL_PADDING_PX,
26
+ SCRAPER_SCROLL_STEP_MS,
27
+ SCRAPER_WINDOW_SCROLL_PX,
28
+ SHUTDOWN_TIMEOUT_MS,
29
+ TOOL_EXECUTION_TIMEOUT_MS,
30
+ TTS_TIMEOUT_MS
31
+ } from "./chunk-LCMHAUNK.js";
32
+ import "./chunk-QGM4M3NI.js";
33
+ export {
34
+ BATCH_TRIGGER_DELAY_MS,
35
+ BROWSER_NAVIGATION_TIMEOUT_MS,
36
+ DEFAULT_FETCH_TIMEOUT_MS,
37
+ GRAMJS_RETRY_DELAY_MS,
38
+ MESSAGE_HANDLER_LOCK_TIMEOUT_MS,
39
+ ONBOARDING_PROMPT_TIMEOUT_MS,
40
+ RETRY_BLOCKCHAIN_BASE_DELAY_MS,
41
+ RETRY_BLOCKCHAIN_MAX_DELAY_MS,
42
+ RETRY_BLOCKCHAIN_TIMEOUT_MS,
43
+ RETRY_DEFAULT_BASE_DELAY_MS,
44
+ RETRY_DEFAULT_MAX_ATTEMPTS,
45
+ RETRY_DEFAULT_MAX_DELAY_MS,
46
+ RETRY_DEFAULT_TIMEOUT_MS,
47
+ SCRAPER_COLLECTION_NAV_MS,
48
+ SCRAPER_COLLECTION_SCROLL_MS,
49
+ SCRAPER_FILTER_CLICK_MS,
50
+ SCRAPER_FILTER_OPEN_MS,
51
+ SCRAPER_MAX_SCROLL_ITERATIONS,
52
+ SCRAPER_MODEL_CLICK_MS,
53
+ SCRAPER_MODEL_OPEN_MS,
54
+ SCRAPER_PAGE_LOAD_MS,
55
+ SCRAPER_PRE_SCROLL_MS,
56
+ SCRAPER_SCROLL_INCREMENT_PX,
57
+ SCRAPER_SCROLL_PADDING_PX,
58
+ SCRAPER_SCROLL_STEP_MS,
59
+ SCRAPER_WINDOW_SCROLL_PX,
60
+ SHUTDOWN_TIMEOUT_MS,
61
+ TOOL_EXECUTION_TIMEOUT_MS,
62
+ TTS_TIMEOUT_MS
63
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teleton",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "Personal AI Agent for Telegram",
5
5
  "author": "ZKProof (https://t.me/zkproof)",
6
6
  "license": "MIT",
@@ -50,14 +50,17 @@
50
50
  "dependencies": {
51
51
  "@clack/prompts": "^0.7.0",
52
52
  "@dedust/sdk": "^0.8.7",
53
+ "@evaafi/sdk": "^0.9.5",
53
54
  "@mariozechner/pi-ai": "^0.50.9",
54
55
  "@orbs-network/ton-access": "^2.3.3",
55
56
  "@sinclair/typebox": "^0.34.48",
57
+ "@storm-trade/sdk": "^1.0.0-rc.4",
56
58
  "@ton/core": "^0.63.0",
57
59
  "@ton/crypto": "^3.3.0",
58
60
  "@ton/ton": "^16.1.0",
59
61
  "better-sqlite3": "^11.7.0",
60
62
  "commander": "^12.0.0",
63
+ "crypto-js": "^4.2.0",
61
64
  "grammy": "^1.39.3",
62
65
  "js-tiktoken": "^1.0.21",
63
66
  "playwright": "^1.58.1",