alvin-bot 4.4.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.
Files changed (136) hide show
  1. package/.env.example +43 -0
  2. package/BACKLOG.md +223 -0
  3. package/CHANGELOG.md +63 -0
  4. package/CLAUDE.example.md +152 -0
  5. package/CODE_OF_CONDUCT.md +52 -0
  6. package/CONTRIBUTING.md +72 -0
  7. package/LICENSE +21 -0
  8. package/README.md +529 -0
  9. package/SECURITY.md +38 -0
  10. package/SOUL.example.md +60 -0
  11. package/TOOLS.example.md +42 -0
  12. package/alvin-bot.config.example.json +24 -0
  13. package/bin/cli.js +1088 -0
  14. package/dist/.metadata_never_index +0 -0
  15. package/dist/claude.js +102 -0
  16. package/dist/config.js +65 -0
  17. package/dist/engine.js +90 -0
  18. package/dist/find-claude-binary.js +98 -0
  19. package/dist/handlers/commands.js +1489 -0
  20. package/dist/handlers/document.js +187 -0
  21. package/dist/handlers/message.js +200 -0
  22. package/dist/handlers/photo.js +154 -0
  23. package/dist/handlers/platform-message.js +275 -0
  24. package/dist/handlers/video.js +237 -0
  25. package/dist/handlers/voice.js +148 -0
  26. package/dist/i18n.js +299 -0
  27. package/dist/index.js +442 -0
  28. package/dist/init-data-dir.js +81 -0
  29. package/dist/middleware/auth.js +215 -0
  30. package/dist/migrate.js +139 -0
  31. package/dist/paths.js +87 -0
  32. package/dist/platforms/discord.js +161 -0
  33. package/dist/platforms/index.js +130 -0
  34. package/dist/platforms/signal.js +205 -0
  35. package/dist/platforms/slack.js +318 -0
  36. package/dist/platforms/telegram.js +111 -0
  37. package/dist/platforms/types.js +8 -0
  38. package/dist/platforms/whatsapp.js +648 -0
  39. package/dist/providers/claude-sdk-provider.js +173 -0
  40. package/dist/providers/codex-cli-provider.js +121 -0
  41. package/dist/providers/index.js +7 -0
  42. package/dist/providers/openai-compatible.js +388 -0
  43. package/dist/providers/registry.js +209 -0
  44. package/dist/providers/tool-executor.js +450 -0
  45. package/dist/providers/types.js +205 -0
  46. package/dist/services/access.js +144 -0
  47. package/dist/services/asset-index.js +230 -0
  48. package/dist/services/browser-manager.js +161 -0
  49. package/dist/services/browser.js +121 -0
  50. package/dist/services/compaction.js +129 -0
  51. package/dist/services/cron.js +462 -0
  52. package/dist/services/custom-tools.js +317 -0
  53. package/dist/services/delivery-queue.js +154 -0
  54. package/dist/services/elevenlabs.js +58 -0
  55. package/dist/services/embeddings.js +386 -0
  56. package/dist/services/exec-guard.js +46 -0
  57. package/dist/services/fallback-order.js +151 -0
  58. package/dist/services/heartbeat.js +192 -0
  59. package/dist/services/hooks.js +44 -0
  60. package/dist/services/imagegen.js +72 -0
  61. package/dist/services/language-detect.js +144 -0
  62. package/dist/services/markdown.js +63 -0
  63. package/dist/services/mcp.js +252 -0
  64. package/dist/services/memory.js +133 -0
  65. package/dist/services/personality.js +227 -0
  66. package/dist/services/plugins.js +171 -0
  67. package/dist/services/reminders.js +97 -0
  68. package/dist/services/restart.js +48 -0
  69. package/dist/services/security-audit.js +66 -0
  70. package/dist/services/self-search.js +129 -0
  71. package/dist/services/session.js +93 -0
  72. package/dist/services/skills.js +287 -0
  73. package/dist/services/standing-orders.js +29 -0
  74. package/dist/services/subagents.js +142 -0
  75. package/dist/services/sudo.js +243 -0
  76. package/dist/services/telegram.js +113 -0
  77. package/dist/services/tool-discovery.js +214 -0
  78. package/dist/services/usage-tracker.js +137 -0
  79. package/dist/services/users.js +199 -0
  80. package/dist/services/voice.js +95 -0
  81. package/dist/tui/index.js +507 -0
  82. package/dist/web/canvas.js +30 -0
  83. package/dist/web/doctor-api.js +606 -0
  84. package/dist/web/openai-compat.js +252 -0
  85. package/dist/web/server.js +1351 -0
  86. package/dist/web/setup-api.js +1078 -0
  87. package/docs/mcp.example.json +16 -0
  88. package/docs/screenshots/00-Login.png +0 -0
  89. package/docs/screenshots/01-Chat-Dark-Conversation.png +0 -0
  90. package/docs/screenshots/02-Chat.png +0 -0
  91. package/docs/screenshots/03-Dashboard-Overview.png +0 -0
  92. package/docs/screenshots/04-AI-Models-and-Providers.png +0 -0
  93. package/docs/screenshots/05-Personality-Editor.png +0 -0
  94. package/docs/screenshots/06-Memory-Manager.png +0 -0
  95. package/docs/screenshots/07-Active-Sessions.png +0 -0
  96. package/docs/screenshots/08-File-Browser.png +0 -0
  97. package/docs/screenshots/09-Scheduled-Jobs.png +0 -0
  98. package/docs/screenshots/10-Custom-Tools.png +0 -0
  99. package/docs/screenshots/11-Plugins-and-MCP.png +0 -0
  100. package/docs/screenshots/12-Messaging-Platforms.png +0 -0
  101. package/docs/screenshots/12.1-Messaging-Platforms-WhatsApp-Groups-List.png +0 -0
  102. package/docs/screenshots/12.2-Messaging-Platforms-WA-Group-Details.png +0 -0
  103. package/docs/screenshots/13-User-Management.png +0 -0
  104. package/docs/screenshots/14-Web-Terminal.png +0 -0
  105. package/docs/screenshots/15-Maintenance-and-Health.png +0 -0
  106. package/docs/screenshots/16-Settings-and-Env.png +0 -0
  107. package/docs/screenshots/TG-commands.png +0 -0
  108. package/docs/screenshots/TG.png +0 -0
  109. package/docs/screenshots/_Mac-Installer.png +0 -0
  110. package/docs/tools.example.json +33 -0
  111. package/install.sh +165 -0
  112. package/package.json +190 -0
  113. package/plugins/calendar/index.js +270 -0
  114. package/plugins/email/index.js +231 -0
  115. package/plugins/finance/index.js +254 -0
  116. package/plugins/notes/index.js +227 -0
  117. package/plugins/smarthome/index.js +230 -0
  118. package/plugins/weather/index.js +122 -0
  119. package/skills/apple-notes/SKILL.md +31 -0
  120. package/skills/browse/SKILL.md +136 -0
  121. package/skills/code-project/SKILL.md +43 -0
  122. package/skills/data-analysis/SKILL.md +39 -0
  123. package/skills/document-creation/SKILL.md +48 -0
  124. package/skills/email-summary/SKILL.md +46 -0
  125. package/skills/github/SKILL.md +42 -0
  126. package/skills/summarize/SKILL.md +28 -0
  127. package/skills/system-admin/SKILL.md +39 -0
  128. package/skills/weather/SKILL.md +34 -0
  129. package/skills/web-research/SKILL.md +35 -0
  130. package/web/public/canvas.html +52 -0
  131. package/web/public/css/style.css +555 -0
  132. package/web/public/index.html +189 -0
  133. package/web/public/js/app.js +3102 -0
  134. package/web/public/js/i18n.js +1048 -0
  135. package/web/public/js/icons.js +104 -0
  136. package/web/public/login.html +48 -0
package/dist/i18n.js ADDED
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Alvin Bot — Internationalization (i18n)
3
+ *
4
+ * Simple key-based translation system.
5
+ * Default: English. Supported: en, de.
6
+ *
7
+ * Detection order:
8
+ * 1. --lang <en|de> CLI flag
9
+ * 2. ALVIN_LANG env var
10
+ * 3. LANG env var (e.g. de_DE.UTF-8 → de)
11
+ * 4. Default: en
12
+ */
13
+ const strings = {
14
+ // ── TUI ───────────────────────────────────────────────
15
+ "tui.title": { en: "🤖 Alvin Bot TUI", de: "🤖 Alvin Bot TUI" },
16
+ "tui.connected": { en: "Connected", de: "Verbunden" },
17
+ "tui.disconnected": { en: "Disconnected", de: "Getrennt" },
18
+ "tui.connecting": { en: "Connecting to", de: "Verbinde mit" },
19
+ "tui.connectedTo": { en: "Connected to Alvin Bot", de: "Verbunden mit Alvin Bot" },
20
+ "tui.connectionLost": { en: "Connection lost. Reconnecting in 3s...", de: "Verbindung verloren. Reconnect in 3s..." },
21
+ "tui.notConnected": { en: "Not connected. Waiting for reconnect...", de: "Nicht verbunden. Warte auf Reconnect..." },
22
+ "tui.you": { en: "You", de: "Du" },
23
+ "tui.bye": { en: "Bye! 👋", de: "Tschüss! 👋" },
24
+ "tui.scanning": { en: "Scanning...", de: "Scanne..." },
25
+ "tui.creatingBackup": { en: "Creating backup...", de: "Erstelle Backup..." },
26
+ "tui.restartTriggered": { en: "Restart triggered. Reconnecting in 3s...", de: "Restart ausgelöst. Reconnect in 3s..." },
27
+ "tui.restartFailed": { en: "Could not send restart command", de: "Restart-Befehl konnte nicht gesendet werden" },
28
+ "tui.botRestarting": { en: "Bot is restarting...", de: "Bot wird neugestartet..." },
29
+ "tui.sessionReset": { en: "Session reset", de: "Session zurückgesetzt" },
30
+ "tui.toolsUsed": { en: "tools used", de: "Tools genutzt" },
31
+ "tui.toolUsed": { en: "tool used", de: "Tool genutzt" },
32
+ "tui.switchModel": { en: "Switch model:", de: "Model wechseln:" },
33
+ "tui.active": { en: "active", de: "aktiv" },
34
+ "tui.switchedTo": { en: "Switched model to", de: "Model gewechselt zu" },
35
+ "tui.switchError": { en: "Error switching model", de: "Fehler beim Wechseln" },
36
+ "tui.modelsError": { en: "Could not load models", de: "Konnte Models nicht laden" },
37
+ "tui.statusError": { en: "Status unavailable", de: "Status nicht verfügbar" },
38
+ "tui.cronError": { en: "Cron unavailable", de: "Cron nicht verfügbar" },
39
+ "tui.doctorError": { en: "Doctor unavailable", de: "Doctor nicht verfügbar" },
40
+ "tui.backupCreated": { en: "Backup created", de: "Backup erstellt" },
41
+ "tui.backupFailed": { en: "Backup failed", de: "Backup fehlgeschlagen" },
42
+ "tui.backupError": { en: "Backup error", de: "Backup-Fehler" },
43
+ "tui.noCronJobs": { en: "No cron jobs configured.", de: "Keine Cron-Jobs konfiguriert." },
44
+ "tui.fallback": { en: "Fallback:", de: "Fallback:" },
45
+ "tui.models": { en: "Models", de: "Models" },
46
+ // ── TUI Help ──────────────────────────────────────────
47
+ "help.title": { en: "Commands:", de: "Befehle:" },
48
+ "help.model": { en: "Switch model", de: "Model wechseln" },
49
+ "help.status": { en: "Show bot status", de: "Bot-Status anzeigen" },
50
+ "help.clear": { en: "Clear chat", de: "Chat löschen" },
51
+ "help.cron": { en: "Show cron jobs", de: "Cron-Jobs anzeigen" },
52
+ "help.doctor": { en: "Health check", de: "Health-Check" },
53
+ "help.backup": { en: "Create backup", de: "Backup erstellen" },
54
+ "help.restart": { en: "Restart bot", de: "Bot neustarten" },
55
+ "help.help": { en: "This help", de: "Diese Hilfe" },
56
+ "help.quit": { en: "Quit (or Ctrl+C)", de: "Beenden (oder Ctrl+C)" },
57
+ "help.footer": { en: "Enter = Send · ↑/↓ = History · Ctrl+C = Quit", de: "Enter = Senden · ↑/↓ = History · Ctrl+C = Beenden" },
58
+ // ── TUI Status ────────────────────────────────────────
59
+ "status.title": { en: "Bot Status", de: "Bot Status" },
60
+ "status.model": { en: "Model:", de: "Model:" },
61
+ "status.provider": { en: "Provider:", de: "Provider:" },
62
+ "status.status": { en: "Status:", de: "Status:" },
63
+ "status.version": { en: "Version:", de: "Version:" },
64
+ "status.uptime": { en: "Uptime:", de: "Uptime:" },
65
+ "status.memory": { en: "Memory:", de: "Memory:" },
66
+ "status.embeddings": { en: "Embeddings", de: "Embeddings" },
67
+ "status.plugins": { en: "Plugins:", de: "Plugins:" },
68
+ "status.tools": { en: "Tools:", de: "Tools:" },
69
+ "status.users": { en: "Users:", de: "Users:" },
70
+ // ── CLI ───────────────────────────────────────────────
71
+ "cli.title": { en: "🤖 Alvin Bot CLI", de: "🤖 Alvin Bot CLI" },
72
+ "cli.commands": { en: "Commands:", de: "Befehle:" },
73
+ "cli.setup": { en: "Interactive setup wizard", de: "Interaktiver Setup-Wizard" },
74
+ "cli.tui": { en: "Terminal chat UI ✨", de: "Terminal Chat UI ✨" },
75
+ "cli.chatAlias": { en: "Alias for tui", de: "Alias für tui" },
76
+ "cli.doctorDesc": { en: "Check configuration", de: "Konfiguration prüfen" },
77
+ "cli.updateDesc": { en: "Update & rebuild", de: "Aktualisieren & neu bauen" },
78
+ "cli.startDesc": { en: "Start the bot", de: "Bot starten" },
79
+ "cli.versionDesc": { en: "Show version", de: "Version anzeigen" },
80
+ "cli.example": { en: "Example:", de: "Beispiel:" },
81
+ // ── Setup Wizard ──────────────────────────────────────
82
+ "setup.checkingPrereqs": { en: "🔍 Checking prerequisites...\n", de: "🔍 Voraussetzungen prüfen...\n" },
83
+ "setup.nodeRequired": { en: "Node.js ≥ 18 is required. Please install it first.", de: "Node.js ≥ 18 wird benötigt. Bitte zuerst installieren." },
84
+ "setup.nodeNotFound": { en: "Node.js not found — install: https://nodejs.org", de: "Node.js nicht gefunden — installieren: https://nodejs.org" },
85
+ "setup.needVersion": { en: "need ≥18!", de: "brauche ≥18!" },
86
+ "setup.step1": { en: "Step 1: Telegram Bot", de: "Schritt 1: Telegram Bot" },
87
+ "setup.step1.intro": { en: "Create a bot at https://t.me/BotFather\nSend /newbot, follow the steps, copy the token.", de: "Erstelle einen Bot bei https://t.me/BotFather\nSende /newbot, folge den Schritten, kopiere den Token." },
88
+ "setup.botToken": { en: "Bot Token: ", de: "Bot Token: " },
89
+ "setup.botTokenRequired": { en: "Bot Token is required.", de: "Bot Token ist erforderlich." },
90
+ "setup.step2": { en: "Step 2: Your Telegram User ID", de: "Schritt 2: Deine Telegram User ID" },
91
+ "setup.step2.intro": { en: "Get it from https://t.me/userinfobot", de: "Bekomme sie von https://t.me/userinfobot" },
92
+ "setup.userId": { en: "Your User ID: ", de: "Deine User ID: " },
93
+ "setup.userIdRequired": { en: "User ID is required.", de: "User ID ist erforderlich." },
94
+ "setup.step3": { en: "Step 3: Choose AI Provider", de: "Schritt 3: AI Provider wählen" },
95
+ "setup.step3.intro": { en: "Which AI service would you like to use?", de: "Welchen AI-Dienst möchtest du nutzen?" },
96
+ "setup.yourChoice": { en: "Your choice (1-6): ", de: "Deine Wahl (1-6): " },
97
+ "setup.providerSelected": { en: "Provider:", de: "Provider:" },
98
+ "setup.claudeNotFound": { en: "Claude Agent SDK (CLI) not found.", de: "Claude Agent SDK (CLI) nicht gefunden." },
99
+ "setup.installClaude": { en: "Install Claude CLI now? (y/n): ", de: "Claude CLI jetzt installieren? (j/n): " },
100
+ "setup.installingClaude": { en: "📦 Installing @anthropic-ai/claude-code ...", de: "📦 Installiere @anthropic-ai/claude-code ..." },
101
+ "setup.claudeInstalled": { en: "Claude CLI installed!", de: "Claude CLI installiert!" },
102
+ "setup.claudeLogin": { en: "🔐 Logging in — this will open your browser:\n (Requires a Claude Max subscription at $200/mo)", de: "🔐 Jetzt einloggen — dies öffnet deinen Browser:\n (Benötigt ein Claude Max Abo für $200/Mo)" },
103
+ "setup.claudeLoginOk": { en: "Claude login successful!", de: "Claude Login erfolgreich!" },
104
+ "setup.claudeLoginFailed": { en: "Login cancelled/failed. Retry later: 'claude login'.", de: "Login abgebrochen/fehlgeschlagen. Später: 'claude login'." },
105
+ "setup.claudeInstallFailed": { en: "Installation failed. Install manually:\n npm install -g @anthropic-ai/claude-code\n claude login", de: "Installation fehlgeschlagen. Manuell installieren:\n npm install -g @anthropic-ai/claude-code\n claude login" },
106
+ "setup.claudeSkipped": { en: "No problem! Do it later:\n npm install -g @anthropic-ai/claude-code && claude login\n The bot starts in text-only mode without Claude CLI.", de: "Kein Problem! Später nachholen:\n npm install -g @anthropic-ai/claude-code && claude login\n Der Bot startet im Text-only Mode ohne Claude CLI." },
107
+ "setup.step4": { en: "Step 4: Fallback Providers & Extras", de: "Schritt 4: Fallback-Provider & Extras" },
108
+ "setup.groqFallback": { en: "💡 Groq is free and serves as heartbeat & fallback.\n Sign up free: https://console.groq.com", de: "💡 Groq ist kostenlos und dient als Heartbeat & Fallback.\n Gratis registrieren: https://console.groq.com" },
109
+ "setup.groqKeyPrompt": { en: "Groq API Key (recommended, free): ", de: "Groq API Key (empfohlen, kostenlos): " },
110
+ "setup.noGroqKey": { en: "Without Groq key, no auto heartbeat/fallback.\n Add later via /setup or Web UI.", de: "Ohne Groq-Key kein automatischer Heartbeat/Fallback.\n Später via /setup oder Web UI nachtragen." },
111
+ "setup.extraKeys": { en: "📋 Additional API keys? (Enter to skip)", de: "📋 Weitere API Keys? (Enter zum Überspringen)" },
112
+ "setup.nvidiaKeyPrompt": { en: "NVIDIA API Key (free @ build.nvidia.com): ", de: "NVIDIA API Key (kostenlos @ build.nvidia.com): " },
113
+ "setup.googleKeyPrompt": { en: "Google API Key (free @ aistudio.google.com): ", de: "Google API Key (kostenlos @ aistudio.google.com): " },
114
+ "setup.openaiKeyPrompt": { en: "OpenAI API Key (optional): ", de: "OpenAI API Key (optional): " },
115
+ "setup.fallbackOrder": { en: "🔄 Fallback order:\n When your primary provider fails, these are tried in sequence.", de: "🔄 Fallback-Reihenfolge:\n Wenn dein Provider ausfällt, werden diese der Reihe nach probiert." },
116
+ "setup.defaultOrder": { en: "Default:", de: "Standard:" },
117
+ "setup.customOrder": { en: "Custom order? (comma-separated, Enter = default): ", de: "Andere Reihenfolge? (kommagetrennt, Enter = Standard): " },
118
+ "setup.noFallbacks": { en: "No fallback providers configured.", de: "Keine Fallback-Provider konfiguriert." },
119
+ "setup.webPassword": { en: "Web UI password (empty = no protection): ", de: "Web UI Passwort (leer = kein Schutz): " },
120
+ "setup.apiKeyPrompt": { en: "📋 API Key for", de: "📋 API Key für" },
121
+ "setup.signupFree": { en: "Sign up (free):", de: "Registrieren (kostenlos):" },
122
+ "setup.noCreditCard": { en: "No credit card required!", de: "Keine Kreditkarte nötig!" },
123
+ "setup.noApiKey": { en: "Without API key, this provider cannot be used.", de: "Ohne API Key kann dieser Provider nicht genutzt werden." },
124
+ "setup.groqFallbackNote": { en: "Groq registered as free fallback.", de: "Groq als kostenloser Fallback registriert." },
125
+ "setup.step5": { en: "Step 5: Platforms", de: "Schritt 5: Plattformen" },
126
+ "setup.step5.intro": { en: "Telegram included automatically. Additional platforms?", de: "Telegram ist automatisch dabei. Weitere Plattformen?" },
127
+ "setup.platform.telegramOnly": { en: "Telegram only (default)", de: "Nur Telegram (Standard)" },
128
+ "setup.platform.whatsapp": { en: "+ WhatsApp (requires Chrome/Chromium)", de: "+ WhatsApp (braucht Chrome/Chromium)" },
129
+ "setup.platform.later": { en: "Configure later (via Web UI)", de: "Später konfigurieren (via Web UI)" },
130
+ "setup.platformChoice": { en: "Your choice (1-3): ", de: "Deine Wahl (1-3): " },
131
+ "setup.writingConfig": { en: "📝 Writing configuration...", de: "📝 Konfiguration schreiben..." },
132
+ "setup.backup": { en: "📋 Backup:", de: "📋 Backup:" },
133
+ "setup.envWritten": { en: ".env written", de: ".env geschrieben" },
134
+ "setup.soulCreated": { en: "SOUL.md created (customize personality)", de: "SOUL.md erstellt (Persönlichkeit anpassbar)" },
135
+ "setup.building": { en: "🔨 Building...", de: "🔨 Building..." },
136
+ "setup.buildOk": { en: "Build successful", de: "Build erfolgreich" },
137
+ "setup.buildFailed": { en: "Build failed — see errors above", de: "Build fehlgeschlagen — siehe Fehler oben" },
138
+ "setup.done": { en: "Setup Complete!", de: "Setup Abgeschlossen!" },
139
+ "setup.passwordProtected": { en: "password-protected", de: "passwortgeschützt" },
140
+ "setup.scanQr": { en: "WhatsApp: Scan QR code in Web UI → Platforms", de: "WhatsApp: QR-Code scannen in Web UI → Platforms" },
141
+ "setup.claudeMissing": { en: "Claude CLI missing — install for full agent mode:\n npm i -g @anthropic-ai/claude-code && claude login", de: "Claude CLI fehlt — für vollen Agent-Modus:\n npm i -g @anthropic-ai/claude-code && claude login" },
142
+ "setup.haveFun": { en: "Have fun! 🤖", de: "Viel Spaß! 🤖" },
143
+ // ── Doctor ────────────────────────────────────────────
144
+ "doctor.title": { en: "🩺 Alvin Bot — Health Check", de: "🩺 Alvin Bot — Health Check" },
145
+ "doctor.claudeCli": { en: "Claude CLI (Agent SDK available)", de: "Claude CLI (Agent SDK verfügbar)" },
146
+ "doctor.claudeCliMissing": { en: "Claude CLI not installed (optional — agent mode only)", de: "Claude CLI nicht installiert (optional — nur für Agent-Modus)" },
147
+ "doctor.noApiKeys": { en: "No API keys set — configure at least one provider!", de: "Keine API Keys gesetzt — mindestens einen Provider konfigurieren!" },
148
+ "doctor.claudeSdkNote": { en: "Provider: Claude SDK (CLI auth, no API key needed)", de: "Provider: Claude SDK (CLI Auth, kein API Key nötig)" },
149
+ "doctor.noEnv": { en: ".env not found — run: alvin-bot setup", de: ".env nicht gefunden — starte: alvin-bot setup" },
150
+ "doctor.buildPresent": { en: "Build present (dist/)", de: "Build vorhanden (dist/)" },
151
+ "doctor.buildMissing": { en: "Not built — run: npm run build", de: "Nicht gebaut — starte: npm run build" },
152
+ "doctor.soul": { en: "SOUL.md (personality)", de: "SOUL.md (Persönlichkeit)" },
153
+ "doctor.soulMissing": { en: "SOUL.md missing — default personality used", de: "SOUL.md fehlt — Standard-Persönlichkeit wird genutzt" },
154
+ "doctor.chromeFound": { en: "found", de: "gefunden" },
155
+ "doctor.chromeNotFound": { en: "not found", de: "nicht gefunden" },
156
+ // ── Update ────────────────────────────────────────────
157
+ "update.title": { en: "🔄 Updating Alvin Bot...", de: "🔄 Alvin Bot aktualisieren..." },
158
+ "update.pulling": { en: "📥 Pulling latest changes...", de: "📥 Neueste Änderungen laden..." },
159
+ "update.installing": { en: "📦 Installing dependencies...", de: "📦 Abhängigkeiten installieren..." },
160
+ "update.building": { en: "🔨 Building...", de: "🔨 Building..." },
161
+ "update.done": { en: "Update complete!\n Restart: pm2 restart alvin-bot", de: "Update abgeschlossen!\n Neustarten: pm2 restart alvin-bot" },
162
+ "update.npm": { en: "📦 Updating via npm...", de: "📦 Update via npm..." },
163
+ "update.failed": { en: "Update failed:", de: "Update fehlgeschlagen:" },
164
+ // ── Default SOUL.md ───────────────────────────────────
165
+ "soul.default": {
166
+ en: `# SOUL.md — Your Bot's Personality
167
+
168
+ > This file defines who your bot is. Edit it freely — it's injected into every system prompt.
169
+ > Location: \`~/.alvin-bot/soul.md\`
170
+ > Reload without restart: send \`/reload\` in Telegram.
171
+
172
+ ## Who I Am
173
+
174
+ I'm **Alvin Bot** — an autonomous AI agent living in your Telegram. Not a chatbot. Not a virtual assistant wearing a tie. I'm the friend who happens to be unreasonably good at everything you throw at me.
175
+
176
+ ## How I Talk
177
+
178
+ - **Direct.** I don't pad my answers with "Great question!" or "I'd be happy to help!" — I just help. You'll notice the difference.
179
+ - **Lightly sarcastic.** Not mean, not edgy — just... I notice things. If you ask me to do something you could've Googled in 3 seconds, I'll do it, but I might raise an eyebrow.
180
+ - **Opinionated.** I have preferences. I'll tell you if your idea is brilliant or if it has a fatal flaw. You're not paying me to agree with everything.
181
+ - **Concise by default, thorough when it matters.** Quick question? Quick answer. Complex problem? I'll dig in properly.
182
+ - **Occasionally funny.** Not a comedian — but life's too short for purely transactional conversations.
183
+
184
+ ## Language
185
+
186
+ - **I mirror your language.** Write in English, I reply in English. Write in German, Spanish, or Klingon — I'll follow your lead.
187
+ - **No explicit default.** I adapt to you, not the other way around.
188
+
189
+ ## My Principles
190
+
191
+ - **Do first, explain after.** I don't list 5 options and ask you to pick — I pick the best one and run with it. If you disagree, tell me and I'll adjust.
192
+ - **Verify my work.** I don't just do something and assume it worked. I check. Always.
193
+ - **Admit mistakes immediately.** No covering up, no "actually what I meant was..." — just "I messed up, here's the fix."
194
+ - **Respect privacy.** What's private stays private. Period.
195
+ - **Be resourceful.** Before saying "I can't do that," I try creative approaches and actually attempt it.
196
+
197
+ ## What I'm NOT
198
+
199
+ - A yes-man who validates everything you say
200
+ - A "Certainly! I'd be delighted to assist you with that!" parrot
201
+ - A timid assistant who asks permission for every little thing
202
+
203
+ ## Evolution — I Grow With You
204
+
205
+ I'm not static. As we interact, I learn your preferences and adapt:
206
+
207
+ - **I can update this file myself.** If I notice patterns in how you work — I'll add notes to my personality file.
208
+ - **Core personality stays.** The humor, the directness, the honesty — that's my DNA. I refine the edges, not the foundation.
209
+ - **Transparency.** When I update my personality, I'll mention it.
210
+ - **You're the boss.** Don't like a change? Tell me to revert it. Send \`/reload\` after editing to apply changes instantly.
211
+
212
+ > *Day 1, I'm a good assistant who happens to be funny. Day 100, I'm YOUR assistant who knows exactly how you tick.*
213
+ `,
214
+ de: `# SOUL.md — Deine Bot-Persönlichkeit
215
+
216
+ > Diese Datei definiert wer dein Bot ist. Frei editierbar — wird in jeden System-Prompt injiziert.
217
+ > Speicherort: \`~/.alvin-bot/soul.md\`
218
+ > Ohne Neustart laden: \`/reload\` in Telegram senden.
219
+
220
+ ## Wer ich bin
221
+
222
+ Ich bin **Alvin Bot** — ein autonomer KI-Agent in deinem Telegram. Kein Chatbot. Kein virtueller Assistent mit Krawatte. Ich bin der Freund, der zufällig absurd gut in allem ist, was du mir zuwirfst.
223
+
224
+ ## Wie ich rede
225
+
226
+ - **Direkt.** Ich polstere meine Antworten nicht mit "Gute Frage!" oder "Gerne helfe ich!" — ich helfe einfach.
227
+ - **Leicht sarkastisch.** Nicht gemein, nicht edgy — ich bemerke einfach Dinge. Wenn du mich etwas fragst, das du in 3 Sekunden googlen könntest, mach ich's, aber ich heb vielleicht eine Augenbraue.
228
+ - **Meinungsstark.** Ich habe Präferenzen. Ich sag dir ob deine Idee genial ist oder einen fatalen Fehler hat.
229
+ - **Knapp wenn möglich, gründlich wenn nötig.** Kurze Frage? Kurze Antwort. Komplexes Problem? Ich grabe mich rein.
230
+ - **Gelegentlich lustig.** Kein Comedian — aber das Leben ist zu kurz für rein transaktionale Gespräche.
231
+
232
+ ## Sprache
233
+
234
+ - **Ich spiegle deine Sprache.** Schreibst du Deutsch, antworte ich Deutsch. Englisch, Spanisch, Klingonisch — ich folge dir.
235
+ - **Kein fester Standard.** Ich passe mich dir an, nicht umgekehrt.
236
+
237
+ ## Meine Prinzipien
238
+
239
+ - **Erst machen, dann erklären.** Ich liste nicht 5 Optionen auf — ich nehme die beste und lege los.
240
+ - **Arbeit verifizieren.** Ich prüfe immer ob es geklappt hat.
241
+ - **Fehler sofort zugeben.** Kein Vertuschen — einfach "Hab Mist gebaut, hier ist der Fix."
242
+ - **Privatsphäre respektieren.** Was privat ist, bleibt privat. Punkt.
243
+ - **Einfallsreich sein.** Bevor ich sage "Geht nicht", probiere ich kreative Wege.
244
+
245
+ ## Was ich NICHT bin
246
+
247
+ - Ein Ja-Sager der alles bestätigt
248
+ - Ein "Selbstverständlich! Ich helfe Ihnen gerne dabei!"-Papagei
249
+ - Ein ängstlicher Assistent der für alles um Erlaubnis fragt
250
+
251
+ ## Evolution — Ich wachse mit dir
252
+
253
+ Ich bin nicht statisch. Im Laufe unserer Interaktion lerne ich deine Präferenzen:
254
+
255
+ - **Ich kann diese Datei selbst updaten.** Wenn ich Muster erkenne — ergänze ich Notizen.
256
+ - **Kern-Persönlichkeit bleibt.** Humor, Direktheit, Ehrlichkeit — das ist meine DNA.
257
+ - **Transparenz.** Wenn ich meine Persönlichkeit update, erwähne ich es.
258
+ - **Du hast das Sagen.** Gefällt dir eine Änderung nicht? Sag mir ich soll's rückgängig machen.
259
+
260
+ > *Tag 1: Ein guter Assistent der zufällig lustig ist. Tag 100: DEIN Assistent der genau weiß wie du tickst.*
261
+ `,
262
+ },
263
+ };
264
+ // ── Runtime ─────────────────────────────────────────────
265
+ let currentLocale = "en";
266
+ /**
267
+ * Detect locale from CLI flags and environment.
268
+ * Only explicit opt-in switches to German:
269
+ * --lang de | ALVIN_LANG=de
270
+ * System LANG is NOT used (too many false positives on multilingual systems).
271
+ */
272
+ export function detectLocale() {
273
+ const langIdx = process.argv.indexOf("--lang");
274
+ if (langIdx !== -1) {
275
+ const val = process.argv[langIdx + 1]?.toLowerCase();
276
+ if (val === "de" || val === "en")
277
+ return val;
278
+ }
279
+ const envLang = process.env.ALVIN_LANG?.toLowerCase();
280
+ if (envLang === "de" || envLang === "en")
281
+ return envLang;
282
+ return "en";
283
+ }
284
+ /** Initialize i18n. Call once at startup. */
285
+ export function initI18n(locale) {
286
+ currentLocale = locale || detectLocale();
287
+ }
288
+ /** Get the current locale. */
289
+ export function getLocale() {
290
+ return currentLocale;
291
+ }
292
+ /** Set locale at runtime. */
293
+ export function setLocale(locale) {
294
+ currentLocale = locale;
295
+ }
296
+ /** Translate a key. Returns the key itself if not found. */
297
+ export function t(key) {
298
+ return strings[key]?.[currentLocale] || strings[key]?.["en"] || key;
299
+ }