teleton 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -3,23 +3,36 @@ import {
3
3
  ConfigSchema,
4
4
  DealsConfigSchema,
5
5
  MarketConfigSchema,
6
+ TelegramUserClient,
6
7
  configExists,
7
8
  ensureWorkspace,
8
9
  generateWallet,
9
10
  getDefaultConfigPath,
10
11
  getProviderMetadata,
11
12
  getSupportedProviders,
13
+ importWallet,
12
14
  isNewWorkspace,
15
+ loadWallet,
13
16
  main,
14
17
  saveWallet,
15
- validateApiKeyFormat
16
- } from "../chunk-WXVHT6CI.js";
18
+ validateApiKeyFormat,
19
+ walletExists
20
+ } from "../chunk-UQUYPDZJ.js";
17
21
  import "../chunk-XBGUNXF2.js";
18
- import "../chunk-WDUHRPGA.js";
22
+ import {
23
+ fetchWithTimeout
24
+ } from "../chunk-MPU2XS5H.js";
19
25
  import "../chunk-UR2LQEKR.js";
20
26
  import {
21
27
  TELETON_ROOT
22
28
  } from "../chunk-7NJ46ZIX.js";
29
+ import "../chunk-I6ZVPVLK.js";
30
+ import {
31
+ TELEGRAM_MAX_MESSAGE_LENGTH
32
+ } from "../chunk-5BEHAIBQ.js";
33
+ import {
34
+ ONBOARDING_PROMPT_TIMEOUT_MS
35
+ } from "../chunk-EBFMA7CL.js";
23
36
 
24
37
  // src/cli/index.ts
25
38
  import { Command } from "commander";
@@ -179,8 +192,9 @@ function createPrompter() {
179
192
  }
180
193
 
181
194
  // src/cli/commands/onboard.ts
182
- import { writeFileSync } from "fs";
195
+ import { writeFileSync, readFileSync, existsSync, chmodSync } from "fs";
183
196
  import { execSync } from "child_process";
197
+ import { join } from "path";
184
198
  import YAML from "yaml";
185
199
  async function onboardCommand(options = {}) {
186
200
  const prompter = createPrompter();
@@ -245,6 +259,18 @@ ${blue2} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25
245
259
  return;
246
260
  }
247
261
  }
262
+ const agentName = await prompter.text({
263
+ message: "Give your agent a name (optional)",
264
+ placeholder: "e.g. Nova, Kai, Echo..."
265
+ });
266
+ if (agentName && agentName.trim() && existsSync(workspace.identityPath)) {
267
+ const identity = readFileSync(workspace.identityPath, "utf-8");
268
+ const updated = identity.replace(
269
+ "[Ton nom - choisis-en un ou demande \xE0 ton humain]",
270
+ agentName.trim()
271
+ );
272
+ writeFileSync(workspace.identityPath, updated, "utf-8");
273
+ }
248
274
  const flow = await prompter.select({
249
275
  message: "Installation mode",
250
276
  options: [
@@ -253,6 +279,22 @@ ${blue2} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25
253
279
  ],
254
280
  initialValue: "quick"
255
281
  });
282
+ const enabledModules = await prompter.multiselect({
283
+ message: "Enable optional modules",
284
+ options: [
285
+ { value: "casino", label: "Casino", hint: "Slot machine & dice games with TON bets" },
286
+ { value: "deals", label: "Deals", hint: "Secure gift/TON trading with inline buttons" },
287
+ {
288
+ value: "market",
289
+ label: "Gifts Market Data",
290
+ hint: "Scrape gift floor prices (requires Chromium)"
291
+ }
292
+ ],
293
+ required: false
294
+ });
295
+ const casinoEnabled = enabledModules.includes("casino");
296
+ const dealsEnabled = enabledModules.includes("deals");
297
+ const marketEnabled = enabledModules.includes("market");
256
298
  const providers = getSupportedProviders();
257
299
  const selectedProvider = await prompter.select({
258
300
  message: "AI Provider",
@@ -276,22 +318,29 @@ some may be truncated.`,
276
318
  "You need Telegram credentials from https://my.telegram.org/apps\nCreate an application and note the API ID and API Hash",
277
319
  "Telegram"
278
320
  );
321
+ const envApiId = process.env.TELETON_TG_API_ID;
322
+ const envApiHash = process.env.TELETON_TG_API_HASH;
323
+ const envPhone = process.env.TELETON_TG_PHONE;
324
+ const envApiKey = process.env.TELETON_API_KEY;
279
325
  const apiIdStr = options.apiId ? options.apiId.toString() : await prompter.text({
280
- message: "API ID (from my.telegram.org)",
326
+ message: envApiId ? "API ID (from env)" : "API ID (from my.telegram.org)",
327
+ initialValue: envApiId,
281
328
  validate: (value) => {
282
329
  if (!value || isNaN(parseInt(value))) return "Invalid API ID (must be a number)";
283
330
  }
284
331
  });
285
332
  const apiId = parseInt(apiIdStr);
286
333
  const apiHash = options.apiHash ? options.apiHash : await prompter.text({
287
- message: "API Hash (from my.telegram.org)",
334
+ message: envApiHash ? "API Hash (from env)" : "API Hash (from my.telegram.org)",
335
+ initialValue: envApiHash,
288
336
  validate: (value) => {
289
337
  if (!value || value.length < 10) return "Invalid API Hash";
290
338
  }
291
339
  });
292
340
  const phone = options.phone ? options.phone : await prompter.text({
293
- message: "Phone number (international format, e.g. +1234567890)",
341
+ message: envPhone ? "Phone number (from env)" : "Phone number (international format, e.g. +1234567890)",
294
342
  placeholder: "+1234567890",
343
+ initialValue: envPhone,
295
344
  validate: (value) => {
296
345
  if (!value || !value.startsWith("+")) return "Invalid format (must start with +)";
297
346
  }
@@ -312,19 +361,100 @@ some may be truncated.`,
312
361
  Get it at: ${providerMeta.consoleUrl}`,
313
362
  "API Key"
314
363
  );
315
- const apiKey = options.apiKey ? options.apiKey : await prompter.password({
316
- message: `${providerMeta.displayName} API Key (${providerMeta.keyHint})`,
317
- validate: (value) => validateApiKeyFormat(selectedProvider, value)
318
- });
364
+ let apiKey;
365
+ if (options.apiKey) {
366
+ apiKey = options.apiKey;
367
+ } else if (envApiKey) {
368
+ const validationError = validateApiKeyFormat(selectedProvider, envApiKey);
369
+ if (validationError) {
370
+ prompter.warn(`TELETON_API_KEY env var found but invalid: ${validationError}`);
371
+ apiKey = await prompter.password({
372
+ message: `${providerMeta.displayName} API Key (${providerMeta.keyHint})`,
373
+ validate: (value) => validateApiKeyFormat(selectedProvider, value)
374
+ });
375
+ } else {
376
+ prompter.log(`Using API key from TELETON_API_KEY env var`);
377
+ apiKey = envApiKey;
378
+ }
379
+ } else {
380
+ apiKey = await prompter.password({
381
+ message: `${providerMeta.displayName} API Key (${providerMeta.keyHint})`,
382
+ validate: (value) => validateApiKeyFormat(selectedProvider, value)
383
+ });
384
+ }
385
+ const MODEL_OPTIONS = {
386
+ anthropic: [
387
+ { value: "claude-opus-4-5-20251101", label: "Claude Opus 4.5", hint: "Most capable, $5/M" },
388
+ { value: "claude-sonnet-4-0", label: "Claude Sonnet 4", hint: "Balanced, $3/M" },
389
+ { value: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5", hint: "Fast & cheap, $1/M" },
390
+ { value: "claude-3-5-haiku-20241022", label: "Claude 3.5 Haiku", hint: "Cheapest, $0.80/M" }
391
+ ],
392
+ openai: [
393
+ { value: "gpt-5", label: "GPT-5", hint: "Most capable, 400K ctx, $1.25/M" },
394
+ { value: "gpt-4o", label: "GPT-4o", hint: "Balanced, 128K ctx, $2.50/M" },
395
+ { value: "gpt-4.1", label: "GPT-4.1", hint: "1M ctx, $2/M" },
396
+ { value: "gpt-4.1-mini", label: "GPT-4.1 Mini", hint: "1M ctx, cheap, $0.40/M" },
397
+ { value: "o3", label: "o3", hint: "Reasoning, 200K ctx, $2/M" }
398
+ ],
399
+ google: [
400
+ { value: "gemini-2.5-flash", label: "Gemini 2.5 Flash", hint: "Fast, 1M ctx, $0.30/M" },
401
+ { value: "gemini-2.5-pro", label: "Gemini 2.5 Pro", hint: "Most capable, 1M ctx, $1.25/M" },
402
+ { value: "gemini-2.0-flash", label: "Gemini 2.0 Flash", hint: "Cheap, 1M ctx, $0.10/M" }
403
+ ],
404
+ xai: [
405
+ { value: "grok-4-fast", label: "Grok 4 Fast", hint: "Vision, 2M ctx, $0.20/M" },
406
+ { value: "grok-4", label: "Grok 4", hint: "Reasoning, 256K ctx, $3/M" },
407
+ { value: "grok-3", label: "Grok 3", hint: "Stable, 131K ctx, $3/M" }
408
+ ],
409
+ groq: [
410
+ {
411
+ value: "meta-llama/llama-4-maverick-17b-128e-instruct",
412
+ label: "Llama 4 Maverick",
413
+ hint: "Vision, 131K ctx, $0.20/M"
414
+ },
415
+ { value: "qwen/qwen3-32b", label: "Qwen3 32B", hint: "Reasoning, 131K ctx, $0.29/M" },
416
+ {
417
+ value: "deepseek-r1-distill-llama-70b",
418
+ label: "DeepSeek R1 70B",
419
+ hint: "Reasoning, 131K ctx, $0.75/M"
420
+ },
421
+ {
422
+ value: "llama-3.3-70b-versatile",
423
+ label: "Llama 3.3 70B",
424
+ hint: "General purpose, 131K ctx, $0.59/M"
425
+ }
426
+ ],
427
+ openrouter: [
428
+ { value: "anthropic/claude-opus-4.5", label: "Claude Opus 4.5", hint: "200K ctx, $5/M" },
429
+ { value: "openai/gpt-5", label: "GPT-5", hint: "400K ctx, $1.25/M" },
430
+ { value: "google/gemini-2.5-flash", label: "Gemini 2.5 Flash", hint: "1M ctx, $0.30/M" },
431
+ { value: "deepseek/deepseek-r1", label: "DeepSeek R1", hint: "Reasoning, 64K ctx, $0.70/M" },
432
+ { value: "x-ai/grok-4", label: "Grok 4", hint: "256K ctx, $3/M" }
433
+ ]
434
+ };
319
435
  let selectedModel = providerMeta.defaultModel;
320
436
  if (flow === "advanced") {
321
- const customModel = await prompter.text({
322
- message: `Model ID (default: ${providerMeta.defaultModel})`,
323
- placeholder: providerMeta.defaultModel,
437
+ const providerModels = MODEL_OPTIONS[selectedProvider] || [];
438
+ const modelOptions = [
439
+ ...providerModels,
440
+ { value: "__custom__", label: "Custom", hint: "Enter a model ID manually" }
441
+ ];
442
+ const modelChoice = await prompter.select({
443
+ message: "Model",
444
+ options: modelOptions,
324
445
  initialValue: providerMeta.defaultModel
325
446
  });
326
- if (customModel && customModel.trim()) {
327
- selectedModel = customModel.trim();
447
+ if (modelChoice === "__custom__") {
448
+ const customModel = await prompter.text({
449
+ message: "Model ID",
450
+ placeholder: providerMeta.defaultModel,
451
+ initialValue: providerMeta.defaultModel
452
+ });
453
+ if (customModel && customModel.trim()) {
454
+ selectedModel = customModel.trim();
455
+ }
456
+ } else {
457
+ selectedModel = modelChoice;
328
458
  }
329
459
  }
330
460
  let dmPolicy = "open";
@@ -354,6 +484,46 @@ Get it at: ${providerMeta.consoleUrl}`,
354
484
  initialValue: true
355
485
  });
356
486
  }
487
+ let botToken;
488
+ let botUsername;
489
+ const setupBot = dealsEnabled ? await prompter.confirm({
490
+ message: "Set up a Telegram bot for deal confirmations? (inline buttons)",
491
+ initialValue: true
492
+ }) : false;
493
+ if (setupBot) {
494
+ prompter.note(
495
+ "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",
496
+ "Deals Bot"
497
+ );
498
+ const tokenInput = await prompter.password({
499
+ message: "Bot token (from @BotFather)",
500
+ validate: (value) => {
501
+ if (!value || !value.includes(":")) return "Invalid bot token format (expected id:hash)";
502
+ }
503
+ });
504
+ spinner2.start("Validating bot token...");
505
+ try {
506
+ const res = await fetchWithTimeout(`https://api.telegram.org/bot${tokenInput}/getMe`);
507
+ const data = await res.json();
508
+ if (!data.ok) {
509
+ spinner2.stop("\u26A0 Bot token is invalid - skipping bot setup");
510
+ } else {
511
+ botToken = tokenInput;
512
+ botUsername = data.result.username;
513
+ spinner2.stop(`\u2713 Bot verified: @${botUsername}`);
514
+ }
515
+ } catch {
516
+ spinner2.stop("\u26A0 Could not validate bot token (network error) - saving anyway");
517
+ botToken = tokenInput;
518
+ const usernameInput = await prompter.text({
519
+ message: "Bot username (without @)",
520
+ validate: (value) => {
521
+ if (!value || value.length < 3) return "Username too short";
522
+ }
523
+ });
524
+ botUsername = usernameInput;
525
+ }
526
+ }
357
527
  const config = {
358
528
  meta: {
359
529
  version: "1.0.0",
@@ -386,15 +556,16 @@ Get it at: ${providerMeta.consoleUrl}`,
386
556
  group_policy: groupPolicy,
387
557
  group_allow_from: [],
388
558
  require_mention: requireMention,
389
- max_message_length: 4096,
559
+ max_message_length: TELEGRAM_MAX_MESSAGE_LENGTH,
390
560
  typing_simulation: true,
391
561
  rate_limit_messages_per_second: 1,
392
562
  rate_limit_groups_per_minute: 20,
393
563
  admin_ids: [userId],
564
+ owner_id: userId,
394
565
  agent_channel: null,
395
566
  debounce_ms: 1500,
396
- bot_token: "YOUR_BOT_TOKEN_FROM_BOTFATHER",
397
- bot_username: "your_deals_bot"
567
+ bot_token: botToken,
568
+ bot_username: botUsername
398
569
  },
399
570
  storage: {
400
571
  sessions_file: `${workspace.root}/sessions.json`,
@@ -402,50 +573,125 @@ Get it at: ${providerMeta.consoleUrl}`,
402
573
  memory_file: `${workspace.root}/memory.json`,
403
574
  history_limit: 100
404
575
  },
405
- casino: CasinoConfigSchema.parse({}),
406
- deals: DealsConfigSchema.parse({}),
407
- market: MarketConfigSchema.parse({})
576
+ casino: CasinoConfigSchema.parse({ enabled: casinoEnabled }),
577
+ deals: DealsConfigSchema.parse({ enabled: dealsEnabled }),
578
+ market: MarketConfigSchema.parse({ enabled: marketEnabled })
408
579
  };
409
580
  spinner2.start("Saving configuration...");
410
581
  const configYaml = YAML.stringify(config);
411
582
  writeFileSync(workspace.configPath, configYaml, "utf-8");
583
+ chmodSync(workspace.configPath, 384);
412
584
  spinner2.stop("\u2713 Configuration saved");
413
- spinner2.start("Generating TON wallet...");
414
- const wallet = await generateWallet();
415
- saveWallet(wallet);
416
- spinner2.stop("\u2713 TON wallet generated");
417
- spinner2.start("Installing browser for market data...");
418
- try {
419
- execSync("npx playwright install chromium", {
420
- stdio: "pipe",
421
- timeout: 12e4
422
- // 2 minutes timeout
585
+ let wallet;
586
+ const existingWallet = walletExists() ? loadWallet() : null;
587
+ if (existingWallet) {
588
+ prompter.note(`Existing wallet found: ${existingWallet.address}`, "TON Wallet");
589
+ const walletAction = await prompter.select({
590
+ message: "A TON wallet already exists. What do you want to do?",
591
+ options: [
592
+ { value: "keep", label: "Keep existing", hint: `${existingWallet.address}` },
593
+ { value: "regenerate", label: "Generate new", hint: "WARNING: old wallet will be lost" },
594
+ { value: "import", label: "Import mnemonic", hint: "Restore from 24-word seed" }
595
+ ],
596
+ initialValue: "keep"
423
597
  });
424
- spinner2.stop("\u2713 Browser installed");
425
- } catch (err) {
426
- spinner2.stop(
427
- "\u26A0 Browser install failed (can be done later with: npx playwright install chromium)"
598
+ if (walletAction === "keep") {
599
+ wallet = existingWallet;
600
+ } else if (walletAction === "import") {
601
+ const mnemonicInput = await prompter.text({
602
+ message: "Enter your 24-word mnemonic (space-separated)",
603
+ validate: (value) => {
604
+ const words = value.trim().split(/\s+/);
605
+ if (words.length !== 24) return `Expected 24 words, got ${words.length}`;
606
+ }
607
+ });
608
+ spinner2.start("Importing wallet...");
609
+ wallet = await importWallet(mnemonicInput.trim().split(/\s+/));
610
+ saveWallet(wallet);
611
+ spinner2.stop(`\u2713 Wallet imported: ${wallet.address}`);
612
+ } else {
613
+ spinner2.start("Generating new TON wallet...");
614
+ wallet = await generateWallet();
615
+ saveWallet(wallet);
616
+ spinner2.stop("\u2713 New TON wallet generated");
617
+ }
618
+ } else {
619
+ spinner2.start("Generating TON wallet...");
620
+ wallet = await generateWallet();
621
+ saveWallet(wallet);
622
+ spinner2.stop("\u2713 TON wallet generated");
623
+ }
624
+ if (marketEnabled) {
625
+ spinner2.start("Installing browser for market data...");
626
+ try {
627
+ execSync("npx playwright install chromium", {
628
+ stdio: "pipe",
629
+ timeout: ONBOARDING_PROMPT_TIMEOUT_MS
630
+ });
631
+ spinner2.stop("\u2713 Browser installed");
632
+ } catch {
633
+ spinner2.stop(
634
+ "\u26A0 Browser install failed (can be done later with: npx playwright install chromium)"
635
+ );
636
+ }
637
+ }
638
+ if (!existingWallet || wallet !== existingWallet) {
639
+ prompter.note(
640
+ "BACKUP REQUIRED - WRITE DOWN THESE 24 WORDS:\n\n" + wallet.mnemonic.join(" ") + "\n\nThese words allow you to recover your wallet.\nWithout them, you will lose access to your TON.\nWrite them on paper and keep them safe.",
641
+ "Mnemonic Seed (24 words)"
428
642
  );
429
643
  }
430
- prompter.note(
431
- "BACKUP REQUIRED - WRITE DOWN THESE 24 WORDS:\n\n" + wallet.mnemonic.join(" ") + "\n\nThese words allow you to recover your wallet.\nWithout them, you will lose access to your TON.\nWrite them on paper and keep them safe.",
432
- "Mnemonic Seed (24 words)"
433
- );
644
+ let telegramConnected = false;
645
+ const connectNow = await prompter.confirm({
646
+ message: "Connect to Telegram now? (you'll need the verification code sent to your phone)",
647
+ initialValue: true
648
+ });
649
+ if (connectNow) {
650
+ prompter.log("Connecting to Telegram... Check your phone for the verification code.");
651
+ try {
652
+ const sessionPath = join(TELETON_ROOT, "telegram_session.txt");
653
+ const client = new TelegramUserClient({
654
+ apiId,
655
+ apiHash,
656
+ phone,
657
+ sessionPath
658
+ });
659
+ await client.connect();
660
+ const me = client.getMe();
661
+ await client.disconnect();
662
+ telegramConnected = true;
663
+ prompter.success(
664
+ `\u2713 Telegram connected as ${me?.firstName || ""}${me?.username ? ` (@${me.username})` : ""}`
665
+ );
666
+ } catch (err) {
667
+ prompter.warn(
668
+ `Telegram connection failed: ${err instanceof Error ? err.message : String(err)}
669
+ You can authenticate later when running: teleton start`
670
+ );
671
+ }
672
+ }
434
673
  prompter.note(
435
674
  `Workspace: ${workspace.root}
436
675
  Config: ${workspace.configPath}
437
676
  Templates: SOUL.md, MEMORY.md, IDENTITY.md, USER.md
438
- Telegram: ${phone} (API ID: ${apiId})
677
+ Telegram: ${phone} (API ID: ${apiId})${telegramConnected ? " \u2713 connected" : ""}
439
678
  Admin: User ID ${userId}
440
679
  Provider: ${providerMeta.displayName}
441
680
  Model: ${selectedModel}
442
681
  TON Wallet: ${wallet.address}`,
443
682
  "Setup complete"
444
683
  );
445
- prompter.note(
446
- "Next steps:\n\n1. Start the agent:\n $ teleton start\n\n2. On first launch, you will be asked for:\n - Telegram verification code\n - 2FA password (if enabled)\n\n3. Send a message to your Telegram account to test",
447
- "Ready"
448
- );
684
+ if (telegramConnected) {
685
+ prompter.note(
686
+ "Next steps:\n\n1. Start the agent:\n $ teleton start\n\n2. Send a message to your Telegram account to test",
687
+ "Ready"
688
+ );
689
+ } else {
690
+ prompter.note(
691
+ "Next steps:\n\n1. Start the agent:\n $ teleton start\n\n2. On first launch, you will be asked for:\n - Telegram verification code\n - 2FA password (if enabled)\n\n3. Send a message to your Telegram account to test",
692
+ "Ready"
693
+ );
694
+ }
449
695
  prompter.outro("Good luck!");
450
696
  }
451
697
  async function runNonInteractiveOnboarding(options, prompter) {
@@ -493,15 +739,16 @@ async function runNonInteractiveOnboarding(options, prompter) {
493
739
  group_policy: "open",
494
740
  group_allow_from: [],
495
741
  require_mention: true,
496
- max_message_length: 4096,
742
+ max_message_length: TELEGRAM_MAX_MESSAGE_LENGTH,
497
743
  typing_simulation: true,
498
744
  rate_limit_messages_per_second: 1,
499
745
  rate_limit_groups_per_minute: 20,
500
746
  admin_ids: [options.userId],
747
+ owner_id: options.userId,
501
748
  agent_channel: null,
502
749
  debounce_ms: 1500,
503
- bot_token: "YOUR_BOT_TOKEN_FROM_BOTFATHER",
504
- bot_username: "your_deals_bot"
750
+ bot_token: void 0,
751
+ bot_username: void 0
505
752
  },
506
753
  storage: {
507
754
  sessions_file: `${workspace.root}/sessions.json`,
@@ -515,12 +762,13 @@ async function runNonInteractiveOnboarding(options, prompter) {
515
762
  };
516
763
  const configYaml = YAML.stringify(config);
517
764
  writeFileSync(workspace.configPath, configYaml, "utf-8");
765
+ chmodSync(workspace.configPath, 384);
518
766
  prompter.success(`\u2713 Configuration created: ${workspace.configPath}`);
519
767
  }
520
768
 
521
769
  // src/cli/commands/doctor.ts
522
- import { existsSync, readFileSync, statSync } from "fs";
523
- import { join } from "path";
770
+ import { existsSync as existsSync2, readFileSync as readFileSync2, statSync } from "fs";
771
+ import { join as join2 } from "path";
524
772
  import { homedir } from "os";
525
773
  import { parse } from "yaml";
526
774
  var green = "\x1B[32m";
@@ -533,8 +781,8 @@ function formatResult(result) {
533
781
  return `${icon} ${result.name}: ${result.message}`;
534
782
  }
535
783
  async function checkConfig(workspaceDir) {
536
- const configPath = join(workspaceDir, "config.yaml");
537
- if (!existsSync(configPath)) {
784
+ const configPath = join2(workspaceDir, "config.yaml");
785
+ if (!existsSync2(configPath)) {
538
786
  return {
539
787
  name: "Config file",
540
788
  status: "error",
@@ -542,7 +790,7 @@ async function checkConfig(workspaceDir) {
542
790
  };
543
791
  }
544
792
  try {
545
- const content = readFileSync(configPath, "utf-8");
793
+ const content = readFileSync2(configPath, "utf-8");
546
794
  const raw = parse(content);
547
795
  const result = ConfigSchema.safeParse(raw);
548
796
  if (!result.success) {
@@ -566,8 +814,8 @@ async function checkConfig(workspaceDir) {
566
814
  }
567
815
  }
568
816
  async function checkTelegramCredentials(workspaceDir) {
569
- const configPath = join(workspaceDir, "config.yaml");
570
- if (!existsSync(configPath)) {
817
+ const configPath = join2(workspaceDir, "config.yaml");
818
+ if (!existsSync2(configPath)) {
571
819
  return {
572
820
  name: "Telegram credentials",
573
821
  status: "error",
@@ -575,7 +823,7 @@ async function checkTelegramCredentials(workspaceDir) {
575
823
  };
576
824
  }
577
825
  try {
578
- const content = readFileSync(configPath, "utf-8");
826
+ const content = readFileSync2(configPath, "utf-8");
579
827
  const config = parse(content);
580
828
  if (!config.telegram?.api_id || !config.telegram?.api_hash) {
581
829
  return {
@@ -605,8 +853,8 @@ async function checkTelegramCredentials(workspaceDir) {
605
853
  }
606
854
  }
607
855
  async function checkApiKey(workspaceDir) {
608
- const configPath = join(workspaceDir, "config.yaml");
609
- if (!existsSync(configPath)) {
856
+ const configPath = join2(workspaceDir, "config.yaml");
857
+ if (!existsSync2(configPath)) {
610
858
  return {
611
859
  name: "API key",
612
860
  status: "error",
@@ -614,7 +862,7 @@ async function checkApiKey(workspaceDir) {
614
862
  };
615
863
  }
616
864
  try {
617
- const content = readFileSync(configPath, "utf-8");
865
+ const content = readFileSync2(configPath, "utf-8");
618
866
  const config = parse(content);
619
867
  const provider = config.agent?.provider || "anthropic";
620
868
  const apiKey = config.agent?.api_key;
@@ -659,8 +907,8 @@ async function checkApiKey(workspaceDir) {
659
907
  }
660
908
  }
661
909
  async function checkWallet(workspaceDir) {
662
- const walletPath = join(workspaceDir, "wallet.json");
663
- if (!existsSync(walletPath)) {
910
+ const walletPath = join2(workspaceDir, "wallet.json");
911
+ if (!existsSync2(walletPath)) {
664
912
  return {
665
913
  name: "TON wallet",
666
914
  status: "warn",
@@ -668,7 +916,7 @@ async function checkWallet(workspaceDir) {
668
916
  };
669
917
  }
670
918
  try {
671
- const content = readFileSync(walletPath, "utf-8");
919
+ const content = readFileSync2(walletPath, "utf-8");
672
920
  const wallet = JSON.parse(content);
673
921
  if (!wallet.address) {
674
922
  return {
@@ -692,8 +940,8 @@ async function checkWallet(workspaceDir) {
692
940
  }
693
941
  }
694
942
  async function checkSoul(workspaceDir) {
695
- const soulPath = join(workspaceDir, "SOUL.md");
696
- if (!existsSync(soulPath)) {
943
+ const soulPath = join2(workspaceDir, "SOUL.md");
944
+ if (!existsSync2(soulPath)) {
697
945
  return {
698
946
  name: "SOUL.md",
699
947
  status: "warn",
@@ -717,8 +965,8 @@ async function checkSoul(workspaceDir) {
717
965
  }
718
966
  }
719
967
  async function checkDatabase(workspaceDir) {
720
- const dbPath = join(workspaceDir, "memory.db");
721
- if (!existsSync(dbPath)) {
968
+ const dbPath = join2(workspaceDir, "memory.db");
969
+ if (!existsSync2(dbPath)) {
722
970
  return {
723
971
  name: "Memory database",
724
972
  status: "warn",
@@ -742,8 +990,8 @@ async function checkDatabase(workspaceDir) {
742
990
  }
743
991
  }
744
992
  async function checkTelegramSession(workspaceDir) {
745
- const sessionPath = join(workspaceDir, "telegram_session.txt");
746
- if (!existsSync(sessionPath)) {
993
+ const sessionPath = join2(workspaceDir, "telegram_session.txt");
994
+ if (!existsSync2(sessionPath)) {
747
995
  return {
748
996
  name: "Telegram session",
749
997
  status: "warn",
@@ -775,8 +1023,8 @@ async function checkTelegramSession(workspaceDir) {
775
1023
  }
776
1024
  }
777
1025
  async function checkMarketData(workspaceDir) {
778
- const dbPath = join(workspaceDir, "gifts.db");
779
- if (!existsSync(dbPath)) {
1026
+ const dbPath = join2(workspaceDir, "gifts.db");
1027
+ if (!existsSync2(dbPath)) {
780
1028
  return {
781
1029
  name: "Gift market data",
782
1030
  status: "warn",
@@ -830,8 +1078,8 @@ async function checkMarketData(workspaceDir) {
830
1078
  }
831
1079
  }
832
1080
  async function checkModel(workspaceDir) {
833
- const configPath = join(workspaceDir, "config.yaml");
834
- if (!existsSync(configPath)) {
1081
+ const configPath = join2(workspaceDir, "config.yaml");
1082
+ if (!existsSync2(configPath)) {
835
1083
  return {
836
1084
  name: "AI Model",
837
1085
  status: "error",
@@ -839,7 +1087,7 @@ async function checkModel(workspaceDir) {
839
1087
  };
840
1088
  }
841
1089
  try {
842
- const content = readFileSync(configPath, "utf-8");
1090
+ const content = readFileSync2(configPath, "utf-8");
843
1091
  const config = parse(content);
844
1092
  const provider = config.agent?.provider || "anthropic";
845
1093
  let model = config.agent?.model;
@@ -864,8 +1112,8 @@ async function checkModel(workspaceDir) {
864
1112
  }
865
1113
  }
866
1114
  async function checkAdmins(workspaceDir) {
867
- const configPath = join(workspaceDir, "config.yaml");
868
- if (!existsSync(configPath)) {
1115
+ const configPath = join2(workspaceDir, "config.yaml");
1116
+ if (!existsSync2(configPath)) {
869
1117
  return {
870
1118
  name: "Admin users",
871
1119
  status: "error",
@@ -873,7 +1121,7 @@ async function checkAdmins(workspaceDir) {
873
1121
  };
874
1122
  }
875
1123
  try {
876
- const content = readFileSync(configPath, "utf-8");
1124
+ const content = readFileSync2(configPath, "utf-8");
877
1125
  const config = parse(content);
878
1126
  const admins = config.telegram?.admin_ids || [];
879
1127
  if (admins.length === 0) {
@@ -915,14 +1163,14 @@ async function checkNodeVersion() {
915
1163
  async function checkPlaywrightBrowser() {
916
1164
  const homeDir = homedir();
917
1165
  const browserPaths = [
918
- join(homeDir, ".cache", "ms-playwright", "chromium-*"),
919
- join(homeDir, ".cache", "ms-playwright"),
920
- join(homeDir, "Library", "Caches", "ms-playwright"),
921
- join(homeDir, "AppData", "Local", "ms-playwright")
1166
+ join2(homeDir, ".cache", "ms-playwright", "chromium-*"),
1167
+ join2(homeDir, ".cache", "ms-playwright"),
1168
+ join2(homeDir, "Library", "Caches", "ms-playwright"),
1169
+ join2(homeDir, "AppData", "Local", "ms-playwright")
922
1170
  ];
923
1171
  for (const basePath of browserPaths) {
924
1172
  const checkPath = basePath.replace("/chromium-*", "");
925
- if (existsSync(checkPath)) {
1173
+ if (existsSync2(checkPath)) {
926
1174
  try {
927
1175
  const { readdirSync } = await import("fs");
928
1176
  const contents = readdirSync(checkPath);
@@ -994,15 +1242,15 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
994
1242
  }
995
1243
 
996
1244
  // src/cli/index.ts
997
- import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
998
- import { dirname, join as join2 } from "path";
1245
+ import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
1246
+ import { dirname, join as join3 } from "path";
999
1247
  import { fileURLToPath } from "url";
1000
1248
  function findPackageJson() {
1001
1249
  let dir = dirname(fileURLToPath(import.meta.url));
1002
1250
  for (let i = 0; i < 10; i++) {
1003
- const candidate = join2(dir, "package.json");
1004
- if (existsSync2(candidate)) {
1005
- return JSON.parse(readFileSync2(candidate, "utf-8"));
1251
+ const candidate = join3(dir, "package.json");
1252
+ if (existsSync3(candidate)) {
1253
+ return JSON.parse(readFileSync3(candidate, "utf-8"));
1006
1254
  }
1007
1255
  dir = dirname(dir);
1008
1256
  }