Fix HOME volume mount, genericize topic, add progress statuses, extract lexicon

- Volume was mounted at ~/.claude only, but claude-code writes auth to
  ~/.claude.json too — that file lived on the ephemeral container layer and
  was lost on every recreate. Now the whole $HOME is on the named volume,
  and claude-config moved outside HOME (/app) so it isn't shadowed by it.
- Default /news topic was hardcoded to AI; now it's a configurable
  DEFAULT_TOPIC (plain "главные новости дня"), topic is fully free-form.
- Prompt now instructs Claude to send interim " ..." progress updates via
  send_to_telegram while researching, not just the final digest — a bare
  request like "call this tool" was already taking 3+ minutes end-to-end,
  so silence read as broken.
- All user-facing/prompt text moved into bot/lib/lexicon.dart.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 21:53:38 +03:00
parent cb2041fc56
commit 7bfe0dfe0c
8 changed files with 93 additions and 52 deletions

View File

@@ -3,6 +3,7 @@ import 'dart:io';
import '../lib/config.dart';
import '../lib/telegram.dart';
import '../lib/claude_runner.dart';
import '../lib/lexicon.dart';
void main() async {
final config = Config.fromEnv();
@@ -41,12 +42,10 @@ void main() async {
continue;
}
stderr.writeln('[$chatId] $text');
if (text == '/start') {
await telegram.sendMessage(
chatId,
'Привет! Я agent-news. Команда /news — свежая выжимка по ИИ '
'(ресёрч делает Claude Code, займёт 1-3 минуты).',
);
await telegram.sendMessage(chatId, Lexicon.welcome);
continue;
}
@@ -54,17 +53,13 @@ void main() async {
final topic = text.startsWith('/news ') ? text.substring(6).trim() : null;
if (claude.isBusy) {
await telegram.sendMessage(chatId, 'Уже выполняю другой запрос, подожди.',
replyToMessageId: messageId);
await telegram.sendMessage(chatId, Lexicon.alreadyBusy, replyToMessageId: messageId);
continue;
}
await telegram.sendMessage(
chatId,
'🔎 Ищу свежую информацию${topic != null ? ' по теме «$topic»' : ' по ИИ'}, '
'это займёт пару минут…',
replyToMessageId: messageId,
);
final effectiveTopic = (topic == null || topic.isEmpty) ? config.defaultTopic : topic;
await telegram.sendMessage(chatId, Lexicon.starting(effectiveTopic),
replyToMessageId: messageId);
await telegram.sendTyping(chatId);
unawaited(_runNews(claude, telegram, chatId, topic));
@@ -88,11 +83,12 @@ Future<void> _runNews(
case ClaudeOutcome.busy:
break; // уже сообщили выше
case ClaudeOutcome.timeout:
await telegram.sendMessage(chatId, 'Не успел уложиться по времени, попробуй позже.');
stderr.writeln('news for $chatId timed out');
await telegram.sendMessage(chatId, Lexicon.timedOut);
break;
case ClaudeOutcome.failure:
stderr.writeln('news for $chatId failed: ${result.detail}');
await telegram.sendMessage(chatId, 'Не получилось выполнить ресёрч, попробуй позже.');
await telegram.sendMessage(chatId, Lexicon.failed);
break;
}
}