teleton 0.7.2 → 0.7.4

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 (31) hide show
  1. package/README.md +31 -12
  2. package/dist/{chunk-ND2X5FWB.js → chunk-5PLZ3KSO.js} +16 -3
  3. package/dist/{chunk-NERLQY2H.js → chunk-BGC2IUM5.js} +73 -15
  4. package/dist/{chunk-FNV5FF35.js → chunk-EK7M5K26.js} +29 -13
  5. package/dist/chunk-JQDLW7IE.js +107 -0
  6. package/dist/{chunk-VSMUAU5X.js → chunk-LAQOUFOJ.js} +2419 -2132
  7. package/dist/chunk-QOQWUUA4.js +158 -0
  8. package/dist/{chunk-LRCPA7SC.js → chunk-RMLQS3X6.js} +15 -3
  9. package/dist/{chunk-UDD7FYOU.js → chunk-WIKM24GZ.js} +1 -18
  10. package/dist/{chunk-RBU6JXD3.js → chunk-XDYDA2KV.js} +1 -1
  11. package/dist/{chunk-JHKWHGBM.js → chunk-YFG2QHLA.js} +380 -47
  12. package/dist/cli/index.js +216 -272
  13. package/dist/{client-3VWE7NC4.js → client-RTNALK7W.js} +3 -2
  14. package/dist/{get-my-gifts-RI7FAXAL.js → get-my-gifts-TPVUGUWT.js} +1 -1
  15. package/dist/index.js +9 -10
  16. package/dist/{memory-5SS3Q5EA.js → memory-JQZ6MTRU.js} +2 -2
  17. package/dist/{migrate-M7SJMDOL.js → migrate-GS5ACQDA.js} +2 -2
  18. package/dist/{server-NPSODUMA.js → server-TCJOBV3D.js} +292 -11
  19. package/dist/{setup-server-C7ZTPHD5.js → setup-server-YHYJLAMA.js} +77 -112
  20. package/dist/{tool-index-MIVK3D7H.js → tool-index-6HBRVXVG.js} +1 -1
  21. package/dist/web/assets/index-B6M9knfJ.css +1 -0
  22. package/dist/web/assets/index-DAGeQfVZ.js +72 -0
  23. package/dist/web/assets/{index.es-D81xLR29.js → index.es-CqZHj0tz.js} +1 -1
  24. package/dist/web/index.html +2 -2
  25. package/package.json +2 -2
  26. package/dist/chunk-EHEV7FJ7.js +0 -157
  27. package/dist/chunk-QUAPFI2N.js +0 -42
  28. package/dist/endpoint-FLYNEZ2F.js +0 -7
  29. package/dist/format-transactions-FD74HI5N.js +0 -9
  30. package/dist/web/assets/index-BqwoDycr.js +0 -72
  31. package/dist/web/assets/index-CRDIf07k.css +0 -1
@@ -1,14 +1,13 @@
1
1
  import {
2
2
  ConfigSchema,
3
+ getCachedTonClient,
3
4
  getKeyPair,
4
5
  getTonPrice,
5
6
  getWalletAddress,
6
7
  getWalletBalance,
8
+ invalidateTonClientCache,
7
9
  loadWallet
8
- } from "./chunk-NERLQY2H.js";
9
- import {
10
- getCachedHttpEndpoint
11
- } from "./chunk-QUAPFI2N.js";
10
+ } from "./chunk-BGC2IUM5.js";
12
11
  import {
13
12
  require_BigInteger
14
13
  } from "./chunk-TSKJCWQQ.js";
@@ -17,7 +16,7 @@ import {
17
16
  } from "./chunk-XBE4JB7C.js";
18
17
  import {
19
18
  getProviderMetadata
20
- } from "./chunk-LRCPA7SC.js";
19
+ } from "./chunk-RMLQS3X6.js";
21
20
  import {
22
21
  createDbWrapper,
23
22
  migrateFromMainDb,
@@ -92,13 +91,12 @@ Run 'teleton setup' to create one.`);
92
91
  }
93
92
  const config = result.data;
94
93
  const provider = config.agent.provider;
95
- if (provider !== "anthropic" && !raw.agent?.model) {
94
+ if (provider !== "anthropic" && provider !== "claude-code" && !raw.agent?.model) {
96
95
  const meta = getProviderMetadata(provider);
97
96
  config.agent.model = meta.defaultModel;
98
97
  }
99
98
  config.telegram.session_path = expandPath(config.telegram.session_path);
100
99
  config.storage.sessions_file = expandPath(config.storage.sessions_file);
101
- config.storage.pairing_file = expandPath(config.storage.pairing_file);
102
100
  config.storage.memory_file = expandPath(config.storage.memory_file);
103
101
  if (process.env.TELETON_API_KEY) {
104
102
  config.agent.api_key = process.env.TELETON_API_KEY;
@@ -657,7 +655,7 @@ var PluginSDKError = class extends Error {
657
655
  var SDK_VERSION = "1.0.0";
658
656
 
659
657
  // src/ton/transfer.ts
660
- import { WalletContractV5R1, TonClient, toNano, internal } from "@ton/ton";
658
+ import { WalletContractV5R1, toNano, internal } from "@ton/ton";
661
659
  import { Address, SendMode } from "@ton/core";
662
660
 
663
661
  // src/ton/tx-lock.ts
@@ -699,8 +697,7 @@ async function sendTon(params) {
699
697
  workchain: 0,
700
698
  publicKey: keyPair.publicKey
701
699
  });
702
- const endpoint = await getCachedHttpEndpoint();
703
- const client = new TonClient({ endpoint });
700
+ const client = await getCachedTonClient();
704
701
  const contract = client.open(wallet);
705
702
  const seqno = await contract.getSeqno();
706
703
  await contract.sendTransfer({
@@ -720,8 +717,11 @@ async function sendTon(params) {
720
717
  log4.info(`Sent ${amount} TON to ${toAddress.slice(0, 8)}... - seqno: ${seqno}`);
721
718
  return pseudoHash;
722
719
  } catch (error) {
720
+ if (error?.status >= 500 || error?.response?.status >= 500) {
721
+ invalidateTonClientCache();
722
+ }
723
723
  log4.error({ err: error }, "Error sending TON");
724
- return null;
724
+ throw error;
725
725
  }
726
726
  });
727
727
  }
@@ -775,11 +775,181 @@ async function withBlockchainRetry(fn, operation = "blockchain operation") {
775
775
  }
776
776
 
777
777
  // src/sdk/ton.ts
778
- import { toNano as tonToNano, fromNano as tonFromNano } from "@ton/ton";
779
- import { Address as TonAddress } from "@ton/core";
778
+ import {
779
+ toNano as tonToNano,
780
+ fromNano as tonFromNano,
781
+ WalletContractV5R1 as WalletContractV5R12,
782
+ internal as internal2
783
+ } from "@ton/ton";
784
+ import { Address as TonAddress, beginCell, SendMode as SendMode2 } from "@ton/core";
785
+
786
+ // src/ton/format-transactions.ts
787
+ import { fromNano } from "@ton/ton";
788
+ var OP_CODES = {
789
+ COMMENT: 0,
790
+ JETTON_TRANSFER: 260734629,
791
+ JETTON_TRANSFER_NOTIFICATION: 1935855772,
792
+ JETTON_INTERNAL_TRANSFER: 395134233,
793
+ JETTON_BURN: 1499400124,
794
+ NFT_TRANSFER: 1607220500,
795
+ NFT_OWNERSHIP_ASSIGNED: 85167505,
796
+ EXCESSES: 3576854235,
797
+ BOUNCE: 4294967295
798
+ };
799
+ function parseMessageBody(body) {
800
+ if (!body) return null;
801
+ try {
802
+ const slice = body.beginParse();
803
+ if (slice.remainingBits < 32) return null;
804
+ const op = slice.loadUint(32);
805
+ if (op === OP_CODES.COMMENT && slice.remainingBits > 0) {
806
+ return { op, comment: slice.loadStringTail() };
807
+ }
808
+ if (op === OP_CODES.JETTON_TRANSFER_NOTIFICATION) {
809
+ const _queryId = slice.loadUint(64);
810
+ const amount = slice.loadCoins();
811
+ const _sender = slice.loadAddress();
812
+ return { op, jettonAmount: amount.toString() };
813
+ }
814
+ if (op === OP_CODES.JETTON_TRANSFER) {
815
+ const _queryId = slice.loadUint(64);
816
+ const amount = slice.loadCoins();
817
+ const _destination = slice.loadAddress();
818
+ return { op, jettonAmount: amount.toString() };
819
+ }
820
+ if (op === OP_CODES.NFT_OWNERSHIP_ASSIGNED) {
821
+ const _queryId = slice.loadUint(64);
822
+ const _prevOwner = slice.loadAddress();
823
+ return { op };
824
+ }
825
+ if (op === OP_CODES.NFT_TRANSFER) {
826
+ const _queryId = slice.loadUint(64);
827
+ const newOwner = slice.loadAddress();
828
+ return { op, nftAddress: newOwner?.toString() };
829
+ }
830
+ return { op };
831
+ } catch {
832
+ return null;
833
+ }
834
+ }
835
+ function formatTransactions(transactions) {
836
+ return transactions.map((tx) => {
837
+ const inMsg = tx.inMessage;
838
+ const outMsgArray = [...tx.outMessages.values()];
839
+ const hash = tx.hash().toString("hex");
840
+ const explorer = `https://tonviewer.com/transaction/${hash}`;
841
+ const txTimeMs = tx.now * 1e3;
842
+ const date = new Date(txTimeMs).toISOString();
843
+ const secondsAgo = Math.max(0, Math.floor((Date.now() - txTimeMs) / 1e3));
844
+ if (inMsg?.info.type === "internal") {
845
+ const tonAmount = fromNano(inMsg.info.value.coins);
846
+ const from = inMsg.info.src?.toString() || "unknown";
847
+ const parsed = parseMessageBody(inMsg.body);
848
+ if (parsed?.op === OP_CODES.EXCESSES) {
849
+ return {
850
+ type: "gas_refund",
851
+ hash,
852
+ amount: `${tonAmount} TON`,
853
+ from,
854
+ date,
855
+ secondsAgo,
856
+ explorer
857
+ };
858
+ }
859
+ if (parsed?.op === OP_CODES.JETTON_TRANSFER_NOTIFICATION) {
860
+ return {
861
+ type: "jetton_received",
862
+ hash,
863
+ jettonAmount: parsed.jettonAmount,
864
+ jettonWallet: from,
865
+ date,
866
+ secondsAgo,
867
+ explorer
868
+ };
869
+ }
870
+ if (parsed?.op === OP_CODES.NFT_OWNERSHIP_ASSIGNED) {
871
+ return { type: "nft_received", hash, nftAddress: from, date, secondsAgo, explorer };
872
+ }
873
+ if (inMsg.info.bounced || parsed?.op === OP_CODES.BOUNCE) {
874
+ return {
875
+ type: "bounce",
876
+ hash,
877
+ amount: `${tonAmount} TON`,
878
+ from,
879
+ date,
880
+ secondsAgo,
881
+ explorer
882
+ };
883
+ }
884
+ return {
885
+ type: "ton_received",
886
+ hash,
887
+ amount: `${tonAmount} TON`,
888
+ from,
889
+ comment: parsed?.comment || null,
890
+ date,
891
+ secondsAgo,
892
+ explorer
893
+ };
894
+ }
895
+ if (outMsgArray.length > 0) {
896
+ const results = [];
897
+ for (const outMsg of outMsgArray) {
898
+ if (outMsg.info.type !== "internal") continue;
899
+ const info = outMsg.info;
900
+ const to = info.dest?.toString() || "unknown";
901
+ const tonAmount = fromNano(info.value.coins);
902
+ const parsed = parseMessageBody(outMsg.body);
903
+ if (parsed?.op === OP_CODES.JETTON_TRANSFER) {
904
+ results.push({
905
+ type: "jetton_sent",
906
+ hash,
907
+ jettonAmount: parsed.jettonAmount,
908
+ jettonWallet: to,
909
+ date,
910
+ secondsAgo,
911
+ explorer
912
+ });
913
+ continue;
914
+ }
915
+ if (parsed?.op === OP_CODES.NFT_TRANSFER) {
916
+ results.push({ type: "nft_sent", hash, nftAddress: to, date, secondsAgo, explorer });
917
+ continue;
918
+ }
919
+ results.push({
920
+ type: "ton_sent",
921
+ hash,
922
+ amount: `${tonAmount} TON`,
923
+ to,
924
+ comment: parsed?.comment || null,
925
+ date,
926
+ secondsAgo,
927
+ explorer
928
+ });
929
+ }
930
+ if (results.length === 1) return results[0];
931
+ if (results.length > 1) {
932
+ return { type: "multi_send", hash, transfers: results, date, secondsAgo, explorer };
933
+ }
934
+ }
935
+ return { type: "contract_call", hash, date, secondsAgo, explorer };
936
+ });
937
+ }
938
+
939
+ // src/sdk/ton.ts
780
940
  var DEFAULT_MAX_AGE_MINUTES = 10;
781
941
  var DEFAULT_TX_RETENTION_DAYS = 30;
782
942
  var CLEANUP_PROBABILITY = 0.1;
943
+ function findJettonBalance(balances, jettonAddress) {
944
+ return balances.find((b) => {
945
+ if (b.jetton.address.toLowerCase() === jettonAddress.toLowerCase()) return true;
946
+ try {
947
+ return TonAddress.parse(b.jetton.address).toString() === TonAddress.parse(jettonAddress).toString();
948
+ } catch {
949
+ return false;
950
+ }
951
+ });
952
+ }
783
953
  function cleanupOldTransactions(db, retentionDays, log7) {
784
954
  if (Math.random() > CLEANUP_PROBABILITY) return;
785
955
  try {
@@ -829,8 +999,7 @@ function createTonSDK(log7, db) {
829
999
  throw new PluginSDKError("Amount must be a positive number", "OPERATION_FAILED");
830
1000
  }
831
1001
  try {
832
- const { Address: Address2 } = await import("@ton/core");
833
- Address2.parse(to);
1002
+ TonAddress.parse(to);
834
1003
  } catch {
835
1004
  throw new PluginSDKError("Invalid TON address format", "INVALID_ADDRESS");
836
1005
  }
@@ -858,13 +1027,8 @@ function createTonSDK(log7, db) {
858
1027
  },
859
1028
  async getTransactions(address, limit) {
860
1029
  try {
861
- const { TonClient: TonClient2 } = await import("@ton/ton");
862
- const { Address: Address2 } = await import("@ton/core");
863
- const { getCachedHttpEndpoint: getCachedHttpEndpoint2 } = await import("./endpoint-FLYNEZ2F.js");
864
- const { formatTransactions } = await import("./format-transactions-FD74HI5N.js");
865
- const addressObj = Address2.parse(address);
866
- const endpoint = await getCachedHttpEndpoint2();
867
- const client = new TonClient2({ endpoint });
1030
+ const addressObj = TonAddress.parse(address);
1031
+ const client = await getCachedTonClient();
868
1032
  const transactions = await withBlockchainRetry(
869
1033
  () => client.getTransactions(addressObj, {
870
1034
  limit: Math.min(limit ?? 10, 50)
@@ -935,7 +1099,7 @@ function createTonSDK(log7, db) {
935
1099
  try {
936
1100
  const addr = ownerAddress ?? getWalletAddress();
937
1101
  if (!addr) return [];
938
- const response = await tonapiFetch(`/accounts/${addr}/jettons`);
1102
+ const response = await tonapiFetch(`/accounts/${encodeURIComponent(addr)}/jettons`);
939
1103
  if (!response.ok) {
940
1104
  log7.error(`ton.getJettonBalances() TonAPI error: ${response.status}`);
941
1105
  return [];
@@ -971,7 +1135,7 @@ function createTonSDK(log7, db) {
971
1135
  },
972
1136
  async getJettonInfo(jettonAddress) {
973
1137
  try {
974
- const response = await tonapiFetch(`/jettons/${jettonAddress}`);
1138
+ const response = await tonapiFetch(`/jettons/${encodeURIComponent(jettonAddress)}`);
975
1139
  if (response.status === 404) return null;
976
1140
  if (!response.ok) {
977
1141
  log7.error(`ton.getJettonInfo() TonAPI error: ${response.status}`);
@@ -997,9 +1161,6 @@ function createTonSDK(log7, db) {
997
1161
  }
998
1162
  },
999
1163
  async sendJetton(jettonAddress, to, amount, opts) {
1000
- const { Address: Address2, beginCell, SendMode: SendMode2 } = await import("@ton/core");
1001
- const { WalletContractV5R1: WalletContractV5R12, TonClient: TonClient2, toNano: toNano2, internal: internal2 } = await import("@ton/ton");
1002
- const { getCachedHttpEndpoint: getCachedHttpEndpoint2 } = await import("./endpoint-FLYNEZ2F.js");
1003
1164
  const walletData = loadWallet();
1004
1165
  if (!walletData) {
1005
1166
  throw new PluginSDKError("Wallet not initialized", "WALLET_NOT_INITIALIZED");
@@ -1008,12 +1169,14 @@ function createTonSDK(log7, db) {
1008
1169
  throw new PluginSDKError("Amount must be a positive number", "OPERATION_FAILED");
1009
1170
  }
1010
1171
  try {
1011
- Address2.parse(to);
1172
+ TonAddress.parse(to);
1012
1173
  } catch {
1013
1174
  throw new PluginSDKError("Invalid recipient address", "INVALID_ADDRESS");
1014
1175
  }
1015
1176
  try {
1016
- const jettonsResponse = await tonapiFetch(`/accounts/${walletData.address}/jettons`);
1177
+ const jettonsResponse = await tonapiFetch(
1178
+ `/accounts/${encodeURIComponent(walletData.address)}/jettons`
1179
+ );
1017
1180
  if (!jettonsResponse.ok) {
1018
1181
  throw new PluginSDKError(
1019
1182
  `Failed to fetch jetton balances: ${jettonsResponse.status}`,
@@ -1021,9 +1184,7 @@ function createTonSDK(log7, db) {
1021
1184
  );
1022
1185
  }
1023
1186
  const jettonsData = await jettonsResponse.json();
1024
- const jettonBalance = jettonsData.balances?.find(
1025
- (b) => b.jetton.address.toLowerCase() === jettonAddress.toLowerCase() || Address2.parse(b.jetton.address).toString() === Address2.parse(jettonAddress).toString()
1026
- );
1187
+ const jettonBalance = findJettonBalance(jettonsData.balances ?? [], jettonAddress);
1027
1188
  if (!jettonBalance) {
1028
1189
  throw new PluginSDKError(
1029
1190
  `You don't own any of this jetton: ${jettonAddress}`,
@@ -1048,7 +1209,7 @@ function createTonSDK(log7, db) {
1048
1209
  forwardPayload = beginCell().storeUint(0, 32).storeStringTail(comment).endCell();
1049
1210
  }
1050
1211
  const JETTON_TRANSFER_OP = 260734629;
1051
- const messageBody = beginCell().storeUint(JETTON_TRANSFER_OP, 32).storeUint(0, 64).storeCoins(amountInUnits).storeAddress(Address2.parse(to)).storeAddress(Address2.parse(walletData.address)).storeBit(false).storeCoins(comment ? toNano2("0.01") : BigInt(1)).storeBit(comment ? true : false).storeMaybeRef(comment ? forwardPayload : null).endCell();
1212
+ const messageBody = beginCell().storeUint(JETTON_TRANSFER_OP, 32).storeUint(0, 64).storeCoins(amountInUnits).storeAddress(TonAddress.parse(to)).storeAddress(TonAddress.parse(walletData.address)).storeBit(false).storeCoins(comment ? tonToNano("0.01") : BigInt(1)).storeBit(comment ? 1 : 0).storeRef(comment ? forwardPayload : beginCell().endCell()).endCell();
1052
1213
  const keyPair = await getKeyPair();
1053
1214
  if (!keyPair) {
1054
1215
  throw new PluginSDKError("Wallet key derivation failed", "OPERATION_FAILED");
@@ -1058,8 +1219,7 @@ function createTonSDK(log7, db) {
1058
1219
  workchain: 0,
1059
1220
  publicKey: keyPair.publicKey
1060
1221
  });
1061
- const endpoint = await getCachedHttpEndpoint2();
1062
- const client = new TonClient2({ endpoint });
1222
+ const client = await getCachedTonClient();
1063
1223
  const walletContract = client.open(wallet);
1064
1224
  const seq = await walletContract.getSeqno();
1065
1225
  await walletContract.sendTransfer({
@@ -1068,8 +1228,8 @@ function createTonSDK(log7, db) {
1068
1228
  sendMode: SendMode2.PAY_GAS_SEPARATELY,
1069
1229
  messages: [
1070
1230
  internal2({
1071
- to: Address2.parse(senderJettonWallet),
1072
- value: toNano2("0.05"),
1231
+ to: TonAddress.parse(senderJettonWallet),
1232
+ value: tonToNano("0.05"),
1073
1233
  body: messageBody,
1074
1234
  bounce: true
1075
1235
  })
@@ -1088,16 +1248,13 @@ function createTonSDK(log7, db) {
1088
1248
  },
1089
1249
  async getJettonWalletAddress(ownerAddress, jettonAddress) {
1090
1250
  try {
1091
- const response = await tonapiFetch(`/accounts/${ownerAddress}/jettons`);
1251
+ const response = await tonapiFetch(`/accounts/${encodeURIComponent(ownerAddress)}/jettons`);
1092
1252
  if (!response.ok) {
1093
1253
  log7.error(`ton.getJettonWalletAddress() TonAPI error: ${response.status}`);
1094
1254
  return null;
1095
1255
  }
1096
- const { Address: Address2 } = await import("@ton/core");
1097
1256
  const data = await response.json();
1098
- const match = (data.balances || []).find(
1099
- (b) => b.jetton.address.toLowerCase() === jettonAddress.toLowerCase() || Address2.parse(b.jetton.address).toString() === Address2.parse(jettonAddress).toString()
1100
- );
1257
+ const match = findJettonBalance(data.balances ?? [], jettonAddress);
1101
1258
  return match ? match.wallet_address.address : null;
1102
1259
  } catch (err) {
1103
1260
  log7.error("ton.getJettonWalletAddress() failed:", err);
@@ -1126,7 +1283,7 @@ function createTonSDK(log7, db) {
1126
1283
  },
1127
1284
  async getNftInfo(nftAddress) {
1128
1285
  try {
1129
- const response = await tonapiFetch(`/nfts/${nftAddress}`);
1286
+ const response = await tonapiFetch(`/nfts/${encodeURIComponent(nftAddress)}`);
1130
1287
  if (response.status === 404) return null;
1131
1288
  if (!response.ok) {
1132
1289
  log7.error(`ton.getNftInfo() TonAPI error: ${response.status}`);
@@ -2864,11 +3021,22 @@ function numberInRange(min, max) {
2864
3021
  function enumValidator(options) {
2865
3022
  return (v) => options.includes(v) ? void 0 : `Must be one of: ${options.join(", ")}`;
2866
3023
  }
3024
+ function positiveInteger(v) {
3025
+ const n = Number(v);
3026
+ if (!Number.isInteger(n) || n <= 0) return "Must be a positive integer";
3027
+ return void 0;
3028
+ }
3029
+ function validateUrl(v) {
3030
+ if (v === "") return void 0;
3031
+ if (v.startsWith("http://") || v.startsWith("https://")) return void 0;
3032
+ return "Must be empty or start with http:// or https://";
3033
+ }
2867
3034
  var CONFIGURABLE_KEYS = {
2868
3035
  // ─── API Keys ──────────────────────────────────────────────────────
2869
3036
  "agent.api_key": {
2870
3037
  type: "string",
2871
3038
  category: "API Keys",
3039
+ label: "LLM API Key",
2872
3040
  description: "LLM provider API key",
2873
3041
  sensitive: true,
2874
3042
  validate: (v) => v.length >= 10 ? void 0 : "Must be at least 10 characters",
@@ -2878,6 +3046,7 @@ var CONFIGURABLE_KEYS = {
2878
3046
  tavily_api_key: {
2879
3047
  type: "string",
2880
3048
  category: "API Keys",
3049
+ label: "Tavily API Key",
2881
3050
  description: "Tavily API key for web search",
2882
3051
  sensitive: true,
2883
3052
  validate: (v) => v.startsWith("tvly-") ? void 0 : "Must start with 'tvly-'",
@@ -2887,6 +3056,7 @@ var CONFIGURABLE_KEYS = {
2887
3056
  tonapi_key: {
2888
3057
  type: "string",
2889
3058
  category: "API Keys",
3059
+ label: "TonAPI Key",
2890
3060
  description: "TonAPI key for higher rate limits",
2891
3061
  sensitive: true,
2892
3062
  validate: (v) => v.length >= 10 ? void 0 : "Must be at least 10 characters",
@@ -2896,6 +3066,7 @@ var CONFIGURABLE_KEYS = {
2896
3066
  "telegram.bot_token": {
2897
3067
  type: "string",
2898
3068
  category: "API Keys",
3069
+ label: "Bot Token",
2899
3070
  description: "Bot token from @BotFather",
2900
3071
  sensitive: true,
2901
3072
  validate: (v) => v.includes(":") ? void 0 : "Must contain ':' (e.g., 123456:ABC...)",
@@ -2906,10 +3077,12 @@ var CONFIGURABLE_KEYS = {
2906
3077
  "agent.provider": {
2907
3078
  type: "enum",
2908
3079
  category: "Agent",
3080
+ label: "Provider",
2909
3081
  description: "LLM provider",
2910
3082
  sensitive: false,
2911
3083
  options: [
2912
3084
  "anthropic",
3085
+ "claude-code",
2913
3086
  "openai",
2914
3087
  "google",
2915
3088
  "xai",
@@ -2922,6 +3095,7 @@ var CONFIGURABLE_KEYS = {
2922
3095
  ],
2923
3096
  validate: enumValidator([
2924
3097
  "anthropic",
3098
+ "claude-code",
2925
3099
  "openai",
2926
3100
  "google",
2927
3101
  "xai",
@@ -2938,6 +3112,7 @@ var CONFIGURABLE_KEYS = {
2938
3112
  "agent.model": {
2939
3113
  type: "string",
2940
3114
  category: "Agent",
3115
+ label: "Model",
2941
3116
  description: "Main LLM model ID",
2942
3117
  sensitive: false,
2943
3118
  validate: nonEmpty,
@@ -2947,6 +3122,7 @@ var CONFIGURABLE_KEYS = {
2947
3122
  "agent.utility_model": {
2948
3123
  type: "string",
2949
3124
  category: "Agent",
3125
+ label: "Utility Model",
2950
3126
  description: "Cheap model for summarization (auto-detected if empty)",
2951
3127
  sensitive: false,
2952
3128
  validate: noValidation,
@@ -2956,6 +3132,7 @@ var CONFIGURABLE_KEYS = {
2956
3132
  "agent.temperature": {
2957
3133
  type: "number",
2958
3134
  category: "Agent",
3135
+ label: "Temperature",
2959
3136
  description: "Response creativity (0.0 = deterministic, 2.0 = max)",
2960
3137
  sensitive: false,
2961
3138
  validate: numberInRange(0, 2),
@@ -2965,6 +3142,7 @@ var CONFIGURABLE_KEYS = {
2965
3142
  "agent.max_tokens": {
2966
3143
  type: "number",
2967
3144
  category: "Agent",
3145
+ label: "Max Tokens",
2968
3146
  description: "Maximum response length in tokens",
2969
3147
  sensitive: false,
2970
3148
  validate: numberInRange(256, 128e3),
@@ -2974,16 +3152,38 @@ var CONFIGURABLE_KEYS = {
2974
3152
  "agent.max_agentic_iterations": {
2975
3153
  type: "number",
2976
3154
  category: "Agent",
3155
+ label: "Max Iterations",
2977
3156
  description: "Max tool-call loop iterations per message",
2978
3157
  sensitive: false,
2979
3158
  validate: numberInRange(1, 20),
2980
3159
  mask: identity,
2981
3160
  parse: (v) => Number(v)
2982
3161
  },
3162
+ "agent.base_url": {
3163
+ type: "string",
3164
+ category: "Agent",
3165
+ label: "API Base URL",
3166
+ description: "Base URL for local LLM server (requires restart)",
3167
+ sensitive: false,
3168
+ validate: validateUrl,
3169
+ mask: identity,
3170
+ parse: identity
3171
+ },
3172
+ "cocoon.port": {
3173
+ type: "number",
3174
+ category: "Agent",
3175
+ label: "Cocoon Port",
3176
+ description: "Cocoon proxy port (requires restart)",
3177
+ sensitive: false,
3178
+ validate: numberInRange(1, 65535),
3179
+ mask: identity,
3180
+ parse: (v) => Number(v)
3181
+ },
2983
3182
  // ─── Session ───────────────────────────────────────────────────
2984
3183
  "agent.session_reset_policy.daily_reset_enabled": {
2985
3184
  type: "boolean",
2986
3185
  category: "Session",
3186
+ label: "Daily Reset",
2987
3187
  description: "Enable daily session reset at specified hour",
2988
3188
  sensitive: false,
2989
3189
  validate: enumValidator(["true", "false"]),
@@ -2993,6 +3193,7 @@ var CONFIGURABLE_KEYS = {
2993
3193
  "agent.session_reset_policy.daily_reset_hour": {
2994
3194
  type: "number",
2995
3195
  category: "Session",
3196
+ label: "Reset Hour",
2996
3197
  description: "Hour (0-23 UTC) for daily session reset",
2997
3198
  sensitive: false,
2998
3199
  validate: numberInRange(0, 23),
@@ -3002,6 +3203,7 @@ var CONFIGURABLE_KEYS = {
3002
3203
  "agent.session_reset_policy.idle_expiry_enabled": {
3003
3204
  type: "boolean",
3004
3205
  category: "Session",
3206
+ label: "Idle Expiry",
3005
3207
  description: "Enable automatic session expiry after idle period",
3006
3208
  sensitive: false,
3007
3209
  validate: enumValidator(["true", "false"]),
@@ -3011,6 +3213,7 @@ var CONFIGURABLE_KEYS = {
3011
3213
  "agent.session_reset_policy.idle_expiry_minutes": {
3012
3214
  type: "number",
3013
3215
  category: "Session",
3216
+ label: "Idle Minutes",
3014
3217
  description: "Idle minutes before session expires (minimum 1)",
3015
3218
  sensitive: false,
3016
3219
  validate: numberInRange(1, Number.MAX_SAFE_INTEGER),
@@ -3021,6 +3224,7 @@ var CONFIGURABLE_KEYS = {
3021
3224
  "telegram.bot_username": {
3022
3225
  type: "string",
3023
3226
  category: "Telegram",
3227
+ label: "Bot Username",
3024
3228
  description: "Bot username without @",
3025
3229
  sensitive: false,
3026
3230
  validate: (v) => v.length >= 3 ? void 0 : "Must be at least 3 characters",
@@ -3030,19 +3234,23 @@ var CONFIGURABLE_KEYS = {
3030
3234
  "telegram.dm_policy": {
3031
3235
  type: "enum",
3032
3236
  category: "Telegram",
3033
- description: "DM access policy",
3237
+ label: "DM Policy",
3238
+ description: "Who can message the bot in private",
3034
3239
  sensitive: false,
3035
- options: ["pairing", "allowlist", "open", "disabled"],
3036
- validate: enumValidator(["pairing", "allowlist", "open", "disabled"]),
3240
+ options: ["open", "allowlist", "disabled"],
3241
+ optionLabels: { open: "Open", allowlist: "Allow Users", disabled: "Admin Only" },
3242
+ validate: enumValidator(["allowlist", "open", "disabled"]),
3037
3243
  mask: identity,
3038
3244
  parse: identity
3039
3245
  },
3040
3246
  "telegram.group_policy": {
3041
3247
  type: "enum",
3042
3248
  category: "Telegram",
3043
- description: "Group access policy",
3249
+ label: "Group Policy",
3250
+ description: "Which groups the bot can respond in",
3044
3251
  sensitive: false,
3045
3252
  options: ["open", "allowlist", "disabled"],
3253
+ optionLabels: { open: "Open", allowlist: "Allow Groups", disabled: "Disabled" },
3046
3254
  validate: enumValidator(["open", "allowlist", "disabled"]),
3047
3255
  mask: identity,
3048
3256
  parse: identity
@@ -3050,6 +3258,7 @@ var CONFIGURABLE_KEYS = {
3050
3258
  "telegram.require_mention": {
3051
3259
  type: "boolean",
3052
3260
  category: "Telegram",
3261
+ label: "Require Mention",
3053
3262
  description: "Require @mention in groups to respond",
3054
3263
  sensitive: false,
3055
3264
  validate: enumValidator(["true", "false"]),
@@ -3059,6 +3268,7 @@ var CONFIGURABLE_KEYS = {
3059
3268
  "telegram.owner_name": {
3060
3269
  type: "string",
3061
3270
  category: "Telegram",
3271
+ label: "Owner Name",
3062
3272
  description: "Owner's first name (used in system prompt)",
3063
3273
  sensitive: false,
3064
3274
  validate: noValidation,
@@ -3068,6 +3278,7 @@ var CONFIGURABLE_KEYS = {
3068
3278
  "telegram.owner_username": {
3069
3279
  type: "string",
3070
3280
  category: "Telegram",
3281
+ label: "Owner Username",
3071
3282
  description: "Owner's Telegram username (without @)",
3072
3283
  sensitive: false,
3073
3284
  validate: noValidation,
@@ -3077,6 +3288,7 @@ var CONFIGURABLE_KEYS = {
3077
3288
  "telegram.debounce_ms": {
3078
3289
  type: "number",
3079
3290
  category: "Telegram",
3291
+ label: "Debounce (ms)",
3080
3292
  description: "Group message debounce delay in ms (0 = disabled)",
3081
3293
  sensitive: false,
3082
3294
  validate: numberInRange(0, 1e4),
@@ -3086,6 +3298,7 @@ var CONFIGURABLE_KEYS = {
3086
3298
  "telegram.agent_channel": {
3087
3299
  type: "string",
3088
3300
  category: "Telegram",
3301
+ label: "Agent Channel",
3089
3302
  description: "Channel username for auto-publishing",
3090
3303
  sensitive: false,
3091
3304
  validate: noValidation,
@@ -3095,16 +3308,91 @@ var CONFIGURABLE_KEYS = {
3095
3308
  "telegram.typing_simulation": {
3096
3309
  type: "boolean",
3097
3310
  category: "Telegram",
3311
+ label: "Typing Simulation",
3098
3312
  description: "Simulate typing indicator before sending replies",
3099
3313
  sensitive: false,
3100
3314
  validate: enumValidator(["true", "false"]),
3101
3315
  mask: identity,
3102
3316
  parse: (v) => v === "true"
3103
3317
  },
3318
+ "telegram.owner_id": {
3319
+ type: "number",
3320
+ category: "Telegram",
3321
+ label: "Admin ID",
3322
+ description: "Primary admin Telegram user ID (auto-added to Admin IDs)",
3323
+ sensitive: false,
3324
+ validate: positiveInteger,
3325
+ mask: identity,
3326
+ parse: (v) => Number(v)
3327
+ },
3328
+ "telegram.max_message_length": {
3329
+ type: "number",
3330
+ category: "Telegram",
3331
+ label: "Max Message Length",
3332
+ description: "Maximum message length in characters",
3333
+ sensitive: false,
3334
+ validate: numberInRange(1, 32768),
3335
+ mask: identity,
3336
+ parse: (v) => Number(v)
3337
+ },
3338
+ "telegram.rate_limit_messages_per_second": {
3339
+ type: "number",
3340
+ category: "Telegram",
3341
+ label: "Rate Limit \u2014 Messages/sec",
3342
+ description: "Rate limit: messages per second (requires restart)",
3343
+ sensitive: false,
3344
+ validate: numberInRange(0.1, 10),
3345
+ mask: identity,
3346
+ parse: (v) => Number(v)
3347
+ },
3348
+ "telegram.rate_limit_groups_per_minute": {
3349
+ type: "number",
3350
+ category: "Telegram",
3351
+ label: "Rate Limit \u2014 Groups/min",
3352
+ description: "Rate limit: groups per minute (requires restart)",
3353
+ sensitive: false,
3354
+ validate: numberInRange(1, 60),
3355
+ mask: identity,
3356
+ parse: (v) => Number(v)
3357
+ },
3358
+ "telegram.admin_ids": {
3359
+ type: "array",
3360
+ itemType: "number",
3361
+ category: "Telegram",
3362
+ label: "Admin IDs",
3363
+ description: "Admin user IDs with elevated access",
3364
+ sensitive: false,
3365
+ validate: positiveInteger,
3366
+ mask: identity,
3367
+ parse: (v) => Number(v)
3368
+ },
3369
+ "telegram.allow_from": {
3370
+ type: "array",
3371
+ itemType: "number",
3372
+ category: "Telegram",
3373
+ label: "Allowed Users",
3374
+ description: "User IDs allowed for DM access",
3375
+ sensitive: false,
3376
+ validate: positiveInteger,
3377
+ mask: identity,
3378
+ parse: (v) => Number(v)
3379
+ },
3380
+ "telegram.group_allow_from": {
3381
+ type: "array",
3382
+ itemType: "number",
3383
+ category: "Telegram",
3384
+ label: "Allowed Groups",
3385
+ description: "Group IDs allowed for group access",
3386
+ sensitive: false,
3387
+ validate: positiveInteger,
3388
+ mask: identity,
3389
+ parse: (v) => Number(v)
3390
+ },
3104
3391
  // ─── Embedding ─────────────────────────────────────────────────────
3105
3392
  "embedding.provider": {
3106
3393
  type: "enum",
3107
3394
  category: "Embedding",
3395
+ label: "Embedding Provider",
3108
3396
  description: "Embedding provider for RAG",
3109
3397
  sensitive: false,
3110
3398
  options: ["local", "anthropic", "none"],
@@ -3112,10 +3400,21 @@ var CONFIGURABLE_KEYS = {
3112
3400
  mask: identity,
3113
3401
  parse: identity
3114
3402
  },
3403
+ "embedding.model": {
3404
+ type: "string",
3405
+ category: "Embedding",
3406
+ label: "Embedding Model",
3407
+ description: "Embedding model ID (requires restart)",
3408
+ sensitive: false,
3409
+ validate: noValidation,
3410
+ mask: identity,
3411
+ parse: identity
3412
+ },
3115
3413
  // ─── WebUI ─────────────────────────────────────────────────────────
3116
3414
  "webui.port": {
3117
3415
  type: "number",
3118
3416
  category: "WebUI",
3417
+ label: "WebUI Port",
3119
3418
  description: "HTTP server port (requires restart)",
3120
3419
  sensitive: false,
3121
3420
  validate: numberInRange(1024, 65535),
@@ -3125,6 +3424,7 @@ var CONFIGURABLE_KEYS = {
3125
3424
  "webui.log_requests": {
3126
3425
  type: "boolean",
3127
3426
  category: "WebUI",
3427
+ label: "Log HTTP Requests",
3128
3428
  description: "Log all HTTP requests to console",
3129
3429
  sensitive: false,
3130
3430
  validate: enumValidator(["true", "false"]),
@@ -3135,16 +3435,48 @@ var CONFIGURABLE_KEYS = {
3135
3435
  "deals.enabled": {
3136
3436
  type: "boolean",
3137
3437
  category: "Deals",
3438
+ label: "Deals Enabled",
3138
3439
  description: "Enable the deals/escrow module",
3139
3440
  sensitive: false,
3140
3441
  validate: enumValidator(["true", "false"]),
3141
3442
  mask: identity,
3142
3443
  parse: (v) => v === "true"
3143
3444
  },
3445
+ "deals.expiry_seconds": {
3446
+ type: "number",
3447
+ category: "Deals",
3448
+ label: "Deal Expiry",
3449
+ description: "Deal expiry timeout in seconds",
3450
+ sensitive: false,
3451
+ validate: numberInRange(10, 3600),
3452
+ mask: identity,
3453
+ parse: (v) => Number(v)
3454
+ },
3455
+ "deals.buy_max_floor_percent": {
3456
+ type: "number",
3457
+ category: "Deals",
3458
+ label: "Buy Max Floor %",
3459
+ description: "Maximum floor % for buy deals",
3460
+ sensitive: false,
3461
+ validate: numberInRange(1, 100),
3462
+ mask: identity,
3463
+ parse: (v) => Number(v)
3464
+ },
3465
+ "deals.sell_min_floor_percent": {
3466
+ type: "number",
3467
+ category: "Deals",
3468
+ label: "Sell Min Floor %",
3469
+ description: "Minimum floor % for sell deals",
3470
+ sensitive: false,
3471
+ validate: numberInRange(100, 500),
3472
+ mask: identity,
3473
+ parse: (v) => Number(v)
3474
+ },
3144
3475
  // ─── Developer ─────────────────────────────────────────────────────
3145
3476
  "dev.hot_reload": {
3146
3477
  type: "boolean",
3147
3478
  category: "Developer",
3479
+ label: "Hot Reload",
3148
3480
  description: "Watch ~/.teleton/plugins/ for live changes",
3149
3481
  sensitive: false,
3150
3482
  validate: enumValidator(["true", "false"]),
@@ -3240,6 +3572,7 @@ export {
3240
3572
  randomLong,
3241
3573
  withBlockchainRetry,
3242
3574
  sendTon,
3575
+ formatTransactions,
3243
3576
  adaptPlugin,
3244
3577
  ensurePluginDeps,
3245
3578
  loadEnhancedPlugins,