Commit Graph

2955 Commits

Author SHA1 Message Date
cc1b9e8054 Merge pull request '[TEST] Add Comprehensive Security Test Coverage' (#61) from tests/security-coverage into main
Some checks failed
Nix / nix (ubuntu-latest) (push) Failing after 9s
Tests / test (push) Failing after 18s
Docker Build and Publish / build-and-push (push) Failing after 45s
Nix / nix (macos-latest) (push) Has been cancelled
2026-03-30 23:49:35 +00:00
e2e88b271d test: add comprehensive security test coverage
Some checks failed
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Successful in 29s
Docker Build and Publish / build-and-push (pull_request) Failing after 37s
Tests / test (pull_request) Failing after 28s
Add extensive test suites for all critical security fixes:
- tests/tools/test_path_traversal.py: Path traversal detection tests
- tests/tools/test_command_injection.py: Command injection prevention tests
- tests/tools/test_interrupt.py: Race condition validation tests
- validate_security.py: Automated security validation suite

Coverage includes:
- Unix/Windows traversal patterns
- URL-encoded bypass attempts
- Null byte injection
- Concurrent access race conditions
- Subprocess security patterns

Refs: Issue #51 - Test coverage gaps
Refs: V-001, V-002, V-007 security fixes
2026-03-30 23:49:20 +00:00
0e01f3321d Merge pull request '[SECURITY] Fix Race Condition in Interrupt Propagation (CVSS 8.5)' (#60) from security/fix-race-condition into main
Some checks failed
Tests / test (push) Failing after 19s
Nix / nix (ubuntu-latest) (push) Failing after 9s
Docker Build and Publish / build-and-push (push) Failing after 45s
Nix / nix (macos-latest) (push) Has been cancelled
2026-03-30 23:47:22 +00:00
13265971df security: fix race condition in interrupt propagation (V-007)
Some checks failed
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Successful in 29s
Docker Build and Publish / build-and-push (pull_request) Failing after 38s
Tests / test (pull_request) Failing after 28s
Add proper RLock synchronization to prevent race conditions when multiple
threads access interrupt state simultaneously.

Changes:
- tools/interrupt.py: Add RLock, nesting count tracking, new APIs
- tools/terminal_tool.py: Remove direct _interrupt_event exposure
- tests/tools/test_interrupt.py: Comprehensive race condition tests

CVSS: 8.5 (High)
Refs: V-007, Issue #48
Fixes: CWE-362: Concurrent Execution using Shared Resource
2026-03-30 23:47:04 +00:00
6da1fc11a2 Merge pull request '[SECURITY] Add Connection-Level SSRF Protection (CVSS 9.4)' (#59) from security/fix-ssrf into main
Some checks failed
Nix / nix (ubuntu-latest) (push) Failing after 15s
Tests / test (push) Failing after 24s
Docker Build and Publish / build-and-push (push) Failing after 53s
Nix / nix (macos-latest) (push) Has been cancelled
2026-03-30 23:44:15 +00:00
0019381d75 security: add connection-level SSRF protection (CVSS 9.4)
Some checks failed
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Successful in 32s
Tests / test (pull_request) Failing after 28s
Docker Build and Publish / build-and-push (pull_request) Failing after 55s
Add runtime IP validation at connection time to mitigate DNS rebinding
attacks (TOCTOU vulnerability).

Changes:
- tools/url_safety.py: Add create_safe_socket() for connection-time validation
- Add get_safe_httpx_transport() for httpx integration
- Document V-005 security fix

This closes the gap where attacker-controlled DNS servers could return
different IPs between pre-flight check and actual connection.

CVSS: 9.4 (Critical)
Refs: V-005 in SECURITY_AUDIT_REPORT.md
Fixes: CWE-918 (Server-Side Request Forgery)
2026-03-30 23:43:58 +00:00
05000f091f Merge pull request '[SECURITY] Fix Secret Leakage via Environment Variables (CVSS 9.3)' (#58) from security/fix-secret-leakage into main
Some checks failed
Nix / nix (ubuntu-latest) (push) Failing after 13s
Tests / test (push) Failing after 24s
Docker Build and Publish / build-and-push (push) Failing after 53s
Nix / nix (macos-latest) (push) Has been cancelled
2026-03-30 23:43:03 +00:00
08abea4905 security: fix secret leakage via whitelist-only env vars (CVSS 9.3)
Some checks failed
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Successful in 32s
Tests / test (pull_request) Failing after 30s
Docker Build and Publish / build-and-push (pull_request) Failing after 55s
Replace blacklist approach with explicit whitelist for child process
environment variables to prevent secret exfiltration via creative naming.

Changes:
- tools/code_execution_tool.py: Implement _ALLOWED_ENV_VARS frozenset
- Only pass explicitly listed env vars to sandboxed child processes
- Drop all other variables silently to prevent credential theft

Fixes CWE-526: Exposure of Sensitive Information to an Unauthorized Actor

CVSS: 9.3 (Critical)
Refs: V-003 in SECURITY_AUDIT_REPORT.md
2026-03-30 23:42:43 +00:00
65d9fc2b59 Merge path traversal security fix
Some checks failed
Tests / test (push) Failing after 19s
Nix / nix (ubuntu-latest) (push) Failing after 4s
Docker Build and Publish / build-and-push (push) Failing after 29s
Nix / nix (macos-latest) (push) Has been cancelled
2026-03-30 23:40:52 +00:00
510367bfc2 Merge pull request 'feat: Gen AI Evolution Phases 1-3 — Self-Correction, World Modeling, and Domain Distillation' (#43) from feat/gen-ai-evolution-phases-1-3 into main
Some checks failed
Nix / nix (ubuntu-latest) (push) Failing after 4s
Tests / test (push) Failing after 15s
Docker Build and Publish / build-and-push (push) Failing after 25s
Nix / nix (macos-latest) (push) Has been cancelled
2026-03-30 23:40:00 +00:00
33bf5967ec Merge pull request '[SECURITY] Fix Command Injection Vulnerabilities (CVSS 9.8)' (#53) from security/fix-command-injection into main
Some checks failed
Tests / test (push) Failing after 15s
Nix / nix (ubuntu-latest) (push) Failing after 4s
Docker Build and Publish / build-and-push (push) Failing after 25s
Nix / nix (macos-latest) (push) Has been cancelled
2026-03-30 23:39:24 +00:00
78f0a5c01b security: fix path traversal vulnerability (CVSS 9.1)
Add comprehensive path traversal detection and validation to prevent
unauthorized file access outside working directories.

Changes:
- tools/file_operations.py: Add _validate_safe_path(), _contains_path_traversal()
- Validate all paths in read_file(), write_file() before processing
- Detect patterns: ../, ..\, URL-encoded, null bytes, control chars

Fixes CWE-22: Path Traversal vulnerability where malicious paths like
../../../etc/shadow could access sensitive files.

CVSS: 9.1 (Critical)
Refs: V-002 in SECURITY_AUDIT_REPORT.md
2026-03-30 23:17:09 +00:00
10271c6b44 security: fix command injection vulnerabilities (CVSS 9.8)
Some checks failed
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Failing after 25s
Tests / test (pull_request) Failing after 24s
Docker Build and Publish / build-and-push (pull_request) Failing after 35s
Replace shell=True with list-based subprocess execution to prevent
command injection via malicious user input.

Changes:
- tools/transcription_tools.py: Use shlex.split() + shell=False
- tools/environments/docker.py: List-based commands with container ID validation

Fixes CVE-level vulnerability where malicious file paths or container IDs
could inject arbitrary commands.

CVSS: 9.8 (Critical)
Refs: V-001 in SECURITY_AUDIT_REPORT.md
2026-03-30 23:15:11 +00:00
e6599b8651 feat: implement Phase 3 - Domain Distiller
Some checks failed
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Failing after 45s
Tests / test (pull_request) Failing after 27s
Docker Build and Publish / build-and-push (pull_request) Failing after 1m11s
2026-03-30 22:59:57 +00:00
679d2cd81d feat: implement Phase 2 - World Modeler 2026-03-30 22:59:56 +00:00
e7b2fe8196 feat: implement Phase 1 - Self-Correction Generator 2026-03-30 22:59:55 +00:00
5b948356b7 Merge PR #9: SOTA Sovereign Intersymbolic Knowledge Graph (SIKG)
Some checks failed
Tests / test (push) Failing after 17s
Docker Build and Publish / build-and-push (push) Failing after 30s
Nix / nix (ubuntu-latest) (push) Failing after 5s
Nix / nix (macos-latest) (push) Has been cancelled
Features:
- tools/graph_store.py: Sovereign triple-store with Gitea persistence
- agent/symbolic_memory.py: Neural-to-symbolic bridge with multi-hop search
- skills/memory/intersymbolic_graph.py: Graph query skill
- Integrated into KnowledgeIngester for automatic symbolic extraction

Tests added:
- tests/tools/test_graph_store.py (127 lines)
- tests/agent/test_symbolic_memory.py (144 lines)

Reviewed and merged by Allegro (BURN MODE).
2026-03-30 22:31:43 +00:00
1bff6d17d5 feat: enhance Knowledge Ingester with symbolic extraction
Some checks failed
Docker Build and Publish / build-and-push (pull_request) Failing after 1m20s
Tests / test (pull_request) Failing after 16s
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Failing after 34s
2026-03-30 22:28:59 +00:00
b5527fee26 feat: add Intersymbolic Graph Query skill 2026-03-30 22:28:58 +00:00
482b6c5aea feat: add Sovereign Intersymbolic Memory Layer 2026-03-30 22:28:57 +00:00
5ac5c7f44c feat: add sovereign Graph Store tool 2026-03-30 22:28:56 +00:00
0f508c9600 Merge PR #4: Sovereign Real-time Learning System
Some checks failed
Tests / test (push) Failing after 40s
Docker Build and Publish / build-and-push (push) Failing after 55s
Nix / nix (ubuntu-latest) (push) Failing after 21s
Nix / nix (macos-latest) (push) Has been cancelled
2026-03-30 22:27:14 +00:00
6aeb5a71df Merge PR #3: Sovereign Reasoning Engine — Gemini 3.1 Pro Integration 2026-03-30 22:27:14 +00:00
f1b409cba4 feat: add Real-time Learning skill
Some checks failed
Tests / test (pull_request) Failing after 12m7s
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Failing after 24s
Docker Build and Publish / build-and-push (pull_request) Failing after 34s
2026-03-30 22:19:28 +00:00
d1defbe06a feat: add Sovereign Knowledge Ingester 2026-03-30 22:19:27 +00:00
e2ee3b7819 feat: add sovereign Gitea client tool 2026-03-30 22:19:26 +00:00
689b8e705a chore: add google-genai dependency
Some checks failed
Tests / test (pull_request) Failing after 10s
Nix / nix (ubuntu-latest) (pull_request) Failing after 8s
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Successful in 42s
Docker Build and Publish / build-and-push (pull_request) Failing after 1m1s
Nix / nix (macos-latest) (pull_request) Has been cancelled
2026-03-30 22:16:33 +00:00
79f411de4d feat: add Sovereign Thinking skill 2026-03-30 22:16:32 +00:00
8411f124cd feat: add Meta-Reasoning Layer 2026-03-30 22:16:31 +00:00
7fe402fb70 feat: add native Gemini 3 series adapter 2026-03-30 22:16:29 +00:00
f8bc71823d feat: add Sovereign Thinking skill 2026-03-30 22:16:20 +00:00
fdce07ff40 feat: add Meta-Reasoning Layer 2026-03-30 22:16:19 +00:00
bf82581189 feat: add native Gemini 3 series adapter 2026-03-30 22:16:18 +00:00
Teknium
fb634068df fix(security): extend secret redaction to ElevenLabs, Tavily and Exa API keys (#3920)
Some checks failed
Nix / nix (ubuntu-latest) (push) Failing after 3m9s
Docker Build and Publish / build-and-push (push) Failing after 4m1s
Tests / test (push) Failing after 29m41s
Nix / nix (macos-latest) (push) Has been cancelled
ElevenLabs (sk_), Tavily (tvly-), and Exa (exa_) keys were not covered
by _PREFIX_PATTERNS, leaking in plain text via printenv or log output.

Salvaged from PR #3790 by @memosr. Tests rewritten with correct
assertions (original tests had vacuously true checks).

Co-authored-by: memosr <memosr@users.noreply.github.com>
2026-03-30 08:13:01 -07:00
Teknium
74181fe726 fix: add TTY guard to interactive CLI commands to prevent CPU spin (#3933)
When interactive TUI commands are invoked non-interactively (e.g. via
the agent's terminal() tool through a subprocess pipe), curses loops
spin at 100% CPU and input() calls hang indefinitely.

Defense in depth — two layers:

1. Source-level guard in curses_checklist() (curses_ui.py + checklist.py):
   Returns cancel_returns immediately when stdin is not a TTY. This
   catches ALL callers automatically, including future code.

2. Command-level guards with clear error messages:
   - hermes tools (interactive checklist, not list/disable/enable)
   - hermes setup (interactive wizard)
   - hermes model (provider/model picker)
   - hermes whatsapp (pairing setup)
   - hermes skills config (skill toggle)
   - hermes mcp configure (tool selection)
   - hermes uninstall (confirmation prompt)

Non-interactive subcommands (hermes tools list, hermes tools enable,
hermes mcp add/remove/list/test, hermes skills search/install/browse)
remain unaffected.
2026-03-30 08:10:23 -07:00
Teknium
1e896b0251 fix: resolve 7 failing CI tests (#3936)
1. matrix voice: _on_room_message_media unconditionally overwrote
   media_urls with the image cache path (always None for non-images),
   wiping the locally-cached voice path. Now only overrides when
   cached_path is truthy.

2. cli_tools_command: /tools disable no longer prompts for confirmation
   (input() removed in earlier commit to fix TUI hang), but tests still
   expected the old Y/N prompt flow. Updated tests to match current
   behavior (direct apply + session reset).

3. slack app_mention: connect() was refactored for multi-workspace
   (creates AsyncWebClient per token), but test only mocked the old
   self._app.client path. Added AsyncWebClient and acquire_scoped_lock
   mocks.

4. website_policy: module-level _cached_policy from earlier tests caused
   fast-path return of None. Added invalidate_cache() before assertion.

5. codex 401 refresh: already passing on current main (fixed by
   intervening commit).
2026-03-30 08:10:14 -07:00
0xbyt4
0b0c1b326c fix: openclaw migration overwrites model config dict with string (#3924)
migrate_model_config() was writing `config["model"] = model_str` which
replaces the entire model dict (default, provider, base_url) with a
bare string. This causes 'str' object has no attribute 'get' errors
throughout Hermes when any code does model_cfg.get("default").

Now preserves the existing model dict and only updates the "default"
key, keeping provider/base_url intact.
2026-03-30 03:02:28 -07:00
Teknium
b4496b33b5 fix: background task media delivery + vision download timeout (#3919)
* feat(telegram): add webhook mode as alternative to polling

When TELEGRAM_WEBHOOK_URL is set, the adapter starts an HTTP webhook
server (via python-telegram-bot's start_webhook()) instead of long
polling. This enables cloud platforms like Fly.io and Railway to
auto-wake suspended machines on inbound HTTP traffic.

Polling remains the default — no behavior change unless the env var
is set.

Env vars:
  TELEGRAM_WEBHOOK_URL    Public HTTPS URL for Telegram to push to
  TELEGRAM_WEBHOOK_PORT   Local listen port (default 8443)
  TELEGRAM_WEBHOOK_SECRET Secret token for update verification

Cherry-picked and adapted from PR #2022 by SHL0MS. Preserved all
current main enhancements (network error recovery, polling conflict
detection, DM topics setup).

Co-authored-by: SHL0MS <SHL0MS@users.noreply.github.com>

* fix: send_document call in background task delivery + vision download timeout

Two fixes salvaged from PR #2269 by amethystani:

1. gateway/run.py: adapter.send_file() → adapter.send_document()
   send_file() doesn't exist on BasePlatformAdapter. Background task
   media files were silently never delivered (AttributeError swallowed
   by except Exception: pass).

2. tools/vision_tools.py: configurable image download timeout via
   HERMES_VISION_DOWNLOAD_TIMEOUT env var (default 30s), plus guard
   against raise None when max_retries=0.

The third fix in #2269 (opencode-go auth config) was already resolved
on main.

Co-authored-by: amethystani <amethystani@users.noreply.github.com>

---------

Co-authored-by: SHL0MS <SHL0MS@users.noreply.github.com>
Co-authored-by: amethystani <amethystani@users.noreply.github.com>
2026-03-30 02:59:39 -07:00
Teknium
d028a94b83 fix(whatsapp): skip reply prefix in bot mode — only needed for self-chat (#3931)
The WhatsApp bridge prepends '⚕ *Hermes Agent*\n────────────\n' to
every outgoing message. In self-chat mode this is necessary to
distinguish the bot's responses from the user's own messages. In bot
mode the messages already come from a different number, making the
prefix redundant and cluttered.

Now only prepends the prefix when WHATSAPP_MODE is 'self-chat' (the
default). Bot mode messages are sent clean.
2026-03-30 02:55:33 -07:00
Teknium
0e592aa5b4 fix(cli): remove input() from /tools disable that freezes the terminal (#3918)
input() hangs inside prompt_toolkit's TUI event loop — this is a known
pitfall (AGENTS.md). The /tools disable and /tools enable commands used
input() for a Y/N confirmation prompt, causing the terminal to freeze
with no way to type a response.

Fix: remove the confirmation prompt. The user typing '/tools disable web'
is implicit consent. The change is applied directly with a status message.
2026-03-30 02:53:21 -07:00
Wing Lian
efae525dc5 feat(plugins): add inject_message interface for remote message injection (#3778) 2026-03-30 02:48:06 -07:00
Teknium
5148682b43 feat: mount skills directory into all remote backends with live sync (#3890)
Skills with scripts/, templates/, and references/ subdirectories need
those files available inside sandboxed execution environments. Previously
the skills directory was missing entirely from remote backends.

Live sync — files stay current as credentials refresh and skills update:
- Docker/Singularity: bind mounts are inherently live (host changes
  visible immediately)
- Modal: _sync_files() runs before each command with mtime+size caching,
  pushing only changed credential and skill files (~13μs no-op overhead)
- SSH: rsync --safe-links before each command (naturally incremental)
- Daytona: _upload_if_changed() with mtime+size caching before each command

Security — symlink filtering:
- Docker/Singularity: sanitized temp copy when symlinks detected
- Modal/Daytona: iter_skills_files() skips symlinks
- SSH: rsync --safe-links skips symlinks pointing outside source tree
- Temp dir cleanup via atexit + reuse across calls

Non-root user support:
- SSH: detects remote home via echo $HOME, syncs to $HOME/.hermes/
- Daytona: detects sandbox home before sync, uploads to $HOME/.hermes/
- Docker/Modal/Singularity: run as root, /root/.hermes/ is correct

Also:
- credential_files.py: fix name/path key fallback in required_credential_files
- Singularity, SSH, Daytona: gained credential file support
- 14 tests covering symlink filtering, name/path fallback, iter_skills_files
2026-03-30 02:45:41 -07:00
Teknium
791f4e94b2 feat(slack): multi-workspace support via OAuth token file (#3903)
Salvaged from PR #2033 by yoannes. Adds multi-workspace Slack support
so a single Hermes instance can serve multiple Slack workspaces after
OAuth installs.

Changes:
- Support comma-separated bot tokens in SLACK_BOT_TOKEN env var
- Load additional OAuth-persisted tokens from HERMES_HOME/slack_tokens.json
- Route all Slack API calls through workspace-aware _get_client(chat_id)
  instead of always using the primary app client
- Track channel → workspace mapping from incoming events
- Per-workspace bot_user_id for correct mention detection
- Workspace-aware file downloads (correct auth token per workspace)

Backward compatible: single-token setups work identically.

Token file format (slack_tokens.json):
  {"T12345": {"token": "xoxb-...", "team_name": "My Workspace"}}

Fixed from original PR:
- Uses get_hermes_home() instead of hardcoded ~/.hermes/ path

Co-authored-by: yoannes <yoannes@users.noreply.github.com>
2026-03-30 01:51:48 -07:00
Teknium
a4b064763d fix(cron): tighten [SILENT] instruction to prevent report-with-silent-prefix (#3901)
The model was interpreting [SILENT] as a metadata prefix and writing
full reports with [SILENT] slapped at the front. The old instruction
said 'optionally followed by a brief internal note' which gave too
much room. New instruction explicitly says: [SILENT] means nothing
else, do NOT combine it with a report.
2026-03-30 00:11:00 -07:00
Teknium
138ea3fbe8 fix(docs): escape angle-bracket URLs in feishu.md breaking MDX build (#3902) 2026-03-30 00:09:30 -07:00
Teknium
ee61485cac feat(matrix): support native voice messages via MSC3245 (#3877)
* feat(matrix): support native voice messages

* fix: skip matrix voice tests when matrix-nio not installed

---------

Co-authored-by: Carlos Alberto Pereira Gomes <carlosapgomes@users.noreply.github.com>
2026-03-30 00:02:51 -07:00
Teknium
947faed3bc feat(approvals): make dangerous command approval timeout configurable (#3886)
* feat(approvals): make dangerous command approval timeout configurable

Read `approvals.timeout` from config.yaml (default 60s) instead of
hardcoding 60 seconds in both the fallback CLI prompt and the TUI
prompt_toolkit callback.

Follows the same pattern as `clarify.timeout` which is already
configurable via CLI_CONFIG.

Closes #3765

* fix: add timeout default to approvals section in DEFAULT_CONFIG

---------

Co-authored-by: acsezen <asezen@icloud.com>
2026-03-30 00:02:02 -07:00
kshitij
c288bbfb57 fix(cli): prevent status bar wrapping into duplicate rows (#3883)
- measure status bar display width using prompt_toolkit cell widths
- trim rendered status text when fragments would overflow
- add a final single-fragment fallback to prevent wrapping
- update width assertions to validate display cells instead of len()
2026-03-29 23:59:07 -07:00
Teknium
a347921314 docs: comprehensive OpenClaw migration guide (#3900)
New standalone guide at guides/migrate-from-openclaw.md with:
- Complete config key mapping tables for every category
- Agent behavior mappings (thinkingDefault → reasoning_effort, etc.)
- Session reset policy mapping (session.reset vs resetTriggers)
- TTS dual-source explanation (messages.tts.providers + talk config)
- MCP server field-by-field mapping
- Messaging platform table with exact config paths and env vars
- API key resolution: 3 sources, priority order, supported targets
- SecretRef handling: plain strings, env templates, SecretRef objects
- Post-migration checklist (6 steps)
- Troubleshooting section
- Complete archived items table with recreation guidance

CLI commands reference condensed to summary + link to full guide.
Added to sidebar under Guides & Tutorials.
2026-03-29 23:58:12 -07:00
Teknium
09def65eff fix(migration): expand OpenClaw migration to cover full data footprint (#3869)
Cross-referenced the OpenClaw Zod schema and TypeScript source against
our migration script. Found and fixed:

Expanded data sources:
- Legacy config fallback: clawdbot.json, moldbot.json
- Legacy dir fallback: ~/.clawdbot/, ~/.moldbot/
- API keys from ~/.openclaw/.env and auth-profiles.json
- Personal skills from ~/.agents/skills/
- Project skills from workspace/.agents/skills/
- BOOTSTRAP.md archived (was silently skipped)
- Expanded env key allowlist: DEEPSEEK, GEMINI, ZAI, MINIMAX

Fixed wrong config paths (verified against Zod schema):
- humanDelay.enabled → humanDelay.mode (field doesn't exist as .enabled)
- agents.defaults.exec.timeout → tools.exec.timeoutSec (wrong path + name)
- messages.tts.elevenlabs.voiceId → messages.tts.providers.elevenlabs.voiceId
- session.resetTriggers (string[]) → session.reset (structured object)
- approvals.mode → approvals.exec.mode (no top-level mode)
- browser.inactivityTimeoutMs → doesn't exist; map cdpUrl+headless instead
- tools.webSearch.braveApiKey → tools.web.search.brave.apiKey
- tools.exec.timeout → tools.exec.timeoutSec

Added SecretRef resolution:
- All token/apiKey fields in OpenClaw can be strings, env templates
  (${VAR}), or SecretRef objects ({source:'env',id:'VAR'}). Added
  resolve_secret_input() to handle all three forms.

Fixed auth-profiles.json:
- Canonical field is 'key' not 'apiKey' (though alias accepted)
- File wraps entries in a 'profiles' key — now handled

Fixed TTS config:
- Provider settings at messages.tts.providers.{name} (not flat)
- Also checks top-level 'talk' config as fallback source

Docs updated with new sources and key list.
2026-03-29 22:49:34 -07:00