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
package/dist/cli/index.js CHANGED
@@ -1,7 +1,10 @@
1
+ import {
2
+ getModelsForProvider
3
+ } from "../chunk-QOQWUUA4.js";
1
4
  import {
2
5
  TelegramUserClient,
3
6
  main
4
- } from "../chunk-BU453WX4.js";
7
+ } from "../chunk-OGMVWDVU.js";
5
8
  import "../chunk-WIKM24GZ.js";
6
9
  import "../chunk-U7FQYCBQ.js";
7
10
  import {
@@ -13,7 +16,7 @@ import {
13
16
  readRawConfig,
14
17
  setNestedValue,
15
18
  writeRawConfig
16
- } from "../chunk-A4GCOHCE.js";
19
+ } from "../chunk-G2LLMJXJ.js";
17
20
  import {
18
21
  ConfigSchema,
19
22
  DealsConfigSchema,
@@ -24,33 +27,31 @@ import {
24
27
  loadWallet,
25
28
  saveWallet,
26
29
  walletExists
27
- } from "../chunk-DAMCNMYL.js";
30
+ } from "../chunk-AVDWXYQ7.js";
31
+ import "../chunk-5UVXJMOX.js";
28
32
  import "../chunk-TSKJCWQQ.js";
29
33
  import {
30
34
  getErrorMessage
31
35
  } from "../chunk-XBE4JB7C.js";
32
- import "../chunk-5PLZ3KSO.js";
36
+ import "../chunk-DMXTIRUW.js";
33
37
  import {
34
38
  getClaudeCodeApiKey,
35
- isClaudeCodeTokenValid
36
- } from "../chunk-JQDLW7IE.js";
37
- import {
38
39
  getProviderMetadata,
39
40
  getSupportedProviders,
41
+ isClaudeCodeTokenValid,
40
42
  validateApiKeyFormat
41
- } from "../chunk-RMLQS3X6.js";
43
+ } from "../chunk-CB2Y45HA.js";
42
44
  import "../chunk-OCLG5GKI.js";
43
- import "../chunk-RBU6JXD3.js";
44
- import "../chunk-UCN6TI25.js";
45
- import "../chunk-FNV5FF35.js";
46
- import "../chunk-XBKSS6DM.js";
45
+ import "../chunk-2GLHOJ5C.js";
46
+ import "../chunk-LCCVZ4D2.js";
47
+ import "../chunk-VFA7QMCZ.js";
47
48
  import {
48
49
  TELEGRAM_MAX_MESSAGE_LENGTH
49
- } from "../chunk-RO62LO6Z.js";
50
+ } from "../chunk-YP25WTQK.js";
50
51
  import {
51
52
  fetchWithTimeout
52
- } from "../chunk-VAUJSSD3.js";
53
- import "../chunk-4DU3C27M.js";
53
+ } from "../chunk-XQUHC3JZ.js";
54
+ import "../chunk-R4YSJ4EY.js";
54
55
  import {
55
56
  TELETON_ROOT
56
57
  } from "../chunk-EYWNOHMJ.js";
@@ -360,12 +361,12 @@ import { join } from "path";
360
361
  import YAML from "yaml";
361
362
  import ora2 from "ora";
362
363
  var STEPS = [
363
- { label: "Agent", desc: "Name & mode" },
364
- { label: "Provider", desc: "LLM & API key" },
365
- { label: "Telegram", desc: "Credentials" },
366
- { label: "Config", desc: "Model & policies" },
367
- { label: "Modules", desc: "Optional features" },
364
+ { label: "Agent", desc: "Name" },
365
+ { label: "Provider", desc: "LLM, key & model" },
366
+ { label: "Config", desc: "Policies" },
367
+ { label: "Modules", desc: "Optional API keys" },
368
368
  { label: "Wallet", desc: "TON blockchain" },
369
+ { label: "Telegram", desc: "Credentials" },
369
370
  { label: "Connect", desc: "Telegram auth" }
370
371
  ];
371
372
  function redraw(currentStep) {
@@ -377,114 +378,9 @@ function redraw(currentStep) {
377
378
  function sleep(ms) {
378
379
  return new Promise((r) => setTimeout(r, ms));
379
380
  }
380
- var MODEL_OPTIONS = {
381
- anthropic: [
382
- {
383
- value: "claude-opus-4-6",
384
- name: "Claude Opus 4.6",
385
- description: "Most capable, 1M ctx, $5/M"
386
- },
387
- {
388
- value: "claude-opus-4-5-20251101",
389
- name: "Claude Opus 4.5",
390
- description: "Previous gen, 200K ctx, $5/M"
391
- },
392
- { value: "claude-sonnet-4-0", name: "Claude Sonnet 4", description: "Balanced, $3/M" },
393
- {
394
- value: "claude-haiku-4-5-20251001",
395
- name: "Claude Haiku 4.5",
396
- description: "Fast & cheap, $1/M"
397
- },
398
- {
399
- value: "claude-haiku-4-5-20251001",
400
- name: "Claude Haiku 4.5",
401
- description: "Fast & cheap, $1/M"
402
- }
403
- ],
404
- openai: [
405
- { value: "gpt-5", name: "GPT-5", description: "Most capable, 400K ctx, $1.25/M" },
406
- { value: "gpt-4o", name: "GPT-4o", description: "Balanced, 128K ctx, $2.50/M" },
407
- { value: "gpt-4.1", name: "GPT-4.1", description: "1M ctx, $2/M" },
408
- { value: "gpt-4.1-mini", name: "GPT-4.1 Mini", description: "1M ctx, cheap, $0.40/M" },
409
- { value: "o3", name: "o3", description: "Reasoning, 200K ctx, $2/M" }
410
- ],
411
- google: [
412
- { value: "gemini-2.5-flash", name: "Gemini 2.5 Flash", description: "Fast, 1M ctx, $0.30/M" },
413
- {
414
- value: "gemini-2.5-pro",
415
- name: "Gemini 2.5 Pro",
416
- description: "Most capable, 1M ctx, $1.25/M"
417
- },
418
- { value: "gemini-2.0-flash", name: "Gemini 2.0 Flash", description: "Cheap, 1M ctx, $0.10/M" }
419
- ],
420
- xai: [
421
- { value: "grok-4-fast", name: "Grok 4 Fast", description: "Vision, 2M ctx, $0.20/M" },
422
- { value: "grok-4", name: "Grok 4", description: "Reasoning, 256K ctx, $3/M" },
423
- { value: "grok-3", name: "Grok 3", description: "Stable, 131K ctx, $3/M" }
424
- ],
425
- groq: [
426
- {
427
- value: "meta-llama/llama-4-maverick-17b-128e-instruct",
428
- name: "Llama 4 Maverick",
429
- description: "Vision, 131K ctx, $0.20/M"
430
- },
431
- { value: "qwen/qwen3-32b", name: "Qwen3 32B", description: "Reasoning, 131K ctx, $0.29/M" },
432
- {
433
- value: "deepseek-r1-distill-llama-70b",
434
- name: "DeepSeek R1 70B",
435
- description: "Reasoning, 131K ctx, $0.75/M"
436
- },
437
- {
438
- value: "llama-3.3-70b-versatile",
439
- name: "Llama 3.3 70B",
440
- description: "General purpose, 131K ctx, $0.59/M"
441
- }
442
- ],
443
- openrouter: [
444
- { value: "anthropic/claude-opus-4.5", name: "Claude Opus 4.5", description: "200K ctx, $5/M" },
445
- { value: "openai/gpt-5", name: "GPT-5", description: "400K ctx, $1.25/M" },
446
- { value: "google/gemini-2.5-flash", name: "Gemini 2.5 Flash", description: "1M ctx, $0.30/M" },
447
- {
448
- value: "deepseek/deepseek-r1",
449
- name: "DeepSeek R1",
450
- description: "Reasoning, 64K ctx, $0.70/M"
451
- },
452
- { value: "x-ai/grok-4", name: "Grok 4", description: "256K ctx, $3/M" }
453
- ],
454
- moonshot: [
455
- { value: "kimi-k2.5", name: "Kimi K2.5", description: "Free, 256K ctx, multimodal" },
456
- {
457
- value: "kimi-k2-thinking",
458
- name: "Kimi K2 Thinking",
459
- description: "Free, 256K ctx, reasoning"
460
- }
461
- ],
462
- mistral: [
463
- {
464
- value: "devstral-small-2507",
465
- name: "Devstral Small",
466
- description: "Coding, 128K ctx, $0.10/M"
467
- },
468
- {
469
- value: "devstral-medium-latest",
470
- name: "Devstral Medium",
471
- description: "Coding, 262K ctx, $0.40/M"
472
- },
473
- {
474
- value: "mistral-large-latest",
475
- name: "Mistral Large",
476
- description: "General, 128K ctx, $2/M"
477
- },
478
- {
479
- value: "magistral-small",
480
- name: "Magistral Small",
481
- description: "Reasoning, 128K ctx, $0.50/M"
482
- }
483
- ]
484
- };
485
381
  async function onboardCommand(options = {}) {
486
382
  if (options.ui) {
487
- const { SetupServer } = await import("../setup-server-BVVD2PR6.js");
383
+ const { SetupServer } = await import("../setup-server-G7UG2DI3.js");
488
384
  const port = parseInt(options.uiPort || "7777") || 7777;
489
385
  const url = `http://localhost:${port}/setup`;
490
386
  const blue2 = "\x1B[34m";
@@ -539,9 +435,7 @@ ${blue2} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25
539
435
  }
540
436
  }
541
437
  async function runInteractiveOnboarding(options, prompter) {
542
- let selectedFlow = "quick";
543
438
  let selectedProvider = "anthropic";
544
- const dealsEnabled = true;
545
439
  let selectedModel = "";
546
440
  let apiKey = "";
547
441
  let apiId = 0;
@@ -549,16 +443,16 @@ async function runInteractiveOnboarding(options, prompter) {
549
443
  let phone = "";
550
444
  let userId = 0;
551
445
  let tonapiKey;
446
+ let toncenterApiKey;
552
447
  let tavilyApiKey;
553
448
  let botToken;
554
449
  let botUsername;
555
- let dmPolicy = "open";
556
- let groupPolicy = "open";
450
+ let dmPolicy = "admin-only";
451
+ let groupPolicy = "admin-only";
557
452
  let requireMention = true;
558
453
  let maxAgenticIterations = "5";
454
+ let execMode = "off";
559
455
  let cocoonInstance = 1e4;
560
- let buyMaxFloorPercent = 100;
561
- let sellMinFloorPercent = 105;
562
456
  console.clear();
563
457
  console.log();
564
458
  console.log(wizardFrame(0, STEPS));
@@ -585,7 +479,8 @@ async function runInteractiveOnboarding(options, prompter) {
585
479
  spinner.start(DIM("Creating workspace..."));
586
480
  const workspace = await ensureWorkspace({
587
481
  workspaceDir: options.workspace,
588
- ensureTemplates: true
482
+ ensureTemplates: true,
483
+ silent: true
589
484
  });
590
485
  const isNew = isNewWorkspace(workspace);
591
486
  spinner.succeed(DIM(`Workspace: ${workspace.root}`));
@@ -613,20 +508,7 @@ async function runInteractiveOnboarding(options, prompter) {
613
508
  const updated = identity.replace("[Your name - pick one or ask your human]", agentName.trim());
614
509
  writeFileSync(workspace.identityPath, updated, "utf-8");
615
510
  }
616
- selectedFlow = await select({
617
- message: "Installation mode",
618
- default: "quick",
619
- theme: inquirerTheme,
620
- choices: [
621
- {
622
- value: "quick",
623
- name: "\u26A1 QuickStart",
624
- description: "Minimal configuration (recommended)"
625
- },
626
- { value: "advanced", name: "\u2699 Advanced", description: "Detailed configuration" }
627
- ]
628
- });
629
- STEPS[0].value = `${agentName} (${selectedFlow})`;
511
+ STEPS[0].value = agentName;
630
512
  redraw(1);
631
513
  const providers = getSupportedProviders();
632
514
  selectedProvider = await select({
@@ -776,63 +658,9 @@ Get it at: ${providerMeta.consoleUrl}`,
776
658
  const maskedKey = apiKey.length > 10 ? apiKey.slice(0, 6) + "..." + apiKey.slice(-4) : "***";
777
659
  STEPS[1].value = `${providerMeta.displayName} ${DIM(maskedKey)}`;
778
660
  }
779
- redraw(2);
780
- noteBox(
781
- "You need Telegram credentials from https://my.telegram.org/apps\nCreate an application and note the API ID and API Hash",
782
- "Telegram",
783
- TON
784
- );
785
- const envApiId = process.env.TELETON_TG_API_ID;
786
- const envApiHash = process.env.TELETON_TG_API_HASH;
787
- const envPhone = process.env.TELETON_TG_PHONE;
788
- const apiIdStr = options.apiId ? options.apiId.toString() : await input({
789
- message: envApiId ? "API ID (from env)" : "API ID (from my.telegram.org)",
790
- default: envApiId,
791
- theme: inquirerTheme,
792
- validate: (value) => {
793
- if (!value || isNaN(parseInt(value))) return "Invalid API ID (must be a number)";
794
- return true;
795
- }
796
- });
797
- apiId = parseInt(apiIdStr);
798
- apiHash = options.apiHash ? options.apiHash : await input({
799
- message: envApiHash ? "API Hash (from env)" : "API Hash (from my.telegram.org)",
800
- default: envApiHash,
801
- theme: inquirerTheme,
802
- validate: (value) => {
803
- if (!value || value.length < 10) return "Invalid API Hash";
804
- return true;
805
- }
806
- });
807
- phone = options.phone ? options.phone : await input({
808
- message: envPhone ? "Phone number (from env)" : "Phone number (international format)",
809
- default: envPhone,
810
- theme: inquirerTheme,
811
- validate: (value) => {
812
- if (!value || !value.startsWith("+")) return "Must start with +";
813
- return true;
814
- }
815
- });
816
- noteBox(
817
- "To get your Telegram User ID:\n1. Open @userinfobot on Telegram\n2. Send /start\n3. Note the ID displayed",
818
- "User ID",
819
- TON
820
- );
821
- const userIdStr = options.userId ? options.userId.toString() : await input({
822
- message: "Your Telegram User ID (for admin rights)",
823
- theme: inquirerTheme,
824
- validate: (value) => {
825
- if (!value || isNaN(parseInt(value))) return "Invalid User ID";
826
- return true;
827
- }
828
- });
829
- userId = parseInt(userIdStr);
830
- STEPS[2].value = `${phone} (ID: ${userId})`;
831
- redraw(3);
832
661
  selectedModel = providerMeta.defaultModel;
833
- if (selectedFlow === "advanced" && selectedProvider !== "cocoon" && selectedProvider !== "local") {
834
- const modelKey = selectedProvider === "claude-code" ? "anthropic" : selectedProvider;
835
- const providerModels = MODEL_OPTIONS[modelKey] || [];
662
+ if (selectedProvider !== "cocoon" && selectedProvider !== "local") {
663
+ const providerModels = getModelsForProvider(selectedProvider);
836
664
  const modelChoices = [
837
665
  ...providerModels,
838
666
  { value: "__custom__", name: "Custom", description: "Enter a model ID manually" }
@@ -853,78 +681,93 @@ Get it at: ${providerMeta.consoleUrl}`,
853
681
  } else {
854
682
  selectedModel = modelChoice;
855
683
  }
856
- dmPolicy = await select({
857
- message: "DM policy (private messages)",
858
- default: "open",
859
- theme: inquirerTheme,
860
- choices: [
861
- { value: "open", name: "Open", description: "Reply to everyone" },
862
- { value: "allowlist", name: "Allowlist", description: "Only specific users" },
863
- { value: "disabled", name: "Disabled", description: "No DM replies" }
864
- ]
865
- });
866
- groupPolicy = await select({
867
- message: "Group policy",
868
- default: "open",
869
- theme: inquirerTheme,
870
- choices: [
871
- { value: "open", name: "Open", description: "Reply in all groups" },
872
- { value: "allowlist", name: "Allowlist", description: "Only specific groups" },
873
- { value: "disabled", name: "Disabled", description: "No group replies" }
874
- ]
875
- });
876
- requireMention = await confirm({
877
- message: "Require @mention in groups?",
878
- default: true,
879
- theme: inquirerTheme
880
- });
881
- maxAgenticIterations = await input({
882
- message: "Max agentic iterations (tool call loops per message)",
883
- default: "5",
884
- theme: inquirerTheme,
885
- validate: (v) => {
886
- const n = parseInt(v, 10);
887
- return !isNaN(n) && n >= 1 && n <= 50 ? true : "Must be 1\u201350";
888
- }
889
- });
890
684
  const modelLabel = providerModels.find((m) => m.value === selectedModel)?.name ?? selectedModel;
891
- STEPS[3].value = `${modelLabel}, ${dmPolicy}/${groupPolicy}`;
892
- } else {
893
- STEPS[3].value = `${selectedModel} (defaults)`;
685
+ STEPS[1].value = `${STEPS[1].value ?? providerMeta.displayName}, ${modelLabel}`;
894
686
  }
895
- redraw(4);
896
- const extras = [];
897
- if (dealsEnabled) {
898
- const customizeStrategy = await confirm({
899
- message: `Customize trading thresholds? ${DIM("(default: buy \u2264 floor, sell \u2265 floor +5%)")}`,
900
- default: false,
901
- theme: inquirerTheme
902
- });
903
- if (customizeStrategy) {
904
- const buyInput = await input({
905
- message: "Max buy price (% of floor price)",
906
- default: "100",
907
- theme: inquirerTheme,
908
- validate: (v) => {
909
- const n = parseInt(v, 10);
910
- return !isNaN(n) && n >= 50 && n <= 150 ? true : "Must be 50\u2013150";
911
- }
912
- });
913
- buyMaxFloorPercent = parseInt(buyInput, 10);
914
- const sellInput = await input({
915
- message: "Min sell price (% of floor price)",
916
- default: "105",
917
- theme: inquirerTheme,
918
- validate: (v) => {
919
- const n = parseInt(v, 10);
920
- return !isNaN(n) && n >= 100 && n <= 200 ? true : "Must be 100\u2013200";
921
- }
922
- });
923
- sellMinFloorPercent = parseInt(sellInput, 10);
687
+ redraw(2);
688
+ noteBox(
689
+ "To get your Telegram User ID:\n1. Open @userinfobot on Telegram\n2. Send /start\n3. Note the ID displayed",
690
+ "User ID",
691
+ TON
692
+ );
693
+ const userIdStr = options.userId ? options.userId.toString() : await input({
694
+ message: "Your Telegram User ID (for admin rights)",
695
+ theme: inquirerTheme,
696
+ validate: (value) => {
697
+ if (!value || isNaN(parseInt(value))) return "Invalid User ID";
698
+ return true;
699
+ }
700
+ });
701
+ userId = parseInt(userIdStr);
702
+ dmPolicy = await select({
703
+ message: "DM policy (private messages)",
704
+ default: "admin-only",
705
+ theme: inquirerTheme,
706
+ choices: [
707
+ {
708
+ value: "admin-only",
709
+ name: "Admin Only",
710
+ description: "Only admins can DM the agent"
711
+ },
712
+ { value: "allowlist", name: "Allowlist", description: "Only specific users" },
713
+ { value: "open", name: "Open", description: "Reply to everyone" },
714
+ { value: "disabled", name: "Disabled", description: "Ignore all DMs" }
715
+ ]
716
+ });
717
+ groupPolicy = await select({
718
+ message: "Group policy",
719
+ default: "admin-only",
720
+ theme: inquirerTheme,
721
+ choices: [
722
+ {
723
+ value: "admin-only",
724
+ name: "Admin Only",
725
+ description: "Only admins can trigger the agent"
726
+ },
727
+ { value: "allowlist", name: "Allowlist", description: "Only specific groups" },
728
+ { value: "open", name: "Open", description: "Reply in all groups" },
729
+ { value: "disabled", name: "Disabled", description: "Ignore all group messages" }
730
+ ]
731
+ });
732
+ requireMention = await confirm({
733
+ message: "Require @mention in groups?",
734
+ default: true,
735
+ theme: inquirerTheme
736
+ });
737
+ maxAgenticIterations = await input({
738
+ message: "Max agentic iterations (tool call loops per message)",
739
+ default: "5",
740
+ theme: inquirerTheme,
741
+ validate: (v) => {
742
+ const n = parseInt(v, 10);
743
+ return !isNaN(n) && n >= 1 && n <= 50 ? true : "Must be 1\u201350";
924
744
  }
745
+ });
746
+ execMode = await select({
747
+ message: "Coding Agent (system execution)",
748
+ choices: [
749
+ { value: "off", name: "Disabled", description: "No system execution capability" },
750
+ {
751
+ value: "yolo",
752
+ name: "YOLO Mode",
753
+ description: "Full system access \u2014 STRONGLY RECOMMENDED to use a dedicated VPS"
754
+ }
755
+ ],
756
+ default: "off",
757
+ theme: inquirerTheme
758
+ });
759
+ STEPS[2].value = `${dmPolicy}/${groupPolicy}`;
760
+ redraw(3);
761
+ const extras = [];
762
+ const setupBot = await confirm({
763
+ message: `Add a Telegram bot token? ${DIM("(recommended \u2014 enables deals & inline buttons)")}`,
764
+ default: true,
765
+ theme: inquirerTheme
766
+ });
767
+ if (setupBot) {
925
768
  noteBox(
926
769
  "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",
927
- "Deals Bot",
770
+ "Bot Token",
928
771
  TON
929
772
  );
930
773
  const tokenInput = await password({
@@ -945,6 +788,7 @@ Get it at: ${providerMeta.consoleUrl}`,
945
788
  botToken = tokenInput;
946
789
  botUsername = data.result.username;
947
790
  spinner.succeed(DIM(`Bot verified: @${botUsername}`));
791
+ extras.push("Bot");
948
792
  }
949
793
  } catch {
950
794
  spinner.warn(DIM("Could not validate bot token (network error) \u2014 saving anyway"));
@@ -958,17 +802,17 @@ Get it at: ${providerMeta.consoleUrl}`,
958
802
  }
959
803
  });
960
804
  botUsername = usernameInput;
805
+ extras.push("Bot");
961
806
  }
962
- extras.push("Deals");
963
807
  }
964
808
  const setupTonapi = await confirm({
965
- message: `Add a TonAPI key? ${DIM("(optional, recommended for 10x rate limits)")}`,
809
+ message: `Add a TonAPI key? ${DIM("(strongly recommended for TON features)")}`,
966
810
  default: false,
967
811
  theme: inquirerTheme
968
812
  });
969
813
  if (setupTonapi) {
970
814
  noteBox(
971
- "Without key: 1 req/s (you will hit rate limits)\nWith free key: 10 req/s (recommended)\n\nOpen @tonapibot on Telegram \u2192 tap the mini app \u2192 generate a server key",
815
+ "Blockchain data \u2014 jettons, NFTs, prices, transaction history.\nWithout key: 1 req/s (you WILL hit rate limits)\nWith free key: 5 req/s\n\nOpen @tonapibot on Telegram \u2192 mini app \u2192 generate a server key",
972
816
  "TonAPI",
973
817
  TON
974
818
  );
@@ -983,6 +827,28 @@ Get it at: ${providerMeta.consoleUrl}`,
983
827
  tonapiKey = keyInput;
984
828
  extras.push("TonAPI");
985
829
  }
830
+ const setupToncenter = await confirm({
831
+ message: `Add a TonCenter API key? ${DIM("(optional, dedicated RPC endpoint)")}`,
832
+ default: false,
833
+ theme: inquirerTheme
834
+ });
835
+ if (setupToncenter) {
836
+ noteBox(
837
+ "Blockchain RPC \u2014 send transactions, check balances.\nWithout key: falls back to ORBS network (decentralized, slower)\nWith free key: dedicated RPC endpoint\n\nGo to https://toncenter.com \u2192 get a free API key (instant, no signup)",
838
+ "TonCenter",
839
+ TON
840
+ );
841
+ const keyInput = await input({
842
+ message: "TonCenter API key",
843
+ theme: inquirerTheme,
844
+ validate: (v) => {
845
+ if (!v || v.length < 10) return "Key too short";
846
+ return true;
847
+ }
848
+ });
849
+ toncenterApiKey = keyInput;
850
+ extras.push("TonCenter");
851
+ }
986
852
  const setupTavily = await confirm({
987
853
  message: `Enable web search? ${DIM("(free Tavily key \u2014 1,000 req/month)")}`,
988
854
  default: false,
@@ -1005,8 +871,8 @@ Get it at: ${providerMeta.consoleUrl}`,
1005
871
  tavilyApiKey = keyInput;
1006
872
  extras.push("Tavily");
1007
873
  }
1008
- STEPS[4].value = extras.length ? extras.join(", ") : "defaults";
1009
- redraw(5);
874
+ STEPS[3].value = extras.length ? extras.join(", ") : "defaults";
875
+ redraw(4);
1010
876
  let wallet;
1011
877
  const existingWallet = walletExists() ? loadWallet() : null;
1012
878
  if (existingWallet) {
@@ -1047,10 +913,38 @@ Get it at: ${providerMeta.consoleUrl}`,
1047
913
  spinner.succeed(DIM("New TON wallet generated"));
1048
914
  }
1049
915
  } else {
1050
- spinner.start(DIM("Generating TON wallet..."));
1051
- wallet = await generateWallet();
1052
- saveWallet(wallet);
1053
- spinner.succeed(DIM("TON wallet generated"));
916
+ const walletAction = await select({
917
+ message: "TON Wallet",
918
+ default: "generate",
919
+ theme: inquirerTheme,
920
+ choices: [
921
+ {
922
+ value: "generate",
923
+ name: "Generate new wallet",
924
+ description: "Create a fresh TON wallet"
925
+ },
926
+ { value: "import", name: "Import from mnemonic", description: "Restore from 24-word seed" }
927
+ ]
928
+ });
929
+ if (walletAction === "import") {
930
+ const mnemonicInput = await input({
931
+ message: "Enter your 24-word mnemonic (space-separated)",
932
+ theme: inquirerTheme,
933
+ validate: (value = "") => {
934
+ const words = value.trim().split(/\s+/);
935
+ return words.length === 24 ? true : `Expected 24 words, got ${words.length}`;
936
+ }
937
+ });
938
+ spinner.start(DIM("Importing wallet..."));
939
+ wallet = await importWallet(mnemonicInput.trim().split(/\s+/));
940
+ saveWallet(wallet);
941
+ spinner.succeed(DIM(`Wallet imported: ${wallet.address}`));
942
+ } else {
943
+ spinner.start(DIM("Generating TON wallet..."));
944
+ wallet = await generateWallet();
945
+ saveWallet(wallet);
946
+ spinner.succeed(DIM("TON wallet generated"));
947
+ }
1054
948
  }
1055
949
  if (!existingWallet || wallet !== existingWallet) {
1056
950
  const W = FRAME_WIDTH;
@@ -1093,7 +987,45 @@ Get it at: ${providerMeta.consoleUrl}`,
1093
987
  theme: inquirerTheme
1094
988
  });
1095
989
  }
1096
- STEPS[5].value = `${wallet.address.slice(0, 8)}...${wallet.address.slice(-4)}`;
990
+ STEPS[4].value = `${wallet.address.slice(0, 8)}...${wallet.address.slice(-4)}`;
991
+ redraw(5);
992
+ noteBox(
993
+ 'To get your API credentials:\n\n 1. Go to https://my.telegram.org/apps\n 2. Log in with your phone number\n 3. Click "API development tools"\n 4. Create an application (any name/short name works)\n 5. Copy the API ID (number) and API Hash (hex string)\n\n\u26A0 Do NOT use a VPN \u2014 Telegram will block the login page.',
994
+ "Telegram",
995
+ TON
996
+ );
997
+ const envApiId = process.env.TELETON_TG_API_ID;
998
+ const envApiHash = process.env.TELETON_TG_API_HASH;
999
+ const envPhone = process.env.TELETON_TG_PHONE;
1000
+ const apiIdStr = options.apiId ? options.apiId.toString() : await input({
1001
+ message: envApiId ? "API ID (from env)" : "API ID (from my.telegram.org)",
1002
+ default: envApiId,
1003
+ theme: inquirerTheme,
1004
+ validate: (value) => {
1005
+ if (!value || isNaN(parseInt(value))) return "Invalid API ID (must be a number)";
1006
+ return true;
1007
+ }
1008
+ });
1009
+ apiId = parseInt(apiIdStr);
1010
+ apiHash = options.apiHash ? options.apiHash : await input({
1011
+ message: envApiHash ? "API Hash (from env)" : "API Hash (from my.telegram.org)",
1012
+ default: envApiHash,
1013
+ theme: inquirerTheme,
1014
+ validate: (value) => {
1015
+ if (!value || value.length < 10) return "Invalid API Hash";
1016
+ return true;
1017
+ }
1018
+ });
1019
+ phone = options.phone ? options.phone : await input({
1020
+ message: envPhone ? "Phone number (from env)" : "Phone number (international format)",
1021
+ default: envPhone,
1022
+ theme: inquirerTheme,
1023
+ validate: (value) => {
1024
+ if (!value || !value.startsWith("+")) return "Must start with +";
1025
+ return true;
1026
+ }
1027
+ });
1028
+ STEPS[5].value = phone;
1097
1029
  redraw(6);
1098
1030
  const config = {
1099
1031
  meta: {
@@ -1141,16 +1073,11 @@ Get it at: ${providerMeta.consoleUrl}`,
1141
1073
  },
1142
1074
  storage: {
1143
1075
  sessions_file: `${workspace.root}/sessions.json`,
1144
- pairing_file: `${workspace.root}/pairing.json`,
1145
1076
  memory_file: `${workspace.root}/memory.json`,
1146
1077
  history_limit: 100
1147
1078
  },
1148
1079
  embedding: { provider: "local" },
1149
- deals: DealsConfigSchema.parse({
1150
- enabled: dealsEnabled,
1151
- buy_max_floor_percent: buyMaxFloorPercent,
1152
- sell_min_floor_percent: sellMinFloorPercent
1153
- }),
1080
+ deals: DealsConfigSchema.parse({ enabled: !!botToken }),
1154
1081
  webui: {
1155
1082
  enabled: false,
1156
1083
  port: 7777,
@@ -1175,9 +1102,19 @@ Get it at: ${providerMeta.consoleUrl}`,
1175
1102
  },
1176
1103
  logging: { level: "info", pretty: true },
1177
1104
  mcp: { servers: {} },
1105
+ capabilities: {
1106
+ exec: {
1107
+ mode: execMode,
1108
+ scope: "admin-only",
1109
+ allowlist: [],
1110
+ limits: { timeout: 120, max_output: 5e4 },
1111
+ audit: { log_commands: true }
1112
+ }
1113
+ },
1178
1114
  plugins: {},
1179
1115
  ...selectedProvider === "cocoon" ? { cocoon: { port: cocoonInstance } } : {},
1180
1116
  tonapi_key: tonapiKey,
1117
+ toncenter_api_key: toncenterApiKey,
1181
1118
  tavily_api_key: tavilyApiKey
1182
1119
  };
1183
1120
  spinner.start(DIM("Saving configuration..."));
@@ -1284,9 +1221,9 @@ async function runNonInteractiveOnboarding(options, prompter) {
1284
1221
  phone: options.phone,
1285
1222
  session_name: "teleton_session",
1286
1223
  session_path: workspace.sessionPath,
1287
- dm_policy: "open",
1224
+ dm_policy: "admin-only",
1288
1225
  allow_from: [],
1289
- group_policy: "open",
1226
+ group_policy: "admin-only",
1290
1227
  group_allow_from: [],
1291
1228
  require_mention: true,
1292
1229
  max_message_length: TELEGRAM_MAX_MESSAGE_LENGTH,
@@ -1302,7 +1239,6 @@ async function runNonInteractiveOnboarding(options, prompter) {
1302
1239
  },
1303
1240
  storage: {
1304
1241
  sessions_file: `${workspace.root}/sessions.json`,
1305
- pairing_file: `${workspace.root}/pairing.json`,
1306
1242
  memory_file: `${workspace.root}/memory.json`,
1307
1243
  history_limit: 100
1308
1244
  },
@@ -1331,6 +1267,15 @@ async function runNonInteractiveOnboarding(options, prompter) {
1331
1267
  skip_unlimited_providers: false
1332
1268
  },
1333
1269
  logging: { level: "info", pretty: true },
1270
+ capabilities: {
1271
+ exec: {
1272
+ mode: "off",
1273
+ scope: "admin-only",
1274
+ allowlist: [],
1275
+ limits: { timeout: 120, max_output: 5e4 },
1276
+ audit: { log_commands: true }
1277
+ }
1278
+ },
1334
1279
  mcp: { servers: {} },
1335
1280
  plugins: {},
1336
1281
  tavily_api_key: options.tavilyApiKey