alvin-bot 4.4.3 → 4.4.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,37 @@
2
2
 
3
3
  All notable changes to Alvin Bot are documented here.
4
4
 
5
+ ## [4.4.5] — 2026-04-09
6
+
7
+ ### 🔐 Security / Information Disclosure
8
+
9
+ **`BACKLOG.md` removed from published tarball** — The project's internal roadmap was listed in `.gitignore` but not in `.npmignore`, so every `npm install -g alvin-bot` shipped an 8.7 KB file containing the full list of open P0/P1 issues, including known-but-unpatched security weaknesses (WebSocket auth gap, tool-executor sandbox gaps, Web UI HTTP-only, etc.). A published backlog of known vulnerabilities is effectively an attack roadmap for anyone inspecting the package.
10
+
11
+ `BACKLOG.md` is now listed in `.npmignore` alongside `CLAUDE.md`, `SOUL.md`, and `TOOLS.md`. Verified with `npm pack --dry-run`: the file no longer appears in the tarball.
12
+
13
+ Users on `4.4.4` or earlier should update:
14
+ ```bash
15
+ npm update -g alvin-bot
16
+ ```
17
+
18
+ ## [4.4.4] — 2026-04-09
19
+
20
+ ### 🔐 Security / Data Layout
21
+
22
+ **`.env` now lives only in `DATA_DIR`** — The `ENV_FILE` path constant in `src/paths.ts` has been moved from `BOT_ROOT/.env` to `DATA_DIR/.env` (e.g. `~/.alvin-bot/.env`). This fixes a latent drift bug affecting 6 code sites in `web/server.ts`, `web/setup-api.ts`, `web/doctor-api.ts`, and `services/fallback-order.ts`: before this release, the Web UI's Settings tab, the setup wizard, the doctor repair flow, and the `/fallback` sync were all writing to `BOT_ROOT/.env`, while the bot's config loader in `src/config.ts` reads from `DATA_DIR/.env` first. Changes made through any of those tools were silently written to a file the bot never reads (for globally-installed users, `BOT_ROOT` is inside `node_modules/alvin-bot/` and gets wiped on `npm update -g`).
23
+
24
+ Why this also matters for security: keeping `.env` inside the code repo is defense-in-depth weak. `.gitignore` can be edited, editors create swap files (`.env.swp`, `.env~`), `git add -f` bypasses ignores, backup tools sync whole project folders, and screensharing shows project directories. Secrets belong physically outside the repo.
25
+
26
+ **Automatic migration for legacy installs** — `src/migrate.ts` now copies a legacy `BOT_ROOT/.env` to `DATA_DIR/.env` on first run (only if the destination doesn't exist) and enforces `0600` mode regardless of the source permissions. `hasLegacyData()` now recognizes a stray `BOT_ROOT/.env` as a migration trigger. No action is required from existing users — the bot migrates itself.
27
+
28
+ ### 📦 Compatibility
29
+
30
+ No breaking changes. Existing installs upgrade in place and are auto-migrated.
31
+
32
+ ```bash
33
+ npm update -g alvin-bot
34
+ ```
35
+
5
36
  ## [4.4.3] — 2026-04-09
6
37
 
7
38
  ### 🔐 Security
package/dist/migrate.js CHANGED
@@ -20,7 +20,7 @@
20
20
  */
21
21
  import fs from "fs";
22
22
  import { resolve } from "path";
23
- import { BOT_ROOT, MEMORY_DIR, USERS_DIR, BACKUP_DIR, SOUL_FILE, TOOLS_MD, TOOLS_JSON, CRON_FILE, MCP_CONFIG, FALLBACK_FILE, CUSTOM_MODELS, WA_GROUPS, WHATSAPP_AUTH, WA_MEDIA_DIR, ACCESS_FILE, SUDO_ENC_FILE, SUDO_KEY_FILE, MEMORY_FILE, EMBEDDINGS_IDX } from "./paths.js";
23
+ import { BOT_ROOT, MEMORY_DIR, USERS_DIR, BACKUP_DIR, SOUL_FILE, TOOLS_MD, TOOLS_JSON, CRON_FILE, MCP_CONFIG, FALLBACK_FILE, CUSTOM_MODELS, WA_GROUPS, WHATSAPP_AUTH, WA_MEDIA_DIR, ACCESS_FILE, SUDO_ENC_FILE, SUDO_KEY_FILE, MEMORY_FILE, EMBEDDINGS_IDX, ENV_FILE } from "./paths.js";
24
24
  /**
25
25
  * Check if legacy data exists in the old locations.
26
26
  */
@@ -31,7 +31,13 @@ export function hasLegacyData() {
31
31
  resolve(BOT_ROOT, "docs", "users"),
32
32
  resolve(BOT_ROOT, "data", "access.json"),
33
33
  resolve(BOT_ROOT, "SOUL.md"),
34
- ];
34
+ // A BOT_ROOT/.env without a corresponding DATA_DIR/.env is a legacy layout
35
+ // — the loader prefers DATA_DIR, so keeping .env in BOT_ROOT silently
36
+ // breaks Settings/Setup/Doctor/fallback-order sync.
37
+ (fs.existsSync(resolve(BOT_ROOT, ".env")) && !fs.existsSync(ENV_FILE))
38
+ ? resolve(BOT_ROOT, ".env")
39
+ : "",
40
+ ].filter(Boolean);
35
41
  return legacyIndicators.some(p => fs.existsSync(p));
36
42
  }
37
43
  /**
@@ -47,6 +53,21 @@ function copyIfNew(src, dest) {
47
53
  }
48
54
  return false;
49
55
  }
56
+ /**
57
+ * Copy a file if source exists and destination doesn't, then enforce a specific file mode.
58
+ * Used for files containing secrets (e.g. .env) where 0600 must be guaranteed
59
+ * regardless of the source file's permissions or the process umask.
60
+ */
61
+ function copyIfNewWithMode(src, dest, mode) {
62
+ const copied = copyIfNew(src, dest);
63
+ if (copied) {
64
+ try {
65
+ fs.chmodSync(dest, mode);
66
+ }
67
+ catch { /* best effort */ }
68
+ }
69
+ return copied;
70
+ }
50
71
  /**
51
72
  * Recursively copy a directory if source exists and destination doesn't have the files.
52
73
  */
@@ -89,6 +110,8 @@ export function migrateFromLegacy() {
89
110
  skipped.push(label);
90
111
  }
91
112
  // ── Single files ─────────────────────────────────────────
113
+ // .env → .env (secrets — enforce 0600 mode regardless of source perms)
114
+ track(".env → .env", copyIfNewWithMode(resolve(BOT_ROOT, ".env"), ENV_FILE, 0o600));
92
115
  // SOUL.md → soul.md
93
116
  track("SOUL.md → soul.md", copyIfNew(resolve(BOT_ROOT, "SOUL.md"), SOUL_FILE));
94
117
  // TOOLS.md → tools.md
package/dist/paths.js CHANGED
@@ -23,13 +23,22 @@ export const PLUGINS_DIR = resolve(BOT_ROOT, "plugins");
23
23
  export const SKILLS_DIR = resolve(BOT_ROOT, "skills");
24
24
  /** User skills directory (custom, outside repo) */
25
25
  export const USER_SKILLS_DIR = resolve(DATA_DIR, "skills");
26
- /** .env — Environment config (stays in BOT_ROOT for dev, or DATA_DIR for packaged) */
27
- export const ENV_FILE = resolve(BOT_ROOT, ".env");
28
26
  /** Example/template files (always in repo) */
29
27
  export const SOUL_EXAMPLE = resolve(BOT_ROOT, "SOUL.example.md");
30
28
  export const TOOLS_EXAMPLE_MD = resolve(BOT_ROOT, "TOOLS.example.md");
31
29
  export const TOOLS_EXAMPLE_JSON = resolve(BOT_ROOT, "docs", "tools.example.json");
32
30
  // ── Data paths (DATA_DIR = ~/.alvin-bot) ───────────────────────────
31
+ /**
32
+ * .env — Environment config with secrets (BOT_TOKEN, API keys, etc.)
33
+ *
34
+ * Lives in DATA_DIR (outside the code repo) for three reasons:
35
+ * 1. Defense in depth against accidental commits — secrets never touch BOT_ROOT
36
+ * 2. Survives `npm update -g` (BOT_ROOT in global installs = node_modules, gets wiped)
37
+ * 3. Consistent with the loader priority in src/config.ts (DATA_DIR is Priority 1)
38
+ *
39
+ * Legacy installs with BOT_ROOT/.env are auto-migrated on first run (see src/migrate.ts).
40
+ */
41
+ export const ENV_FILE = resolve(DATA_DIR, ".env");
33
42
  /** memory/ — Daily logs and embeddings */
34
43
  export const MEMORY_DIR = resolve(DATA_DIR, "memory");
35
44
  /** memory/MEMORY.md — Long-term curated memory */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alvin-bot",
3
- "version": "4.4.3",
3
+ "version": "4.4.5",
4
4
  "description": "Alvin Bot — Your personal AI agent on Telegram, WhatsApp, Discord, Signal, and Web.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/BACKLOG.md DELETED
@@ -1,223 +0,0 @@
1
- # BACKLOG.md — Alvin Bot Entwicklung
2
-
3
- > Interne Projektdatei. Wird NICHT ins Git gepusht (.gitignore).
4
- > Letzte Aktualisierung: 2026-03-03
5
-
6
- ---
7
-
8
- ## Legende
9
-
10
- | Prio | Bedeutung |
11
- |------|-----------|
12
- | P0 | Sicherheitslücke / Kritisch |
13
- | P1 | Wichtig für Stabilität & Code-Qualität |
14
- | P2 | Feature / Developer Experience |
15
- | P3 | Nice-to-Have / Zukunft |
16
-
17
- ---
18
-
19
- ## P0 — Security
20
-
21
- ### [ ] WebSocket Auth fehlt
22
- - Aktuell kann jeder, der `localhost:3100` erreicht, über WebSocket chatten
23
- - Lösung: Auth-Token als Query-Param beim WS-Connect (`ws://localhost:3100?token=xxx`)
24
- - Token aus WEB_PASSWORD ableiten oder Session-Cookie validieren
25
-
26
- ### [ ] Tool Executor: Unzureichendes Sandboxing
27
- - `run_shell` Blocklist ist minimal (nur `rm -rf /`, `mkfs`, `dd`)
28
- - `rm -rf ~/Projects/` würde durchgehen
29
- - `write_file` kann `.env` und Systemdateien überschreiben
30
- - `python_execute` führt beliebigen Code ohne Sandbox aus
31
- - Lösung: Working-Directory-Sandboxing, Blocklist für sensitive Pfade (.env, /etc/, ~/.ssh/)
32
-
33
- ### [ ] Web UI: Kein HTTPS
34
- - HTTP-only → Passwörter und Chat im Klartext
35
- - Lösung: Optionaler HTTPS-Modus mit self-signed Cert, oder Warnung wenn WEB_PASSWORD gesetzt aber kein HTTPS
36
-
37
- ### [ ] Sudo-Passwort in CLI-Argument (macOS)
38
- - `security add-generic-password` bekommt das Passwort als CLI-Arg → sichtbar in `ps aux`
39
- - Lösung: Passwort über stdin pipen statt als Argument
40
-
41
- ---
42
-
43
- ## P1 — Code-Qualität & Stabilität
44
-
45
- ### [ ] commands.ts aufteilen (74KB Monolith!)
46
- - Aktuell: ALLE Telegram-Commands in einer Datei (~1700 Zeilen)
47
- - Vorschlag: `src/handlers/commands/` Ordner mit je einer Datei pro Bereich:
48
- - `chat.ts` (help, start, new, cancel)
49
- - `model.ts` (model, effort, fallback, voice)
50
- - `tools.ts` (web, imagine, browse, remind)
51
- - `memory.ts` (recall, remember, reindex, export, memory)
52
- - `admin.ts` (status, dir, groups, security, users, setup, sudo)
53
- - `cron.ts` (cron)
54
- - `extensions.ts` (plugins, mcp, tools, webui)
55
- - `index.ts` (registriert alle)
56
-
57
- ### [ ] web/server.ts aufteilen (57KB Monolith!)
58
- - Aktuell: REST-API, WebSocket, Static-Serving, Auth — alles in einer Datei
59
- - Vorschlag: Router-Module nach Bereich (api/models.ts, api/memory.ts, api/sessions.ts, etc.)
60
-
61
- ### [ ] web/public/js/app.js refactoren (3079 Zeilen)
62
- - Vanilla JS ohne Struktur → schwer wartbar
63
- - Option A: Alpine.js oder Petite-Vue für reaktive Bindings (minimaler Overhead)
64
- - Option B: Web Components für Isolation der Sektionen
65
- - Option C: Zumindest in Module aufteilen (ES Module Imports)
66
-
67
- ### [ ] Config-Validation mit Zod
68
- - Aktuell: Kein Validation → `ALLOWED_USERS=""` ergibt `[NaN]`
69
- - `BOT_TOKEN` fehlt → kryptischer Fehler statt klare Meldung
70
- - Lösung: `src/config.ts` mit Zod-Schema, Startup-Validation, klare Fehlermeldungen
71
-
72
- ### [ ] MAX_BUDGET_USD wird nie enforced
73
- - Variable wird gelesen aber nirgendwo geprüft
74
- - Lösung: In `queryWithFallback()` vor jedem API-Call prüfen, bei Überschreitung blockieren
75
-
76
- ### [ ] Tests einführen
77
- - Aktuell: Null Tests im gesamten Projekt
78
- - Priorität für Tests:
79
- 1. Provider-Registry (Fallback-Chain Logik)
80
- 2. Cron-Parser (Edge Cases bei Zeitberechnung)
81
- 3. Tool-Executor (Security-Blocklist)
82
- 4. Config-Validation
83
- 5. Markdown-Sanitizer
84
- - Framework: Vitest (schnell, ESM-nativ, kein Babel nötig)
85
-
86
- ### [ ] Watch-Mode für Development
87
- - Aktuell: `npm run dev` = `tsx src/index.ts` (einmal starten, manuell restarten)
88
- - Lösung: `tsx watch src/index.ts` oder `nodemon` mit TS-Loader
89
-
90
- ---
91
-
92
- ## P2 — Features & Verbesserungen
93
-
94
- ### [ ] Session-Persistence (optional)
95
- - Sessions überleben keinen Restart — Chat-History weg nach `pm2 restart`
96
- - Option A: SQLite-File für Sessions (leichtgewichtig, kein DB-Server)
97
- - Option B: JSON-Files pro User in `data/sessions/`
98
- - Opt-in via `SESSION_PERSIST=true` in .env
99
-
100
- ### [ ] Session-Timeout / Cleanup
101
- - Sessions akkumulieren sich unbegrenzt im Speicher
102
- - Lösung: Inaktive Sessions nach 24h aus dem RAM entfernen (History bleibt in Memory-Logs)
103
-
104
- ### [ ] Memory-Rotation
105
- - Daily Logs (`~/.alvin-bot/memory/YYYY-MM-DD.md`) wachsen unbegrenzt
106
- - Lösung: Nach 30 Tagen alte Logs in `~/.alvin-bot/memory/archive/` verschieben oder komprimieren
107
- - Optional: Automatische Zusammenfassung alter Logs via AI
108
-
109
- ### [ ] Embedding-Provider erweitern
110
- - Aktuell: Nur Google `text-embedding-004`
111
- - Alternativen: OpenAI Embeddings, lokale Ollama-Embeddings, Cohere
112
- - Fallback-Chain wie bei Chat-Providern
113
-
114
- ### [ ] Plugin-Tools für alle Provider
115
- - Plugin-Tools funktionieren aktuell nur über Telegram-Commands
116
- - Sie sollten auch als Agent-Tools in `OpenAICompatibleProvider` injiziert werden
117
- - Damit können alle LLMs Plugin-Funktionen nutzen (nicht nur Claude SDK)
118
-
119
- ### [ ] MCP HTTP/SSE Transport fertigstellen
120
- - Aktuell nur stdio-Transport implementiert
121
- - HTTP/SSE ist stub: `"HTTP/SSE transport not yet supported"`
122
- - Wichtig für Remote-MCP-Server (z.B. Cloudflare Workers)
123
-
124
- ### [ ] Discord: Richtige Integration
125
- - `discord.js` fehlt in package.json (muss manuell installiert werden)
126
- - Kein Support für Discord Slash-Commands
127
- - Kein Rate-Limiting
128
- - Lösung: Als optional peer dependency, Slash-Command Registration
129
-
130
- ### [ ] WhatsApp Media Cleanup
131
- - `data/wa-media/` sammelt empfangene Medien-Dateien und löscht sie nie
132
- - Lösung: Cron-Job oder TTL-basiertes Cleanup (z.B. nach 7 Tagen löschen)
133
-
134
- ### [ ] Heartbeat-Kosten reduzieren
135
- - Heartbeat macht echte API-Calls ("Hi") an alle Provider → erzeugt Kosten
136
- - Lösung: Für Provider mit bekanntem Status-Endpoint nur diesen pingen
137
- - Für kostenlose Provider (Groq, NVIDIA): OK so lassen
138
-
139
- ### [ ] Kosten-Tracking verbessern
140
- - `estimateCost()` schätzt nur Output-Tokens, keine Input-Tokens
141
- - Preise teilweise veraltet
142
- - Lösung: Aktuelle Preistabelle pflegen, Input+Output getrennt tracken
143
-
144
- ### [ ] Cron-Parser erweitern
145
- - Kein Support für `@daily`, `@hourly`, `@reboot`, `@weekly`
146
- - Kein `L` (last day of month), kein `W` (nearest weekday)
147
- - Lösung: Aliases in `parseSchedule()` hinzufügen
148
-
149
- ---
150
-
151
- ## P3 — Nice-to-Have / Zukunft
152
-
153
- ### [ ] Multi-Language über DE/EN hinaus
154
- - i18n-System unterstützt nur `de | en`
155
- - Erweiterbar auf FR, ES, TR, RU etc.
156
- - Web UI hat bereits ~500 Keys → Übersetzung nötig
157
-
158
- ### [ ] Skill-Matching mit Embeddings
159
- - Aktuell: Simples `text.includes(trigger)` — sehr unzuverlässig
160
- - Besser: Embedding-basiertes Similarity-Matching für Skill-Trigger
161
- - Oder: LLM-basierte Skill-Auswahl ("Welcher Skill passt zu dieser Nachricht?")
162
-
163
- ### [ ] Plugin Hot-Reload über Web UI
164
- - Aktuell: Plugin-Änderungen erfordern Bot-Restart
165
- - Lösung: "Reload Plugin" Button in Web UI → `pluginManager.reload(name)`
166
-
167
- ### [ ] Conversation-Export als PDF
168
- - `/export` gibt aktuell Markdown → könnte auch als formatiertes PDF exportieren
169
- - Tools vorhanden: `pandoc`, `wkhtmltopdf`
170
-
171
- ### [ ] Streaming für OpenAI-Compatible + Tool-Use
172
- - Aktuell schließen sich Streaming und Tool-Use gegenseitig aus
173
- - Lösung: Tool-Calls aus Stream-Chunks akkumulieren (wie OpenAI es unterstützt)
174
-
175
- ### [ ] Windows .exe Build
176
- - Braucht Windows-Umgebung oder Cross-Compilation
177
- - electron-builder unterstützt es, aber nicht von macOS aus testbar
178
-
179
- ### [ ] Linux .AppImage Build
180
- - Braucht Linux-Umgebung oder CI (GitHub Actions)
181
- - Vorschlag: GitHub Actions Workflow für Multi-Platform Builds
182
-
183
- ### [ ] CI/CD Pipeline (GitHub Actions)
184
- - Build-Verification auf Push
185
- - Lint (ESLint) + Type-Check + Tests
186
- - Auto-Publish zu npm bei Tag
187
- - Multi-Platform Electron Builds (macOS, Windows, Linux)
188
-
189
- ### [ ] Rate-Limiting für API-Endpoints
190
- - Web UI API-Endpoints haben kein Rate-Limiting
191
- - Lösung: Simpler in-memory Counter pro IP (kein Redis nötig)
192
-
193
- ### [ ] Electron: asar wieder aktivieren
194
- - `asar: false` wegen electron-builder 26.x Bug
195
- - Bei neuerer Version testen ob es gefixt ist → Source-Code wäre dann nicht mehr exposed
196
-
197
- ### [ ] Provider-Config via Web UI erweitern
198
- - Neue Provider-Presets (z.B. Anthropic API direkt, DeepSeek, Mistral) über Web UI registrieren
199
- - Aktuell nur über .env oder Code möglich
200
-
201
- ---
202
-
203
- ## Erledigte Items
204
-
205
- ### [x] i18n English-First (v3.3.0)
206
- - Alle Telegram-Commands, TUI, Services, Plugins auf Englisch
207
- - Web UI bleibt bilingual (DE/EN Toggle)
208
- - TUI nur noch mit explizitem --lang de auf Deutsch
209
-
210
- ### [x] /webui Telegram-Befehl (v3.3.0)
211
- - Sendet Web UI URL als Text (kein Inline-Button, da Telegram localhost-URLs blockiert)
212
-
213
- ### [x] Smart Port Selection (v3.3.0)
214
- - Web UI findet automatisch freien Port wenn 3100 belegt
215
-
216
- ### [x] Multi-Platform Support (Phase 7)
217
- - Telegram, WhatsApp, Discord, Signal
218
-
219
- ### [x] Universal Tool Use (Phase 8)
220
- - Alle Provider können Shell, File I/O, Web Fetch, Python ausführen
221
-
222
- ### [x] Skill System (Phase 9)
223
- - SKILL.md-basierte Domain-Expertise