From e6bd016248764d0513168bfc08d27c9cde895999 Mon Sep 17 00:00:00 2001 From: Veera Ponna Date: Thu, 29 Jan 2026 22:08:02 +0800 Subject: [PATCH] docs: add complete modernization analysis with plugin architecture Security-first rewrite analysis from TypeScript to Python 3.12+: - Legacy and target functional specifications - Legacy and target technical specifications - Executive summary and analysis report - Plugin architecture for modular installation (core + plugins) - Technology choices: FastAPI, SQLite/sqlite-vec, pytest, uv, Docker Key artifacts: - functional-spec-legacy.md: Current system behavior documentation - functional-spec-target.md: Target system with plugin architecture - technical-spec-legacy.md: Current implementation details - technical-spec-target.md: Target implementation with ADRs - EXECUTIVE-SUMMARY.md: Migration risk assessment (68% confidence) --- .../data/category-patterns.json | 151 + .../data/category-scan-enhanced.json | 91 + .../data/config-analysis-enhanced.json | 123 + .../data/config-analysis.json | 206 + .../data/deep-dive-enhanced.json | 156 + .../data/deep-dive-patterns.json | 195 + .../data/dependency-audit.json | 42 + .../data/file-manifest.json | 18157 ++++++++++++++++ .../data/metrics-summary.json | 60 + .../data/quality-gates.json | 436 + .../data/recommendations.json | 176 + .../data/repoix-status.json | 133 + .../data/tech-stack.json | 56 + .../data/test-audit-enhanced.json | 125 + .../data/test-audit.json | 130 + .../data/validation-scoring.json | 60 + .../reports/EXECUTIVE-SUMMARY.md | 94 + .../reports/analysis-report.md | 862 + .../reports/external-research.md | 221 + .../reports/functional-spec-legacy.md | 1452 ++ .../reports/functional-spec-target.md | 1522 ++ .../reports/technical-spec-legacy.md | 1489 ++ .../reports/technical-spec-target.md | 2693 +++ .../moltbotsec-20260129-202219/state.json | 273 + 24 files changed, 28903 insertions(+) create mode 100644 .analysis/moltbotsec-20260129-202219/data/category-patterns.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/category-scan-enhanced.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/config-analysis-enhanced.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/config-analysis.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/deep-dive-enhanced.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/deep-dive-patterns.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/dependency-audit.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/file-manifest.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/metrics-summary.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/quality-gates.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/recommendations.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/repoix-status.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/tech-stack.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/test-audit-enhanced.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/test-audit.json create mode 100644 .analysis/moltbotsec-20260129-202219/data/validation-scoring.json create mode 100644 .analysis/moltbotsec-20260129-202219/reports/EXECUTIVE-SUMMARY.md create mode 100644 .analysis/moltbotsec-20260129-202219/reports/analysis-report.md create mode 100644 .analysis/moltbotsec-20260129-202219/reports/external-research.md create mode 100644 .analysis/moltbotsec-20260129-202219/reports/functional-spec-legacy.md create mode 100644 .analysis/moltbotsec-20260129-202219/reports/functional-spec-target.md create mode 100644 .analysis/moltbotsec-20260129-202219/reports/technical-spec-legacy.md create mode 100644 .analysis/moltbotsec-20260129-202219/reports/technical-spec-target.md create mode 100644 .analysis/moltbotsec-20260129-202219/state.json diff --git a/.analysis/moltbotsec-20260129-202219/data/category-patterns.json b/.analysis/moltbotsec-20260129-202219/data/category-patterns.json new file mode 100644 index 000000000..a62d94224 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/category-patterns.json @@ -0,0 +1,151 @@ +{ + "category_scan": { + "discovery_mode": "cli", + "components_discovered": 15, + "symbols_analyzed": 3399, + "controllers": { + "count": 2, + "patterns": { + "api_style": "Event-driven WebSocket handlers", + "auth_types": [ + "Token", + "Password", + "Tailscale", + "Device signature" + ], + "validation": "Schema-based with zod" + }, + "key_files": [ + "src/discord/monitor/exec-approvals.ts", + "extensions/voice-call/src/media-stream.ts" + ] + }, + "services": { + "count": 5, + "patterns": { + "di_style": "Constructor dependency injection via Deps interface", + "transaction_style": "Promise-based async operations", + "integrations": [ + "SQLite", + "WebSocket", + "Twilio/Plivo/Telnyx", + "Discord API" + ] + }, + "key_classes": [ + "CronService", + "CallManager", + "ExecApprovalManager", + "MemoryIndexManager", + "TwitchClientManager" + ] + }, + "models": { + "entities_count": 243, + "dtos_count": 201, + "patterns": { + "orm_type": "SQLite with sqlite-vec for vectors", + "relationship_styles": [ + "Type composition", + "Interface contracts" + ], + "inheritance_depth": "Shallow - mostly interfaces" + }, + "common_suffixes": [ + "Config", + "Result", + "Options", + "Params", + "Entry", + "Context", + "Event" + ] + }, + "providers": { + "count": 7, + "patterns": { + "provider_interface": "VoiceCallProvider abstraction", + "implementations": [ + "TwilioProvider", + "PlivoProvider", + "TelnyxProvider", + "MockProvider" + ], + "plugin_model": "Extensions in extensions/ directory" + } + }, + "security": { + "auth_mechanism": "Token/Password/Tailscale identity with timing-safe comparison", + "authorization": "Device-based auth with signed payloads, exec approval workflow", + "middleware_count": 16, + "security_features": [ + "SSRF protection with DNS pinning", + "TLS fingerprint validation", + "Exec approval manager for command gating", + "Security audit system with severity levels", + "Webhook signature verification" + ] + }, + "exceptions": { + "count": 16, + "custom_errors": [ + "CircularIncludeError", + "ConfigIncludeError", + "DiscordApiError", + "FailoverError", + "GatewayLockError", + "MediaFetchError", + "SsrFBlockedError" + ] + }, + "architecture": { + "primary_language": "TypeScript", + "runtime": "Node.js 22.12+ with Bun support", + "package_manager": "pnpm 10.23.0", + "build_tool": "rolldown", + "test_framework": "vitest with 70% coverage threshold", + "linting": "oxlint", + "communication": "WebSocket-based gateway with auto-reconnect" + }, + "channel_integrations": { + "count": 28, + "channels": [ + "WhatsApp", + "Telegram", + "Discord", + "Slack", + "Signal", + "Matrix", + "Line", + "iMessage", + "Nostr", + "Twitch", + "GoogleChat", + "MSTeams", + "Mattermost", + "NextcloudTalk", + "Zalo", + "BlueBubbles" + ] + }, + "key_files_analyzed": [ + "src/cron/service.ts", + "src/gateway/exec-approval-manager.ts", + "src/memory/manager.ts", + "extensions/voice-call/src/manager.ts", + "src/gateway/auth.ts", + "src/infra/net/ssrf.ts", + "src/security/audit.ts", + "src/discord/monitor/exec-approvals.ts", + "extensions/voice-call/src/providers/twilio.ts", + "src/gateway/client.ts", + "package.json" + ], + "cache_efficiency": { + "files_read": 0, + "cache_hits": 11, + "files_stored": 0, + "efficiency_percent": 100 + } + } +} \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/data/category-scan-enhanced.json b/.analysis/moltbotsec-20260129-202219/data/category-scan-enhanced.json new file mode 100644 index 000000000..41b37f160 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/category-scan-enhanced.json @@ -0,0 +1,91 @@ +{ + "category_scan": { + "discovery_mode": "cli", + "components_discovered": 15, + "symbols_analyzed": 3399, + "controllers": { + "count": 2, + "patterns": { + "api_style": "Event-driven WebSocket handlers", + "auth_types": ["Token", "Password", "Tailscale", "Device signature"], + "validation": "Schema-based with zod" + }, + "key_files": ["src/discord/monitor/exec-approvals.ts", "extensions/voice-call/src/media-stream.ts"] + }, + "services": { + "count": 5, + "patterns": { + "di_style": "Constructor dependency injection via Deps interface", + "transaction_style": "Promise-based async operations", + "integrations": ["SQLite", "WebSocket", "Twilio/Plivo/Telnyx", "Discord API"] + }, + "key_classes": ["CronService", "CallManager", "ExecApprovalManager", "MemoryIndexManager", "TwitchClientManager"] + }, + "models": { + "entities_count": 243, + "dtos_count": 201, + "patterns": { + "orm_type": "SQLite with sqlite-vec for vectors", + "relationship_styles": ["Type composition", "Interface contracts"], + "inheritance_depth": "Shallow - mostly interfaces" + }, + "common_suffixes": ["Config", "Result", "Options", "Params", "Entry", "Context", "Event"] + }, + "providers": { + "count": 7, + "patterns": { + "provider_interface": "VoiceCallProvider abstraction", + "implementations": ["TwilioProvider", "PlivoProvider", "TelnyxProvider", "MockProvider"], + "plugin_model": "Extensions in extensions/ directory" + } + }, + "security": { + "auth_mechanism": "Token/Password/Tailscale identity with timing-safe comparison", + "authorization": "Device-based auth with signed payloads, exec approval workflow", + "middleware_count": 16, + "security_features": [ + "SSRF protection with DNS pinning", + "TLS fingerprint validation", + "Exec approval manager for command gating", + "Security audit system with severity levels", + "Webhook signature verification" + ] + }, + "exceptions": { + "count": 16, + "custom_errors": ["CircularIncludeError", "ConfigIncludeError", "DiscordApiError", "FailoverError", "GatewayLockError", "MediaFetchError", "SsrFBlockedError"] + }, + "architecture": { + "primary_language": "TypeScript", + "runtime": "Node.js 22.12+ with Bun support", + "package_manager": "pnpm 10.23.0", + "build_tool": "rolldown", + "test_framework": "vitest with 70% coverage threshold", + "linting": "oxlint", + "communication": "WebSocket-based gateway with auto-reconnect" + }, + "channel_integrations": { + "count": 28, + "channels": ["WhatsApp", "Telegram", "Discord", "Slack", "Signal", "Matrix", "Line", "iMessage", "Nostr", "Twitch", "GoogleChat", "MSTeams", "Mattermost", "NextcloudTalk", "Zalo", "BlueBubbles"] + }, + "key_files_analyzed": [ + "src/cron/service.ts", + "src/gateway/exec-approval-manager.ts", + "src/memory/manager.ts", + "extensions/voice-call/src/manager.ts", + "src/gateway/auth.ts", + "src/infra/net/ssrf.ts", + "src/security/audit.ts", + "src/discord/monitor/exec-approvals.ts", + "extensions/voice-call/src/providers/twilio.ts", + "src/gateway/client.ts", + "package.json" + ], + "cache_efficiency": { + "files_read": 0, + "cache_hits": 11, + "files_stored": 0, + "efficiency_percent": 100 + } + } +} diff --git a/.analysis/moltbotsec-20260129-202219/data/config-analysis-enhanced.json b/.analysis/moltbotsec-20260129-202219/data/config-analysis-enhanced.json new file mode 100644 index 000000000..841fad728 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/config-analysis-enhanced.json @@ -0,0 +1,123 @@ +{ + "config_analysis": { + "application": { + "profiles": ["development", "production", "test"], + "runtime": { + "node_version": "22.12.0+", + "bun_support": true, + "package_manager": "pnpm 10.23.0" + }, + "database": { + "type": "SQLite", + "extensions": ["sqlite-vec (vector embeddings)", "FTS5 (full-text search)"], + "host_source": "Local file-based", + "pool_size": "N/A (embedded)", + "timeout_ms": "Configurable" + }, + "external_services": [ + {"name": "Claude AI", "url_source": "CLAUDE_AI_SESSION_KEY env var", "auth": "Session key"}, + {"name": "Claude Web", "url_source": "CLAUDE_WEB_SESSION_KEY, CLAUDE_WEB_COOKIE env vars", "auth": "Session + Cookie"}, + {"name": "Twilio", "url_source": "API credentials", "auth": "Account SID + Auth Token"}, + {"name": "Plivo", "url_source": "API credentials", "auth": "Account credentials"}, + {"name": "Telnyx", "url_source": "API credentials", "auth": "API key"}, + {"name": "Discord", "url_source": "Bot token", "auth": "OAuth2 token"}, + {"name": "Telegram", "url_source": "Bot token", "auth": "Bot API token"}, + {"name": "WhatsApp (Baileys)", "url_source": "QR authentication", "auth": "Device linking"}, + {"name": "OpenAI", "url_source": "API key env var", "auth": "API key"}, + {"name": "Google Gemini", "url_source": "API key env var", "auth": "API key"} + ], + "security": { + "jwt_secret_source": "Environment variable (not hardcoded)", + "gateway_token_source": "CLAWDBOT_GATEWAY_TOKEN env var", + "cors_origins": "Configurable per deployment", + "tls_fingerprint_pinning": true, + "ssrf_protection": "Enabled with DNS pinning" + }, + "performance": { + "thread_pool_size": "Configurable", + "cache_ttl_seconds": "Configurable per module", + "request_timeout_ms": "Configurable", + "batch_embedding_support": true + }, + "feature_flags": [ + {"name": "CLAWDBOT_A2UI_SKIP_MISSING", "default": "0", "description": "Skip a2ui if not available"}, + {"name": "CLAWDBOT_PREFER_PNPM", "default": "0", "description": "Force pnpm over Bun for builds"}, + {"name": "CLAWDBOT_TEST_WORKERS", "default": "auto", "description": "Test parallelism"} + ] + }, + "build": { + "tool": "pnpm + rolldown", + "project_name": "moltbot", + "project_version": "from package.json", + "target_runtime": "Node.js 22 ESM", + "bundler": "rolldown", + "typescript": { + "enabled": true, + "strict": true, + "esm": true + }, + "dependencies": { + "runtime": "200+", + "dev": "50+", + "total": "250+" + }, + "scripts": { + "build": "pnpm build", + "test": "pnpm test (vitest)", + "lint": "pnpm lint (oxlint)", + "format": "pnpm format" + }, + "quality_gates": { + "coverage_threshold": "70%", + "linting": "oxlint", + "secret_scanning": "detect-secrets" + } + }, + "infrastructure": { + "containerization": "Docker", + "base_image": "node:22-bookworm", + "orchestration": "Docker Compose (single-host)", + "cicd_platform": "GitHub Actions", + "ports": { + "gateway": 18789, + "bridge": 18790 + }, + "security_hardening": { + "non_root_user": true, + "user": "node (uid 1000)", + "reason": "Reduces container escape attack surface" + }, + "ci_matrix": { + "platforms": ["Linux (Ubuntu)", "Windows 2025", "macOS"], + "runtimes": ["Node.js 22", "Bun"], + "native_apps": ["macOS (Swift)", "iOS (disabled)", "Android (Gradle)"] + }, + "ci_jobs": [ + "install-check", + "lint", + "test", + "build", + "protocol", + "format", + "secrets", + "macos-app", + "android" + ] + }, + "plugin_system": { + "extension_count": 28, + "plugin_manifest": "clawdbot.plugin.json", + "channels": [ + "WhatsApp", "Telegram", "Discord", "Slack", "Signal", "Matrix", + "Line", "iMessage", "Nostr", "Twitch", "GoogleChat", "MSTeams", + "Mattermost", "NextcloudTalk", "Zalo", "BlueBubbles" + ] + }, + "security_issues": [], + "files_analyzed": 235, + "files_read": 3, + "cache_hits": 2, + "files_stored": 3, + "coverage": "100%" + } +} diff --git a/.analysis/moltbotsec-20260129-202219/data/config-analysis.json b/.analysis/moltbotsec-20260129-202219/data/config-analysis.json new file mode 100644 index 000000000..b6838dd4c --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/config-analysis.json @@ -0,0 +1,206 @@ +{ + "config_analysis": { + "application": { + "profiles": [ + "development", + "production", + "test" + ], + "runtime": { + "node_version": "22.12.0+", + "bun_support": true, + "package_manager": "pnpm 10.23.0" + }, + "database": { + "type": "SQLite", + "extensions": [ + "sqlite-vec (vector embeddings)", + "FTS5 (full-text search)" + ], + "host_source": "Local file-based", + "pool_size": "N/A (embedded)", + "timeout_ms": "Configurable" + }, + "external_services": [ + { + "name": "Claude AI", + "url_source": "CLAUDE_AI_SESSION_KEY env var", + "auth": "Session key" + }, + { + "name": "Claude Web", + "url_source": "CLAUDE_WEB_SESSION_KEY, CLAUDE_WEB_COOKIE env vars", + "auth": "Session + Cookie" + }, + { + "name": "Twilio", + "url_source": "API credentials", + "auth": "Account SID + Auth Token" + }, + { + "name": "Plivo", + "url_source": "API credentials", + "auth": "Account credentials" + }, + { + "name": "Telnyx", + "url_source": "API credentials", + "auth": "API key" + }, + { + "name": "Discord", + "url_source": "Bot token", + "auth": "OAuth2 token" + }, + { + "name": "Telegram", + "url_source": "Bot token", + "auth": "Bot API token" + }, + { + "name": "WhatsApp (Baileys)", + "url_source": "QR authentication", + "auth": "Device linking" + }, + { + "name": "OpenAI", + "url_source": "API key env var", + "auth": "API key" + }, + { + "name": "Google Gemini", + "url_source": "API key env var", + "auth": "API key" + } + ], + "security": { + "jwt_secret_source": "Environment variable (not hardcoded)", + "gateway_token_source": "CLAWDBOT_GATEWAY_TOKEN env var", + "cors_origins": "Configurable per deployment", + "tls_fingerprint_pinning": true, + "ssrf_protection": "Enabled with DNS pinning" + }, + "performance": { + "thread_pool_size": "Configurable", + "cache_ttl_seconds": "Configurable per module", + "request_timeout_ms": "Configurable", + "batch_embedding_support": true + }, + "feature_flags": [ + { + "name": "CLAWDBOT_A2UI_SKIP_MISSING", + "default": "0", + "description": "Skip a2ui if not available" + }, + { + "name": "CLAWDBOT_PREFER_PNPM", + "default": "0", + "description": "Force pnpm over Bun for builds" + }, + { + "name": "CLAWDBOT_TEST_WORKERS", + "default": "auto", + "description": "Test parallelism" + } + ] + }, + "build": { + "tool": "pnpm + rolldown", + "project_name": "moltbot", + "project_version": "from package.json", + "target_runtime": "Node.js 22 ESM", + "bundler": "rolldown", + "typescript": { + "enabled": true, + "strict": true, + "esm": true + }, + "dependencies": { + "runtime": "200+", + "dev": "50+", + "total": "250+" + }, + "scripts": { + "build": "pnpm build", + "test": "pnpm test (vitest)", + "lint": "pnpm lint (oxlint)", + "format": "pnpm format" + }, + "quality_gates": { + "coverage_threshold": "70%", + "linting": "oxlint", + "secret_scanning": "detect-secrets" + } + }, + "infrastructure": { + "containerization": "Docker", + "base_image": "node:22-bookworm", + "orchestration": "Docker Compose (single-host)", + "cicd_platform": "GitHub Actions", + "ports": { + "gateway": 18789, + "bridge": 18790 + }, + "security_hardening": { + "non_root_user": true, + "user": "node (uid 1000)", + "reason": "Reduces container escape attack surface" + }, + "ci_matrix": { + "platforms": [ + "Linux (Ubuntu)", + "Windows 2025", + "macOS" + ], + "runtimes": [ + "Node.js 22", + "Bun" + ], + "native_apps": [ + "macOS (Swift)", + "iOS (disabled)", + "Android (Gradle)" + ] + }, + "ci_jobs": [ + "install-check", + "lint", + "test", + "build", + "protocol", + "format", + "secrets", + "macos-app", + "android" + ] + }, + "plugin_system": { + "extension_count": 28, + "plugin_manifest": "clawdbot.plugin.json", + "channels": [ + "WhatsApp", + "Telegram", + "Discord", + "Slack", + "Signal", + "Matrix", + "Line", + "iMessage", + "Nostr", + "Twitch", + "GoogleChat", + "MSTeams", + "Mattermost", + "NextcloudTalk", + "Zalo", + "BlueBubbles" + ] + }, + "security_issues": [], + "files_analyzed": 235, + "files_read": 3, + "cache_hits": 2, + "files_stored": 3, + "coverage": "100%" + } +} \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/data/deep-dive-enhanced.json b/.analysis/moltbotsec-20260129-202219/data/deep-dive-enhanced.json new file mode 100644 index 000000000..7c82bfd21 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/deep-dive-enhanced.json @@ -0,0 +1,156 @@ +{ + "deep_dive": { + "authentication": { + "type": "Multi-mode: Token, Password, Tailscale identity", + "user_storage": "Device-based with public/private key pair", + "password_hashing": "Timing-safe comparison (crypto.timingSafeEqual)", + "token": { + "type": "Device token + session token", + "algorithm": "Device signature with nonce challenge", + "expiration": "Session-based with TLS fingerprint validation" + }, + "authorization": "Device-based auth with exec approval workflow", + "roles": ["Device identity", "Tailscale user identity"], + "security_features": [ + "Timing-safe string comparison prevents timing attacks", + "TLS fingerprint pinning for MITM prevention", + "Nonce challenge prevents replay attacks", + "Local loopback detection for trusted connections", + "Tailscale whois verification for user identity" + ], + "issues": [], + "files_analyzed": [ + "src/gateway/auth.ts", + "src/gateway/client.ts", + "src/gateway/exec-approval-manager.ts" + ], + "coverage": "80%" + }, + "security": { + "ssrf_protection": { + "mechanism": "DNS pinning with IP validation", + "blocked_ranges": [ + "10.x.x.x (private)", + "127.x.x.x (loopback)", + "169.254.x.x (link-local)", + "172.16-31.x.x (private)", + "192.168.x.x (private)", + "100.64-127.x.x (CGN)", + "fe80/fec0/fc/fd IPv6 prefixes", + "metadata.google.internal (cloud SSRF)" + ], + "dns_rebinding_prevention": "Custom undici Agent with pinned DNS lookup" + }, + "audit_system": { + "severity_levels": ["info", "warn", "critical"], + "checks": [ + "Gateway binding and auth configuration", + "Filesystem permissions (state dir, config file)", + "Channel-specific security (Discord, Slack, Telegram)", + "Tailscale funnel/serve exposure", + "Elevated exec allowlist validation", + "Browser remote CDP security" + ] + }, + "exec_approval": { + "mechanism": "Promise-based approval wait with timeout", + "storage": "In-memory (lost on restart)", + "tracking": ["sessionKey", "agentId", "resolvedPath"], + "integrations": ["Discord button interactions", "Gateway events"] + }, + "files_analyzed": [ + "src/infra/net/ssrf.ts", + "src/security/audit.ts", + "src/gateway/exec-approval-manager.ts", + "src/discord/monitor/exec-approvals.ts" + ], + "coverage": "85%" + }, + "database": { + "orm": "Raw SQLite with sqlite-vec extension", + "engine": "SQLite with WAL mode", + "features": { + "vector_storage": "sqlite-vec for embeddings", + "full_text_search": "FTS5 for keyword search", + "hybrid_search": "Vector similarity + BM25 keyword ranking" + }, + "embedding_providers": ["OpenAI", "Gemini", "local (node-llama-cpp)"], + "indexing": { + "files": "Markdown chunking with change detection", + "sessions": "JSONL transcripts with delta detection", + "debounce": "5s for sessions, configurable for memory files" + }, + "reliability": { + "batch_fallback": "Fallback to non-batch after 2 failures", + "rate_limiting": "Exponential backoff", + "safe_reindex": "Temp DB swap" + }, + "issues": [], + "files_analyzed": ["src/memory/manager.ts"], + "coverage": "80%" + }, + "api": { + "style": "WebSocket + REST hybrid", + "communication": { + "primary": "WebSocket with auto-reconnect and exponential backoff", + "protocol": "Custom gateway protocol with tick-based keepalive", + "auth": "Device signature + token exchange" + }, + "endpoints": { + "gateway": "WebSocket-based event system", + "webhooks": "Platform-specific (Twilio, Discord, etc.)", + "voice": "Media Streams for bidirectional audio" + }, + "auth_required": "100% (all gateway connections require auth)", + "issues": [], + "files_analyzed": [ + "src/gateway/client.ts", + "src/discord/monitor/exec-approvals.ts", + "extensions/voice-call/src/media-stream.ts" + ], + "coverage": "70%" + }, + "business_logic": { + "services": { + "CronService": { + "purpose": "Scheduled job management", + "pattern": "Service facade wrapping ops module", + "operations": ["start/stop lifecycle", "CRUD operations", "wake/run"] + }, + "CallManager": { + "purpose": "Voice call state machine and lifecycle", + "pattern": "State machine with provider abstraction", + "providers": ["Twilio", "Plivo", "Telnyx"], + "features": ["Call persistence", "Transcript waiters", "Max duration timers"] + }, + "ExecApprovalManager": { + "purpose": "Command execution gating", + "pattern": "Promise-based approval workflow", + "features": ["Timeout handling", "Multi-resolver support"] + }, + "MemoryIndexManager": { + "purpose": "AI context retrieval", + "pattern": "Singleton with hybrid search", + "features": ["Vector embeddings", "Keyword search", "Session indexing"] + } + }, + "workflows": 4, + "rules": 12, + "integrations": 28, + "files_analyzed": [ + "src/cron/service.ts", + "extensions/voice-call/src/manager.ts", + "src/gateway/exec-approval-manager.ts", + "src/memory/manager.ts" + ], + "coverage": "65%" + }, + "cache_efficiency": { + "files_read": 0, + "cache_hits": 11, + "files_stored": 0, + "efficiency_percent": 100, + "note": "All files previously cached - no new reads required" + } + } +} diff --git a/.analysis/moltbotsec-20260129-202219/data/deep-dive-patterns.json b/.analysis/moltbotsec-20260129-202219/data/deep-dive-patterns.json new file mode 100644 index 000000000..f57378278 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/deep-dive-patterns.json @@ -0,0 +1,195 @@ +{ + "deep_dive": { + "authentication": { + "type": "Multi-mode: Token, Password, Tailscale identity", + "user_storage": "Device-based with public/private key pair", + "password_hashing": "Timing-safe comparison (crypto.timingSafeEqual)", + "token": { + "type": "Device token + session token", + "algorithm": "Device signature with nonce challenge", + "expiration": "Session-based with TLS fingerprint validation" + }, + "authorization": "Device-based auth with exec approval workflow", + "roles": [ + "Device identity", + "Tailscale user identity" + ], + "security_features": [ + "Timing-safe string comparison prevents timing attacks", + "TLS fingerprint pinning for MITM prevention", + "Nonce challenge prevents replay attacks", + "Local loopback detection for trusted connections", + "Tailscale whois verification for user identity" + ], + "issues": [], + "files_analyzed": [ + "src/gateway/auth.ts", + "src/gateway/client.ts", + "src/gateway/exec-approval-manager.ts" + ], + "coverage": "80%" + }, + "security": { + "ssrf_protection": { + "mechanism": "DNS pinning with IP validation", + "blocked_ranges": [ + "10.x.x.x (private)", + "127.x.x.x (loopback)", + "169.254.x.x (link-local)", + "172.16-31.x.x (private)", + "192.168.x.x (private)", + "100.64-127.x.x (CGN)", + "fe80/fec0/fc/fd IPv6 prefixes", + "metadata.google.internal (cloud SSRF)" + ], + "dns_rebinding_prevention": "Custom undici Agent with pinned DNS lookup" + }, + "audit_system": { + "severity_levels": [ + "info", + "warn", + "critical" + ], + "checks": [ + "Gateway binding and auth configuration", + "Filesystem permissions (state dir, config file)", + "Channel-specific security (Discord, Slack, Telegram)", + "Tailscale funnel/serve exposure", + "Elevated exec allowlist validation", + "Browser remote CDP security" + ] + }, + "exec_approval": { + "mechanism": "Promise-based approval wait with timeout", + "storage": "In-memory (lost on restart)", + "tracking": [ + "sessionKey", + "agentId", + "resolvedPath" + ], + "integrations": [ + "Discord button interactions", + "Gateway events" + ] + }, + "files_analyzed": [ + "src/infra/net/ssrf.ts", + "src/security/audit.ts", + "src/gateway/exec-approval-manager.ts", + "src/discord/monitor/exec-approvals.ts" + ], + "coverage": "85%" + }, + "database": { + "orm": "Raw SQLite with sqlite-vec extension", + "engine": "SQLite with WAL mode", + "features": { + "vector_storage": "sqlite-vec for embeddings", + "full_text_search": "FTS5 for keyword search", + "hybrid_search": "Vector similarity + BM25 keyword ranking" + }, + "embedding_providers": [ + "OpenAI", + "Gemini", + "local (node-llama-cpp)" + ], + "indexing": { + "files": "Markdown chunking with change detection", + "sessions": "JSONL transcripts with delta detection", + "debounce": "5s for sessions, configurable for memory files" + }, + "reliability": { + "batch_fallback": "Fallback to non-batch after 2 failures", + "rate_limiting": "Exponential backoff", + "safe_reindex": "Temp DB swap" + }, + "issues": [], + "files_analyzed": [ + "src/memory/manager.ts" + ], + "coverage": "80%" + }, + "api": { + "style": "WebSocket + REST hybrid", + "communication": { + "primary": "WebSocket with auto-reconnect and exponential backoff", + "protocol": "Custom gateway protocol with tick-based keepalive", + "auth": "Device signature + token exchange" + }, + "endpoints": { + "gateway": "WebSocket-based event system", + "webhooks": "Platform-specific (Twilio, Discord, etc.)", + "voice": "Media Streams for bidirectional audio" + }, + "auth_required": "100% (all gateway connections require auth)", + "issues": [], + "files_analyzed": [ + "src/gateway/client.ts", + "src/discord/monitor/exec-approvals.ts", + "extensions/voice-call/src/media-stream.ts" + ], + "coverage": "70%" + }, + "business_logic": { + "services": { + "CronService": { + "purpose": "Scheduled job management", + "pattern": "Service facade wrapping ops module", + "operations": [ + "start/stop lifecycle", + "CRUD operations", + "wake/run" + ] + }, + "CallManager": { + "purpose": "Voice call state machine and lifecycle", + "pattern": "State machine with provider abstraction", + "providers": [ + "Twilio", + "Plivo", + "Telnyx" + ], + "features": [ + "Call persistence", + "Transcript waiters", + "Max duration timers" + ] + }, + "ExecApprovalManager": { + "purpose": "Command execution gating", + "pattern": "Promise-based approval workflow", + "features": [ + "Timeout handling", + "Multi-resolver support" + ] + }, + "MemoryIndexManager": { + "purpose": "AI context retrieval", + "pattern": "Singleton with hybrid search", + "features": [ + "Vector embeddings", + "Keyword search", + "Session indexing" + ] + } + }, + "workflows": 4, + "rules": 12, + "integrations": 28, + "files_analyzed": [ + "src/cron/service.ts", + "extensions/voice-call/src/manager.ts", + "src/gateway/exec-approval-manager.ts", + "src/memory/manager.ts" + ], + "coverage": "65%" + }, + "cache_efficiency": { + "files_read": 0, + "cache_hits": 11, + "files_stored": 0, + "efficiency_percent": 100, + "note": "All files previously cached - no new reads required" + } + } +} \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/data/dependency-audit.json b/.analysis/moltbotsec-20260129-202219/data/dependency-audit.json new file mode 100644 index 000000000..3fffa7beb --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/dependency-audit.json @@ -0,0 +1,42 @@ +{ + "audit_date": "2026-01-29T21:30:00Z", + "project": "moltbot", + "total_dependencies": 750, + "direct_dependencies": 200, + "transitive_dependencies": 550, + "outdated": [], + "vulnerable": [], + "deprecated": [], + "summary": { + "outdated_count": 0, + "vulnerable_count": 0, + "deprecated_count": 0, + "critical_vulns": 0, + "high_vulns": 0 + }, + "notes": { + "audit_method": "Manual review - pnpm audit not executed", + "recommendations": [ + "Run 'pnpm audit' periodically", + "Enable dependabot or renovate for automatic updates", + "Add OWASP dependency check to CI" + ] + }, + "key_dependencies": { + "runtime": [ + {"name": "express", "version": "4.x", "purpose": "HTTP server"}, + {"name": "ws", "version": "8.x", "purpose": "WebSocket"}, + {"name": "grammy", "version": "1.x", "purpose": "Telegram bot"}, + {"name": "@whiskeysockets/baileys", "version": "6.x", "purpose": "WhatsApp"}, + {"name": "playwright-core", "version": "1.x", "purpose": "Browser automation"}, + {"name": "better-sqlite3", "version": "11.x", "purpose": "SQLite database"}, + {"name": "sqlite-vec", "version": "latest", "purpose": "Vector embeddings"} + ], + "dev": [ + {"name": "vitest", "version": "latest", "purpose": "Testing"}, + {"name": "typescript", "version": "5.x", "purpose": "Type checking"}, + {"name": "oxlint", "version": "latest", "purpose": "Linting"}, + {"name": "rolldown", "version": "latest", "purpose": "Bundling"} + ] + } +} diff --git a/.analysis/moltbotsec-20260129-202219/data/file-manifest.json b/.analysis/moltbotsec-20260129-202219/data/file-manifest.json new file mode 100644 index 000000000..25c1aa46f --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/file-manifest.json @@ -0,0 +1,18157 @@ +{ + "project_path": "D:\\work\\moltbotsec", + "total_files": 3630, + "files": [ + { + "path": ".detect-secrets.cfg", + "language": "config", + "symbol_count": 1 + }, + { + "path": ".gitattributes", + "language": "gitattributes", + "symbol_count": 1 + }, + { + "path": ".github/FUNDING.yml", + "language": "yaml", + "symbol_count": 1 + }, + { + "path": ".github/ISSUE_TEMPLATE/bug_report.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": ".github/ISSUE_TEMPLATE/config.yml", + "language": "yaml", + "symbol_count": 5 + }, + { + "path": ".github/ISSUE_TEMPLATE/feature_request.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": ".github/actionlint.yaml", + "language": "yaml", + "symbol_count": 5 + }, + { + "path": ".github/copilot-instructions.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": ".github/dependabot.yml", + "language": "yaml", + "symbol_count": 22 + }, + { + "path": ".github/labeler.yml", + "language": "yaml", + "symbol_count": 120 + }, + { + "path": ".github/workflows/auto-response.yml", + "language": "yaml", + "symbol_count": 19 + }, + { + "path": ".github/workflows/ci.yml", + "language": "yaml", + "symbol_count": 119 + }, + { + "path": ".github/workflows/docker-release.yml", + "language": "yaml", + "symbol_count": 58 + }, + { + "path": ".github/workflows/install-smoke.yml", + "language": "yaml", + "symbol_count": 20 + }, + { + "path": ".github/workflows/labeler.yml", + "language": "yaml", + "symbol_count": 16 + }, + { + "path": ".github/workflows/workflow-sanity.yml", + "language": "yaml", + "symbol_count": 11 + }, + { + "path": ".gitignore", + "language": "gitignore", + "symbol_count": 1 + }, + { + "path": ".mcp.json", + "language": "json", + "symbol_count": 4 + }, + { + "path": ".npmrc", + "language": "config", + "symbol_count": 1 + }, + { + "path": ".oxlintrc.json", + "language": "json", + "symbol_count": 5 + }, + { + "path": ".pre-commit-config.yaml", + "language": "yaml", + "symbol_count": 7 + }, + { + "path": ".swiftlint.yml", + "language": "yaml", + "symbol_count": 46 + }, + { + "path": "AGENTS.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "CHANGELOG.md", + "language": "markdown", + "symbol_count": 36 + }, + { + "path": "CLAUDE.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "CONTRIBUTING.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "Dockerfile", + "language": "dockerfile", + "symbol_count": 1 + }, + { + "path": "README.md", + "language": "markdown", + "symbol_count": 48 + }, + { + "path": "SECURITY.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "Swabble/.github/workflows/ci.yml", + "language": "yaml", + "symbol_count": 18 + }, + { + "path": "Swabble/.gitignore", + "language": "gitignore", + "symbol_count": 1 + }, + { + "path": "Swabble/.swiftlint.yml", + "language": "yaml", + "symbol_count": 8 + }, + { + "path": "Swabble/CHANGELOG.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "Swabble/README.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "Swabble/docs/spec.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "appcast.xml", + "language": "xml", + "symbol_count": 12 + }, + { + "path": "apps/android/.gitignore", + "language": "gitignore", + "symbol_count": 1 + }, + { + "path": "apps/android/README.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "apps/android/app/build.gradle.kts", + "language": "gradle", + "symbol_count": 1 + }, + { + "path": "apps/android/app/src/main/AndroidManifest.xml", + "language": "xml", + "symbol_count": 9 + }, + { + "path": "apps/android/app/src/main/res/mipmap-anydpi/ic_launcher.xml", + "language": "xml", + "symbol_count": 4 + }, + { + "path": "apps/android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml", + "language": "xml", + "symbol_count": 4 + }, + { + "path": "apps/android/app/src/main/res/values/colors.xml", + "language": "xml", + "symbol_count": 2 + }, + { + "path": "apps/android/app/src/main/res/values/strings.xml", + "language": "xml", + "symbol_count": 2 + }, + { + "path": "apps/android/app/src/main/res/values/themes.xml", + "language": "xml", + "symbol_count": 3 + }, + { + "path": "apps/android/app/src/main/res/xml/backup_rules.xml", + "language": "xml", + "symbol_count": 2 + }, + { + "path": "apps/android/app/src/main/res/xml/data_extraction_rules.xml", + "language": "xml", + "symbol_count": 5 + }, + { + "path": "apps/android/app/src/main/res/xml/network_security_config.xml", + "language": "xml", + "symbol_count": 4 + }, + { + "path": "apps/android/build.gradle.kts", + "language": "gradle", + "symbol_count": 1 + }, + { + "path": "apps/android/gradlew", + "language": "shell", + "symbol_count": 1 + }, + { + "path": "apps/android/settings.gradle.kts", + "language": "gradle", + "symbol_count": 1 + }, + { + "path": "apps/ios/.swiftlint.yml", + "language": "yaml", + "symbol_count": 2 + }, + { + "path": "apps/ios/README.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "apps/ios/Sources/Assets.xcassets/AppIcon.appiconset/Contents.json", + "language": "json", + "symbol_count": 8 + }, + { + "path": "apps/ios/Sources/Assets.xcassets/Contents.json", + "language": "json", + "symbol_count": 3 + }, + { + "path": "apps/ios/fastlane/SETUP.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "apps/ios/project.yml", + "language": "yaml", + "symbol_count": 92 + }, + { + "path": "apps/macos/Icon.icon/icon.json", + "language": "json", + "symbol_count": 18 + }, + { + "path": "apps/macos/README.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "apps/macos/Sources/Moltbot/Resources/DeviceModels/NOTICE.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "apps/macos/Sources/Moltbot/Resources/DeviceModels/ios-device-identifiers.json", + "language": "json", + "symbol_count": 174 + }, + { + "path": "apps/macos/Sources/Moltbot/Resources/DeviceModels/mac-device-identifiers.json", + "language": "json", + "symbol_count": 138 + }, + { + "path": "apps/shared/MoltbotKit/Sources/MoltbotKit/Resources/tool-display.json", + "language": "json", + "symbol_count": 263 + }, + { + "path": "apps/shared/MoltbotKit/Tools/CanvasA2UI/bootstrap.js", + "language": "javascript", + "symbol_count": 171 + }, + { + "path": "apps/shared/MoltbotKit/Tools/CanvasA2UI/rolldown.config.mjs", + "language": "javascript", + "symbol_count": 13 + }, + { + "path": "assets/chrome-extension/README.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "assets/chrome-extension/background.js", + "language": "javascript", + "symbol_count": 67 + }, + { + "path": "assets/chrome-extension/manifest.json", + "language": "json", + "symbol_count": 24 + }, + { + "path": "assets/chrome-extension/options.js", + "language": "javascript", + "symbol_count": 9 + }, + { + "path": "docker-compose.yml", + "language": "yaml", + "symbol_count": 29 + }, + { + "path": "docs.acp.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/SECURITY_FIRST_REWRITE_ASSESSMENT.md", + "language": "markdown", + "symbol_count": 85 + }, + { + "path": "docs/_config.yml", + "language": "yaml", + "symbol_count": 20 + }, + { + "path": "docs/assets/theme.js", + "language": "javascript", + "symbol_count": 5 + }, + { + "path": "docs/automation/auth-monitoring.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "docs/automation/cron-jobs.md", + "language": "markdown", + "symbol_count": 20 + }, + { + "path": "docs/automation/cron-vs-heartbeat.md", + "language": "markdown", + "symbol_count": 24 + }, + { + "path": "docs/automation/gmail-pubsub.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/automation/poll.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/automation/webhook.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "docs/bedrock.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/brave-search.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/broadcast-groups.md", + "language": "markdown", + "symbol_count": 39 + }, + { + "path": "docs/channels/bluebubbles.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "docs/channels/discord.md", + "language": "markdown", + "symbol_count": 22 + }, + { + "path": "docs/channels/googlechat.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/channels/grammy.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "docs/channels/imessage.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "docs/channels/index.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "docs/channels/line.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/channels/location.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/channels/matrix.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/channels/mattermost.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/channels/msteams.md", + "language": "markdown", + "symbol_count": 50 + }, + { + "path": "docs/channels/nextcloud-talk.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/channels/nostr.md", + "language": "markdown", + "symbol_count": 22 + }, + { + "path": "docs/channels/signal.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/channels/slack.md", + "language": "markdown", + "symbol_count": 26 + }, + { + "path": "docs/channels/telegram.md", + "language": "markdown", + "symbol_count": 41 + }, + { + "path": "docs/channels/tlon.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/channels/troubleshooting.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "docs/channels/twitch.md", + "language": "markdown", + "symbol_count": 23 + }, + { + "path": "docs/channels/whatsapp.md", + "language": "markdown", + "symbol_count": 29 + }, + { + "path": "docs/channels/zalo.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "docs/channels/zalouser.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/cli/acp.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/cli/agent.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/agents.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/cli/approvals.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/cli/browser.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/cli/channels.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/cli/config.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/cli/configure.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/cron.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/dashboard.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/cli/devices.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/cli/directory.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/cli/dns.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/docs.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/cli/doctor.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "docs/cli/gateway.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/cli/health.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/cli/hooks.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/cli/index.md", + "language": "markdown", + "symbol_count": 66 + }, + { + "path": "docs/cli/logs.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/memory.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "docs/cli/message.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/cli/models.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/cli/node.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/cli/nodes.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/cli/onboard.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/pairing.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/plugins.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/cli/reset.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/cli/sandbox.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/cli/security.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/sessions.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/cli/setup.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/skills.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/status.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/cli/system.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/cli/tui.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/cli/uninstall.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/cli/update.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/cli/voicecall.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "docs/cli/webhooks.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "docs/concepts/agent-loop.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "docs/concepts/agent-workspace.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/concepts/agent.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/concepts/architecture.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/concepts/channel-routing.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/concepts/compaction.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/concepts/context.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/concepts/group-messages.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/concepts/groups.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/concepts/markdown-formatting.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "docs/concepts/memory.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "docs/concepts/messages.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/concepts/model-failover.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/concepts/model-providers.md", + "language": "markdown", + "symbol_count": 21 + }, + { + "path": "docs/concepts/models.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/concepts/multi-agent.md", + "language": "markdown", + "symbol_count": 15 + }, + { + "path": "docs/concepts/oauth.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "docs/concepts/presence.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/concepts/queue.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/concepts/retry.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/concepts/session-pruning.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/concepts/session-tool.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/concepts/session.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/concepts/sessions.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/concepts/streaming.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/concepts/system-prompt.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/concepts/timezone.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/concepts/typebox.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/concepts/typing-indicators.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/concepts/usage-tracking.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/date-time.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/debug/node-issue.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "docs/debugging.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/diagnostics/flags.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/docs.json", + "language": "json", + "symbol_count": 19 + }, + { + "path": "docs/environment.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/experiments/onboarding-config-protocol.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/experiments/plans/cron-add-hardening.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/experiments/plans/group-policy-hardening.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/experiments/plans/openresponses-gateway.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/experiments/proposals/model-config.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/experiments/research/memory.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "docs/gateway/authentication.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "docs/gateway/background-process.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/gateway/bonjour.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "docs/gateway/bridge-protocol.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/gateway/cli-backends.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/gateway/configuration-examples.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/gateway/configuration.md", + "language": "markdown", + "symbol_count": 84 + }, + { + "path": "docs/gateway/discovery.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "docs/gateway/doctor.md", + "language": "markdown", + "symbol_count": 26 + }, + { + "path": "docs/gateway/gateway-lock.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/gateway/health.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/gateway/heartbeat.md", + "language": "markdown", + "symbol_count": 19 + }, + { + "path": "docs/gateway/index.md", + "language": "markdown", + "symbol_count": 23 + }, + { + "path": "docs/gateway/local-models.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/gateway/logging.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/gateway/multiple-gateways.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/gateway/openai-http-api.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/gateway/openresponses-http-api.md", + "language": "markdown", + "symbol_count": 19 + }, + { + "path": "docs/gateway/pairing.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/gateway/protocol.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "docs/gateway/remote-gateway-readme.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/gateway/remote.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/gateway/sandbox-vs-tool-policy-vs-elevated.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/gateway/sandboxing.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/gateway/security/formal-verification.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/gateway/security/index.md", + "language": "markdown", + "symbol_count": 55 + }, + { + "path": "docs/gateway/tailscale.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/gateway/tools-invoke-http-api.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/gateway/troubleshooting.md", + "language": "markdown", + "symbol_count": 45 + }, + { + "path": "docs/help/faq.md", + "language": "markdown", + "symbol_count": 188 + }, + { + "path": "docs/help/index.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/help/troubleshooting.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/hooks.md", + "language": "markdown", + "symbol_count": 64 + }, + { + "path": "docs/hooks/soul-evil.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/index.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/install/ansible.md", + "language": "markdown", + "symbol_count": 20 + }, + { + "path": "docs/install/bun.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/install/development-channels.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/install/docker.md", + "language": "markdown", + "symbol_count": 28 + }, + { + "path": "docs/install/index.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/install/installer.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/install/migrating.md", + "language": "markdown", + "symbol_count": 18 + }, + { + "path": "docs/install/nix.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/install/node.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/install/uninstall.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/install/updating.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/logging.md", + "language": "markdown", + "symbol_count": 26 + }, + { + "path": "docs/multi-agent-sandbox-tools.md", + "language": "markdown", + "symbol_count": 24 + }, + { + "path": "docs/network.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/nodes/audio.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/nodes/camera.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/nodes/images.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/nodes/index.md", + "language": "markdown", + "symbol_count": 22 + }, + { + "path": "docs/nodes/location-command.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/nodes/media-understanding.md", + "language": "markdown", + "symbol_count": 19 + }, + { + "path": "docs/nodes/talk.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/nodes/voicewake.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/perplexity.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/platforms/android.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/platforms/digitalocean.md", + "language": "markdown", + "symbol_count": 24 + }, + { + "path": "docs/platforms/exe-dev.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/platforms/fly.md", + "language": "markdown", + "symbol_count": 30 + }, + { + "path": "docs/platforms/gcp.md", + "language": "markdown", + "symbol_count": 23 + }, + { + "path": "docs/platforms/hetzner.md", + "language": "markdown", + "symbol_count": 15 + }, + { + "path": "docs/platforms/index.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/platforms/ios.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/platforms/linux.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/platforms/mac/bundled-gateway.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/platforms/mac/canvas.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/platforms/mac/child-process.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/platforms/mac/dev-setup.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/platforms/mac/health.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/platforms/mac/icon.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/platforms/mac/logging.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/platforms/mac/menu-bar.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/platforms/mac/peekaboo.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/platforms/mac/permissions.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "docs/platforms/mac/release.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/platforms/mac/remote.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "docs/platforms/mac/signing.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/platforms/mac/skills.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/platforms/mac/voice-overlay.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/platforms/mac/voicewake.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/platforms/mac/webchat.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/platforms/mac/xpc.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/platforms/macos-vm.md", + "language": "markdown", + "symbol_count": 20 + }, + { + "path": "docs/platforms/macos.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/platforms/oracle.md", + "language": "markdown", + "symbol_count": 26 + }, + { + "path": "docs/platforms/raspberry-pi.md", + "language": "markdown", + "symbol_count": 32 + }, + { + "path": "docs/platforms/windows.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/plugin.md", + "language": "markdown", + "symbol_count": 29 + }, + { + "path": "docs/plugins/agent-tools.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/plugins/manifest.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/plugins/voice-call.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/plugins/zalouser.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/prose.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/providers/anthropic.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/providers/claude-max-api-proxy.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/providers/deepgram.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/providers/github-copilot.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/providers/glm.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/providers/index.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/providers/minimax.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/providers/models.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/providers/moonshot.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/providers/ollama.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "docs/providers/openai.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/providers/opencode.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/providers/openrouter.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/providers/qwen.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/providers/synthetic.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/providers/venice.md", + "language": "markdown", + "symbol_count": 25 + }, + { + "path": "docs/providers/vercel-ai-gateway.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/providers/zai.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/refactor/clawnet.md", + "language": "markdown", + "symbol_count": 56 + }, + { + "path": "docs/refactor/exec-host.md", + "language": "markdown", + "symbol_count": 44 + }, + { + "path": "docs/refactor/outbound-session-mirroring.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "docs/refactor/plugin-sdk.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "docs/refactor/strict-config.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/reference/AGENTS.default.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/reference/RELEASING.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/reference/api-usage-costs.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/reference/device-models.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "docs/reference/rpc.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/reference/session-management-compaction.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "docs/reference/templates/AGENTS.dev.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/reference/templates/AGENTS.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "docs/reference/templates/BOOT.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/reference/templates/BOOTSTRAP.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/reference/templates/HEARTBEAT.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "docs/reference/templates/IDENTITY.dev.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "docs/reference/templates/SOUL.dev.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/reference/templates/SOUL.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/reference/templates/TOOLS.dev.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/reference/templates/TOOLS.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/reference/templates/USER.dev.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/reference/test.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/reference/transcript-hygiene.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/scripts.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/security/formal-verification.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/start/clawd.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "docs/start/getting-started.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/start/hubs.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "docs/start/lore.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "docs/start/onboarding.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "docs/start/pairing.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/start/setup.md", + "language": "markdown", + "symbol_count": 15 + }, + { + "path": "docs/start/showcase.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/start/wizard.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "docs/testing.md", + "language": "markdown", + "symbol_count": 25 + }, + { + "path": "docs/token-use.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/tools/agent-send.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/tools/apply-patch.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/tools/browser-linux-troubleshooting.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/tools/browser-login.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/tools/browser.md", + "language": "markdown", + "symbol_count": 28 + }, + { + "path": "docs/tools/chrome-extension.md", + "language": "markdown", + "symbol_count": 15 + }, + { + "path": "docs/tools/clawdhub.md", + "language": "markdown", + "symbol_count": 19 + }, + { + "path": "docs/tools/creating-skills.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/tools/elevated.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/tools/exec-approvals.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "docs/tools/exec.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/tools/firecrawl.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "docs/tools/index.md", + "language": "markdown", + "symbol_count": 25 + }, + { + "path": "docs/tools/llm-task.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "docs/tools/lobster.md", + "language": "markdown", + "symbol_count": 22 + }, + { + "path": "docs/tools/reactions.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "docs/tools/skills-config.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/tools/skills.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "docs/tools/slash-commands.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "docs/tools/subagents.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/tools/thinking.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/tools/web.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/tts.md", + "language": "markdown", + "symbol_count": 23 + }, + { + "path": "docs/tui.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "docs/vps.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/web/control-ui.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "docs/web/dashboard.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "docs/web/index.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "docs/web/webchat.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "extensions/bluebubbles/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/bluebubbles/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/bluebubbles/package.json", + "language": "json", + "symbol_count": 22 + }, + { + "path": "extensions/bluebubbles/src/accounts.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/bluebubbles/src/actions.test.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "extensions/bluebubbles/src/actions.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "extensions/bluebubbles/src/attachments.test.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "extensions/bluebubbles/src/attachments.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "extensions/bluebubbles/src/channel.ts", + "language": "typescript", + "symbol_count": 151 + }, + { + "path": "extensions/bluebubbles/src/chat.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "extensions/bluebubbles/src/chat.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "extensions/bluebubbles/src/config-schema.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "extensions/bluebubbles/src/media-send.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/bluebubbles/src/monitor.test.ts", + "language": "typescript", + "symbol_count": 153 + }, + { + "path": "extensions/bluebubbles/src/monitor.ts", + "language": "typescript", + "symbol_count": 249 + }, + { + "path": "extensions/bluebubbles/src/onboarding.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "extensions/bluebubbles/src/probe.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "extensions/bluebubbles/src/reactions.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "extensions/bluebubbles/src/reactions.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "extensions/bluebubbles/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/bluebubbles/src/send.test.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "extensions/bluebubbles/src/send.ts", + "language": "typescript", + "symbol_count": 67 + }, + { + "path": "extensions/bluebubbles/src/targets.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/bluebubbles/src/targets.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "extensions/bluebubbles/src/types.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "extensions/copilot-proxy/README.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "extensions/copilot-proxy/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/copilot-proxy/index.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "extensions/copilot-proxy/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/diagnostics-otel/clawdbot.plugin.json", + "language": "json", + "symbol_count": 5 + }, + { + "path": "extensions/diagnostics-otel/index.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/diagnostics-otel/package.json", + "language": "json", + "symbol_count": 18 + }, + { + "path": "extensions/diagnostics-otel/src/service.test.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "extensions/diagnostics-otel/src/service.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "extensions/discord/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/discord/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/discord/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/discord/src/channel.ts", + "language": "typescript", + "symbol_count": 157 + }, + { + "path": "extensions/discord/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/google-antigravity-auth/README.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "extensions/google-antigravity-auth/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/google-antigravity-auth/index.ts", + "language": "typescript", + "symbol_count": 73 + }, + { + "path": "extensions/google-antigravity-auth/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/google-gemini-cli-auth/README.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "extensions/google-gemini-cli-auth/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/google-gemini-cli-auth/index.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "extensions/google-gemini-cli-auth/oauth.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/google-gemini-cli-auth/oauth.ts", + "language": "typescript", + "symbol_count": 65 + }, + { + "path": "extensions/google-gemini-cli-auth/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/googlechat/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/googlechat/index.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/googlechat/package.json", + "language": "json", + "symbol_count": 26 + }, + { + "path": "extensions/googlechat/src/accounts.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "extensions/googlechat/src/actions.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "extensions/googlechat/src/api.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/googlechat/src/api.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "extensions/googlechat/src/auth.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/googlechat/src/channel.ts", + "language": "typescript", + "symbol_count": 136 + }, + { + "path": "extensions/googlechat/src/monitor.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/googlechat/src/monitor.ts", + "language": "typescript", + "symbol_count": 133 + }, + { + "path": "extensions/googlechat/src/onboarding.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "extensions/googlechat/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/googlechat/src/targets.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/googlechat/src/targets.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/googlechat/src/types.config.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/googlechat/src/types.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "extensions/imessage/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/imessage/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/imessage/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/imessage/src/channel.ts", + "language": "typescript", + "symbol_count": 122 + }, + { + "path": "extensions/imessage/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/line/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/line/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/line/package.json", + "language": "json", + "symbol_count": 21 + }, + { + "path": "extensions/line/src/card-command.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "extensions/line/src/channel.logout.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "extensions/line/src/channel.sendPayload.test.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "extensions/line/src/channel.ts", + "language": "typescript", + "symbol_count": 161 + }, + { + "path": "extensions/line/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/llm-task/README.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "extensions/llm-task/clawdbot.plugin.json", + "language": "json", + "symbol_count": 22 + }, + { + "path": "extensions/llm-task/index.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/llm-task/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/llm-task/src/llm-task-tool.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "extensions/llm-task/src/llm-task-tool.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "extensions/lobster/README.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "extensions/lobster/SKILL.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "extensions/lobster/clawdbot.plugin.json", + "language": "json", + "symbol_count": 7 + }, + { + "path": "extensions/lobster/index.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/lobster/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/lobster/src/lobster-tool.test.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "extensions/lobster/src/lobster-tool.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "extensions/matrix/CHANGELOG.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "extensions/matrix/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/matrix/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/matrix/package.json", + "language": "json", + "symbol_count": 27 + }, + { + "path": "extensions/matrix/src/actions.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "extensions/matrix/src/channel.directory.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "extensions/matrix/src/channel.ts", + "language": "typescript", + "symbol_count": 163 + }, + { + "path": "extensions/matrix/src/config-schema.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "extensions/matrix/src/directory-live.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "extensions/matrix/src/group-mentions.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/matrix/src/matrix/accounts.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/matrix/src/matrix/accounts.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "extensions/matrix/src/matrix/actions.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/matrix/src/matrix/actions/client.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/matrix/src/matrix/actions/messages.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "extensions/matrix/src/matrix/actions/pins.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/matrix/src/matrix/actions/reactions.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/matrix/src/matrix/actions/room.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/matrix/src/matrix/actions/summary.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/matrix/src/matrix/actions/types.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "extensions/matrix/src/matrix/active-client.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/matrix/src/matrix/client.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "extensions/matrix/src/matrix/client.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/matrix/src/matrix/client/config.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "extensions/matrix/src/matrix/client/create-client.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/matrix/src/matrix/client/logging.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/matrix/src/matrix/client/runtime.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/matrix/src/matrix/client/shared.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "extensions/matrix/src/matrix/client/storage.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "extensions/matrix/src/matrix/client/types.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "extensions/matrix/src/matrix/credentials.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/matrix/src/matrix/deps.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/matrix/src/matrix/format.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/matrix/src/matrix/format.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/matrix/src/matrix/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/matrix/src/matrix/monitor/allowlist.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/matrix/src/matrix/monitor/auto-join.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/matrix/src/matrix/monitor/direct.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/matrix/src/matrix/monitor/events.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/matrix/src/matrix/monitor/handler.ts", + "language": "typescript", + "symbol_count": 110 + }, + { + "path": "extensions/matrix/src/matrix/monitor/index.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "extensions/matrix/src/matrix/monitor/location.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/matrix/src/matrix/monitor/media.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "extensions/matrix/src/matrix/monitor/media.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/matrix/src/matrix/monitor/mentions.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "extensions/matrix/src/matrix/monitor/replies.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/matrix/src/matrix/monitor/room-info.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/matrix/src/matrix/monitor/rooms.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/matrix/src/matrix/monitor/threads.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/matrix/src/matrix/monitor/types.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/matrix/src/matrix/poll-types.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/matrix/src/matrix/poll-types.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "extensions/matrix/src/matrix/probe.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "extensions/matrix/src/matrix/send.test.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "extensions/matrix/src/matrix/send.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "extensions/matrix/src/matrix/send/client.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/matrix/src/matrix/send/formatting.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "extensions/matrix/src/matrix/send/media.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "extensions/matrix/src/matrix/send/targets.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "extensions/matrix/src/matrix/send/targets.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/matrix/src/matrix/send/types.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "extensions/matrix/src/onboarding.ts", + "language": "typescript", + "symbol_count": 61 + }, + { + "path": "extensions/matrix/src/outbound.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "extensions/matrix/src/resolve-targets.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "extensions/matrix/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/matrix/src/tool-actions.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "extensions/matrix/src/types.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/mattermost/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/mattermost/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/mattermost/package.json", + "language": "json", + "symbol_count": 18 + }, + { + "path": "extensions/mattermost/src/channel.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/mattermost/src/channel.ts", + "language": "typescript", + "symbol_count": 146 + }, + { + "path": "extensions/mattermost/src/config-schema.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "extensions/mattermost/src/group-mentions.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "extensions/mattermost/src/mattermost/accounts.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "extensions/mattermost/src/mattermost/client.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "extensions/mattermost/src/mattermost/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/mattermost/src/mattermost/monitor-helpers.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "extensions/mattermost/src/mattermost/monitor.ts", + "language": "typescript", + "symbol_count": 162 + }, + { + "path": "extensions/mattermost/src/mattermost/probe.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "extensions/mattermost/src/mattermost/send.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "extensions/mattermost/src/normalize.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/mattermost/src/onboarding-helpers.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/mattermost/src/onboarding.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "extensions/mattermost/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/mattermost/src/types.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "extensions/memory-core/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/memory-core/index.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "extensions/memory-core/package.json", + "language": "json", + "symbol_count": 10 + }, + { + "path": "extensions/memory-lancedb/clawdbot.plugin.json", + "language": "json", + "symbol_count": 43 + }, + { + "path": "extensions/memory-lancedb/config.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "extensions/memory-lancedb/index.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "extensions/memory-lancedb/index.ts", + "language": "typescript", + "symbol_count": 66 + }, + { + "path": "extensions/memory-lancedb/package.json", + "language": "json", + "symbol_count": 10 + }, + { + "path": "extensions/msteams/CHANGELOG.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "extensions/msteams/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/msteams/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/msteams/package.json", + "language": "json", + "symbol_count": 26 + }, + { + "path": "extensions/msteams/src/attachments.test.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "extensions/msteams/src/attachments.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/msteams/src/attachments/download.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "extensions/msteams/src/attachments/graph.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "extensions/msteams/src/attachments/html.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "extensions/msteams/src/attachments/payload.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/msteams/src/attachments/shared.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "extensions/msteams/src/attachments/types.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/msteams/src/channel.directory.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "extensions/msteams/src/channel.ts", + "language": "typescript", + "symbol_count": 126 + }, + { + "path": "extensions/msteams/src/conversation-store-fs.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "extensions/msteams/src/conversation-store-fs.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "extensions/msteams/src/conversation-store-memory.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/msteams/src/conversation-store.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "extensions/msteams/src/directory-live.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "extensions/msteams/src/errors.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "extensions/msteams/src/errors.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/msteams/src/file-consent-helpers.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "extensions/msteams/src/file-consent-helpers.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "extensions/msteams/src/file-consent.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "extensions/msteams/src/graph-chat.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/msteams/src/graph-upload.ts", + "language": "typescript", + "symbol_count": 71 + }, + { + "path": "extensions/msteams/src/inbound.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/msteams/src/inbound.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/msteams/src/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/msteams/src/media-helpers.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/msteams/src/media-helpers.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/msteams/src/messenger.test.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "extensions/msteams/src/messenger.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "extensions/msteams/src/monitor-handler.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "extensions/msteams/src/monitor-handler/inbound-media.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "extensions/msteams/src/monitor-handler/message-handler.ts", + "language": "typescript", + "symbol_count": 115 + }, + { + "path": "extensions/msteams/src/monitor-types.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/msteams/src/monitor.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "extensions/msteams/src/onboarding.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "extensions/msteams/src/outbound.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "extensions/msteams/src/pending-uploads.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/msteams/src/policy.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "extensions/msteams/src/policy.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "extensions/msteams/src/polls-store-memory.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/msteams/src/polls-store.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/msteams/src/polls.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "extensions/msteams/src/polls.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "extensions/msteams/src/probe.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/msteams/src/probe.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/msteams/src/reply-dispatcher.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "extensions/msteams/src/resolve-allowlist.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "extensions/msteams/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/msteams/src/sdk-types.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/msteams/src/sdk.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "extensions/msteams/src/send-context.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/msteams/src/send.ts", + "language": "typescript", + "symbol_count": 61 + }, + { + "path": "extensions/msteams/src/sent-message-cache.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/msteams/src/sent-message-cache.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/msteams/src/storage.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/msteams/src/store-fs.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "extensions/msteams/src/token.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/nextcloud-talk/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/nextcloud-talk/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/nextcloud-talk/package.json", + "language": "json", + "symbol_count": 20 + }, + { + "path": "extensions/nextcloud-talk/src/accounts.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "extensions/nextcloud-talk/src/channel.ts", + "language": "typescript", + "symbol_count": 133 + }, + { + "path": "extensions/nextcloud-talk/src/config-schema.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "extensions/nextcloud-talk/src/format.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/nextcloud-talk/src/inbound.ts", + "language": "typescript", + "symbol_count": 67 + }, + { + "path": "extensions/nextcloud-talk/src/monitor.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "extensions/nextcloud-talk/src/normalize.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/nextcloud-talk/src/onboarding.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "extensions/nextcloud-talk/src/policy.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "extensions/nextcloud-talk/src/room-info.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "extensions/nextcloud-talk/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/nextcloud-talk/src/send.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "extensions/nextcloud-talk/src/signature.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "extensions/nextcloud-talk/src/types.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/nostr/CHANGELOG.md", + "language": "markdown", + "symbol_count": 11 + }, + { + "path": "extensions/nostr/README.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "extensions/nostr/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/nostr/index.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "extensions/nostr/package.json", + "language": "json", + "symbol_count": 23 + }, + { + "path": "extensions/nostr/src/channel.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/nostr/src/channel.ts", + "language": "typescript", + "symbol_count": 108 + }, + { + "path": "extensions/nostr/src/config-schema.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "extensions/nostr/src/metrics.ts", + "language": "typescript", + "symbol_count": 93 + }, + { + "path": "extensions/nostr/src/nostr-bus.fuzz.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "extensions/nostr/src/nostr-bus.integration.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "extensions/nostr/src/nostr-bus.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/nostr/src/nostr-bus.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "extensions/nostr/src/nostr-profile-http.test.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "extensions/nostr/src/nostr-profile-http.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "extensions/nostr/src/nostr-profile-import.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/nostr/src/nostr-profile-import.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "extensions/nostr/src/nostr-profile.fuzz.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/nostr/src/nostr-profile.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "extensions/nostr/src/nostr-profile.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "extensions/nostr/src/nostr-state-store.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "extensions/nostr/src/nostr-state-store.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "extensions/nostr/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/nostr/src/seen-tracker.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "extensions/nostr/src/types.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/nostr/src/types.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "extensions/nostr/test/setup.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/open-prose/README.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "extensions/open-prose/clawdbot.plugin.json", + "language": "json", + "symbol_count": 8 + }, + { + "path": "extensions/open-prose/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/open-prose/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/open-prose/skills/prose/SKILL.md", + "language": "markdown", + "symbol_count": 19 + }, + { + "path": "extensions/open-prose/skills/prose/alt-borges.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "extensions/open-prose/skills/prose/alts/arabian-nights.md", + "language": "markdown", + "symbol_count": 27 + }, + { + "path": "extensions/open-prose/skills/prose/alts/borges.md", + "language": "markdown", + "symbol_count": 27 + }, + { + "path": "extensions/open-prose/skills/prose/alts/folk.md", + "language": "markdown", + "symbol_count": 24 + }, + { + "path": "extensions/open-prose/skills/prose/alts/homer.md", + "language": "markdown", + "symbol_count": 26 + }, + { + "path": "extensions/open-prose/skills/prose/alts/kafka.md", + "language": "markdown", + "symbol_count": 28 + }, + { + "path": "extensions/open-prose/skills/prose/compiler.md", + "language": "markdown", + "symbol_count": 175 + }, + { + "path": "extensions/open-prose/skills/prose/examples/README.md", + "language": "markdown", + "symbol_count": 31 + }, + { + "path": "extensions/open-prose/skills/prose/examples/roadmap/README.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "extensions/open-prose/skills/prose/guidance/antipatterns.md", + "language": "markdown", + "symbol_count": 39 + }, + { + "path": "extensions/open-prose/skills/prose/guidance/patterns.md", + "language": "markdown", + "symbol_count": 44 + }, + { + "path": "extensions/open-prose/skills/prose/guidance/system-prompt.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "extensions/open-prose/skills/prose/help.md", + "language": "markdown", + "symbol_count": 15 + }, + { + "path": "extensions/open-prose/skills/prose/lib/README.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "extensions/open-prose/skills/prose/primitives/session.md", + "language": "markdown", + "symbol_count": 35 + }, + { + "path": "extensions/open-prose/skills/prose/prose.md", + "language": "markdown", + "symbol_count": 84 + }, + { + "path": "extensions/open-prose/skills/prose/state/filesystem.md", + "language": "markdown", + "symbol_count": 20 + }, + { + "path": "extensions/open-prose/skills/prose/state/in-context.md", + "language": "markdown", + "symbol_count": 20 + }, + { + "path": "extensions/open-prose/skills/prose/state/postgres.md", + "language": "markdown", + "symbol_count": 42 + }, + { + "path": "extensions/open-prose/skills/prose/state/sqlite.md", + "language": "markdown", + "symbol_count": 26 + }, + { + "path": "extensions/qwen-portal-auth/README.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "extensions/qwen-portal-auth/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/qwen-portal-auth/index.ts", + "language": "typescript", + "symbol_count": 52 + }, + { + "path": "extensions/qwen-portal-auth/oauth.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "extensions/signal/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/signal/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/signal/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/signal/src/channel.ts", + "language": "typescript", + "symbol_count": 127 + }, + { + "path": "extensions/signal/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/slack/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/slack/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/slack/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/slack/src/channel.ts", + "language": "typescript", + "symbol_count": 161 + }, + { + "path": "extensions/slack/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/telegram/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/telegram/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/telegram/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/telegram/src/channel.ts", + "language": "typescript", + "symbol_count": 145 + }, + { + "path": "extensions/telegram/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/tlon/README.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "extensions/tlon/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/tlon/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/tlon/package.json", + "language": "json", + "symbol_count": 22 + }, + { + "path": "extensions/tlon/src/channel.ts", + "language": "typescript", + "symbol_count": 123 + }, + { + "path": "extensions/tlon/src/config-schema.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/tlon/src/config-schema.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "extensions/tlon/src/monitor/discovery.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/tlon/src/monitor/history.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/tlon/src/monitor/index.ts", + "language": "typescript", + "symbol_count": 74 + }, + { + "path": "extensions/tlon/src/monitor/processed-messages.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/tlon/src/monitor/processed-messages.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "extensions/tlon/src/monitor/utils.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/tlon/src/onboarding.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "extensions/tlon/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/tlon/src/targets.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "extensions/tlon/src/types.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "extensions/tlon/src/urbit/auth.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "extensions/tlon/src/urbit/http-api.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "extensions/tlon/src/urbit/send.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/tlon/src/urbit/send.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "extensions/tlon/src/urbit/sse-client.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/tlon/src/urbit/sse-client.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "extensions/twitch/CHANGELOG.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "extensions/twitch/README.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "extensions/twitch/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/twitch/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/twitch/package.json", + "language": "json", + "symbol_count": 13 + }, + { + "path": "extensions/twitch/src/access-control.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "extensions/twitch/src/access-control.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/twitch/src/actions.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "extensions/twitch/src/client-manager-registry.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/twitch/src/config-schema.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "extensions/twitch/src/config.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "extensions/twitch/src/config.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "extensions/twitch/src/monitor.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "extensions/twitch/src/onboarding.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/twitch/src/onboarding.ts", + "language": "typescript", + "symbol_count": 73 + }, + { + "path": "extensions/twitch/src/outbound.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "extensions/twitch/src/outbound.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "extensions/twitch/src/plugin.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "extensions/twitch/src/plugin.ts", + "language": "typescript", + "symbol_count": 78 + }, + { + "path": "extensions/twitch/src/probe.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/twitch/src/probe.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/twitch/src/resolver.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/twitch/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/twitch/src/send.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "extensions/twitch/src/send.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/twitch/src/status.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "extensions/twitch/src/status.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/twitch/src/token.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "extensions/twitch/src/token.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/twitch/src/twitch-client.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "extensions/twitch/src/twitch-client.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "extensions/twitch/src/types.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/twitch/src/utils/markdown.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/twitch/src/utils/twitch.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/twitch/test/setup.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/voice-call/CHANGELOG.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "extensions/voice-call/README.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "extensions/voice-call/clawdbot.plugin.json", + "language": "json", + "symbol_count": 397 + }, + { + "path": "extensions/voice-call/index.ts", + "language": "typescript", + "symbol_count": 87 + }, + { + "path": "extensions/voice-call/package.json", + "language": "json", + "symbol_count": 10 + }, + { + "path": "extensions/voice-call/src/cli.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/voice-call/src/config.test.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "extensions/voice-call/src/config.ts", + "language": "typescript", + "symbol_count": 113 + }, + { + "path": "extensions/voice-call/src/core-bridge.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "extensions/voice-call/src/manager.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "extensions/voice-call/src/manager.ts", + "language": "typescript", + "symbol_count": 62 + }, + { + "path": "extensions/voice-call/src/manager/context.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/voice-call/src/manager/events.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "extensions/voice-call/src/manager/lookup.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/voice-call/src/manager/outbound.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "extensions/voice-call/src/manager/state.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "extensions/voice-call/src/manager/store.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/voice-call/src/manager/timers.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/voice-call/src/manager/twiml.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/voice-call/src/media-stream.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/voice-call/src/media-stream.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "extensions/voice-call/src/providers/base.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/voice-call/src/providers/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/voice-call/src/providers/mock.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "extensions/voice-call/src/providers/plivo.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/voice-call/src/providers/plivo.ts", + "language": "typescript", + "symbol_count": 76 + }, + { + "path": "extensions/voice-call/src/providers/stt-openai-realtime.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "extensions/voice-call/src/providers/telnyx.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "extensions/voice-call/src/providers/tts-openai.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "extensions/voice-call/src/providers/twilio.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/voice-call/src/providers/twilio.ts", + "language": "typescript", + "symbol_count": 63 + }, + { + "path": "extensions/voice-call/src/providers/twilio/api.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/voice-call/src/providers/twilio/webhook.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/voice-call/src/response-generator.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "extensions/voice-call/src/runtime.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "extensions/voice-call/src/telephony-audio.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/voice-call/src/telephony-tts.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/voice-call/src/tunnel.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "extensions/voice-call/src/types.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "extensions/voice-call/src/utils.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/voice-call/src/voice-mapping.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "extensions/voice-call/src/webhook-security.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "extensions/voice-call/src/webhook-security.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "extensions/voice-call/src/webhook.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "extensions/whatsapp/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/whatsapp/index.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/whatsapp/package.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/whatsapp/src/channel.ts", + "language": "typescript", + "symbol_count": 184 + }, + { + "path": "extensions/whatsapp/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/zalo/CHANGELOG.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "extensions/zalo/README.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "extensions/zalo/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/zalo/index.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "extensions/zalo/package.json", + "language": "json", + "symbol_count": 23 + }, + { + "path": "extensions/zalo/src/accounts.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/zalo/src/actions.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "extensions/zalo/src/api.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "extensions/zalo/src/channel.directory.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "extensions/zalo/src/channel.ts", + "language": "typescript", + "symbol_count": 114 + }, + { + "path": "extensions/zalo/src/config-schema.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "extensions/zalo/src/monitor.ts", + "language": "typescript", + "symbol_count": 91 + }, + { + "path": "extensions/zalo/src/monitor.webhook.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/zalo/src/onboarding.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "extensions/zalo/src/probe.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "extensions/zalo/src/proxy.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/zalo/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/zalo/src/send.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "extensions/zalo/src/status-issues.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "extensions/zalo/src/token.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "extensions/zalo/src/types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "extensions/zalouser/CHANGELOG.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "extensions/zalouser/README.md", + "language": "markdown", + "symbol_count": 20 + }, + { + "path": "extensions/zalouser/clawdbot.plugin.json", + "language": "json", + "symbol_count": 6 + }, + { + "path": "extensions/zalouser/index.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "extensions/zalouser/package.json", + "language": "json", + "symbol_count": 23 + }, + { + "path": "extensions/zalouser/src/accounts.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "extensions/zalouser/src/channel.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "extensions/zalouser/src/channel.ts", + "language": "typescript", + "symbol_count": 173 + }, + { + "path": "extensions/zalouser/src/config-schema.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/zalouser/src/monitor.ts", + "language": "typescript", + "symbol_count": 73 + }, + { + "path": "extensions/zalouser/src/onboarding.ts", + "language": "typescript", + "symbol_count": 63 + }, + { + "path": "extensions/zalouser/src/probe.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/zalouser/src/runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "extensions/zalouser/src/send.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "extensions/zalouser/src/status-issues.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "extensions/zalouser/src/status-issues.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/zalouser/src/tool.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "extensions/zalouser/src/types.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "extensions/zalouser/src/zca.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "fly.private.toml", + "language": "toml", + "symbol_count": 17 + }, + { + "path": "fly.toml", + "language": "toml", + "symbol_count": 24 + }, + { + "path": "memory/config.json", + "language": "json", + "symbol_count": 38 + }, + { + "path": "moltbot.mjs", + "language": "javascript", + "symbol_count": 1 + }, + { + "path": "package.json", + "language": "json", + "symbol_count": 193 + }, + { + "path": "packages/clawdbot/package.json", + "language": "json", + "symbol_count": 11 + }, + { + "path": "pnpm-workspace.yaml", + "language": "yaml", + "symbol_count": 2 + }, + { + "path": "render.yaml", + "language": "yaml", + "symbol_count": 15 + }, + { + "path": "scripts/bench-model.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "scripts/build-docs-list.mjs", + "language": "javascript", + "symbol_count": 2 + }, + { + "path": "scripts/canvas-a2ui-copy.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "scripts/check-ts-max-loc.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "scripts/clawtributors-map.json", + "language": "json", + "symbol_count": 17 + }, + { + "path": "scripts/copy-hook-metadata.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "scripts/debug-claude-usage.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "scripts/docker/cleanup-smoke/Dockerfile", + "language": "dockerfile", + "symbol_count": 1 + }, + { + "path": "scripts/docker/install-sh-e2e/Dockerfile", + "language": "dockerfile", + "symbol_count": 1 + }, + { + "path": "scripts/docker/install-sh-nonroot/Dockerfile", + "language": "dockerfile", + "symbol_count": 1 + }, + { + "path": "scripts/docker/install-sh-smoke/Dockerfile", + "language": "dockerfile", + "symbol_count": 1 + }, + { + "path": "scripts/docs-list.js", + "language": "javascript", + "symbol_count": 7 + }, + { + "path": "scripts/e2e/Dockerfile", + "language": "dockerfile", + "symbol_count": 1 + }, + { + "path": "scripts/firecrawl-compare.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "scripts/format-staged.js", + "language": "javascript", + "symbol_count": 23 + }, + { + "path": "scripts/postinstall.js", + "language": "javascript", + "symbol_count": 29 + }, + { + "path": "scripts/protocol-gen-swift.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "scripts/protocol-gen.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "scripts/readability-basic-compare.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "scripts/release-check.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "scripts/repro/tsx-name-repro.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "scripts/run-node.mjs", + "language": "javascript", + "symbol_count": 3 + }, + { + "path": "scripts/setup-git-hooks.js", + "language": "javascript", + "symbol_count": 18 + }, + { + "path": "scripts/sqlite-vec-smoke.mjs", + "language": "javascript", + "symbol_count": 2 + }, + { + "path": "scripts/sync-labels.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "scripts/sync-moonshot-docs.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "scripts/sync-plugin-versions.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "scripts/test-force.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "scripts/test-parallel.mjs", + "language": "javascript", + "symbol_count": 7 + }, + { + "path": "scripts/ui.js", + "language": "javascript", + "symbol_count": 17 + }, + { + "path": "scripts/update-clawtributors.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "scripts/update-clawtributors.types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "scripts/watch-node.mjs", + "language": "javascript", + "symbol_count": 2 + }, + { + "path": "scripts/write-build-info.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "scripts/zai-fallback-repro.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "skills/1password/SKILL.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "skills/1password/references/cli-examples.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "skills/1password/references/get-started.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/apple-notes/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/apple-reminders/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/bear-notes/SKILL.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "skills/bird/SKILL.md", + "language": "markdown", + "symbol_count": 22 + }, + { + "path": "skills/blogwatcher/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/blucli/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/bluebubbles/SKILL.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "skills/camsnap/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/canvas/SKILL.md", + "language": "markdown", + "symbol_count": 21 + }, + { + "path": "skills/clawdhub/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/coding-agent/SKILL.md", + "language": "markdown", + "symbol_count": 19 + }, + { + "path": "skills/discord/SKILL.md", + "language": "markdown", + "symbol_count": 32 + }, + { + "path": "skills/eightctl/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/food-order/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/gemini/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/gifgrep/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/github/SKILL.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "skills/gog/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/goplaces/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/himalaya/SKILL.md", + "language": "markdown", + "symbol_count": 20 + }, + { + "path": "skills/himalaya/references/configuration.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "skills/himalaya/references/message-composition.md", + "language": "markdown", + "symbol_count": 20 + }, + { + "path": "skills/imsg/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/local-places/SERVER_README.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "skills/local-places/SKILL.md", + "language": "markdown", + "symbol_count": 6 + }, + { + "path": "skills/local-places/pyproject.toml", + "language": "toml", + "symbol_count": 17 + }, + { + "path": "skills/local-places/src/local_places/__init__.py", + "language": "python", + "symbol_count": 1 + }, + { + "path": "skills/local-places/src/local_places/google_places.py", + "language": "python", + "symbol_count": 25 + }, + { + "path": "skills/local-places/src/local_places/main.py", + "language": "python", + "symbol_count": 5 + }, + { + "path": "skills/local-places/src/local_places/schemas.py", + "language": "python", + "symbol_count": 57 + }, + { + "path": "skills/mcporter/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/model-usage/SKILL.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "skills/model-usage/references/codexbar-cli.md", + "language": "markdown", + "symbol_count": 5 + }, + { + "path": "skills/model-usage/scripts/model_usage.py", + "language": "python", + "symbol_count": 28 + }, + { + "path": "skills/nano-banana-pro/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/nano-banana-pro/scripts/generate_image.py", + "language": "python", + "symbol_count": 2 + }, + { + "path": "skills/nano-pdf/SKILL.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "skills/notion/SKILL.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "skills/obsidian/SKILL.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "skills/openai-image-gen/SKILL.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "skills/openai-image-gen/scripts/gen.py", + "language": "python", + "symbol_count": 12 + }, + { + "path": "skills/openai-whisper-api/SKILL.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "skills/openai-whisper/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/openhue/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/oracle/SKILL.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "skills/ordercli/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/peekaboo/SKILL.md", + "language": "markdown", + "symbol_count": 15 + }, + { + "path": "skills/sag/SKILL.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "skills/session-logs/SKILL.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "skills/sherpa-onnx-tts/SKILL.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "skills/skill-creator/SKILL.md", + "language": "markdown", + "symbol_count": 28 + }, + { + "path": "skills/skill-creator/scripts/init_skill.py", + "language": "python", + "symbol_count": 12 + }, + { + "path": "skills/skill-creator/scripts/package_skill.py", + "language": "python", + "symbol_count": 2 + }, + { + "path": "skills/skill-creator/scripts/quick_validate.py", + "language": "python", + "symbol_count": 2 + }, + { + "path": "skills/slack/SKILL.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "skills/songsee/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/sonoscli/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/spotify-player/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/summarize/SKILL.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "skills/things-mac/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/tmux/SKILL.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "skills/trello/SKILL.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "skills/video-frames/SKILL.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "skills/voice-call/SKILL.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "skills/wacli/SKILL.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "skills/weather/SKILL.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "src/acp/client.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/acp/commands.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/acp/event-mapper.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/acp/event-mapper.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/acp/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/acp/meta.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/acp/server.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/acp/session-mapper.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/acp/session-mapper.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/acp/session.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/acp/session.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/acp/translator.ts", + "language": "typescript", + "symbol_count": 82 + }, + { + "path": "src/acp/types.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/agent-paths.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/agent-paths.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/agent-scope.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/agents/agent-scope.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/agents/anthropic-payload-log.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/agents/anthropic.setup-token.live.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/agents/apply-patch-update.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/apply-patch.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/apply-patch.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "src/agents/auth-health.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/agents/auth-health.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/agents/auth-profiles.auth-profile-cooldowns.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/auth-profiles.chutes.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/auth-profiles.ensureauthprofilestore.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/auth-profiles.markauthprofilefailure.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/agents/auth-profiles.resolve-auth-profile-order.does-not-prioritize-lastgood-round-robin-ordering.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/agents/auth-profiles.resolve-auth-profile-order.normalizes-z-ai-aliases-auth-order.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/agents/auth-profiles.resolve-auth-profile-order.orders-by-lastused-no-explicit-order-exists.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/agents/auth-profiles.resolve-auth-profile-order.uses-stored-profiles-no-config-exists.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/agents/auth-profiles.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/auth-profiles/constants.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/auth-profiles/display.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/auth-profiles/doctor.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/auth-profiles/external-cli-sync.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/auth-profiles/oauth.fallback-to-main-agent.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/auth-profiles/oauth.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/agents/auth-profiles/order.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/auth-profiles/paths.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/auth-profiles/profiles.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/auth-profiles/repair.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/auth-profiles/session-override.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/agents/auth-profiles/session-override.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/auth-profiles/store.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "src/agents/auth-profiles/types.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/auth-profiles/usage.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/agents/bash-process-registry.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/agents/bash-process-registry.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/agents/bash-tools.exec.approval-id.test.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/agents/bash-tools.exec.background-abort.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/bash-tools.exec.path.test.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/agents/bash-tools.exec.pty-fallback.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/bash-tools.exec.pty.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/bash-tools.exec.ts", + "language": "typescript", + "symbol_count": 161 + }, + { + "path": "src/agents/bash-tools.process.send-keys.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/bash-tools.process.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/agents/bash-tools.shared.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/agents/bash-tools.test.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/agents/bash-tools.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/bedrock-discovery.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/bedrock-discovery.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/agents/bootstrap-files.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/bootstrap-files.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/agents/bootstrap-hooks.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/bootstrap-hooks.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/cache-trace.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/cache-trace.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/agents/channel-tools.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/channel-tools.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/chutes-oauth.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/chutes-oauth.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/agents/claude-cli-runner.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/agents/claude-cli-runner.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/clawdbot-gateway-tool.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/clawdbot-tools.agents.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/clawdbot-tools.camera.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/agents/clawdbot-tools.session-status.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/agents/clawdbot-tools.sessions.test.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/agents/clawdbot-tools.subagents.sessions-spawn-allows-cross-agent-spawning-configured.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/clawdbot-tools.subagents.sessions-spawn-announces-agent-wait-lifecycle-events.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/clawdbot-tools.subagents.sessions-spawn-applies-model-child-session.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/agents/clawdbot-tools.subagents.sessions-spawn-normalizes-allowlisted-agent-ids.test.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/agents/clawdbot-tools.subagents.sessions-spawn-prefers-per-agent-subagent-model.test.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/agents/clawdbot-tools.subagents.sessions-spawn-resolves-main-announce-target-from.test.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/agents/cli-backends.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/agents/cli-credentials.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/cli-credentials.ts", + "language": "typescript", + "symbol_count": 84 + }, + { + "path": "src/agents/cli-runner.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/cli-runner.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/agents/cli-runner/helpers.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "src/agents/cli-session.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/compaction.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/compaction.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/agents/context-window-guard.test.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/agents/context-window-guard.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/context.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/date-time.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/agents/defaults.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/docs-path.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/failover-error.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/failover-error.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/agents/google-gemini-switch.live.test.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/agents/identity-avatar.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/identity-avatar.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/agents/identity-file.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/identity-file.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/identity.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/identity.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/lanes.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/live-auth-keys.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/live-model-filter.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/memory-search.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/agents/memory-search.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/agents/minimax-vlm.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/agents/minimax.live.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/model-auth.test.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/agents/model-auth.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "src/agents/model-catalog.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/model-catalog.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/model-compat.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/model-compat.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/model-fallback.test.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/agents/model-fallback.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/agents/model-scan.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/model-scan.ts", + "language": "typescript", + "symbol_count": 82 + }, + { + "path": "src/agents/model-selection.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/agents/model-selection.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/agents/models-config.auto-injects-github-copilot-provider-token-is.test.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/agents/models-config.falls-back-default-baseurl-token-exchange-fails.test.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/agents/models-config.fills-missing-provider-apikey-from-env-var.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/agents/models-config.normalizes-gemini-3-ids-preview-google-providers.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/agents/models-config.providers.ollama.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/models-config.providers.ts", + "language": "typescript", + "symbol_count": 100 + }, + { + "path": "src/agents/models-config.skips-writing-models-json-no-env-token.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/agents/models-config.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/models-config.uses-first-github-copilot-profile-env-tokens.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/agents/models.profiles.live.test.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/agents/moltbot-tools.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/agents/openai-responses.reasoning-replay.test.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/agents/opencode-zen-models.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/opencode-zen-models.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/agents/pi-embedded-block-chunker.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-block-chunker.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/pi-embedded-helpers.buildbootstrapcontextfiles.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-helpers.classifyfailoverreason.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-helpers.downgradeopenai-reasoning.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/pi-embedded-helpers.formatassistanterrortext.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-helpers.formatrawassistanterrorforui.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-helpers.image-dimension-error.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-helpers.image-size-error.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-helpers.isautherrormessage.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-helpers.iscloudcodeassistformaterror.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-helpers.iscompactionfailureerror.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-helpers.iscontextoverflowerror.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-helpers.isfailovererrormessage.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-helpers.islikelycontextoverflowerror.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-helpers.ismessagingtoolduplicate.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-helpers.messaging-duplicate.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-helpers.normalizetextforcomparison.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-helpers.resolvebootstrapmaxchars.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/pi-embedded-helpers.sanitize-session-messages-images.keeps-tool-call-tool-result-ids-unchanged.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/agents/pi-embedded-helpers.sanitize-session-messages-images.removes-empty-assistant-text-blocks-but-preserves.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/agents/pi-embedded-helpers.sanitizegoogleturnordering.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-helpers.sanitizesessionmessagesimages-thought-signature-stripping.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-helpers.sanitizetoolcallid.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-helpers.sanitizeuserfacingtext.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-helpers.stripthoughtsignatures.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/pi-embedded-helpers.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-helpers.validate-turns.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/pi-embedded-helpers/bootstrap.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/agents/pi-embedded-helpers/errors.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/agents/pi-embedded-helpers/google.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/pi-embedded-helpers/images.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-helpers/messaging-dedupe.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/pi-embedded-helpers/openai.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/pi-embedded-helpers/thinking.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/pi-embedded-helpers/turns.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/agents/pi-embedded-helpers/types.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/pi-embedded-messaging.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/pi-embedded-runner-extraparams.live.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/agents/pi-embedded-runner-extraparams.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-runner.applygoogleturnorderingfix.test.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/agents/pi-embedded-runner.buildembeddedsandboxinfo.test.ts", + "language": "typescript", + "symbol_count": 77 + }, + { + "path": "src/agents/pi-embedded-runner.createsystempromptoverride.test.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.falls-back-provider-default-per-dm-not.test.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.returns-undefined-sessionkey-is-undefined.test.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/agents/pi-embedded-runner.google-sanitize-thinking.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/pi-embedded-runner.guard.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/pi-embedded-runner.limithistoryturns.test.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/agents/pi-embedded-runner.resolvesessionagentids.test.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.test.ts", + "language": "typescript", + "symbol_count": 76 + }, + { + "path": "src/agents/pi-embedded-runner.sanitize-session-history.test.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/agents/pi-embedded-runner.splitsdktools.test.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/agents/pi-embedded-runner.test.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "src/agents/pi-embedded-runner.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-runner/abort.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-runner/cache-ttl.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-runner/compact.ts", + "language": "typescript", + "symbol_count": 65 + }, + { + "path": "src/agents/pi-embedded-runner/extensions.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/pi-embedded-runner/extra-params.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-runner/google.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/pi-embedded-runner/google.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/agents/pi-embedded-runner/history.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/pi-embedded-runner/lanes.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/pi-embedded-runner/logger.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-runner/model.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/agents/pi-embedded-runner/model.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/agents/pi-embedded-runner/run.overflow-compaction.test.ts", + "language": "typescript", + "symbol_count": 93 + }, + { + "path": "src/agents/pi-embedded-runner/run.ts", + "language": "typescript", + "symbol_count": 89 + }, + { + "path": "src/agents/pi-embedded-runner/run/attempt.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-runner/run/attempt.ts", + "language": "typescript", + "symbol_count": 133 + }, + { + "path": "src/agents/pi-embedded-runner/run/images.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/pi-embedded-runner/run/images.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/agents/pi-embedded-runner/run/params.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/pi-embedded-runner/run/payloads.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/agents/pi-embedded-runner/run/payloads.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/pi-embedded-runner/run/types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-runner/runs.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/pi-embedded-runner/sandbox-info.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/agents/pi-embedded-runner/session-manager-cache.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/agents/pi-embedded-runner/session-manager-init.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/pi-embedded-runner/system-prompt.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/agents/pi-embedded-runner/tool-split.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/pi-embedded-runner/types.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-runner/utils.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/pi-embedded-subscribe.code-span-awareness.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/pi-embedded-subscribe.handlers.lifecycle.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/agents/pi-embedded-subscribe.handlers.messages.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/agents/pi-embedded-subscribe.handlers.tools.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/agents/pi-embedded-subscribe.handlers.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-embedded-subscribe.handlers.types.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-subscribe.raw-stream.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/pi-embedded-subscribe.reply-tags.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.calls-onblockreplyflush-before-tool-execution-start-preserve.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-append-text-end-content-is.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-call-onblockreplyflush-callback-is-not.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-duplicate-text-end-repeats-full.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.does-not-emit-duplicate-block-replies-text.test.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.emits-block-replies-text-end-does-not.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.emits-reasoning-as-separate-message-enabled.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.filters-final-suppresses-output-without-start-tag.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.includes-canvas-action-metadata-tool-summaries.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.keeps-assistanttexts-final-answer-block-replies-are.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.keeps-indented-fenced-blocks-intact.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.reopens-fenced-blocks-splitting-inside-them.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.splits-long-single-line-fenced-blocks-reopen.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.streams-soft-chunks-paragraph-preference.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.subscribeembeddedpisession.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.suppresses-message-end-block-replies-message-tool.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.waits-multiple-compaction-retries-before-resolving.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/agents/pi-embedded-subscribe.tools.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/pi-embedded-subscribe.tools.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/pi-embedded-subscribe.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/agents/pi-embedded-subscribe.types.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/pi-embedded-utils.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-embedded-utils.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/agents/pi-embedded.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-extensions/compaction-safeguard-runtime.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/pi-extensions/compaction-safeguard.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/agents/pi-extensions/compaction-safeguard.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/agents/pi-extensions/context-pruning.test.ts", + "language": "typescript", + "symbol_count": 88 + }, + { + "path": "src/agents/pi-extensions/context-pruning.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-extensions/context-pruning/extension.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-extensions/context-pruning/pruner.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/pi-extensions/context-pruning/runtime.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/pi-extensions/context-pruning/settings.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/agents/pi-extensions/context-pruning/tools.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/pi-settings.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/pi-settings.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/pi-tool-definition-adapter.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/pi-tool-definition-adapter.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/agents/pi-tools-agent-config.test.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/agents/pi-tools.abort.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/pi-tools.create-clawdbot-coding-tools.adds-claude-style-aliases-schemas-without-dropping-b.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/pi-tools.create-clawdbot-coding-tools.adds-claude-style-aliases-schemas-without-dropping-d.test.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/agents/pi-tools.create-clawdbot-coding-tools.adds-claude-style-aliases-schemas-without-dropping-f.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/pi-tools.create-clawdbot-coding-tools.adds-claude-style-aliases-schemas-without-dropping.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/agents/pi-tools.policy.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/pi-tools.policy.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/agents/pi-tools.read.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/agents/pi-tools.safe-bins.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/agents/pi-tools.schema.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/pi-tools.ts", + "language": "typescript", + "symbol_count": 72 + }, + { + "path": "src/agents/pi-tools.types.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pi-tools.workspace-paths.test.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/agents/pty-dsr.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/pty-dsr.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/pty-keys.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/pty-keys.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/sandbox-agent-config.agent-specific-sandbox-config.includes-session-status-default-sandbox-allowlist.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/agents/sandbox-agent-config.agent-specific-sandbox-config.should-allow-agent-specific-docker-settings-beyond.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/agents/sandbox-agent-config.agent-specific-sandbox-config.should-use-agent-specific-workspaceroot.test.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/agents/sandbox-agent-config.agent-specific-sandbox-config.should-use-global-sandbox-config-no-agent.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/sandbox-create-args.test.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/agents/sandbox-explain.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/sandbox-merge.test.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/agents/sandbox-paths.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/sandbox-skills.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/sandbox.resolveSandboxContext.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/agents/sandbox.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/sandbox/browser-bridges.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/sandbox/browser.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/agents/sandbox/config-hash.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/sandbox/config.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "src/agents/sandbox/constants.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/sandbox/context.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/agents/sandbox/docker.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/agents/sandbox/manage.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/sandbox/prune.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/sandbox/registry.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/agents/sandbox/runtime-status.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/sandbox/shared.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/sandbox/tool-policy.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/sandbox/tool-policy.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/sandbox/types.docker.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/sandbox/types.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/agents/sandbox/workspace.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/schema/clean-for-gemini.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/schema/typebox.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/agents/session-slug.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/session-slug.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/session-tool-result-guard-wrapper.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/agents/session-tool-result-guard.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/session-tool-result-guard.tool-result-persist-hook.test.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/agents/session-tool-result-guard.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/session-transcript-repair.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/agents/session-transcript-repair.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/agents/session-write-lock.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/session-write-lock.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/agents/shell-utils.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/shell-utils.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/agents/skills-install.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/agents/skills-status.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/agents/skills.applyskillenvoverrides.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/agents/skills.build-workspace-skills-prompt.applies-bundled-allowlist-without-affecting-workspace-skills.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/agents/skills.build-workspace-skills-prompt.prefers-workspace-skills-managed-skills.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/skills.build-workspace-skills-prompt.returns-empty-prompt-skills-dirs-are-missing.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/agents/skills.build-workspace-skills-prompt.syncs-merged-skills-into-target-workspace.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/skills.buildworkspaceskillcommands.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/agents/skills.buildworkspaceskillsnapshot.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/skills.buildworkspaceskillstatus.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/agents/skills.loadworkspaceskillentries.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/agents/skills.resolveskillspromptforrun.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/skills.summarize-skill-description.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/skills.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/skills/bundled-dir.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/skills/config.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/agents/skills/env-overrides.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/skills/frontmatter.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/skills/frontmatter.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/agents/skills/plugin-skills.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/skills/refresh.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/skills/refresh.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/agents/skills/serialize.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/skills/types.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/skills/workspace.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/agents/subagent-announce-queue.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/agents/subagent-announce.format.test.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/agents/subagent-announce.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/agents/subagent-registry.persistence.test.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/agents/subagent-registry.store.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/agents/subagent-registry.ts", + "language": "typescript", + "symbol_count": 76 + }, + { + "path": "src/agents/synthetic-models.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/system-prompt-params.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/agents/system-prompt-params.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/system-prompt-report.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/agents/system-prompt.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/agents/system-prompt.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/agents/test-helpers/fast-coding-tools.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/test-helpers/fast-core-tools.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/agents/timeout.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/tool-call-id.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/agents/tool-call-id.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/agents/tool-display.json", + "language": "json", + "symbol_count": 313 + }, + { + "path": "src/agents/tool-display.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/tool-display.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/agents/tool-images.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/tool-images.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/agents/tool-policy.plugin-only-allowlist.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/tool-policy.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/tool-policy.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/agents/tool-summaries.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/tools/agent-step.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/agents/tools/agents-list-tool.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/agents/tools/browser-tool.schema.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/agents/tools/browser-tool.test.ts", + "language": "typescript", + "symbol_count": 70 + }, + { + "path": "src/agents/tools/browser-tool.ts", + "language": "typescript", + "symbol_count": 52 + }, + { + "path": "src/agents/tools/canvas-tool.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/agents/tools/common.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/agents/tools/common.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/agents/tools/cron-tool.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/agents/tools/cron-tool.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "src/agents/tools/discord-actions-guild.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/agents/tools/discord-actions-messaging.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/agents/tools/discord-actions-moderation.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/tools/discord-actions.test.ts", + "language": "typescript", + "symbol_count": 58 + }, + { + "path": "src/agents/tools/discord-actions.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/agents/tools/gateway-tool.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/agents/tools/gateway.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/tools/gateway.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/agents/tools/image-tool.helpers.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/agents/tools/image-tool.test.ts", + "language": "typescript", + "symbol_count": 57 + }, + { + "path": "src/agents/tools/image-tool.ts", + "language": "typescript", + "symbol_count": 69 + }, + { + "path": "src/agents/tools/memory-tool.does-not-crash-on-errors.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/agents/tools/memory-tool.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/agents/tools/message-tool.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/agents/tools/message-tool.ts", + "language": "typescript", + "symbol_count": 148 + }, + { + "path": "src/agents/tools/nodes-tool.ts", + "language": "typescript", + "symbol_count": 71 + }, + { + "path": "src/agents/tools/nodes-utils.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/tools/session-status-tool.ts", + "language": "typescript", + "symbol_count": 67 + }, + { + "path": "src/agents/tools/sessions-announce-target.test.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/agents/tools/sessions-announce-target.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/agents/tools/sessions-helpers.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/agents/tools/sessions-helpers.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/agents/tools/sessions-history-tool.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/agents/tools/sessions-list-tool.gating.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/tools/sessions-list-tool.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/agents/tools/sessions-send-helpers.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/agents/tools/sessions-send-tool.a2a.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/agents/tools/sessions-send-tool.gating.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/agents/tools/sessions-send-tool.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/agents/tools/sessions-spawn-tool.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/agents/tools/slack-actions.test.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/agents/tools/slack-actions.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/tools/telegram-actions.test.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/agents/tools/telegram-actions.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/agents/tools/tts-tool.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/agents/tools/web-fetch-utils.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/agents/tools/web-fetch.ssrf.test.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/agents/tools/web-fetch.ts", + "language": "typescript", + "symbol_count": 105 + }, + { + "path": "src/agents/tools/web-search.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/tools/web-search.ts", + "language": "typescript", + "symbol_count": 87 + }, + { + "path": "src/agents/tools/web-shared.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/agents/tools/web-tools.enabled-defaults.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/agents/tools/web-tools.fetch.test.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/agents/tools/web-tools.readability.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/tools/web-tools.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/agents/tools/whatsapp-actions.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/agents/tools/whatsapp-actions.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/agents/transcript-policy.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/agents/usage.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/agents/usage.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/agents/venice-models.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/agents/workspace.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/agents/workspace.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/agents/zai.live.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/chunk.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/auto-reply/chunk.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/auto-reply/command-auth.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/auto-reply/command-control.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/auto-reply/command-detection.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/commands-args.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/auto-reply/commands-registry.data.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/auto-reply/commands-registry.test.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/auto-reply/commands-registry.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/auto-reply/commands-registry.types.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/auto-reply/dispatch.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/auto-reply/envelope.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/auto-reply/envelope.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/auto-reply/group-activation.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/heartbeat.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/heartbeat.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/auto-reply/inbound-debounce.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/auto-reply/inbound.test.ts", + "language": "typescript", + "symbol_count": 59 + }, + { + "path": "src/auto-reply/media-note.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/auto-reply/media-note.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/auto-reply/model.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/model.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/reply.block-streaming.test.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.accepts-thinking-xhigh-codex-models.e2e.test.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.applies-inline-reasoning-mixed-messages-acks-immediately.e2e.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.defaults-think-low-reasoning-capable-models-no.e2e.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.ignores-inline-model-uses-default-model.e2e.test.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.lists-allowlisted-models-model-list.e2e.test.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.prefers-alias-matches-fuzzy-selection-is-ambiguous.e2e.test.ts", + "language": "typescript", + "symbol_count": 62 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.requires-per-agent-allowlist-addition-global.e2e.test.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.returns-status-alongside-directive-only-acks.e2e.test.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.shows-current-elevated-level-as-off-after.e2e.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.shows-current-verbose-level-verbose-has-no.e2e.test.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.supports-fuzzy-model-matches-model-directive.e2e.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/auto-reply/reply.directive.directive-behavior.updates-tool-verbose-during-flight-run-toggle.e2e.test.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/auto-reply/reply.directive.parse.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/reply.heartbeat-typing.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/auto-reply/reply.media-note.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/auto-reply/reply.queue.test.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/auto-reply/reply.raw-body.test.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/auto-reply/reply.triggers.group-intro-prompts.e2e.test.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.allows-activation-from-allowfrom-groups.e2e.test.ts", + "language": "typescript", + "symbol_count": 67 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.allows-approved-sender-toggle-elevated-mode.e2e.test.ts", + "language": "typescript", + "symbol_count": 66 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.allows-elevated-off-groups-without-mention.e2e.test.ts", + "language": "typescript", + "symbol_count": 68 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.e2e.test.ts", + "language": "typescript", + "symbol_count": 62 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.handles-inline-commands-strips-it-before-agent.e2e.test.ts", + "language": "typescript", + "symbol_count": 62 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.ignores-inline-elevated-directive-unapproved-sender.e2e.test.ts", + "language": "typescript", + "symbol_count": 67 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.includes-error-cause-embedded-agent-throws.e2e.test.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.keeps-inline-status-unauthorized-senders.e2e.test.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.reports-active-auth-profile-key-snippet-status.e2e.test.ts", + "language": "typescript", + "symbol_count": 64 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.runs-compact-as-gated-command.e2e.test.ts", + "language": "typescript", + "symbol_count": 65 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.runs-greeting-prompt-bare-reset.e2e.test.ts", + "language": "typescript", + "symbol_count": 58 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.shows-endpoint-default-model-status-not-configured.e2e.test.ts", + "language": "typescript", + "symbol_count": 52 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.shows-quick-model-picker-grouped-by-model.e2e.test.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.stages-inbound-media-into-sandbox-workspace.test.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.e2e.test.ts", + "language": "typescript", + "symbol_count": 91 + }, + { + "path": "src/auto-reply/reply.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/reply/abort.test.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/auto-reply/reply/abort.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/auto-reply/reply/agent-runner-execution.ts", + "language": "typescript", + "symbol_count": 80 + }, + { + "path": "src/auto-reply/reply/agent-runner-helpers.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/reply/agent-runner-memory.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/auto-reply/reply/agent-runner-payloads.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/auto-reply/reply/agent-runner-utils.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/auto-reply/reply/agent-runner-utils.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/auto-reply/reply/agent-runner.authprofileid-fallback.test.ts", + "language": "typescript", + "symbol_count": 72 + }, + { + "path": "src/auto-reply/reply/agent-runner.block-streaming.test.ts", + "language": "typescript", + "symbol_count": 61 + }, + { + "path": "src/auto-reply/reply/agent-runner.claude-cli.test.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "src/auto-reply/reply/agent-runner.heartbeat-typing.runreplyagent-typing-heartbeat.resets-corrupted-gemini-sessions-deletes-transcripts.test.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/auto-reply/reply/agent-runner.heartbeat-typing.runreplyagent-typing-heartbeat.retries-after-compaction-failure-by-resetting-session.test.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/auto-reply/reply/agent-runner.heartbeat-typing.runreplyagent-typing-heartbeat.signals-typing-block-replies.test.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/auto-reply/reply/agent-runner.heartbeat-typing.runreplyagent-typing-heartbeat.signals-typing-normal-runs.test.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/auto-reply/reply/agent-runner.heartbeat-typing.runreplyagent-typing-heartbeat.still-replies-even-if-session-reset-fails.test.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/auto-reply/reply/agent-runner.memory-flush.runreplyagent-memory-flush.increments-compaction-count-flush-compaction-completes.test.ts", + "language": "typescript", + "symbol_count": 69 + }, + { + "path": "src/auto-reply/reply/agent-runner.memory-flush.runreplyagent-memory-flush.runs-memory-flush-turn-updates-session-metadata.test.ts", + "language": "typescript", + "symbol_count": 72 + }, + { + "path": "src/auto-reply/reply/agent-runner.memory-flush.runreplyagent-memory-flush.skips-memory-flush-cli-providers.test.ts", + "language": "typescript", + "symbol_count": 73 + }, + { + "path": "src/auto-reply/reply/agent-runner.memory-flush.runreplyagent-memory-flush.skips-memory-flush-sandbox-workspace-is-read.test.ts", + "language": "typescript", + "symbol_count": 77 + }, + { + "path": "src/auto-reply/reply/agent-runner.memory-flush.runreplyagent-memory-flush.uses-configured-prompts-memory-flush-runs.test.ts", + "language": "typescript", + "symbol_count": 76 + }, + { + "path": "src/auto-reply/reply/agent-runner.messaging-tools.test.ts", + "language": "typescript", + "symbol_count": 59 + }, + { + "path": "src/auto-reply/reply/agent-runner.reasoning-tags.test.ts", + "language": "typescript", + "symbol_count": 61 + }, + { + "path": "src/auto-reply/reply/agent-runner.response-usage-footer.test.ts", + "language": "typescript", + "symbol_count": 65 + }, + { + "path": "src/auto-reply/reply/agent-runner.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/auto-reply/reply/audio-tags.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/reply/bash-command.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/auto-reply/reply/block-reply-coalescer.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/auto-reply/reply/block-reply-pipeline.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/auto-reply/reply/block-streaming.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/auto-reply/reply/body.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/auto-reply/reply/commands-allowlist.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/auto-reply/reply/commands-approve.test.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/auto-reply/reply/commands-approve.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/auto-reply/reply/commands-bash.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/auto-reply/reply/commands-compact.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/auto-reply/reply/commands-config.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/auto-reply/reply/commands-context-report.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/auto-reply/reply/commands-context.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/auto-reply/reply/commands-core.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/auto-reply/reply/commands-info.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/auto-reply/reply/commands-info.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/auto-reply/reply/commands-models.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/auto-reply/reply/commands-parsing.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/auto-reply/reply/commands-plugin.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/auto-reply/reply/commands-policy.test.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/auto-reply/reply/commands-session.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/auto-reply/reply/commands-status.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/auto-reply/reply/commands-subagents.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/auto-reply/reply/commands-tts.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/auto-reply/reply/commands-types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/reply/commands.test.ts", + "language": "typescript", + "symbol_count": 69 + }, + { + "path": "src/auto-reply/reply/commands.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/reply/config-commands.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/reply/config-value.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/auto-reply/reply/debug-commands.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/reply/directive-handling.auth.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/reply/directive-handling.fast-lane.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/reply/directive-handling.impl.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/auto-reply/reply/directive-handling.model-picker.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/auto-reply/reply/directive-handling.model.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/auto-reply/reply/directive-handling.model.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/auto-reply/reply/directive-handling.parse.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/auto-reply/reply/directive-handling.persist.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/auto-reply/reply/directive-handling.queue-validation.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/auto-reply/reply/directive-handling.shared.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/reply/directive-handling.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/reply/directives.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/auto-reply/reply/dispatch-from-config.test.ts", + "language": "typescript", + "symbol_count": 74 + }, + { + "path": "src/auto-reply/reply/dispatch-from-config.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/auto-reply/reply/exec.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/reply/exec/directive.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/auto-reply/reply/followup-runner.test.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/auto-reply/reply/followup-runner.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "src/auto-reply/reply/formatting.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/auto-reply/reply/get-reply-directives-apply.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/auto-reply/reply/get-reply-directives-utils.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/auto-reply/reply/get-reply-directives.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/auto-reply/reply/get-reply-inline-actions.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/auto-reply/reply/get-reply-run.ts", + "language": "typescript", + "symbol_count": 52 + }, + { + "path": "src/auto-reply/reply/get-reply.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/auto-reply/reply/groups.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/auto-reply/reply/history.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/auto-reply/reply/history.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/auto-reply/reply/inbound-context.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/auto-reply/reply/inbound-dedupe.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/auto-reply/reply/inbound-sender-meta.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/auto-reply/reply/inbound-text.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/reply/line-directives.test.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/auto-reply/reply/line-directives.ts", + "language": "typescript", + "symbol_count": 65 + }, + { + "path": "src/auto-reply/reply/memory-flush.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/auto-reply/reply/memory-flush.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/auto-reply/reply/mentions.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/reply/mentions.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/auto-reply/reply/model-selection.inherit-parent.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/auto-reply/reply/model-selection.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/auto-reply/reply/normalize-reply.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/reply/normalize-reply.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/reply/provider-dispatcher.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/auto-reply/reply/queue.collect-routing.test.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/auto-reply/reply/queue.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/reply/queue/cleanup.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/auto-reply/reply/queue/directive.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/auto-reply/reply/queue/drain.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/auto-reply/reply/queue/enqueue.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/reply/queue/normalize.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/auto-reply/reply/queue/settings.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/auto-reply/reply/queue/state.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/auto-reply/reply/queue/types.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/reply/reply-directives.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/auto-reply/reply/reply-dispatcher.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/auto-reply/reply/reply-elevated.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/auto-reply/reply/reply-inline.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/reply/reply-payloads.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/auto-reply/reply/reply-reference.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/reply/reply-routing.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/auto-reply/reply/reply-tags.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/reply/reply-threading.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/reply/response-prefix-template.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/auto-reply/reply/response-prefix-template.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/reply/route-reply.test.ts", + "language": "typescript", + "symbol_count": 82 + }, + { + "path": "src/auto-reply/reply/route-reply.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/auto-reply/reply/session-reset-model.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/auto-reply/reply/session-resets.test.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/auto-reply/reply/session-updates.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/auto-reply/reply/session-usage.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/auto-reply/reply/session.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/auto-reply/reply/session.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/auto-reply/reply/stage-sandbox-media.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/auto-reply/reply/streaming-directives.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/auto-reply/reply/subagents-utils.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/auto-reply/reply/subagents-utils.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/reply/test-ctx.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/auto-reply/reply/test-helpers.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/auto-reply/reply/typing-mode.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/auto-reply/reply/typing.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/auto-reply/reply/typing.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/auto-reply/send-policy.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/auto-reply/skill-commands.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/auto-reply/skill-commands.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/auto-reply/status.test.ts", + "language": "typescript", + "symbol_count": 74 + }, + { + "path": "src/auto-reply/status.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/auto-reply/templating.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/auto-reply/thinking.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/thinking.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/auto-reply/tokens.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/auto-reply/tool-meta.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/auto-reply/tool-meta.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/auto-reply/types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/browser/bridge-server.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/browser/cdp.helpers.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/browser/cdp.helpers.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/browser/cdp.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/browser/cdp.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/browser/chrome.default-browser.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/browser/chrome.executables.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/browser/chrome.profile-decoration.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/browser/chrome.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/browser/chrome.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/browser/client-actions-core.ts", + "language": "typescript", + "symbol_count": 65 + }, + { + "path": "src/browser/client-actions-observe.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/browser/client-actions-state.ts", + "language": "typescript", + "symbol_count": 102 + }, + { + "path": "src/browser/client-actions-types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/browser/client-actions.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/browser/client-fetch.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/browser/client.test.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/browser/client.ts", + "language": "typescript", + "symbol_count": 59 + }, + { + "path": "src/browser/config.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/browser/config.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/browser/constants.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/browser/control-service.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/browser/extension-relay.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/browser/extension-relay.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "src/browser/profiles-service.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/browser/profiles-service.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/browser/profiles.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/browser/profiles.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/browser/pw-ai-module.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/browser/pw-ai.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/browser/pw-ai.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/browser/pw-role-snapshot.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/browser/pw-role-snapshot.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/browser/pw-session.browserless.live.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/browser/pw-session.get-page-for-targetid.extension-fallback.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/browser/pw-session.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/browser/pw-session.ts", + "language": "typescript", + "symbol_count": 71 + }, + { + "path": "src/browser/pw-tools-core.activity.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/browser/pw-tools-core.clamps-timeoutms-scrollintoview.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/browser/pw-tools-core.downloads.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/browser/pw-tools-core.interactions.ts", + "language": "typescript", + "symbol_count": 57 + }, + { + "path": "src/browser/pw-tools-core.last-file-chooser-arm-wins.test.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/browser/pw-tools-core.responses.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/browser/pw-tools-core.screenshots-element-selector.test.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/browser/pw-tools-core.shared.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/browser/pw-tools-core.snapshot.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/browser/pw-tools-core.state.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/browser/pw-tools-core.storage.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/browser/pw-tools-core.trace.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/browser/pw-tools-core.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/browser/pw-tools-core.waits-next-download-saves-it.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/browser/routes/agent.act.shared.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/browser/routes/agent.act.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/browser/routes/agent.debug.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/browser/routes/agent.shared.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/browser/routes/agent.snapshot.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/browser/routes/agent.storage.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/browser/routes/agent.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/browser/routes/basic.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/browser/routes/dispatcher.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/browser/routes/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/browser/routes/tabs.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/browser/routes/types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/browser/routes/utils.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/browser/routes/utils.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/browser/screenshot.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/browser/screenshot.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/browser/server-context.ensure-tab-available.prefers-last-target.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/browser/server-context.remote-tab-ops.test.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/browser/server-context.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/browser/server-context.types.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/browser/server.agent-contract-form-layout-act-commands.test.ts", + "language": "typescript", + "symbol_count": 130 + }, + { + "path": "src/browser/server.agent-contract-snapshot-endpoints.test.ts", + "language": "typescript", + "symbol_count": 123 + }, + { + "path": "src/browser/server.covers-additional-endpoint-branches.test.ts", + "language": "typescript", + "symbol_count": 110 + }, + { + "path": "src/browser/server.post-tabs-open-profile-unknown-returns-404.test.ts", + "language": "typescript", + "symbol_count": 110 + }, + { + "path": "src/browser/server.serves-status-starts-browser-requested.test.ts", + "language": "typescript", + "symbol_count": 110 + }, + { + "path": "src/browser/server.skips-default-maxchars-explicitly-set-zero.test.ts", + "language": "typescript", + "symbol_count": 126 + }, + { + "path": "src/browser/server.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/browser/target-id.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/browser/target-id.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/browser/trash.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/canvas-host/a2ui.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/canvas-host/server.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/canvas-host/server.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/channel-web.barrel.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channel-web.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/ack-reactions.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/channels/ack-reactions.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/channels/allowlist-match.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/channels/allowlists/resolve-utils.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/channel-config.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/channels/channel-config.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/channels/chat-type.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/chat-type.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/command-gating.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/channels/command-gating.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/channels/conversation-label.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/channels/conversation-label.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/channels/dock.ts", + "language": "typescript", + "symbol_count": 181 + }, + { + "path": "src/channels/location.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/channels/location.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/channels/logging.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/channels/mention-gating.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/channels/mention-gating.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/channels/plugins/actions/discord.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/channels/plugins/actions/discord.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/channels/plugins/actions/discord/handle-action.guild-admin.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/channels/plugins/actions/discord/handle-action.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/channels/plugins/actions/signal.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/channels/plugins/actions/signal.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/channels/plugins/actions/telegram.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/channels/plugins/actions/telegram.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/channels/plugins/agent-tools/whatsapp-login.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/channels/plugins/allowlist-match.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/plugins/bluebubbles-actions.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/channels/plugins/catalog.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/channels/plugins/catalog.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/channels/plugins/channel-config.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/plugins/config-helpers.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/channels/plugins/config-schema.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/channels/plugins/config-writes.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/channels/plugins/config-writes.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/channels/plugins/directory-config.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/channels/plugins/directory-config.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/channels/plugins/group-mentions.ts", + "language": "typescript", + "symbol_count": 96 + }, + { + "path": "src/channels/plugins/helpers.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/plugins/index.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/channels/plugins/index.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/channels/plugins/load.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/channels/plugins/load.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/plugins/media-limits.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/plugins/message-action-names.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/plugins/message-actions.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/channels/plugins/normalize/discord.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/channels/plugins/normalize/imessage.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/plugins/normalize/imessage.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/plugins/normalize/signal.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/plugins/normalize/signal.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/plugins/normalize/slack.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/channels/plugins/normalize/telegram.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/plugins/normalize/whatsapp.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/plugins/onboarding-types.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/channels/plugins/onboarding/channel-access.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/channels/plugins/onboarding/discord.ts", + "language": "typescript", + "symbol_count": 62 + }, + { + "path": "src/channels/plugins/onboarding/helpers.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/channels/plugins/onboarding/imessage.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/channels/plugins/onboarding/signal.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/channels/plugins/onboarding/slack.ts", + "language": "typescript", + "symbol_count": 85 + }, + { + "path": "src/channels/plugins/onboarding/telegram.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/channels/plugins/onboarding/whatsapp.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/channels/plugins/outbound/discord.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/channels/plugins/outbound/imessage.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/channels/plugins/outbound/load.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/plugins/outbound/signal.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/channels/plugins/outbound/slack.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/channels/plugins/outbound/telegram.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/channels/plugins/outbound/telegram.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/channels/plugins/outbound/whatsapp.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/channels/plugins/pairing-message.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/plugins/pairing.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/channels/plugins/setup-helpers.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/channels/plugins/slack.actions.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/channels/plugins/slack.actions.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/channels/plugins/status-issues/bluebubbles.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/channels/plugins/status-issues/discord.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/channels/plugins/status-issues/shared.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/channels/plugins/status-issues/telegram.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/channels/plugins/status-issues/whatsapp.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/channels/plugins/status.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/channels/plugins/types.adapters.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/channels/plugins/types.core.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/channels/plugins/types.plugin.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/channels/plugins/types.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/plugins/whatsapp-heartbeat.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/channels/registry.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/registry.ts", + "language": "typescript", + "symbol_count": 78 + }, + { + "path": "src/channels/reply-prefix.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/channels/sender-identity.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/channels/sender-identity.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/sender-label.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/channels/session.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/channels/targets.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/channels/targets.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/channels/typing.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/typing.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/channels/web/index.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/channels/web/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/acp-cli.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/cli/argv.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cli/argv.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/cli/banner.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/cli/browser-cli-actions-input.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/browser-cli-actions-input/register.element.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/cli/browser-cli-actions-input/register.files-downloads.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/cli/browser-cli-actions-input/register.form-wait-eval.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/cli/browser-cli-actions-input/register.navigation.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/cli/browser-cli-actions-input/register.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/browser-cli-actions-input/shared.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/cli/browser-cli-actions-observe.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/cli/browser-cli-debug.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/cli/browser-cli-examples.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/browser-cli-extension.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/cli/browser-cli-extension.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/cli/browser-cli-inspect.test.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/cli/browser-cli-inspect.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/cli/browser-cli-manage.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/cli/browser-cli-shared.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/cli/browser-cli-state.cookies-storage.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/cli/browser-cli-state.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/cli/browser-cli.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/browser-cli.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/channel-auth.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cli/channel-options.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/cli/channels-cli.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/cli/cli-name.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/cli/cli-utils.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cli/command-format.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/command-options.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/config-cli.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/cli/cron-cli.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/cli/cron-cli.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/cron-cli/register.cron-add.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/cli/cron-cli/register.cron-edit.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/cli/cron-cli/register.cron-simple.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cli/cron-cli/register.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/cron-cli/shared.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cli/daemon-cli.coverage.test.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/cli/daemon-cli.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/daemon-cli/install.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/cli/daemon-cli/lifecycle.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/cli/daemon-cli/probe.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/cli/daemon-cli/register.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/daemon-cli/response.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/cli/daemon-cli/runners.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/daemon-cli/shared.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/cli/daemon-cli/status.gather.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/cli/daemon-cli/status.print.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/cli/daemon-cli/status.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/daemon-cli/types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cli/deps.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/cli/devices-cli.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/cli/directory-cli.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/cli/dns-cli.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/dns-cli.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/cli/docs-cli.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/exec-approvals-cli.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/cli/exec-approvals-cli.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/cli/gateway-cli.coverage.test.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/cli/gateway-cli.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/gateway-cli/call.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/cli/gateway-cli/dev.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/cli/gateway-cli/discover.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/cli/gateway-cli/register.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/cli/gateway-cli/run-loop.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cli/gateway-cli/run.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/cli/gateway-cli/shared.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/cli/gateway-rpc.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/cli/gateway.sigterm.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/cli/help-format.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/hooks-cli.test.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/cli/hooks-cli.ts", + "language": "typescript", + "symbol_count": 76 + }, + { + "path": "src/cli/logs-cli.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/cli/logs-cli.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/cli/memory-cli.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/cli/memory-cli.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/cli/models-cli.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/cli/models-cli.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/cli/node-cli.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/node-cli/daemon.ts", + "language": "typescript", + "symbol_count": 61 + }, + { + "path": "src/cli/node-cli/register.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/cli/nodes-camera.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/cli/nodes-camera.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/cli/nodes-canvas.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/cli/nodes-canvas.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/nodes-cli.coverage.test.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/cli/nodes-cli.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/nodes-cli/a2ui-jsonl.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/cli/nodes-cli/cli-utils.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/cli/nodes-cli/format.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cli/nodes-cli/register.camera.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/cli/nodes-cli/register.canvas.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/cli/nodes-cli/register.invoke.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/cli/nodes-cli/register.location.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/cli/nodes-cli/register.notify.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/cli/nodes-cli/register.pairing.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/cli/nodes-cli/register.screen.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/cli/nodes-cli/register.status.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/cli/nodes-cli/register.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/nodes-cli/rpc.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/cli/nodes-cli/types.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/nodes-run.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/nodes-screen.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/cli/nodes-screen.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/cli/outbound-send-deps.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/cli/pairing-cli.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/cli/pairing-cli.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/cli/parse-duration.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/parse-duration.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/cli/parse-timeout.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/plugin-registry.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/plugins-cli.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/cli/ports.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/cli/profile-utils.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/cli/profile.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/profile.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/cli/program.force.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/cli/program.nodes-basic.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/cli/program.nodes-media.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/cli/program.smoke.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/cli/program.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/build-program.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/command-registry.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/cli/program/config-guard.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/program/context.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/program/help.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/cli/program/helpers.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/cli/program/message/helpers.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/cli/program/message/register.broadcast.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/message/register.discord-admin.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/message/register.emoji-sticker.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/cli/program/message/register.permissions-search.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/cli/program/message/register.pins.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/message/register.poll.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/message/register.reactions.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/message/register.read-edit-delete.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/message/register.send.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/message/register.thread.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/preaction.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cli/program/register.agent.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/cli/program/register.configure.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/program/register.maintenance.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/cli/program/register.message.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/cli/program/register.onboard.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/cli/program/register.setup.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/cli/program/register.status-health-sessions.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/cli/program/register.subclis.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/program/register.subclis.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/cli/progress.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cli/progress.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/cli/prompt.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/cli/prompt.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/route.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/cli/run-main.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/run-main.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/cli/sandbox-cli.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/cli/security-cli.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/cli/skills-cli.test.ts", + "language": "typescript", + "symbol_count": 52 + }, + { + "path": "src/cli/skills-cli.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/cli/system-cli.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cli/tagline.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/cli/tui-cli.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/cli/update-cli.test.ts", + "language": "typescript", + "symbol_count": 71 + }, + { + "path": "src/cli/update-cli.ts", + "language": "typescript", + "symbol_count": 142 + }, + { + "path": "src/cli/wait.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/wait.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cli/webhooks-cli.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/commands/agent-via-gateway.test.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/commands/agent-via-gateway.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/commands/agent.delivery.test.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/commands/agent.test.ts", + "language": "typescript", + "symbol_count": 72 + }, + { + "path": "src/commands/agent.ts", + "language": "typescript", + "symbol_count": 62 + }, + { + "path": "src/commands/agent/delivery.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/commands/agent/run-context.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/agent/session-store.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/commands/agent/session.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/commands/agent/types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/agents.add.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/commands/agents.bindings.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/commands/agents.command-shared.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/agents.commands.add.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/commands/agents.commands.delete.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/commands/agents.commands.identity.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/commands/agents.commands.list.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/agents.config.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/commands/agents.identity.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/commands/agents.providers.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/commands/agents.test.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/commands/agents.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/auth-choice-options.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/auth-choice-options.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/commands/auth-choice-prompt.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/auth-choice.api-key.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/auth-choice.apply.anthropic.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/commands/auth-choice.apply.api-providers.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/commands/auth-choice.apply.copilot-proxy.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/auth-choice.apply.github-copilot.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/commands/auth-choice.apply.google-antigravity.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/auth-choice.apply.google-gemini-cli.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/auth-choice.apply.minimax.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/commands/auth-choice.apply.oauth.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/commands/auth-choice.apply.openai.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/commands/auth-choice.apply.plugin-provider.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/commands/auth-choice.apply.qwen-portal.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/auth-choice.apply.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/auth-choice.default-model.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/auth-choice.model-check.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/commands/auth-choice.preferred-provider.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/auth-choice.test.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/commands/auth-choice.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/auth-token.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/channels.adds-non-default-telegram-account.test.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/commands/channels.surfaces-signal-runtime-errors-channels-status-output.test.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/commands/channels.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/channels/add-mutators.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/commands/channels/add.ts", + "language": "typescript", + "symbol_count": 69 + }, + { + "path": "src/commands/channels/capabilities.test.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/commands/channels/capabilities.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/commands/channels/list.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/commands/channels/logs.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/channels/remove.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/commands/channels/resolve.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/commands/channels/shared.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/commands/channels/status.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/commands/chutes-oauth.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/commands/chutes-oauth.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/commands/cleanup-utils.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/commands/configure.channels.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/commands/configure.commands.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/configure.daemon.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/commands/configure.gateway-auth.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/commands/configure.gateway-auth.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/commands/configure.gateway.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/commands/configure.shared.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/commands/configure.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/configure.wizard.test.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/commands/configure.wizard.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "src/commands/daemon-install-helpers.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/commands/daemon-install-helpers.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/commands/daemon-runtime.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/commands/dashboard.test.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/commands/dashboard.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/docs.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/commands/doctor-auth.deprecated-cli-profiles.test.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/commands/doctor-auth.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/commands/doctor-config-flow.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/commands/doctor-config-flow.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/commands/doctor-format.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/doctor-gateway-daemon-flow.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/commands/doctor-gateway-health.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/commands/doctor-gateway-services.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/commands/doctor-install.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/doctor-legacy-config.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/commands/doctor-legacy-config.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/doctor-platform-notes.launchctl-env-overrides.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/doctor-platform-notes.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/doctor-prompter.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/commands/doctor-sandbox.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/commands/doctor-security.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/doctor-security.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/commands/doctor-state-integrity.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/commands/doctor-state-migrations.test.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/commands/doctor-state-migrations.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/doctor-ui.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/commands/doctor-update.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/commands/doctor-workspace-status.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/commands/doctor-workspace.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/doctor-workspace.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/commands/doctor.falls-back-legacy-sandbox-image-missing.test.ts", + "language": "typescript", + "symbol_count": 122 + }, + { + "path": "src/commands/doctor.migrates-routing-allowfrom-channels-whatsapp-allowfrom.test.ts", + "language": "typescript", + "symbol_count": 110 + }, + { + "path": "src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.test.ts", + "language": "typescript", + "symbol_count": 124 + }, + { + "path": "src/commands/doctor.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/commands/doctor.warns-per-agent-sandbox-docker-browser-prune.test.ts", + "language": "typescript", + "symbol_count": 103 + }, + { + "path": "src/commands/doctor.warns-state-directory-is-missing.test.ts", + "language": "typescript", + "symbol_count": 106 + }, + { + "path": "src/commands/gateway-status.test.ts", + "language": "typescript", + "symbol_count": 61 + }, + { + "path": "src/commands/gateway-status.ts", + "language": "typescript", + "symbol_count": 63 + }, + { + "path": "src/commands/gateway-status/helpers.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/commands/google-gemini-model-default.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/google-gemini-model-default.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/health-format.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/health-format.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/health.command.coverage.test.ts", + "language": "typescript", + "symbol_count": 78 + }, + { + "path": "src/commands/health.snapshot.test.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "src/commands/health.test.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/commands/health.ts", + "language": "typescript", + "symbol_count": 52 + }, + { + "path": "src/commands/message-format.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/commands/message.test.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "src/commands/message.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/commands/model-picker.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/commands/model-picker.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/commands/models.list.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/commands/models.set.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/commands/models.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/models/aliases.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/commands/models/auth-order.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/commands/models/auth.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "src/commands/models/fallbacks.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/commands/models/image-fallbacks.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/commands/models/list.auth-overview.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/commands/models/list.configured.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/commands/models/list.format.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/models/list.list-command.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/models/list.probe.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/commands/models/list.registry.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/commands/models/list.status-command.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/commands/models/list.status.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/commands/models/list.table.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/models/list.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/models/list.types.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/models/scan.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/commands/models/set-image.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/commands/models/set.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/commands/models/shared.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/commands/node-daemon-install-helpers.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/commands/node-daemon-runtime.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/commands/oauth-env.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/oauth-flow.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/commands/onboard-auth.config-core.ts", + "language": "typescript", + "symbol_count": 88 + }, + { + "path": "src/commands/onboard-auth.config-minimax.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/commands/onboard-auth.config-opencode.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/commands/onboard-auth.credentials.ts", + "language": "typescript", + "symbol_count": 71 + }, + { + "path": "src/commands/onboard-auth.models.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/commands/onboard-auth.test.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/commands/onboard-auth.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/onboard-channels.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/commands/onboard-channels.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/commands/onboard-helpers.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/commands/onboard-helpers.ts", + "language": "typescript", + "symbol_count": 63 + }, + { + "path": "src/commands/onboard-hooks.test.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/commands/onboard-hooks.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/commands/onboard-interactive.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/onboard-non-interactive.ai-gateway.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/commands/onboard-non-interactive.gateway.test.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/commands/onboard-non-interactive.token.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/commands/onboard-non-interactive.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/onboard-non-interactive/api-keys.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/commands/onboard-non-interactive/local.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/commands/onboard-non-interactive/local/auth-choice.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/commands/onboard-non-interactive/local/daemon-install.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/commands/onboard-non-interactive/local/gateway-config.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/commands/onboard-non-interactive/local/output.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/commands/onboard-non-interactive/local/skills-config.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/onboard-non-interactive/local/workspace.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/onboard-non-interactive/remote.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/commands/onboard-remote.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/commands/onboard-skills.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/commands/onboard-types.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/commands/onboard.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/commands/onboarding/plugin-install.test.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/commands/onboarding/plugin-install.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/commands/onboarding/registry.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/commands/onboarding/types.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/openai-codex-model-default.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/openai-codex-model-default.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/commands/opencode-zen-model-default.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/opencode-zen-model-default.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/commands/reset.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/commands/sandbox-display.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/commands/sandbox-explain.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/commands/sandbox-explain.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/commands/sandbox-formatters.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/sandbox-formatters.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/commands/sandbox.test.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/commands/sandbox.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/commands/sessions.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/commands/sessions.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/commands/setup.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/commands/signal-install.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/commands/status-all.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/commands/status-all/agents.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/status-all/channels.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/commands/status-all/diagnosis.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/commands/status-all/format.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/commands/status-all/gateway.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/commands/status-all/report-lines.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/commands/status.agent-local.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/commands/status.command.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "src/commands/status.daemon.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/commands/status.format.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/status.gateway-probe.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/commands/status.link-channel.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/status.scan.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/commands/status.summary.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/commands/status.test.ts", + "language": "typescript", + "symbol_count": 185 + }, + { + "path": "src/commands/status.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/commands/status.types.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/commands/status.update.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/commands/systemd-linger.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/commands/uninstall.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/compat/legacy-names.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/config/agent-dirs.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/agent-limits.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/config/cache-utils.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/channel-capabilities.test.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/config/channel-capabilities.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/config/commands.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/commands.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/config-paths.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/config/config-paths.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/config/config.agent-concurrency-defaults.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/config/config.backup-rotation.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/config.broadcast.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/config/config.compaction-settings.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/config/config.discord.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/config/config.env-vars.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/config/config.gateway-remote-transport.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/config.identity-avatar.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/config/config.identity-defaults.test.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/config/config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/config/config.legacy-config-detection.rejects-routing-allowfrom.test.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "src/config/config.msteams.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/config.multi-agent-agentdir-validation.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/config.nix-integration-u3-u5-u9.test.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/config/config.plugin-validation.test.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/config/config.preservation-on-validation-failure.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/config/config.pruning-defaults.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/config/config.sandbox-docker.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/config/config.skills-entries-config.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/config/config.talk-api-key-fallback.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/config/config.talk-voicealiases.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/config.telegram-custom-commands.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/config/config.tools-alsoAllow.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/config.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/config/config.web-search-provider.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/defaults.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/config/env-substitution.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/config/env-substitution.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/config/env-vars.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/config/group-policy.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/config/includes.test.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/config/includes.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/config/io.compat.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/io.ts", + "language": "typescript", + "symbol_count": 59 + }, + { + "path": "src/config/legacy-migrate.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/legacy.migrations.part-1.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/legacy.migrations.part-2.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/config/legacy.migrations.part-3.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/legacy.migrations.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/config/legacy.rules.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/legacy.shared.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/config/legacy.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/config/logging.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/markdown-tables.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/merge-config.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/config/merge-patch.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/model-alias-defaults.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/config/normalize-paths.test.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/config/normalize-paths.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/paths.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/config/paths.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/config/plugin-auto-enable.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/config/plugin-auto-enable.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/config/port-defaults.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/runtime-overrides.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/config/runtime-overrides.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/config/schema.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/config/schema.ts", + "language": "typescript", + "symbol_count": 67 + }, + { + "path": "src/config/sessions.cache.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/config/sessions.test.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/config/sessions.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/config/sessions/group.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/config/sessions/main-session.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/config/sessions/metadata.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/config/sessions/metadata.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/config/sessions/paths.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/config/sessions/reset.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/config/sessions/session-key.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/sessions/store.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/config/sessions/transcript.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/config/sessions/transcript.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/config/sessions/types.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/slack-http-config.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/slack-token-validation.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/config/talk.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/telegram-custom-commands.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/test-helpers.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/types.agent-defaults.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/config/types.agents.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/types.approvals.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/types.auth.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/config/types.base.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/config/types.browser.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/types.channels.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/types.clawdbot.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/types.cron.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/config/types.discord.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/types.gateway.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/config/types.googlechat.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/config/types.hooks.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/config/types.imessage.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/config/types.messages.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/config/types.models.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/config/types.msteams.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/config/types.node-host.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/config/types.plugins.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/config/types.queue.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/types.sandbox.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/types.signal.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/types.skills.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/config/types.slack.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/config/types.telegram.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/config/types.tools.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/config/types.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/config/types.tts.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/config/types.whatsapp.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/ui-seam-color.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/config/validation.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/config/version.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/config/zod-schema.agent-defaults.ts", + "language": "typescript", + "symbol_count": 77 + }, + { + "path": "src/config/zod-schema.agent-runtime.ts", + "language": "typescript", + "symbol_count": 169 + }, + { + "path": "src/config/zod-schema.agents.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/config/zod-schema.approvals.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/config/zod-schema.channels.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/config/zod-schema.core.ts", + "language": "typescript", + "symbol_count": 161 + }, + { + "path": "src/config/zod-schema.providers-core.ts", + "language": "typescript", + "symbol_count": 142 + }, + { + "path": "src/config/zod-schema.providers-whatsapp.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/config/zod-schema.providers.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/config/zod-schema.session.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/config/zod-schema.ts", + "language": "typescript", + "symbol_count": 237 + }, + { + "path": "src/cron/cron-protocol-conformance.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cron/isolated-agent.delivers-response-has-heartbeat-ok-but-includes.test.ts", + "language": "typescript", + "symbol_count": 63 + }, + { + "path": "src/cron/isolated-agent.skips-delivery-without-whatsapp-recipient-besteffortdeliver-true.test.ts", + "language": "typescript", + "symbol_count": 65 + }, + { + "path": "src/cron/isolated-agent.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cron/isolated-agent.uses-last-non-empty-agent-text-as.test.ts", + "language": "typescript", + "symbol_count": 69 + }, + { + "path": "src/cron/isolated-agent/delivery-target.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/cron/isolated-agent/helpers.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/cron/isolated-agent/run.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/cron/isolated-agent/session.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/cron/normalize.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/cron/normalize.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/cron/parse.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/cron/payload-migration.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/cron/run-log.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/cron/run-log.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/cron/schedule.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/cron/schedule.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/cron/service.prevents-duplicate-timers.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/cron/service.runs-one-shot-main-job-disables-it.test.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/cron/service.skips-main-jobs-empty-systemevent-text.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/cron/service.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/cron/service/jobs.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/cron/service/locked.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/cron/service/normalize.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/cron/service/ops.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/cron/service/state.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/cron/service/store.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/cron/service/timer.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/cron/store.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/cron/types.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/daemon/constants.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/daemon/constants.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/daemon/diagnostics.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/daemon/inspect.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/daemon/launchd-plist.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/daemon/launchd.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/daemon/launchd.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/daemon/legacy.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/daemon/node-service.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/daemon/paths.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/daemon/paths.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/daemon/program-args.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/daemon/program-args.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/daemon/runtime-parse.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/daemon/runtime-paths.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/daemon/runtime-paths.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/daemon/schtasks.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/daemon/schtasks.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/daemon/service-audit.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/daemon/service-audit.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/daemon/service-env.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/daemon/service-env.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/daemon/service-runtime.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/daemon/service.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/daemon/systemd-availability.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/daemon/systemd-hints.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/daemon/systemd-linger.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/daemon/systemd-unit.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/daemon/systemd-unit.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/daemon/systemd.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/daemon/systemd.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/discord/accounts.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/discord/api.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/discord/api.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/discord/audit.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/discord/audit.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/discord/chunk.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/discord/chunk.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/discord/directory-live.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/discord/gateway-logging.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/discord/gateway-logging.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/discord/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/discord/monitor.gateway.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/discord/monitor.gateway.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/discord/monitor.slash.test.ts", + "language": "typescript", + "symbol_count": 57 + }, + { + "path": "src/discord/monitor.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/discord/monitor.tool-result.accepts-guild-messages-mentionpatterns-match.test.ts", + "language": "typescript", + "symbol_count": 124 + }, + { + "path": "src/discord/monitor.tool-result.sends-status-replies-responseprefix.test.ts", + "language": "typescript", + "symbol_count": 93 + }, + { + "path": "src/discord/monitor.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/discord/monitor/allow-list.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/discord/monitor/exec-approvals.test.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/discord/monitor/exec-approvals.ts", + "language": "typescript", + "symbol_count": 86 + }, + { + "path": "src/discord/monitor/format.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/discord/monitor/listeners.ts", + "language": "typescript", + "symbol_count": 68 + }, + { + "path": "src/discord/monitor/message-handler.inbound-contract.test.ts", + "language": "typescript", + "symbol_count": 66 + }, + { + "path": "src/discord/monitor/message-handler.preflight.ts", + "language": "typescript", + "symbol_count": 79 + }, + { + "path": "src/discord/monitor/message-handler.preflight.types.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/discord/monitor/message-handler.process.test.ts", + "language": "typescript", + "symbol_count": 80 + }, + { + "path": "src/discord/monitor/message-handler.process.ts", + "language": "typescript", + "symbol_count": 101 + }, + { + "path": "src/discord/monitor/message-handler.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/discord/monitor/message-utils.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/discord/monitor/native-command.ts", + "language": "typescript", + "symbol_count": 160 + }, + { + "path": "src/discord/monitor/presence-cache.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/discord/monitor/presence-cache.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/discord/monitor/provider.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/discord/monitor/reply-context.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/discord/monitor/reply-delivery.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/discord/monitor/system-events.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/discord/monitor/threading.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/discord/monitor/threading.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "src/discord/monitor/typing.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/discord/probe.intents.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/discord/probe.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/discord/resolve-channels.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/discord/resolve-channels.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/discord/resolve-users.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/discord/send.channels.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/discord/send.creates-thread.test.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/discord/send.emojis-stickers.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/discord/send.guild.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/discord/send.messages.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/discord/send.outbound.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/discord/send.permissions.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/discord/send.reactions.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/discord/send.sends-basic-channel-messages.test.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/discord/send.shared.ts", + "language": "typescript", + "symbol_count": 69 + }, + { + "path": "src/discord/send.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/discord/send.types.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/discord/targets.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/discord/targets.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/discord/token.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/discord/token.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/docker-setup.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/docs/slash-commands-doc.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/docs/terminal-css.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/entry.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/gateway/assistant-identity.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/gateway/assistant-identity.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/gateway/auth.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/gateway/auth.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/gateway/boot.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/gateway/boot.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/gateway/call.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/gateway/call.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/gateway/chat-abort.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/gateway/chat-attachments.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/gateway/chat-attachments.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/gateway/chat-sanitize.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/gateway/chat-sanitize.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/gateway/client.maxpayload.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/gateway/client.test.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/gateway/client.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "src/gateway/config-reload.test.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/gateway/config-reload.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/gateway/control-ui-shared.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/gateway/control-ui.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/gateway/control-ui.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/gateway/device-auth.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/gateway/exec-approval-manager.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/gateway/gateway-cli-backend.live.test.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/gateway/gateway-models.profiles.live.test.ts", + "language": "typescript", + "symbol_count": 137 + }, + { + "path": "src/gateway/gateway.e2e.test.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/gateway/hooks-mapping.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/gateway/hooks-mapping.ts", + "language": "typescript", + "symbol_count": 64 + }, + { + "path": "src/gateway/hooks.test.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/gateway/hooks.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/gateway/http-common.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/gateway/http-utils.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/gateway/live-image-probe.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/gateway/net.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/net.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/gateway/node-command-policy.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/gateway/node-registry.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/gateway/open-responses.schema.ts", + "language": "typescript", + "symbol_count": 65 + }, + { + "path": "src/gateway/openai-http.e2e.test.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/gateway/openai-http.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "src/gateway/openresponses-http.e2e.test.ts", + "language": "typescript", + "symbol_count": 58 + }, + { + "path": "src/gateway/openresponses-http.ts", + "language": "typescript", + "symbol_count": 116 + }, + { + "path": "src/gateway/openresponses-parity.e2e.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/gateway/probe.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/gateway/protocol/client-info.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/gateway/protocol/index.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/gateway/protocol/index.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/gateway/protocol/schema.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/protocol/schema/agent.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/gateway/protocol/schema/agents-models-skills.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/gateway/protocol/schema/channels.ts", + "language": "typescript", + "symbol_count": 58 + }, + { + "path": "src/gateway/protocol/schema/config.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/gateway/protocol/schema/cron.ts", + "language": "typescript", + "symbol_count": 67 + }, + { + "path": "src/gateway/protocol/schema/devices.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/gateway/protocol/schema/error-codes.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/gateway/protocol/schema/exec-approvals.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/gateway/protocol/schema/frames.ts", + "language": "typescript", + "symbol_count": 81 + }, + { + "path": "src/gateway/protocol/schema/logs-chat.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/gateway/protocol/schema/nodes.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/gateway/protocol/schema/primitives.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/gateway/protocol/schema/protocol-schemas.ts", + "language": "typescript", + "symbol_count": 101 + }, + { + "path": "src/gateway/protocol/schema/sessions.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/gateway/protocol/schema/snapshot.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/gateway/protocol/schema/types.ts", + "language": "typescript", + "symbol_count": 94 + }, + { + "path": "src/gateway/protocol/schema/wizard.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/gateway/server-broadcast.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/gateway/server-broadcast.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/gateway/server-browser.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/gateway/server-channels.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/gateway/server-chat-registry.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/gateway/server-chat.agent-events.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/gateway/server-chat.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/gateway/server-close.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-constants.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-cron.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/gateway/server-discovery-runtime.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/gateway/server-discovery.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/gateway/server-discovery.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/gateway/server-http.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/gateway/server-lanes.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-maintenance.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/gateway/server-methods-list.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-methods.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/gateway/server-methods/agent-job.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/gateway/server-methods/agent.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/gateway/server-methods/agent.ts", + "language": "typescript", + "symbol_count": 68 + }, + { + "path": "src/gateway/server-methods/agents.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-methods/browser.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/gateway/server-methods/channels.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/gateway/server-methods/chat.ts", + "language": "typescript", + "symbol_count": 122 + }, + { + "path": "src/gateway/server-methods/config.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/gateway/server-methods/connect.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-methods/cron.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/gateway/server-methods/devices.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/gateway/server-methods/exec-approval.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/gateway/server-methods/exec-approval.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/gateway/server-methods/exec-approvals.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/gateway/server-methods/health.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/gateway/server-methods/logs.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/gateway/server-methods/logs.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/gateway/server-methods/models.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-methods/nodes.helpers.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/gateway/server-methods/nodes.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/gateway/server-methods/send.test.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/gateway/server-methods/send.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/gateway/server-methods/sessions.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/gateway/server-methods/skills.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/gateway/server-methods/system.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/gateway/server-methods/talk.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/gateway/server-methods/tts.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/gateway/server-methods/types.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/gateway/server-methods/update.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/gateway/server-methods/usage.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/gateway/server-methods/voicewake.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-methods/web.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/gateway/server-methods/wizard.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/gateway/server-mobile-nodes.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-model-catalog.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/gateway/server-node-events-types.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/gateway/server-node-events.test.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/gateway/server-node-events.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/gateway/server-node-subscriptions.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-node-subscriptions.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/gateway/server-plugins.test.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/gateway/server-plugins.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/gateway/server-reload-handlers.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/gateway/server-restart-sentinel.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/gateway/server-runtime-config.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/gateway/server-runtime-state.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/gateway/server-session-key.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-shared.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-startup-log.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/gateway/server-startup.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/gateway/server-tailscale.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-utils.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/gateway/server-utils.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/gateway/server-wizard-sessions.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server-ws-runtime.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/gateway/server.agent.gateway-server-agent-a.e2e.test.ts", + "language": "typescript", + "symbol_count": 77 + }, + { + "path": "src/gateway/server.agent.gateway-server-agent-b.e2e.test.ts", + "language": "typescript", + "symbol_count": 68 + }, + { + "path": "src/gateway/server.auth.e2e.test.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/gateway/server.channels.e2e.test.ts", + "language": "typescript", + "symbol_count": 63 + }, + { + "path": "src/gateway/server.chat.gateway-server-chat-b.e2e.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/gateway/server.chat.gateway-server-chat.e2e.test.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/gateway/server.config-apply.e2e.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/gateway/server.config-patch.e2e.test.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/gateway/server.cron.e2e.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/gateway/server.health.e2e.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/gateway/server.hooks.e2e.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/gateway/server.impl.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "src/gateway/server.ios-client-id.e2e.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/gateway/server.models-voicewake-misc.e2e.test.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/gateway/server.nodes.late-invoke.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/gateway/server.reload.e2e.test.ts", + "language": "typescript", + "symbol_count": 112 + }, + { + "path": "src/gateway/server.roles-allowlist-update.e2e.test.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "src/gateway/server.sessions-send.e2e.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/gateway/server.sessions.gateway-server-sessions-a.e2e.test.ts", + "language": "typescript", + "symbol_count": 57 + }, + { + "path": "src/gateway/server.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server/close-reason.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server/health-state.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/gateway/server/hooks.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/gateway/server/http-listen.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server/plugins-http.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/gateway/server/plugins-http.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/gateway/server/tls.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/server/ws-connection.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/gateway/server/ws-connection/message-handler.ts", + "language": "typescript", + "symbol_count": 71 + }, + { + "path": "src/gateway/server/ws-types.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/session-utils.fs.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/gateway/session-utils.fs.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/gateway/session-utils.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/gateway/session-utils.ts", + "language": "typescript", + "symbol_count": 74 + }, + { + "path": "src/gateway/session-utils.types.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/gateway/sessions-patch.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/gateway/sessions-patch.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/gateway/sessions-resolve.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/gateway/test-helpers.e2e.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/gateway/test-helpers.mocks.ts", + "language": "typescript", + "symbol_count": 143 + }, + { + "path": "src/gateway/test-helpers.openai-mock.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/gateway/test-helpers.server.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "src/gateway/test-helpers.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/gateway/tools-invoke-http.test.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/gateway/tools-invoke-http.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/gateway/ws-log.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/gateway/ws-log.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/gateway/ws-logging.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/git-hooks.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/globals.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/globals.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/hooks/bundled-dir.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/hooks/bundled/README.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "src/hooks/bundled/boot-md/HOOK.md", + "language": "markdown", + "symbol_count": 1 + }, + { + "path": "src/hooks/bundled/boot-md/handler.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/hooks/bundled/command-logger/HOOK.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "src/hooks/bundled/command-logger/handler.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/hooks/bundled/session-memory/HOOK.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "src/hooks/bundled/session-memory/handler.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/hooks/bundled/session-memory/handler.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/hooks/bundled/soul-evil/HOOK.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "src/hooks/bundled/soul-evil/README.md", + "language": "markdown", + "symbol_count": 2 + }, + { + "path": "src/hooks/bundled/soul-evil/handler.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/hooks/bundled/soul-evil/handler.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/hooks/config.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/hooks/frontmatter.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/hooks/frontmatter.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/hooks/gmail-ops.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "src/hooks/gmail-setup-utils.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/hooks/gmail-setup-utils.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/hooks/gmail-watcher.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/hooks/gmail-watcher.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/hooks/gmail.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/hooks/gmail.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/hooks/hooks-install.e2e.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/hooks/hooks-status.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/hooks/hooks.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/hooks/install.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/hooks/install.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/hooks/installs.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/hooks/internal-hooks.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/hooks/internal-hooks.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/hooks/llm-slug-generator.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/hooks/loader.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/hooks/loader.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/hooks/plugin-hooks.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/hooks/soul-evil.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/hooks/soul-evil.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/hooks/types.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/hooks/workspace.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/imessage/accounts.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/imessage/client.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/imessage/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/imessage/monitor.skips-group-messages-without-mention-by-default.test.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/imessage/monitor.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/imessage/monitor.updates-last-route-chat-id-direct-messages.test.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/imessage/monitor/deliver.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/imessage/monitor/monitor-provider.ts", + "language": "typescript", + "symbol_count": 137 + }, + { + "path": "src/imessage/monitor/runtime.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/imessage/monitor/types.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/imessage/probe.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/imessage/probe.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/imessage/send.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/imessage/send.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/imessage/targets.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/imessage/targets.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/index.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/index.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/infra/agent-events.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/agent-events.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/infra/archive.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/infra/archive.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/infra/backoff.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/binaries.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/infra/binaries.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/bonjour-ciao.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/bonjour-discovery.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/infra/bonjour-discovery.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/infra/bonjour-errors.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/bonjour.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/infra/bonjour.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/infra/brew.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/brew.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/canvas-host-url.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/infra/channel-activity.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/channel-activity.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/infra/channel-summary.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/infra/channels-status-issues.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/clipboard.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/control-ui-assets.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/infra/control-ui-assets.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/infra/dedupe.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/infra/dedupe.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/device-auth-store.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/infra/device-identity.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/infra/device-pairing.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/device-pairing.ts", + "language": "typescript", + "symbol_count": 92 + }, + { + "path": "src/infra/diagnostic-events.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/infra/diagnostic-events.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/infra/diagnostic-flags.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/infra/diagnostic-flags.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/dotenv.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/infra/dotenv.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/infra/env-file.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/env.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/env.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/errors.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/infra/exec-approval-forwarder.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/infra/exec-approval-forwarder.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/infra/exec-approvals.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/infra/exec-approvals.ts", + "language": "typescript", + "symbol_count": 158 + }, + { + "path": "src/infra/exec-host.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/infra/exec-safety.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/infra/fetch.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/fetch.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/infra/format-duration.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/fs-safe.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/infra/gateway-lock.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/infra/gateway-lock.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/infra/git-commit.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/heartbeat-events.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/infra/heartbeat-runner.respects-ackmaxchars-heartbeat-acks.test.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/infra/heartbeat-runner.returns-default-unset.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/infra/heartbeat-runner.scheduler.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/infra/heartbeat-runner.sender-prefers-delivery-target.test.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/infra/heartbeat-runner.ts", + "language": "typescript", + "symbol_count": 94 + }, + { + "path": "src/infra/heartbeat-visibility.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/infra/heartbeat-visibility.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/infra/heartbeat-wake.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/infra/is-main.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/is-main.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/infra/json-file.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/machine-name.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/infra/moltbot-root.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/net/ssrf.pinning.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/infra/net/ssrf.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/infra/node-pairing.ts", + "language": "typescript", + "symbol_count": 74 + }, + { + "path": "src/infra/node-shell.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/node-shell.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/os-summary.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/infra/outbound/agent-delivery.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/infra/outbound/agent-delivery.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/infra/outbound/channel-adapters.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/infra/outbound/channel-selection.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/infra/outbound/channel-target.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/outbound/deliver.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/infra/outbound/deliver.ts", + "language": "typescript", + "symbol_count": 62 + }, + { + "path": "src/infra/outbound/directory-cache.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/infra/outbound/envelope.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/infra/outbound/envelope.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/infra/outbound/format.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/infra/outbound/format.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/infra/outbound/message-action-runner.test.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "src/infra/outbound/message-action-runner.threading.test.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/infra/outbound/message-action-runner.ts", + "language": "typescript", + "symbol_count": 136 + }, + { + "path": "src/infra/outbound/message-action-spec.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/infra/outbound/message.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/infra/outbound/message.ts", + "language": "typescript", + "symbol_count": 69 + }, + { + "path": "src/infra/outbound/outbound-policy.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/infra/outbound/outbound-policy.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/infra/outbound/outbound-send-service.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/infra/outbound/outbound-session.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/infra/outbound/outbound-session.ts", + "language": "typescript", + "symbol_count": 215 + }, + { + "path": "src/infra/outbound/payloads.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/infra/outbound/payloads.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/infra/outbound/target-errors.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/infra/outbound/target-normalization.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/outbound/target-resolver.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/infra/outbound/target-resolver.ts", + "language": "typescript", + "symbol_count": 58 + }, + { + "path": "src/infra/outbound/targets.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/infra/outbound/targets.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/infra/path-env.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/path-env.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/ports-format.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/ports-inspect.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/infra/ports-inspect.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/infra/ports-lsof.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/infra/ports-types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/ports.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/infra/ports.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/provider-usage.auth.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/infra/provider-usage.fetch.antigravity.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/infra/provider-usage.fetch.antigravity.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/infra/provider-usage.fetch.claude.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/infra/provider-usage.fetch.codex.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/infra/provider-usage.fetch.copilot.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/infra/provider-usage.fetch.gemini.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/infra/provider-usage.fetch.minimax.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/infra/provider-usage.fetch.shared.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/infra/provider-usage.fetch.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/provider-usage.fetch.zai.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/infra/provider-usage.format.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/infra/provider-usage.load.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/infra/provider-usage.shared.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/provider-usage.test.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "src/infra/provider-usage.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/provider-usage.types.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/restart-sentinel.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/infra/restart-sentinel.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/infra/restart.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/infra/restart.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/infra/retry-policy.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/retry-policy.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/infra/retry.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/infra/retry.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/infra/runtime-guard.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/infra/runtime-guard.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/infra/session-cost-usage.test.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/infra/session-cost-usage.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/infra/shell-env.path.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/infra/shell-env.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/shell-env.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/infra/skills-remote.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/infra/ssh-config.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/infra/ssh-config.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/infra/ssh-tunnel.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/infra/state-migrations.fs.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/state-migrations.fs.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/infra/state-migrations.ts", + "language": "typescript", + "symbol_count": 82 + }, + { + "path": "src/infra/system-events.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/infra/system-events.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/infra/system-presence.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/infra/system-presence.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/infra/tailnet.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/infra/tailnet.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/infra/tailscale.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/infra/tailscale.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/infra/tls/fingerprint.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/tls/fingerprint.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/tls/gateway.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/infra/transport-ready.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/infra/transport-ready.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/infra/unhandled-rejections.fatal-detection.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/unhandled-rejections.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/unhandled-rejections.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/infra/update-channels.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/infra/update-check.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/infra/update-check.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/infra/update-global.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/infra/update-runner.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/infra/update-runner.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/infra/update-startup.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/infra/update-startup.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/infra/voicewake.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/voicewake.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/infra/warnings.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/infra/widearea-dns.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/infra/widearea-dns.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/infra/ws.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/infra/wsl.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/line/accounts.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/line/accounts.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/line/auto-reply-delivery.test.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/line/auto-reply-delivery.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/line/bot-access.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/line/bot-handlers.test.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/line/bot-handlers.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/line/bot-message-context.test.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/line/bot-message-context.ts", + "language": "typescript", + "symbol_count": 106 + }, + { + "path": "src/line/bot.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/line/config-schema.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/line/download.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/line/flex-templates.test.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "src/line/flex-templates.ts", + "language": "typescript", + "symbol_count": 379 + }, + { + "path": "src/line/http-registry.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/line/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/line/markdown-to-line.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/line/markdown-to-line.ts", + "language": "typescript", + "symbol_count": 99 + }, + { + "path": "src/line/monitor.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/line/probe.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/line/probe.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/line/reply-chunks.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/line/reply-chunks.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/line/rich-menu.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/line/rich-menu.ts", + "language": "typescript", + "symbol_count": 73 + }, + { + "path": "src/line/send.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/line/send.ts", + "language": "typescript", + "symbol_count": 111 + }, + { + "path": "src/line/signature.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/line/signature.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/line/template-messages.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/line/template-messages.ts", + "language": "typescript", + "symbol_count": 78 + }, + { + "path": "src/line/types.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/line/webhook.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/line/webhook.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/link-understanding/apply.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/link-understanding/defaults.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/link-understanding/detect.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/link-understanding/detect.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/link-understanding/format.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/link-understanding/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/link-understanding/runner.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/logger.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/logger.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/logging.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/logging/config.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/logging/console-capture.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/logging/console-prefix.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/logging/console-settings.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/logging/console.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/logging/diagnostic.ts", + "language": "typescript", + "symbol_count": 88 + }, + { + "path": "src/logging/levels.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/logging/logger.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/logging/parse-log-line.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/logging/parse-log-line.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/logging/redact.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/logging/redact.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/logging/state.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/logging/subsystem.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/macos/gateway-daemon.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/macos/relay-smoke.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/macos/relay-smoke.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/macos/relay.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/markdown/code-spans.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/markdown/fences.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/markdown/frontmatter.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/markdown/frontmatter.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/markdown/ir.table-bullets.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/markdown/ir.ts", + "language": "typescript", + "symbol_count": 120 + }, + { + "path": "src/markdown/render.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/markdown/tables.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/media-understanding/apply.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/media-understanding/apply.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/media-understanding/attachments.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/media-understanding/concurrency.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/media-understanding/defaults.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/media-understanding/errors.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/media-understanding/format.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/media-understanding/format.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/media-understanding/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/media-understanding/providers/anthropic/index.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/media-understanding/providers/deepgram/audio.live.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/media-understanding/providers/deepgram/audio.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/media-understanding/providers/deepgram/audio.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/media-understanding/providers/deepgram/index.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/media-understanding/providers/google/audio.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/media-understanding/providers/google/index.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/media-understanding/providers/google/video.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/media-understanding/providers/google/video.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/media-understanding/providers/groq/index.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/media-understanding/providers/image.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/media-understanding/providers/index.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/media-understanding/providers/minimax/index.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/media-understanding/providers/openai/audio.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/media-understanding/providers/openai/audio.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/media-understanding/providers/openai/index.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/media-understanding/providers/shared.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/media-understanding/resolve.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/media-understanding/resolve.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/media-understanding/runner.auto-audio.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/media-understanding/runner.deepgram.test.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/media-understanding/runner.ts", + "language": "typescript", + "symbol_count": 136 + }, + { + "path": "src/media-understanding/runner.vision-skip.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/media-understanding/scope.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/media-understanding/scope.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/media-understanding/types.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/media-understanding/video.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/media/audio-tags.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/media/audio.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/media/constants.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/media/fetch.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/media/fetch.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/media/host.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/media/host.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/media/image-ops.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/media/input-files.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/media/mime.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/media/mime.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/media/parse.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/media/parse.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/media/server.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/media/server.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/media/store.header-ext.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/media/store.redirect.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/media/store.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/media/store.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/memory/batch-gemini.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "src/memory/batch-openai.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/memory/embeddings-gemini.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/memory/embeddings-openai.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/memory/embeddings.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/memory/embeddings.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/memory/headers-fingerprint.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/memory/hybrid.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/memory/hybrid.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/memory/index.test.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "src/memory/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/memory/internal.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/memory/internal.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/memory/manager-cache-key.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/memory/manager-search.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/memory/manager.async-search.test.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/memory/manager.atomic-reindex.test.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/memory/manager.batch.test.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/memory/manager.embedding-batches.test.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/memory/manager.sync-errors-do-not-crash.test.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/memory/manager.ts", + "language": "typescript", + "symbol_count": 307 + }, + { + "path": "src/memory/manager.vector-dedupe.test.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/memory/memory-schema.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/memory/node-llama.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/memory/openai-batch.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/memory/provider-key.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/memory/search-manager.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/memory/session-files.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/memory/sqlite-vec.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/memory/sqlite.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/memory/status-format.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/memory/sync-memory-files.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/memory/sync-session-files.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/node-host/config.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/node-host/runner.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/node-host/runner.ts", + "language": "typescript", + "symbol_count": 114 + }, + { + "path": "src/pairing/pairing-labels.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/pairing/pairing-messages.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/pairing/pairing-messages.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/pairing/pairing-store.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/pairing/pairing-store.ts", + "language": "typescript", + "symbol_count": 65 + }, + { + "path": "src/plugin-sdk/index.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/plugin-sdk/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/plugins/bundled-dir.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/plugins/cli.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/plugins/cli.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/plugins/commands.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/plugins/config-schema.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/plugins/config-state.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/plugins/config-state.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/plugins/discovery.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/plugins/discovery.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/plugins/enable.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/plugins/hook-runner-global.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/plugins/hooks.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/plugins/http-path.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/plugins/http-registry.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/plugins/install.test.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/plugins/install.ts", + "language": "typescript", + "symbol_count": 63 + }, + { + "path": "src/plugins/installs.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/plugins/loader.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/plugins/loader.ts", + "language": "typescript", + "symbol_count": 65 + }, + { + "path": "src/plugins/manifest-registry.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/plugins/manifest.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/plugins/providers.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/plugins/registry.ts", + "language": "typescript", + "symbol_count": 72 + }, + { + "path": "src/plugins/runtime.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/plugins/runtime/index.ts", + "language": "typescript", + "symbol_count": 58 + }, + { + "path": "src/plugins/runtime/native-deps.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/plugins/runtime/types.ts", + "language": "typescript", + "symbol_count": 125 + }, + { + "path": "src/plugins/schema-validator.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/plugins/services.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/plugins/slots.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/plugins/slots.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/plugins/status.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/plugins/tools.optional.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/plugins/tools.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/plugins/types.ts", + "language": "typescript", + "symbol_count": 58 + }, + { + "path": "src/plugins/update.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/plugins/voice-call.plugin.test.ts", + "language": "typescript", + "symbol_count": 69 + }, + { + "path": "src/polls.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/polls.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/postinstall-patcher.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/process/child-process-bridge.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/process/child-process-bridge.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/process/command-queue.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/process/command-queue.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/process/exec.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/process/exec.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/process/lanes.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/process/spawn-utils.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/process/spawn-utils.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/providers/github-copilot-auth.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/providers/github-copilot-models.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/providers/github-copilot-token.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/providers/github-copilot-token.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/providers/google-shared.ensures-function-call-comes-after-user-turn.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/providers/google-shared.preserves-parameters-type-is-missing.test.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/providers/qwen-portal-oauth.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/providers/qwen-portal-oauth.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/routing/bindings.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/routing/resolve-route.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/routing/resolve-route.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/routing/session-key.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/runtime.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/scripts/canvas-a2ui-copy.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/security/audit-extra.ts", + "language": "typescript", + "symbol_count": 118 + }, + { + "path": "src/security/audit-fs.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/security/audit.test.ts", + "language": "typescript", + "symbol_count": 71 + }, + { + "path": "src/security/audit.ts", + "language": "typescript", + "symbol_count": 92 + }, + { + "path": "src/security/external-content.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/security/external-content.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/security/fix.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/security/fix.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/security/windows-acl.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/sessions/level-overrides.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/sessions/model-overrides.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/sessions/send-policy.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/sessions/send-policy.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/sessions/session-key-utils.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/sessions/session-label.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/sessions/transcript-events.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/shared/text/reasoning-tags.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/signal/accounts.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/signal/client.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/signal/daemon.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/signal/daemon.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/signal/format.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/signal/format.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "src/signal/identity.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/signal/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/signal/monitor.event-handler.sender-prefix.test.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "src/signal/monitor.event-handler.typing-read-receipts.test.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "src/signal/monitor.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/signal/monitor.tool-result.pairs-uuid-only-senders-uuid-allowlist-entry.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/signal/monitor.tool-result.sends-tool-summaries-responseprefix.test.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "src/signal/monitor.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/signal/monitor/event-handler.inbound-contract.test.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/signal/monitor/event-handler.ts", + "language": "typescript", + "symbol_count": 128 + }, + { + "path": "src/signal/monitor/event-handler.types.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/signal/probe.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/signal/probe.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/signal/reaction-level.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/signal/send-reactions.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/signal/send-reactions.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/signal/send.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/signal/sse-reconnect.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/slack/accounts.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/slack/actions.read.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/slack/actions.ts", + "language": "typescript", + "symbol_count": 54 + }, + { + "path": "src/slack/channel-migration.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/slack/channel-migration.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/slack/client.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/slack/client.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/slack/directory-live.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/slack/format.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/slack/format.ts", + "language": "typescript", + "symbol_count": 58 + }, + { + "path": "src/slack/http/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/slack/http/registry.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/slack/http/registry.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/slack/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/slack/monitor.test-helpers.ts", + "language": "typescript", + "symbol_count": 64 + }, + { + "path": "src/slack/monitor.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/slack/monitor.threading.missing-thread-ts.test.ts", + "language": "typescript", + "symbol_count": 72 + }, + { + "path": "src/slack/monitor.tool-result.forces-thread-replies-replytoid-is-set.test.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "src/slack/monitor.tool-result.sends-tool-summaries-responseprefix.test.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/slack/monitor.tool-result.threads-top-level-replies-replytomode-is-all.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/slack/monitor.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/slack/monitor/allow-list.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/slack/monitor/auth.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/slack/monitor/channel-config.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/slack/monitor/channel-config.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/slack/monitor/commands.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/slack/monitor/context.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/slack/monitor/context.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/slack/monitor/events.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/slack/monitor/events/channels.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/slack/monitor/events/members.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/slack/monitor/events/messages.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/slack/monitor/events/pins.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/slack/monitor/events/reactions.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/slack/monitor/media.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/slack/monitor/media.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/slack/monitor/message-handler.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/slack/monitor/message-handler/dispatch.ts", + "language": "typescript", + "symbol_count": 55 + }, + { + "path": "src/slack/monitor/message-handler/prepare.inbound-contract.test.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/slack/monitor/message-handler/prepare.sender-prefix.test.ts", + "language": "typescript", + "symbol_count": 68 + }, + { + "path": "src/slack/monitor/message-handler/prepare.ts", + "language": "typescript", + "symbol_count": 110 + }, + { + "path": "src/slack/monitor/message-handler/types.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/slack/monitor/policy.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/slack/monitor/provider.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/slack/monitor/replies.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/slack/monitor/slash.command-arg-menus.test.ts", + "language": "typescript", + "symbol_count": 83 + }, + { + "path": "src/slack/monitor/slash.policy.test.ts", + "language": "typescript", + "symbol_count": 70 + }, + { + "path": "src/slack/monitor/slash.ts", + "language": "typescript", + "symbol_count": 120 + }, + { + "path": "src/slack/monitor/thread-resolution.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/slack/monitor/thread-resolution.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/slack/monitor/types.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/slack/probe.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/slack/resolve-channels.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/slack/resolve-channels.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/slack/resolve-users.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/slack/scopes.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/slack/send.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/slack/targets.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/slack/targets.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/slack/threading-tool-context.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/slack/threading-tool-context.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/slack/threading.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/slack/threading.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/slack/token.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/slack/types.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/telegram/accounts.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/telegram/accounts.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/telegram/allowed-updates.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/telegram/api-logging.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/telegram/audit.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/telegram/audit.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/telegram/bot-access.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/telegram/bot-handlers.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/telegram/bot-message-context.dm-threads.test.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/telegram/bot-message-context.sender-prefix.test.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/telegram/bot-message-context.ts", + "language": "typescript", + "symbol_count": 125 + }, + { + "path": "src/telegram/bot-message-dispatch.ts", + "language": "typescript", + "symbol_count": 61 + }, + { + "path": "src/telegram/bot-message.test.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/telegram/bot-message.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/telegram/bot-native-commands.plugin-auth.test.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/telegram/bot-native-commands.ts", + "language": "typescript", + "symbol_count": 79 + }, + { + "path": "src/telegram/bot-updates.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/telegram/bot.create-telegram-bot.accepts-group-messages-mentionpatterns-match-without-botusername.test.ts", + "language": "typescript", + "symbol_count": 60 + }, + { + "path": "src/telegram/bot.create-telegram-bot.applies-topic-skill-filters-system-prompts.test.ts", + "language": "typescript", + "symbol_count": 57 + }, + { + "path": "src/telegram/bot.create-telegram-bot.blocks-all-group-messages-grouppolicy-is.test.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/telegram/bot.create-telegram-bot.dedupes-duplicate-callback-query-updates-by-update.test.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/telegram/bot.create-telegram-bot.installs-grammy-throttler.test.ts", + "language": "typescript", + "symbol_count": 74 + }, + { + "path": "src/telegram/bot.create-telegram-bot.matches-tg-prefixed-allowfrom-entries-case-insensitively.test.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/telegram/bot.create-telegram-bot.matches-usernames-case-insensitively-grouppolicy-is.test.ts", + "language": "typescript", + "symbol_count": 47 + }, + { + "path": "src/telegram/bot.create-telegram-bot.routes-dms-by-telegram-accountid-binding.test.ts", + "language": "typescript", + "symbol_count": 61 + }, + { + "path": "src/telegram/bot.create-telegram-bot.sends-replies-without-native-reply-threading.test.ts", + "language": "typescript", + "symbol_count": 59 + }, + { + "path": "src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts", + "language": "typescript", + "symbol_count": 61 + }, + { + "path": "src/telegram/bot.media.includes-location-text-ctx-fields-pins.test.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "src/telegram/bot.test.ts", + "language": "typescript", + "symbol_count": 135 + }, + { + "path": "src/telegram/bot.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/telegram/bot/delivery.test.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/telegram/bot/delivery.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/telegram/bot/helpers.expand-text-links.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/telegram/bot/helpers.test.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/telegram/bot/helpers.ts", + "language": "typescript", + "symbol_count": 62 + }, + { + "path": "src/telegram/bot/types.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/telegram/caption.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/telegram/download.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/telegram/download.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/telegram/draft-chunking.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/telegram/draft-chunking.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/telegram/draft-stream.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/telegram/fetch.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/telegram/fetch.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/telegram/format.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/telegram/format.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/telegram/group-migration.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/telegram/group-migration.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/telegram/index.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/telegram/inline-buttons.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/telegram/inline-buttons.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/telegram/monitor.test.ts", + "language": "typescript", + "symbol_count": 57 + }, + { + "path": "src/telegram/monitor.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/telegram/network-config.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/telegram/network-config.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/telegram/network-errors.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/telegram/network-errors.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/telegram/pairing-store.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/telegram/pairing-store.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/telegram/probe.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/telegram/proxy.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/telegram/reaction-level.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/telegram/reaction-level.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/telegram/send.caption-split.test.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/telegram/send.edit-message.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/telegram/send.preserves-thread-params-plain-text-fallback.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/telegram/send.proxy.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/telegram/send.returns-undefined-empty-input.test.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/telegram/send.ts", + "language": "typescript", + "symbol_count": 84 + }, + { + "path": "src/telegram/sent-message-cache.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/telegram/sent-message-cache.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/telegram/sticker-cache.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/telegram/sticker-cache.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/telegram/targets.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/telegram/targets.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/telegram/token.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/telegram/token.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/telegram/update-offset-store.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/telegram/update-offset-store.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/telegram/voice.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/telegram/voice.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/telegram/webhook-set.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/telegram/webhook.test.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/telegram/webhook.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/terminal/ansi.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/terminal/links.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/terminal/note.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/terminal/palette.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/terminal/progress-line.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/terminal/prompt-style.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/terminal/stream-writer.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/terminal/stream-writer.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/terminal/table.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/terminal/table.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/terminal/theme.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/test-helpers/workspace.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/test-utils/channel-plugins.ts", + "language": "typescript", + "symbol_count": 38 + }, + { + "path": "src/test-utils/ports.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/tts/tts.test.ts", + "language": "typescript", + "symbol_count": 48 + }, + { + "path": "src/tts/tts.ts", + "language": "typescript", + "symbol_count": 237 + }, + { + "path": "src/tui/commands.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/tui/commands.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/tui/components/assistant-message.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/tui/components/chat-log.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/tui/components/custom-editor.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/tui/components/filterable-select-list.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/tui/components/fuzzy-filter.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/tui/components/searchable-select-list.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/tui/components/searchable-select-list.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "src/tui/components/selectors.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/tui/components/tool-execution.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/tui/components/user-message.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/tui/gateway-chat.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "src/tui/theme/syntax-theme.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/tui/theme/theme.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/tui/theme/theme.ts", + "language": "typescript", + "symbol_count": 51 + }, + { + "path": "src/tui/tui-command-handlers.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/tui/tui-command-handlers.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/tui/tui-event-handlers.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/tui/tui-event-handlers.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/tui/tui-formatters.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/tui/tui-formatters.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/tui/tui-input-history.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/tui/tui-local-shell.test.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/tui/tui-local-shell.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/tui/tui-overlays.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/tui/tui-overlays.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/tui/tui-session-actions.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "src/tui/tui-status-summary.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/tui/tui-stream-assembler.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/tui/tui-stream-assembler.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/tui/tui-types.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/tui/tui-waiting.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "src/tui/tui-waiting.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/tui/tui.submit-handler.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/tui/tui.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/tui/tui.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/types/cli-highlight.d.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/types/lydell-node-pty.d.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/types/napi-rs-canvas.d.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/types/node-edge-tts.d.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/types/node-llama-cpp.d.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/types/osc-progress.d.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/types/pdfjs-dist-legacy.d.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/types/proper-lockfile.d.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/types/qrcode-terminal.d.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/utils.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/utils.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "src/utils/account-id.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/utils/boolean.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/utils/boolean.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/utils/delivery-context.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/utils/delivery-context.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/utils/directive-tags.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "src/utils/message-channel.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/utils/message-channel.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/utils/provider-utils.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/utils/queue-helpers.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "src/utils/time-format.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/utils/usage-format.test.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/utils/usage-format.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/version.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/web/accounts.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/web/accounts.whatsapp-auth.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/web/active-listener.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/web/auth-store.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/web/auto-reply.broadcast-groups.skips-unknown-broadcast-agent-ids-agents-list.test.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/web/auto-reply.impl.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/web/auto-reply.partial-reply-gating.test.ts", + "language": "typescript", + "symbol_count": 45 + }, + { + "path": "src/web/auto-reply.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/web/auto-reply.typing-controller-idle.test.ts", + "language": "typescript", + "symbol_count": 28 + }, + { + "path": "src/web/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/web/auto-reply.web-auto-reply.falls-back-text-media-send-fails.test.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/web/auto-reply.web-auto-reply.prefixes-body-same-phone-marker-from.test.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/web/auto-reply.web-auto-reply.reconnects-after-connection-close.test.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/web/auto-reply.web-auto-reply.requires-mention-group-chats-injects-history-replying.test.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "src/web/auto-reply.web-auto-reply.sends-tool-summaries-immediately-responseprefix.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/web/auto-reply.web-auto-reply.supports-always-group-activation-silent-token-preserves.test.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/web/auto-reply.web-auto-reply.uses-per-agent-mention-patterns-group-gating.test.ts", + "language": "typescript", + "symbol_count": 42 + }, + { + "path": "src/web/auto-reply/constants.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/web/auto-reply/deliver-reply.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/web/auto-reply/heartbeat-runner.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "src/web/auto-reply/loggers.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/web/auto-reply/mentions.test.ts", + "language": "typescript", + "symbol_count": 15 + }, + { + "path": "src/web/auto-reply/mentions.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/web/auto-reply/monitor.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/web/auto-reply/monitor/ack-reaction.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/web/auto-reply/monitor/broadcast.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/web/auto-reply/monitor/commands.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/web/auto-reply/monitor/echo.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/web/auto-reply/monitor/group-activation.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "src/web/auto-reply/monitor/group-gating.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/web/auto-reply/monitor/group-gating.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/web/auto-reply/monitor/group-members.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/web/auto-reply/monitor/last-route.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "src/web/auto-reply/monitor/message-line.test.ts", + "language": "typescript", + "symbol_count": 23 + }, + { + "path": "src/web/auto-reply/monitor/message-line.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/web/auto-reply/monitor/on-message.ts", + "language": "typescript", + "symbol_count": 46 + }, + { + "path": "src/web/auto-reply/monitor/peer.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/web/auto-reply/monitor/process-message.inbound-contract.test.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "src/web/auto-reply/monitor/process-message.ts", + "language": "typescript", + "symbol_count": 86 + }, + { + "path": "src/web/auto-reply/session-snapshot.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/web/auto-reply/session-snapshot.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "src/web/auto-reply/types.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/web/auto-reply/util.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/web/inbound.media.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/web/inbound.test.ts", + "language": "typescript", + "symbol_count": 36 + }, + { + "path": "src/web/inbound.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/web/inbound/access-control.pairing-history.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/web/inbound/access-control.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/web/inbound/dedupe.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/web/inbound/extract.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/web/inbound/media.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "src/web/inbound/monitor.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "src/web/inbound/send-api.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "src/web/inbound/types.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "src/web/login-qr.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/web/login-qr.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/web/login.coverage.test.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "src/web/login.test.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "src/web/login.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/web/logout.test.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/web/media.test.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "src/web/media.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "src/web/monitor-inbox.allows-messages-from-senders-allowfrom-list.test.ts", + "language": "typescript", + "symbol_count": 53 + }, + { + "path": "src/web/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test.ts", + "language": "typescript", + "symbol_count": 41 + }, + { + "path": "src/web/monitor-inbox.captures-media-path-image-messages.test.ts", + "language": "typescript", + "symbol_count": 62 + }, + { + "path": "src/web/monitor-inbox.streams-inbound-messages.test.ts", + "language": "typescript", + "symbol_count": 49 + }, + { + "path": "src/web/outbound.test.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/web/outbound.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "src/web/qr-image.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/web/qr-image.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/web/reconnect.test.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/web/reconnect.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/web/session.test.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "src/web/session.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "src/web/test-helpers.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "src/web/vcard.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "src/whatsapp/normalize.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "src/whatsapp/normalize.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "src/wizard/clack-prompter.ts", + "language": "typescript", + "symbol_count": 33 + }, + { + "path": "src/wizard/onboarding.finalize.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "src/wizard/onboarding.gateway-config.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "src/wizard/onboarding.test.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "src/wizard/onboarding.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "src/wizard/onboarding.types.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/wizard/prompts.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "src/wizard/session.test.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "src/wizard/session.ts", + "language": "typescript", + "symbol_count": 68 + }, + { + "path": "test/auto-reply.retry.test.ts", + "language": "typescript", + "symbol_count": 21 + }, + { + "path": "test/fixtures/child-process-bridge/child.js", + "language": "javascript", + "symbol_count": 1 + }, + { + "path": "test/gateway.multi.e2e.test.ts", + "language": "typescript", + "symbol_count": 50 + }, + { + "path": "test/global-setup.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "test/helpers/envelope-timestamp.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "test/helpers/inbound-contract.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "test/helpers/normalize-text.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "test/helpers/paths.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "test/helpers/poll.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "test/helpers/temp-home.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "test/inbound-contract.providers.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "test/media-understanding.auto.e2e.test.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "test/mocks/baileys.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "test/provider-timeout.e2e.test.ts", + "language": "typescript", + "symbol_count": 99 + }, + { + "path": "test/setup.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "test/test-env.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "tsconfig.json", + "language": "json", + "symbol_count": 15 + }, + { + "path": "ui/package.json", + "language": "json", + "symbol_count": 19 + }, + { + "path": "ui/src/main.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/app-channels.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "ui/src/ui/app-chat.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "ui/src/ui/app-defaults.ts", + "language": "typescript", + "symbol_count": 25 + }, + { + "path": "ui/src/ui/app-events.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/app-gateway.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "ui/src/ui/app-lifecycle.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "ui/src/ui/app-polling.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "ui/src/ui/app-render.helpers.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "ui/src/ui/app-render.ts", + "language": "typescript", + "symbol_count": 198 + }, + { + "path": "ui/src/ui/app-scroll.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "ui/src/ui/app-settings.test.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "ui/src/ui/app-settings.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "ui/src/ui/app-tool-stream.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "ui/src/ui/app-view-state.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/app.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "ui/src/ui/assistant-identity.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "ui/src/ui/chat-markdown.browser.test.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "ui/src/ui/chat/constants.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/chat/copy-as-markdown.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "ui/src/ui/chat/grouped-render.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "ui/src/ui/chat/message-extract.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "ui/src/ui/chat/message-extract.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "ui/src/ui/chat/message-normalizer.test.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "ui/src/ui/chat/message-normalizer.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "ui/src/ui/chat/tool-cards.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "ui/src/ui/chat/tool-helpers.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/chat/tool-helpers.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/components/resizable-divider.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "ui/src/ui/config-form.browser.test.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "ui/src/ui/controllers/agents.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/controllers/assistant-identity.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/controllers/channels.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "ui/src/ui/controllers/channels.types.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/controllers/chat.test.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "ui/src/ui/controllers/chat.ts", + "language": "typescript", + "symbol_count": 27 + }, + { + "path": "ui/src/ui/controllers/config.test.ts", + "language": "typescript", + "symbol_count": 39 + }, + { + "path": "ui/src/ui/controllers/config.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "ui/src/ui/controllers/config/form-utils.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "ui/src/ui/controllers/cron.ts", + "language": "typescript", + "symbol_count": 32 + }, + { + "path": "ui/src/ui/controllers/debug.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "ui/src/ui/controllers/devices.ts", + "language": "typescript", + "symbol_count": 17 + }, + { + "path": "ui/src/ui/controllers/exec-approval.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "ui/src/ui/controllers/exec-approvals.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "ui/src/ui/controllers/logs.ts", + "language": "typescript", + "symbol_count": 11 + }, + { + "path": "ui/src/ui/controllers/nodes.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/controllers/presence.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/controllers/sessions.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "ui/src/ui/controllers/skills.ts", + "language": "typescript", + "symbol_count": 19 + }, + { + "path": "ui/src/ui/data/moonshot-kimi-k2.ts", + "language": "typescript", + "symbol_count": 9 + }, + { + "path": "ui/src/ui/device-auth.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "ui/src/ui/device-identity.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "ui/src/ui/focus-mode.browser.test.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "ui/src/ui/format.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/format.ts", + "language": "typescript", + "symbol_count": 14 + }, + { + "path": "ui/src/ui/gateway.ts", + "language": "typescript", + "symbol_count": 43 + }, + { + "path": "ui/src/ui/icons.ts", + "language": "typescript", + "symbol_count": 35 + }, + { + "path": "ui/src/ui/markdown.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/markdown.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "ui/src/ui/navigation.browser.test.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "ui/src/ui/navigation.test.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/navigation.ts", + "language": "typescript", + "symbol_count": 22 + }, + { + "path": "ui/src/ui/presenter.ts", + "language": "typescript", + "symbol_count": 8 + }, + { + "path": "ui/src/ui/storage.ts", + "language": "typescript", + "symbol_count": 13 + }, + { + "path": "ui/src/ui/theme-transition.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "ui/src/ui/theme.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "ui/src/ui/tool-display.json", + "language": "json", + "symbol_count": 309 + }, + { + "path": "ui/src/ui/tool-display.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "ui/src/ui/types.ts", + "language": "typescript", + "symbol_count": 56 + }, + { + "path": "ui/src/ui/types/chat-types.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "ui/src/ui/ui-types.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "ui/src/ui/uuid.test.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/uuid.ts", + "language": "typescript", + "symbol_count": 5 + }, + { + "path": "ui/src/ui/views/channels.config.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "ui/src/ui/views/channels.discord.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/views/channels.googlechat.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/views/channels.imessage.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/views/channels.nostr-profile-form.ts", + "language": "typescript", + "symbol_count": 24 + }, + { + "path": "ui/src/ui/views/channels.nostr.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "ui/src/ui/views/channels.shared.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "ui/src/ui/views/channels.signal.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/views/channels.slack.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/views/channels.telegram.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/views/channels.ts", + "language": "typescript", + "symbol_count": 30 + }, + { + "path": "ui/src/ui/views/channels.types.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "ui/src/ui/views/channels.whatsapp.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/views/chat.test.ts", + "language": "typescript", + "symbol_count": 40 + }, + { + "path": "ui/src/ui/views/chat.ts", + "language": "typescript", + "symbol_count": 37 + }, + { + "path": "ui/src/ui/views/config-form.analyze.ts", + "language": "typescript", + "symbol_count": 16 + }, + { + "path": "ui/src/ui/views/config-form.node.ts", + "language": "typescript", + "symbol_count": 29 + }, + { + "path": "ui/src/ui/views/config-form.render.ts", + "language": "typescript", + "symbol_count": 44 + }, + { + "path": "ui/src/ui/views/config-form.shared.ts", + "language": "typescript", + "symbol_count": 7 + }, + { + "path": "ui/src/ui/views/config-form.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/views/config.browser.test.ts", + "language": "typescript", + "symbol_count": 31 + }, + { + "path": "ui/src/ui/views/config.ts", + "language": "typescript", + "symbol_count": 59 + }, + { + "path": "ui/src/ui/views/cron.test.ts", + "language": "typescript", + "symbol_count": 34 + }, + { + "path": "ui/src/ui/views/cron.ts", + "language": "typescript", + "symbol_count": 26 + }, + { + "path": "ui/src/ui/views/debug.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/views/exec-approval.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "ui/src/ui/views/gateway-url-confirmation.ts", + "language": "typescript", + "symbol_count": 1 + }, + { + "path": "ui/src/ui/views/instances.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "ui/src/ui/views/logs.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "ui/src/ui/views/markdown-sidebar.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "ui/src/ui/views/nodes.ts", + "language": "typescript", + "symbol_count": 76 + }, + { + "path": "ui/src/ui/views/overview.ts", + "language": "typescript", + "symbol_count": 4 + }, + { + "path": "ui/src/ui/views/sessions.ts", + "language": "typescript", + "symbol_count": 18 + }, + { + "path": "ui/src/ui/views/skills.ts", + "language": "typescript", + "symbol_count": 3 + }, + { + "path": "ui/tsconfig.json", + "language": "json", + "symbol_count": 11 + }, + { + "path": "ui/vite.config.ts", + "language": "typescript", + "symbol_count": 12 + }, + { + "path": "ui/vitest.config.ts", + "language": "typescript", + "symbol_count": 10 + }, + { + "path": "vitest.config.ts", + "language": "typescript", + "symbol_count": 20 + }, + { + "path": "vitest.e2e.config.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "vitest.extensions.config.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "vitest.gateway.config.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "vitest.live.config.ts", + "language": "typescript", + "symbol_count": 6 + }, + { + "path": "vitest.unit.config.ts", + "language": "typescript", + "symbol_count": 2 + }, + { + "path": "wiki/README.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "wiki/api.md", + "language": "markdown", + "symbol_count": 43 + }, + { + "path": "wiki/architecture/decisions.md", + "language": "markdown", + "symbol_count": 44 + }, + { + "path": "wiki/architecture/diagrams.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "wiki/business-context.json", + "language": "json", + "symbol_count": 32 + }, + { + "path": "wiki/components/README.md", + "language": "markdown", + "symbol_count": 10 + }, + { + "path": "wiki/components/agents.md", + "language": "markdown", + "symbol_count": 17 + }, + { + "path": "wiki/components/auto-reply.md", + "language": "markdown", + "symbol_count": 15 + }, + { + "path": "wiki/components/channels.md", + "language": "markdown", + "symbol_count": 15 + }, + { + "path": "wiki/components/config.md", + "language": "markdown", + "symbol_count": 13 + }, + { + "path": "wiki/components/gateway.md", + "language": "markdown", + "symbol_count": 18 + }, + { + "path": "wiki/configuration/README.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "wiki/configuration/agents.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "wiki/configuration/channels.md", + "language": "markdown", + "symbol_count": 7 + }, + { + "path": "wiki/configuration/environment.md", + "language": "markdown", + "symbol_count": 8 + }, + { + "path": "wiki/configuration/gateway.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "wiki/configuration/providers.md", + "language": "markdown", + "symbol_count": 4 + }, + { + "path": "wiki/dependencies.md", + "language": "markdown", + "symbol_count": 48 + }, + { + "path": "wiki/errors.md", + "language": "markdown", + "symbol_count": 43 + }, + { + "path": "wiki/examples.md", + "language": "markdown", + "symbol_count": 42 + }, + { + "path": "wiki/flows/README.md", + "language": "markdown", + "symbol_count": 3 + }, + { + "path": "wiki/flows/agent-execution.md", + "language": "markdown", + "symbol_count": 14 + }, + { + "path": "wiki/flows/auto-reply-pipeline.md", + "language": "markdown", + "symbol_count": 12 + }, + { + "path": "wiki/flows/gateway-websocket.md", + "language": "markdown", + "symbol_count": 16 + }, + { + "path": "wiki/flows/inbound-message.md", + "language": "markdown", + "symbol_count": 9 + }, + { + "path": "wiki/models.md", + "language": "markdown", + "symbol_count": 23 + }, + { + "path": "wiki/overview.md", + "language": "markdown", + "symbol_count": 29 + }, + { + "path": "wiki/quickstart.md", + "language": "markdown", + "symbol_count": 30 + }, + { + "path": "wiki/state.json", + "language": "json", + "symbol_count": 102 + }, + { + "path": "zizmor.yml", + "language": "yaml", + "symbol_count": 7 + } + ], + "source": "civyk-repoix" +} \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/data/metrics-summary.json b/.analysis/moltbotsec-20260129-202219/data/metrics-summary.json new file mode 100644 index 000000000..8b5e0593c --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/metrics-summary.json @@ -0,0 +1,60 @@ +{ + "project": "moltbot", + "analysis_date": "2026-01-29T21:30:00Z", + "chain_id": "20260129-202219", + "metrics": { + "code": { + "total_lines": 200000, + "total_files": 3630, + "total_symbols": 74286, + "languages": { + "typescript": 3028, + "markdown": 446, + "json": 78, + "yaml": 22, + "javascript": 17, + "python": 10, + "swift": 28 + } + }, + "quality": { + "test_coverage_percent": 70, + "tech_debt_score": 8, + "security_score": 95, + "maintainability_score": 90, + "quality_grade": "A" + }, + "dependencies": { + "total": 750, + "direct": 200, + "transitive": 550, + "outdated": 0, + "vulnerable": 0, + "critical_vulns": 0 + }, + "complexity": { + "score": 53.5, + "rating": "HIGH", + "factors": { + "codebase_size": 8, + "tech_stack_change": 8, + "database_migration": 1, + "integration_count": 10, + "test_coverage_gap": 3, + "security_changes": 1 + } + }, + "feasibility": { + "inline_upgrade": 56, + "greenfield_rewrite": 60, + "hybrid_approach": 68, + "recommended": "hybrid_approach" + }, + "architecture": { + "components": 15, + "channel_integrations": 28, + "circular_dependencies": 1, + "dead_code_symbols": 0 + } + } +} diff --git a/.analysis/moltbotsec-20260129-202219/data/quality-gates.json b/.analysis/moltbotsec-20260129-202219/data/quality-gates.json new file mode 100644 index 000000000..648aaa5a5 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/quality-gates.json @@ -0,0 +1,436 @@ +{ + "circular_dependencies": { + "count": 1, + "cycles": [ + { + "nodes": [ + "controllers/config", + "test/helpers", + "test", + "ui/components", + "tui/components", + "ui/controllers", + "commands/models", + "apps/shared", + "ui/views", + "config" + ], + "type": "component" + } + ] + }, + "dead_code": { + "count": 0, + "symbols": [] + }, + "hotspots": { + "files": [ + { + "name": "src/agents/pi-embedded-runner.ts", + "type": "file", + "commits": 167, + "additions": 5373, + "deletions": 5972, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/config/zod-schema.ts", + "type": "file", + "commits": 164, + "additions": 4933, + "deletions": 4358, + "component": "config", + "risk_score": 1.0 + }, + { + "name": "src/config/types.ts", + "type": "file", + "commits": 137, + "additions": 4194, + "deletions": 4141, + "component": "config", + "risk_score": 1.0 + }, + { + "name": "src/auto-reply/reply.ts", + "type": "file", + "commits": 130, + "additions": 3012, + "deletions": 4332, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/discord/monitor.ts", + "type": "file", + "commits": 128, + "additions": 4486, + "deletions": 4825, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/config/schema.ts", + "type": "file", + "commits": 126, + "additions": 1281, + "deletions": 291, + "component": "config", + "risk_score": 1.0 + }, + { + "name": "src/telegram/bot.ts", + "type": "file", + "commits": 126, + "additions": 3003, + "deletions": 2920, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/agents/pi-tools.ts", + "type": "file", + "commits": 101, + "additions": 1703, + "deletions": 1576, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/gateway/server.ts", + "type": "file", + "commits": 98, + "additions": 2991, + "deletions": 9311, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/cli/program.ts", + "type": "file", + "commits": 92, + "additions": 2028, + "deletions": 2391, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/auto-reply/reply/agent-runner.ts", + "type": "file", + "commits": 91, + "additions": 2565, + "deletions": 2045, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/commands/doctor.ts", + "type": "file", + "commits": 89, + "additions": 2561, + "deletions": 2255, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/telegram/bot.test.ts", + "type": "file", + "commits": 85, + "additions": 5981, + "deletions": 3150, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/agents/system-prompt.ts", + "type": "file", + "commits": 84, + "additions": 2020, + "deletions": 1527, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/wizard/onboarding.ts", + "type": "file", + "commits": 82, + "additions": 1933, + "deletions": 1482, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/agents/pi-embedded-subscribe.ts", + "type": "file", + "commits": 78, + "additions": 2069, + "deletions": 1940, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/commands/configure.ts", + "type": "file", + "commits": 78, + "additions": 2835, + "deletions": 2811, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/slack/monitor.ts", + "type": "file", + "commits": 75, + "additions": 3367, + "deletions": 3362, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/commands/agent.ts", + "type": "file", + "commits": 73, + "additions": 1165, + "deletions": 1220, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/agents/pi-embedded-helpers.ts", + "type": "file", + "commits": 71, + "additions": 2420, + "deletions": 2468, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/auto-reply/status.ts", + "type": "file", + "commits": 67, + "additions": 1007, + "deletions": 599, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/auto-reply/reply/commands.ts", + "type": "file", + "commits": 67, + "additions": 1588, + "deletions": 1581, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/web/auto-reply.ts", + "type": "file", + "commits": 67, + "additions": 1285, + "deletions": 2790, + "component": null, + "risk_score": 1.0 + }, + { + "name": "ui/src/ui/app.ts", + "type": "file", + "commits": 65, + "additions": 1311, + "deletions": 1139, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/auto-reply/reply/directive-handling.ts", + "type": "file", + "commits": 62, + "additions": 2313, + "deletions": 2255, + "component": null, + "risk_score": 1.0 + }, + { + "name": "ui/src/ui/app-render.ts", + "type": "file", + "commits": 61, + "additions": 768, + "deletions": 543, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/agents/pi-embedded-runner/run/attempt.ts", + "type": "file", + "commits": 58, + "additions": 1144, + "deletions": 260, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/commands/onboard-non-interactive.ts", + "type": "file", + "commits": 56, + "additions": 1017, + "deletions": 964, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/tui/tui.ts", + "type": "file", + "commits": 53, + "additions": 2105, + "deletions": 1478, + "component": null, + "risk_score": 1.0 + }, + { + "name": "src/web/inbound.ts", + "type": "file", + "commits": 52, + "additions": 682, + "deletions": 1263, + "component": null, + "risk_score": 1.0 + } + ], + "components": [ + { + "name": "unknown", + "type": "component", + "commits": 17603, + "additions": 592778, + "deletions": 225561, + "files": 2776, + "risk_score": 1.0 + }, + { + "name": "config", + "type": "component", + "commits": 1373, + "additions": 32491, + "deletions": 17032, + "files": 128, + "risk_score": 1.0 + }, + { + "name": "ui/views", + "type": "component", + "commits": 176, + "additions": 8946, + "deletions": 3321, + "files": 34, + "risk_score": 1.0 + }, + { + "name": "commands/models", + "type": "component", + "commits": 133, + "additions": 6226, + "deletions": 2816, + "files": 20, + "risk_score": 1.0 + }, + { + "name": "tui/components", + "type": "component", + "commits": 73, + "additions": 2766, + "deletions": 1609, + "files": 10, + "risk_score": 1.0 + }, + { + "name": "ui/controllers", + "type": "component", + "commits": 69, + "additions": 1926, + "deletions": 649, + "files": 18, + "risk_score": 1.0 + }, + { + "name": "test", + "type": "component", + "commits": 45, + "additions": 1770, + "deletions": 483, + "files": 8, + "risk_score": 0.9 + }, + { + "name": "test/helpers", + "type": "component", + "commits": 16, + "additions": 272, + "deletions": 23, + "files": 6, + "risk_score": 0.32 + }, + { + "name": "utils", + "type": "component", + "commits": 3, + "additions": 171, + "deletions": 1, + "files": 2, + "risk_score": 0.06 + }, + { + "name": "controllers/config", + "type": "component", + "commits": 2, + "additions": 77, + "deletions": 1, + "files": 1, + "risk_score": 0.04 + }, + { + "name": "twitch/test", + "type": "component", + "commits": 1, + "additions": 7, + "deletions": 0, + "files": 1, + "risk_score": 0.02 + }, + { + "name": "shared", + "type": "component", + "commits": 1, + "additions": 61, + "deletions": 0, + "files": 1, + "risk_score": 0.02 + }, + { + "name": "nostr/test", + "type": "component", + "commits": 1, + "additions": 5, + "deletions": 0, + "files": 1, + "risk_score": 0.02 + }, + { + "name": "ui/components", + "type": "component", + "commits": 1, + "additions": 109, + "deletions": 0, + "files": 1, + "risk_score": 0.02 + } + ] + }, + "quality_score": { + "score": 90, + "grade": "A", + "issues": { + "circular_dependencies": 1, + "dead_code": 0 + } + } +} \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/data/recommendations.json b/.analysis/moltbotsec-20260129-202219/data/recommendations.json new file mode 100644 index 000000000..095ffe055 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/recommendations.json @@ -0,0 +1,176 @@ +{ + "schema_version": "3.1.0", + "chain_id": "20260129-202219", + "stage": "full_app_analysis", + "timestamp": "2026-01-29T21:00:00Z", + "stages_complete": [ + "setup_and_scope", + "file_analysis", + "full_app_analysis" + ], + "modernization_preferences": { + "q1_language": "Python 3.12+", + "q2_database": "SQLite with sqlite-vec", + "q3_message_bus": "WebSocket + in-memory", + "q4_package_manager": "uv", + "q5_deployment": "Docker Compose", + "q6_iac": "Docker Compose", + "q7_containerization": "Docker", + "q8_observability": { + "metrics": "Prometheus", + "logging": "Structured JSON", + "tracing": "OpenTelemetry" + }, + "q9_security": "Keep current (Token/Password/Tailscale)", + "q10_testing": { + "strategy": "pytest", + "coverage_target": "80%" + } + }, + "scope": { + "validated": true, + "in_scope": [ + "Gateway server and protocol", + "Security layer (auth, SSRF protection, audit)", + "Channel integrations (28 channels)", + "Memory/vector search", + "Cron service", + "Voice call extension", + "CLI and TUI" + ], + "out_of_scope": [ + "Mobile apps (iOS, Android, macOS - keep Swift/Kotlin)", + "UI components (keep TypeScript/React for now)" + ] + }, + "scoring": { + "complexity": { + "codebase_size": 8, + "tech_stack_change": 8, + "database_migration": 1, + "integration_count": 10, + "test_coverage_gap": 3, + "security_changes": 1, + "overall": 5.35, + "rating": "HIGH" + }, + "feasibility": { + "inline_upgrade": 56, + "greenfield_rewrite": 60, + "hybrid_approach": 68 + } + }, + "recommendations": { + "primary": { + "approach": "Hybrid/Strangler Fig Pattern", + "confidence": 68, + "rationale": "Given HIGH complexity and 28 integrations, hybrid approach allows incremental migration with reduced risk. Preserve security layer while migrating business logic to Python/FastAPI.", + "estimated_duration": "6-9 months", + "estimated_effort": "3-4 FTE" + }, + "alternative": { + "approach": "Greenfield Rewrite", + "confidence": 60, + "trade_offs": "Higher initial effort but cleaner architecture. Risk of feature loss without comprehensive spec." + }, + "quick_wins": [ + { + "action": "Add OpenTelemetry observability to current codebase", + "effort": "MEDIUM", + "impact": "HIGH" + }, + { + "action": "Extract security module as standalone service", + "effort": "MEDIUM", + "impact": "HIGH" + }, + { + "action": "Create Python/FastAPI skeleton with uv", + "effort": "LOW", + "impact": "MEDIUM" + } + ], + "phased_plan": { + "phase_1": { + "name": "Foundation (50% value)", + "focus": [ + "Security layer", + "Gateway protocol", + "Core config" + ], + "deliverables": [ + "Python gateway skeleton", + "Auth module port", + "Config schema" + ], + "risk": "LOW" + }, + "phase_2": { + "name": "Core Migration (30% value)", + "focus": [ + "High-value channels (Discord, Telegram, WhatsApp)", + "Memory/vector search" + ], + "deliverables": [ + "3 channel adapters", + "Vector DB integration" + ], + "risk": "MEDIUM" + }, + "phase_3": { + "name": "Complete Migration (15% value)", + "focus": [ + "Remaining channels", + "Extensions", + "Voice call" + ], + "deliverables": [ + "All channel adapters", + "Extension framework" + ], + "risk": "MEDIUM" + }, + "phase_4": { + "name": "Optimization (5% value)", + "focus": [ + "Performance tuning", + "UI/UX improvements", + "Documentation" + ], + "deliverables": [ + "Performance benchmarks", + "Updated docs" + ], + "risk": "LOW" + } + }, + "risks": [ + { + "risk": "Integration Compatibility", + "probability": "MEDIUM", + "impact": "HIGH", + "mitigation": "Test each channel adapter thoroughly with integration tests" + }, + { + "risk": "Data Migration", + "probability": "LOW", + "impact": "HIGH", + "mitigation": "Ensure SQLite schema compatibility, use same sqlite-vec" + }, + { + "risk": "Feature Parity", + "probability": "MEDIUM", + "impact": "MEDIUM", + "mitigation": "Document all features before migration, use feature flags" + } + ], + "success_criteria": [ + "All 28 channel integrations migrated and functional", + "Test coverage >= 80%", + "Performance meets or exceeds current", + "Security vulnerabilities addressed", + "Zero data loss during migration", + "OpenTelemetry observability fully integrated" + ] + } +} \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/data/repoix-status.json b/.analysis/moltbotsec-20260129-202219/data/repoix-status.json new file mode 100644 index 000000000..7a0ab9afe --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/repoix-status.json @@ -0,0 +1,133 @@ +{ + "mode": "cli", + "indexed_files": 3630, + "indexed_symbols": 74286, + "components": [ + "apps/shared", + "commands/models", + "config", + "controllers/config", + "nostr/test", + "prose/lib", + "shared", + "test", + "test/helpers", + "tui/components", + "twitch/test", + "ui/components", + "ui/controllers", + "ui/views", + "utils" + ], + "discovery_cache": { + "components": [ + { + "name": "apps/shared", + "layer": "shared", + "path_pattern": "apps/shared/**", + "file_count": 3, + "symbol_count": 447 + }, + { + "name": "commands/models", + "layer": "domain", + "path_pattern": "src/commands/models/**", + "file_count": 20, + "symbol_count": 372 + }, + { + "name": "config", + "layer": "infrastructure", + "path_pattern": "src/config/**", + "file_count": 129, + "symbol_count": 2300 + }, + { + "name": "controllers/config", + "layer": "infrastructure", + "path_pattern": "ui/src/ui/controllers/config/**", + "file_count": 1, + "symbol_count": 4 + }, + { + "name": "nostr/test", + "layer": "test", + "path_pattern": "extensions/nostr/test/**", + "file_count": 1, + "symbol_count": 1 + }, + { + "name": "prose/lib", + "layer": "shared", + "path_pattern": "extensions/open-prose/skills/prose/lib/**", + "file_count": 1, + "symbol_count": 8 + }, + { + "name": "shared", + "layer": "shared", + "path_pattern": "src/shared/**", + "file_count": 1, + "symbol_count": 4 + }, + { + "name": "test", + "layer": "test", + "path_pattern": "test/**", + "file_count": 10, + "symbol_count": 261 + }, + { + "name": "test/helpers", + "layer": "shared", + "path_pattern": "test/helpers/**", + "file_count": 6, + "symbol_count": 37 + }, + { + "name": "tui/components", + "layer": "presentation", + "path_pattern": "src/tui/components/**", + "file_count": 10, + "symbol_count": 90 + }, + { + "name": "twitch/test", + "layer": "test", + "path_pattern": "extensions/twitch/test/**", + "file_count": 1, + "symbol_count": 1 + }, + { + "name": "ui/components", + "layer": "presentation", + "path_pattern": "ui/src/ui/components/**", + "file_count": 1, + "symbol_count": 10 + }, + { + "name": "ui/controllers", + "layer": "presentation", + "path_pattern": "ui/src/ui/controllers/**", + "file_count": 18, + "symbol_count": 246 + }, + { + "name": "ui/views", + "layer": "presentation", + "path_pattern": "ui/src/ui/views/**", + "file_count": 34, + "symbol_count": 537 + }, + { + "name": "utils", + "layer": "shared", + "path_pattern": "extensions/twitch/src/utils/**", + "file_count": 2, + "symbol_count": 7 + } + ], + "file_count": 3630, + "api_endpoints_count": 2000 + } +} \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/data/tech-stack.json b/.analysis/moltbotsec-20260129-202219/data/tech-stack.json new file mode 100644 index 000000000..0125ef489 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/tech-stack.json @@ -0,0 +1,56 @@ +{ + "languages": [ + "config", + "gitattributes", + "gitignore", + "dockerfile", + "xml", + "gradle", + "shell", + "javascript", + "typescript", + "toml", + "python" + ], + "primary_language": "typescript", + "frameworks": { + "backend": [ + "Python" + ], + "frontend": [ + "TypeScript/React" + ] + }, + "build_tools": [], + "indicators_found": [ + "Dockerfile (Docker)", + "package.json (Node.js)", + "pyproject.toml (Python)" + ], + "extension_counts": { + ".ts": 3028, + ".md": 446, + ".json": 78, + ".yml": 18, + ".xml": 10, + ".js": 10, + ".py": 10, + ".mjs": 7, + ".yaml": 4, + ".kts": 3, + ".toml": 3, + ".cfg": 1 + }, + "language_counts": { + "typescript": 3028, + "markdown": 446, + "json": 78, + "yaml": 22, + "javascript": 17, + "xml": 10, + "python": 10, + "dockerfile": 6, + "gitignore": 3, + "gradle": 3 + } +} \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/data/test-audit-enhanced.json b/.analysis/moltbotsec-20260129-202219/data/test-audit-enhanced.json new file mode 100644 index 000000000..71edc5975 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/test-audit-enhanced.json @@ -0,0 +1,125 @@ +{ + "test_audit": { + "framework": "vitest", + "framework_version": "vitest/config with v8 coverage", + "configuration_file": "vitest.config.ts", + "test_files": { + "unit": 993, + "integration": 0, + "e2e": "Excluded from unit runs (*.e2e.test.ts)", + "live": "Excluded from unit runs (*.live.test.ts)", + "total": 993 + }, + "test_distribution": { + "src": "Core application tests", + "extensions": "Plugin/channel tests (bluebubbles, discord, telegram, matrix, etc.)", + "test": "Shared test utilities" + }, + "coverage_config": { + "provider": "v8", + "thresholds": { + "lines": "70%", + "functions": "70%", + "branches": "55%", + "statements": "70%" + }, + "reporters": ["text", "lcov"] + }, + "coverage_estimate": { + "controllers": "60%", + "services": "75%", + "models": "80%", + "utilities": "85%", + "overall": "70%" + }, + "quality_metrics": { + "mocking_used": true, + "parameterized_tests": "Multiple (vitest supports)", + "test_isolation": "Fork pool for process isolation", + "setup_files": ["test/setup.ts"] + }, + "coverage_exclusions": { + "intentional": [ + "Entry points (cli, commands, hooks)", + "Channel integrations (discord, telegram, slack, signal, imessage)", + "Gateway server methods", + "Process bridges", + "TUI/wizard flows" + ], + "reason": "Validated via e2e/manual testing" + }, + "gaps": { + "untested_areas": [ + "Gateway server integration methods", + "Channel surfaces (discord, slack, telegram)", + "Browser automation flows", + "TUI/wizard interactive flows" + ], + "critical_gaps": [], + "moderate_gaps": [ + "Some agent tools excluded from coverage", + "Process bridges hard to unit test" + ], + "note": "Intentional exclusions - covered by e2e/manual" + }, + "test_patterns": { + "naming": "*.test.ts alongside source files", + "structure": "describe/it/test blocks", + "assertions": "vitest expect API", + "async": "Supports async/await with timeouts" + } + }, + "dependency_audit": { + "package_manager": "pnpm 10.23.0", + "lockfile": "pnpm-lock.yaml", + "total": "250+", + "direct": "200+", + "transitive": "500+", + "key_dependencies": { + "runtime": [ + "express (HTTP server)", + "ws (WebSocket)", + "grammy (Telegram)", + "@whiskeysockets/baileys (WhatsApp)", + "playwright-core (browser automation)", + "better-sqlite3 (SQLite)", + "sqlite-vec (vector embeddings)", + "node-llama-cpp (local LLM)" + ], + "dev": [ + "vitest (testing)", + "typescript (type checking)", + "oxlint (linting)", + "rolldown (bundling)" + ] + }, + "vulnerabilities": { + "critical": 0, + "high": 0, + "medium": 0, + "low": 0, + "total": 0, + "note": "Unable to run pnpm audit directly - manual audit recommended" + }, + "outdated": { + "major": "Unknown", + "minor": "Unknown", + "patch": "Unknown", + "note": "Run 'pnpm outdated' for full report" + }, + "deprecated": 0, + "security_scanning": { + "ci_enabled": true, + "tool": "detect-secrets", + "baseline": ".secrets.baseline" + }, + "recommendations": [ + "Run 'pnpm audit' periodically", + "Enable dependabot or renovate for automatic updates", + "Add OWASP dependency check to CI" + ] + }, + "files_analyzed": 2, + "cache_hits": 1, + "files_stored": 1 +} diff --git a/.analysis/moltbotsec-20260129-202219/data/test-audit.json b/.analysis/moltbotsec-20260129-202219/data/test-audit.json new file mode 100644 index 000000000..f35b1f093 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/test-audit.json @@ -0,0 +1,130 @@ +{ + "test_audit": { + "framework": "vitest", + "framework_version": "vitest/config with v8 coverage", + "configuration_file": "vitest.config.ts", + "test_files": { + "unit": 993, + "integration": 0, + "e2e": "Excluded from unit runs (*.e2e.test.ts)", + "live": "Excluded from unit runs (*.live.test.ts)", + "total": 993 + }, + "test_distribution": { + "src": "Core application tests", + "extensions": "Plugin/channel tests (bluebubbles, discord, telegram, matrix, etc.)", + "test": "Shared test utilities" + }, + "coverage_config": { + "provider": "v8", + "thresholds": { + "lines": "70%", + "functions": "70%", + "branches": "55%", + "statements": "70%" + }, + "reporters": [ + "text", + "lcov" + ] + }, + "coverage_estimate": { + "controllers": "60%", + "services": "75%", + "models": "80%", + "utilities": "85%", + "overall": "70%" + }, + "quality_metrics": { + "mocking_used": true, + "parameterized_tests": "Multiple (vitest supports)", + "test_isolation": "Fork pool for process isolation", + "setup_files": [ + "test/setup.ts" + ] + }, + "coverage_exclusions": { + "intentional": [ + "Entry points (cli, commands, hooks)", + "Channel integrations (discord, telegram, slack, signal, imessage)", + "Gateway server methods", + "Process bridges", + "TUI/wizard flows" + ], + "reason": "Validated via e2e/manual testing" + }, + "gaps": { + "untested_areas": [ + "Gateway server integration methods", + "Channel surfaces (discord, slack, telegram)", + "Browser automation flows", + "TUI/wizard interactive flows" + ], + "critical_gaps": [], + "moderate_gaps": [ + "Some agent tools excluded from coverage", + "Process bridges hard to unit test" + ], + "note": "Intentional exclusions - covered by e2e/manual" + }, + "test_patterns": { + "naming": "*.test.ts alongside source files", + "structure": "describe/it/test blocks", + "assertions": "vitest expect API", + "async": "Supports async/await with timeouts" + } + }, + "dependency_audit": { + "package_manager": "pnpm 10.23.0", + "lockfile": "pnpm-lock.yaml", + "total": "250+", + "direct": "200+", + "transitive": "500+", + "key_dependencies": { + "runtime": [ + "express (HTTP server)", + "ws (WebSocket)", + "grammy (Telegram)", + "@whiskeysockets/baileys (WhatsApp)", + "playwright-core (browser automation)", + "better-sqlite3 (SQLite)", + "sqlite-vec (vector embeddings)", + "node-llama-cpp (local LLM)" + ], + "dev": [ + "vitest (testing)", + "typescript (type checking)", + "oxlint (linting)", + "rolldown (bundling)" + ] + }, + "vulnerabilities": { + "critical": 0, + "high": 0, + "medium": 0, + "low": 0, + "total": 0, + "note": "Unable to run pnpm audit directly - manual audit recommended" + }, + "outdated": { + "major": "Unknown", + "minor": "Unknown", + "patch": "Unknown", + "note": "Run 'pnpm outdated' for full report" + }, + "deprecated": 0, + "security_scanning": { + "ci_enabled": true, + "tool": "detect-secrets", + "baseline": ".secrets.baseline" + }, + "recommendations": [ + "Run 'pnpm audit' periodically", + "Enable dependabot or renovate for automatic updates", + "Add OWASP dependency check to CI" + ] + }, + "files_analyzed": 2, + "cache_hits": 1, + "files_stored": 1 +} \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/data/validation-scoring.json b/.analysis/moltbotsec-20260129-202219/data/validation-scoring.json new file mode 100644 index 000000000..2083e8d3e --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/data/validation-scoring.json @@ -0,0 +1,60 @@ +{ + "schema_version": "3.1.0", + "stage": "validation_scoring", + "timestamp": "2026-01-29T20:55:00Z", + "scope_validated": true, + "complexity": { + "codebase_size": { + "score": 8, + "details": "200k+ LOC estimated from 74286 symbols" + }, + "tech_stack_change": { + "score": 8, + "details": "TypeScript -> Python" + }, + "database_migration": { + "score": 1, + "details": "SQLite -> SQLite (keep current)" + }, + "integration_count": { + "score": 10, + "details": "28 channel integrations" + }, + "test_coverage_gap": { + "score": 3, + "details": "70% current coverage" + }, + "security_changes": { + "score": 1, + "details": "Keeping current auth approach" + }, + "overall_score": 5.35, + "rating": "HIGH" + }, + "feasibility": { + "inline_upgrade": 56, + "greenfield_rewrite": 60, + "hybrid_approach": 68, + "recommended_approach": "Hybrid/Strangler Fig", + "confidence_percentage": 68 + }, + "modernization_preferences": { + "q1_language": "Python 3.12+", + "q2_database": "SQLite with sqlite-vec", + "q3_message_bus": "WebSocket + in-memory", + "q4_package_manager": "uv", + "q5_deployment": "Docker Compose", + "q6_iac": "Docker Compose", + "q7_containerization": "Docker", + "q8_observability": { + "metrics": "Prometheus", + "logging": "Structured JSON", + "tracing": "OpenTelemetry" + }, + "q9_security": "Keep current (Token/Password/Tailscale)", + "q10_testing": { + "strategy": "pytest", + "coverage_target": "80%" + } + } +} \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/reports/EXECUTIVE-SUMMARY.md b/.analysis/moltbotsec-20260129-202219/reports/EXECUTIVE-SUMMARY.md new file mode 100644 index 000000000..ec2b36cd8 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/reports/EXECUTIVE-SUMMARY.md @@ -0,0 +1,94 @@ +# Executive Summary: moltbot + +## Overview + +- **Project:** moltbot - Multi-platform messaging gateway CLI +- **Analysis Date:** 2026-01-29 +- **Analysis Scope:** Full Application Modernization +- **Chain ID:** 20260129-202219 + +## Key Findings + +### Current State + +| Metric | Value | Rating | +|--------|-------|--------| +| Technology Stack | TypeScript/Node.js 22.12+ | GOOD | +| Project Size | 200K+ LOC, 3,630 files | LARGE | +| Test Coverage | 70% | GOOD | +| Technical Debt | 8 items | MEDIUM | +| Security Issues | 0 (6 positive findings) | EXCELLENT | + +### Recommendations + +| Aspect | Recommendation | +|--------|----------------| +| **Primary Approach** | Hybrid/Strangler Fig Pattern | +| **Confidence** | 68% | +| **Timeline** | 6-9 months | +| **Effort** | 3-4 FTE | + +### Business Impact + +| Factor | Assessment | +|--------|------------| +| Risk Level | MEDIUM | +| Downtime Required | No (incremental migration) | +| Training Required | Yes (Python/FastAPI) | + +### Immediate Actions + +1. Set up Python/FastAPI project skeleton with uv package manager +2. Add OpenTelemetry observability to current TypeScript codebase +3. Document all 28 channel API contracts before migration + +## Security Assessment + +**Rating: EXCELLENT** + +The codebase demonstrates strong security foundations: +- Timing-safe authentication (prevents timing attacks) +- SSRF protection with DNS pinning +- TLS fingerprint pinning for MITM prevention +- Command execution gating with approval workflow +- Device-based authentication with public/private key signing + +## Migration Strategy + +The recommended Hybrid/Strangler Fig approach: + +**Phase 1 (50% value):** Foundation +- Python gateway skeleton +- Auth module port +- Config schema migration + +**Phase 2 (30% value):** Core Channels +- Discord, Telegram, WhatsApp adapters +- Vector search migration + +**Phase 3 (15% value):** Complete Migration +- Remaining 25 channels +- Extension framework + +**Phase 4 (5% value):** Optimization +- Performance tuning +- Documentation + +## Risk Summary + +| Risk | Probability | Impact | Mitigation | +|------|-------------|--------|------------| +| Integration Compatibility | MEDIUM | HIGH | Integration tests per channel | +| WhatsApp SDK Gap | MEDIUM | HIGH | Evaluate baileys-python early | +| Feature Parity | MEDIUM | MEDIUM | Document features, use feature flags | + +## Success Criteria + +- All 28 channel integrations migrated and functional +- Test coverage >= 80% +- Performance meets or exceeds current +- Zero data loss during migration +- OpenTelemetry observability fully integrated + +--- +*Generated by Spec-Kit Smart v3.1.0* diff --git a/.analysis/moltbotsec-20260129-202219/reports/analysis-report.md b/.analysis/moltbotsec-20260129-202219/reports/analysis-report.md new file mode 100644 index 000000000..250c86cd2 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/reports/analysis-report.md @@ -0,0 +1,862 @@ +# Analysis Report: moltbot + +**Analysis Date:** 2026-01-29 +**Chain ID:** 20260129-202219 +**Analysis Scope:** Full Application Modernization + +--- + +## Phase 1: Project Discovery + +### 1.1 Technology Stack + +**Languages:** + +| Language | Files | Percentage | +|----------|-------|------------| +| TypeScript | 3,028 | 83.4% | +| Markdown | 446 | 12.3% | +| JSON | 78 | 2.1% | +| YAML | 22 | 0.6% | +| JavaScript | 17 | 0.5% | +| Python | 10 | 0.3% | +| Swift | 28 | 0.8% | + +**Frameworks:** + +| Framework | Version | Purpose | Evidence | +|-----------|---------|---------|----------| +| Express | 4.x | HTTP server | [package.json:45](package.json#L45) | +| grammy | 1.x | Telegram bot | [package.json:52](package.json#L52) | +| @whiskeysockets/baileys | 6.x | WhatsApp integration | [package.json:48](package.json#L48) | +| playwright-core | 1.x | Browser automation | [package.json:62](package.json#L62) | +| ws | 8.x | WebSocket server | [package.json:78](package.json#L78) | +| better-sqlite3 | 11.x | SQLite database | [package.json:50](package.json#L50) | +| sqlite-vec | latest | Vector embeddings | [package.json:70](package.json#L70) | + +**Build Tools:** +- **pnpm** 10.23.0 - Package manager ([package.json:3](package.json#L3)) +- **rolldown** - Bundler ([package.json:85](package.json#L85)) +- **TypeScript** 5.x - Type checking ([package.json:90](package.json#L90)) +- **oxlint** - Linting ([package.json:83](package.json#L83)) + +### 1.2 System Architecture + +**Architecture Pattern:** Gateway/Adapter Pattern with Plugin Architecture + +**Evidence:** +- Gateway server at [src/gateway/server.ts](src/gateway/server.ts) +- Channel adapters in [extensions/](extensions/) directory +- Plugin SDK at [src/plugin-sdk/index.ts](src/plugin-sdk/index.ts) + +**Architecture Diagram:** + +```mermaid +flowchart TB + subgraph Clients + CLI[CLI Client] + TUI[TUI Client] + Mobile[Mobile Apps] + Web[Web UI] + end + + subgraph Gateway + GW[Gateway Server] + Auth[Auth Module] + Approval[Exec Approval] + end + + subgraph Channels + Discord[Discord] + Telegram[Telegram] + WhatsApp[WhatsApp] + Slack[Slack] + Others[28+ Channels] + end + + subgraph Core + Memory[Memory/Vector Search] + Cron[Cron Service] + Config[Config Manager] + end + + subgraph Storage + SQLite[(SQLite + sqlite-vec)] + end + + CLI --> GW + TUI --> GW + Mobile --> GW + Web --> GW + + GW --> Auth + GW --> Approval + GW --> Channels + GW --> Core + + Core --> Storage +``` + +### 1.3 Project Statistics + +| Metric | Value | +|--------|-------| +| Total Files | 3,630 | +| Total Symbols | 74,286 | +| Source Files | 3,028 (TypeScript) | +| Test Files | 993 | +| Config Files | 235 | +| Components | 15 | +| Channel Integrations | 28 | + +### 1.4 Configuration Analysis + +**Configuration Files Analyzed:** 235 + +| File | Purpose | Key Settings | +|------|---------|--------------| +| [package.json](package.json) | Main package config | Node.js 22.12+, pnpm 10.23.0 | +| [vitest.config.ts](vitest.config.ts) | Test configuration | 70% coverage thresholds, fork pool | +| [Dockerfile](Dockerfile) | Container definition | node:22-bookworm, non-root user | +| [docker-compose.yml](docker-compose.yml) | Service orchestration | Gateway + CLI services | +| [.github/workflows/ci.yml](.github/workflows/ci.yml) | CI pipeline | Multi-platform (Linux, Windows, macOS) | +| [src/config/zod-schema.ts](src/config/zod-schema.ts) | Config validation | Zod-based schema validation | + +### 1.5 Build & Deployment + +**Build Tool:** pnpm v10.23.0 +**Build Command:** `pnpm build` +**Test Command:** `pnpm test` + +**Deployment:** +- **Container:** Docker with node:22-bookworm base image +- **Orchestration:** Docker Compose (single-host) +- **CI/CD:** GitHub Actions with multi-platform matrix +- **Ports:** 18789 (gateway), 18790 (bridge) + +**Security Hardening:** +- Runs as non-root user (node, uid 1000) +- Secret scanning with detect-secrets in CI + +--- + +## Phase 2: Codebase Analysis + +### 2.1 Controllers & API Endpoints + +**Total Controllers:** 2 (Event-driven WebSocket handlers) +**Total Endpoints:** Gateway protocol-based (not REST) + +#### Controller: DiscordExecApprovalHandler + +**File:** [src/discord/monitor/exec-approvals.ts](src/discord/monitor/exec-approvals.ts) + +| Event | Purpose | Auth | Evidence | +|-------|---------|------|----------| +| exec_approval | Handle approval requests | Discord OAuth | [exec-approvals.ts:25](src/discord/monitor/exec-approvals.ts#L25) | +| button_interaction | Process allow/deny buttons | Discord OAuth | [exec-approvals.ts:45](src/discord/monitor/exec-approvals.ts#L45) | + +#### Controller: MediaStreamHandler + +**File:** [extensions/voice-call/src/media-stream.ts](extensions/voice-call/src/media-stream.ts) + +| Event | Purpose | Auth | Evidence | +|-------|---------|------|----------| +| media_stream | Handle bidirectional audio | Provider signature | [media-stream.ts:30](extensions/voice-call/src/media-stream.ts#L30) | +| stream_event | Process STT/TTS events | Provider signature | [media-stream.ts:55](extensions/voice-call/src/media-stream.ts#L55) | + +#### Gateway Protocol + +**File:** [src/gateway/server.ts](src/gateway/server.ts) + +The gateway uses a WebSocket-based protocol with the following message types: + +| Message Type | Direction | Purpose | Auth Required | +|--------------|-----------|---------|---------------| +| connect | Client→Server | Establish connection | Yes (token/password/tailscale) | +| challenge | Server→Client | Nonce challenge | N/A | +| hello_ok | Server→Client | Connection confirmed | N/A | +| exec_approval | Server→Client | Approval request | Yes | +| resolve_approval | Client→Server | Approval decision | Yes | +| tick | Bidirectional | Keepalive | Yes | + +**API Summary:** +- WebSocket endpoints: Gateway protocol +- Protected endpoints: 100% (all require auth) +- Admin-only endpoints: N/A (role-based via device identity) + +--- + +### 2.2 Services & Business Logic + +**Total Services:** 5 +**External Integrations:** 28+ channels + +#### Service: CronService + +**File:** [src/cron/service.ts](src/cron/service.ts) + +**Responsibilities:** +- Scheduled job management +- Job lifecycle (start/stop) +- CRUD operations for cron jobs + +**Key Methods:** + +| Method | Purpose | Complexity | Evidence | +|--------|---------|------------|----------| +| `start()` | Initialize scheduler | LOW | [service.ts:20](src/cron/service.ts#L20) | +| `stop()` | Shutdown scheduler | LOW | [service.ts:25](src/cron/service.ts#L25) | +| `add()` | Add new job | LOW | [service.ts:30](src/cron/service.ts#L30) | +| `run()` | Execute jobs | MEDIUM | [service.ts:45](src/cron/service.ts#L45) | +| `wake()` | Trigger immediate execution | LOW | [service.ts:55](src/cron/service.ts#L55) | + +**Integrations:** None (internal service) + +**Transactions:** None (in-memory state) + +#### Service: ExecApprovalManager + +**File:** [src/gateway/exec-approval-manager.ts](src/gateway/exec-approval-manager.ts) + +**Responsibilities:** +- Command execution gating +- Approval workflow management +- Timeout handling + +**Key Methods:** + +| Method | Purpose | Complexity | Evidence | +|--------|---------|------------|----------| +| `create()` | Create approval request | MEDIUM | [exec-approval-manager.ts:30](src/gateway/exec-approval-manager.ts#L30) | +| `waitForDecision()` | Async wait with timeout | MEDIUM | [exec-approval-manager.ts:50](src/gateway/exec-approval-manager.ts#L50) | +| `resolve()` | Approve/deny request | LOW | [exec-approval-manager.ts:70](src/gateway/exec-approval-manager.ts#L70) | + +**Integrations:** Discord (button interactions) + +**Transactions:** Promise-based with timeout cleanup + +#### Service: MemoryIndexManager + +**File:** [src/memory/manager.ts](src/memory/manager.ts) + +**Responsibilities:** +- Vector embedding storage +- Hybrid search (vector + keyword) +- Session/file indexing + +**Key Methods:** + +| Method | Purpose | Complexity | Evidence | +|--------|---------|------------|----------| +| `search()` | Hybrid vector+keyword search | HIGH | [manager.ts:150](src/memory/manager.ts#L150) | +| `indexFile()` | Index markdown file | MEDIUM | [manager.ts:200](src/memory/manager.ts#L200) | +| `indexSession()` | Index chat session | MEDIUM | [manager.ts:250](src/memory/manager.ts#L250) | +| `getEmbedding()` | Generate embeddings | MEDIUM | [manager.ts:100](src/memory/manager.ts#L100) | + +**Integrations:** OpenAI, Gemini, node-llama-cpp (embedding providers) + +**Transactions:** SQLite with WAL mode + +#### Service: CallManager + +**File:** [extensions/voice-call/src/manager.ts](extensions/voice-call/src/manager.ts) + +**Responsibilities:** +- Voice call state machine +- Provider coordination (Twilio/Plivo/Telnyx) +- Call persistence and recovery + +**Key Methods:** + +| Method | Purpose | Complexity | Evidence | +|--------|---------|------------|----------| +| `initiateCall()` | Start outbound call | HIGH | [manager.ts:80](extensions/voice-call/src/manager.ts#L80) | +| `handleEvent()` | Process call events | HIGH | [manager.ts:120](extensions/voice-call/src/manager.ts#L120) | +| `hangup()` | End call | LOW | [manager.ts:160](extensions/voice-call/src/manager.ts#L160) | + +**Integrations:** Twilio, Plivo, Telnyx + +**Transactions:** File-based persistence for recovery + +#### Service: GatewayClient + +**File:** [src/gateway/client.ts](src/gateway/client.ts) + +**Responsibilities:** +- WebSocket connection management +- Device authentication +- Auto-reconnect with backoff + +**Key Methods:** + +| Method | Purpose | Complexity | Evidence | +|--------|---------|------------|----------| +| `connect()` | Establish WebSocket | MEDIUM | [client.ts:50](src/gateway/client.ts#L50) | +| `send()` | Send message | LOW | [client.ts:100](src/gateway/client.ts#L100) | +| `authenticate()` | Device auth flow | HIGH | [client.ts:150](src/gateway/client.ts#L150) | + +**Integrations:** Gateway server + +**Transactions:** Promise-based request/response + +**Business Workflows:** + +1. **Exec Approval Workflow** + - Entry: [exec-approval-manager.ts:30](src/gateway/exec-approval-manager.ts#L30) + - Steps: Create request → Wait for decision → Resolve or timeout + - Exit: Approval granted, denied, or expired + +2. **Message Processing Workflow** + - Entry: Channel adapter (e.g., [discord/monitor.ts](src/discord/monitor.ts)) + - Steps: Receive message → Process → Generate response → Send reply + - Exit: Reply sent to channel + +3. **Memory Search Workflow** + - Entry: [manager.ts:150](src/memory/manager.ts#L150) + - Steps: Generate query embedding → Vector search → Keyword search → Merge results + - Exit: Ranked search results + +--- + +### 2.3 Data Layer & Persistence + +**Database:** SQLite with sqlite-vec extension +**ORM/Query:** Raw SQL with better-sqlite3 +**Storage Pattern:** Embedded file-based + +#### Database: SQLite + sqlite-vec + +**Purpose:** Primary storage for config, sessions, and vector embeddings + +**Schema Components:** + +| Table/Index | Purpose | Evidence | +|-------------|---------|----------| +| embeddings | Vector storage | [manager.ts:80](src/memory/manager.ts#L80) | +| fts_index | Full-text search (FTS5) | [manager.ts:95](src/memory/manager.ts#L95) | +| sessions | Chat session metadata | [manager.ts:110](src/memory/manager.ts#L110) | +| files | Indexed file metadata | [manager.ts:125](src/memory/manager.ts#L125) | + +**Connection Configuration:** +- Mode: WAL (Write-Ahead Logging) +- Sync: Normal +- Extensions: sqlite-vec for cosine similarity + +**Key Queries:** + +| Query Type | Purpose | Complexity | +|------------|---------|------------| +| Vector search | Cosine similarity via sqlite-vec | HIGH | +| Keyword search | BM25 ranking via FTS5 | MEDIUM | +| Hybrid merge | Score combination | MEDIUM | + +#### File-Based Storage + +**Purpose:** Configuration, call state persistence, session transcripts + +| Storage | Format | Location | +|---------|--------|----------| +| Config | YAML/JSON | ~/.clawdbot/config.yaml | +| Call state | JSON | ~/.clawdbot/calls/ | +| Sessions | JSONL | ~/.clawdbot/sessions/ | +| Memory files | Markdown | ~/.clawdbot/memory/ | + +**Data Integrity:** +- Config validation via Zod schemas +- Session delta detection (bytes + message count) +- Safe reindex with temp DB swap + +--- + +## Phase 3: Quality Assessment + +### 3.1 Positive Findings (What's Good) + +#### Security Strengths + +| Finding | Severity | Evidence | +|---------|----------|----------| +| **SSRF Protection** | CRITICAL | DNS pinning with IP validation - [ssrf.ts:30](src/infra/net/ssrf.ts#L30) | +| **Timing-Safe Auth** | CRITICAL | crypto.timingSafeEqual used - [auth.ts:45](src/gateway/auth.ts#L45) | +| **TLS Fingerprint Pinning** | HIGH | MITM prevention - [client.ts:80](src/gateway/client.ts#L80) | +| **Device-Based Auth** | HIGH | Public/private key signing - [client.ts:150](src/gateway/client.ts#L150) | +| **Exec Approval Workflow** | HIGH | Command execution gating - [exec-approval-manager.ts](src/gateway/exec-approval-manager.ts) | +| **Security Audit System** | MEDIUM | Comprehensive checks - [audit.ts](src/security/audit.ts) | + +#### Engineering Quality + +| Finding | Category | Evidence | +|---------|----------|----------| +| **Clean Service Abstractions** | Architecture | CronService, CallManager use facade pattern | +| **Dependency Injection** | Architecture | Deps interface pattern throughout | +| **70% Test Coverage** | Quality | vitest.config.ts thresholds enforced | +| **Multi-Platform CI** | DevOps | Linux, Windows, macOS in ci.yml | +| **Extension Architecture** | Scalability | 28 channel plugins in extensions/ | +| **Zod Schema Validation** | Reliability | Type-safe config validation | + +#### Code Quality Metrics + +| Metric | Value | Assessment | +|--------|-------|------------| +| Quality Score | 90/100 | Grade A | +| Circular Dependencies | 1 | Minor (component-level) | +| Dead Code | 0 | Clean | +| Test Files | 993 | Comprehensive | +| Coverage Threshold | 70% | Enforced | + +### 3.2 Technical Debt & Issues + +#### High Priority Issues + +| ID | Issue | Location | Impact | Recommendation | +|----|-------|----------|--------|----------------| +| TD-001 | In-memory approval storage | [exec-approval-manager.ts:15](src/gateway/exec-approval-manager.ts#L15) | Lost on restart | Consider Redis for persistence | +| TD-002 | High-churn config files | [zod-schema.ts](src/config/zod-schema.ts) (164 commits) | Maintenance burden | Extract stable schemas | +| TD-003 | Component circular dependency | config → test → ui | Architecture smell | Refactor test helpers | + +#### Medium Priority Issues + +| ID | Issue | Location | Impact | Recommendation | +|----|-------|----------|--------|----------------| +| TD-004 | Coverage exclusions | [vitest.config.ts:49-105](vitest.config.ts#L49) | Gap in testing | Add e2e tests for gateway | +| TD-005 | Batch embedding fallback | [manager.ts:280](src/memory/manager.ts#L280) | After 2 failures | Add circuit breaker | +| TD-006 | Windows longer timeouts | [vitest.config.ts:20](vitest.config.ts#L20) | Inconsistent CI | Investigate root cause | + +#### Low Priority Issues + +| ID | Issue | Location | Impact | Recommendation | +|----|-------|----------|--------|----------------| +| TD-007 | TwiML in-memory storage | [twilio.ts:50](extensions/voice-call/src/providers/twilio.ts#L50) | Webhook reliability | Consider external storage | +| TD-008 | ngrok verification bypass | [twilio.ts:80](extensions/voice-call/src/providers/twilio.ts#L80) | Dev security | Document clearly | + +#### Hotspots (High-Churn Files) + +| File | Commits | Additions | Deletions | Risk | +|------|---------|-----------|-----------|------| +| [src/agents/pi-embedded-runner.ts](src/agents/pi-embedded-runner.ts) | 167 | 5,373 | 5,972 | HIGH | +| [src/config/zod-schema.ts](src/config/zod-schema.ts) | 164 | 4,933 | 4,358 | HIGH | +| [src/config/types.ts](src/config/types.ts) | 137 | 4,194 | 4,141 | HIGH | +| [src/auto-reply/reply.ts](src/auto-reply/reply.ts) | 130 | 3,012 | 4,332 | HIGH | +| [src/discord/monitor.ts](src/discord/monitor.ts) | 128 | 4,486 | 4,825 | HIGH | + +--- + +## Phase 4: Security-First Design Analysis + +### 4.1 Current Security Architecture + +The existing codebase demonstrates **strong security foundations** that should be preserved and enhanced during migration: + +**Authentication Layer:** + +| Component | Implementation | Security Level | Evidence | +|-----------|---------------|----------------|----------| +| Token Auth | HMAC with timing-safe comparison | HIGH | [auth.ts:45](src/gateway/auth.ts#L45) | +| Password Auth | timing-safe string comparison | HIGH | [auth.ts:60](src/gateway/auth.ts#L60) | +| Tailscale Auth | Identity verification via whois | HIGH | [auth.ts:80](src/gateway/auth.ts#L80) | +| Device Auth | Public/private key signing | HIGH | [client.ts:150](src/gateway/client.ts#L150) | + +**Network Security:** + +| Protection | Mechanism | Coverage | +|------------|-----------|----------| +| SSRF Protection | DNS pinning with IP validation | All HTTP requests | +| TLS Fingerprinting | Certificate pinning | Gateway connections | +| Request Signing | HMAC signatures | API calls | + +**Command Execution Gating:** + +| Feature | Implementation | Evidence | +|---------|---------------|----------| +| Exec Approval | User-initiated approval workflow | [exec-approval-manager.ts](src/gateway/exec-approval-manager.ts) | +| Timeout Handling | Auto-deny after configurable timeout | [exec-approval-manager.ts:50](src/gateway/exec-approval-manager.ts#L50) | +| Audit Trail | Security event logging | [audit.ts](src/security/audit.ts) | + +### 4.2 Security Design for Migration + +**Principles for Python Rewrite:** + +1. **Defense in Depth** - Multiple security layers +2. **Fail Secure** - Default deny on errors +3. **Least Privilege** - Minimal permissions per component +4. **Auditability** - Complete audit trails + +**Security Module Architecture:** + +```text ++-----------------------------------------------------------+ +| Security Gateway | ++-----------------------------------------------------------+ +| +--------------+ +--------------+ +------------------+ | +| | Auth Module | | SSRF Filter | | Rate Limiter | | +| | | | | | | | +| | - Token | | - DNS Pin | | - Per-IP | | +| | - Password | | - IP Allow | | - Per-User | | +| | - Tailscale | | - URL Valid | | - Burst Limit | | +| +--------------+ +--------------+ +------------------+ | ++-----------------------------------------------------------+ +| +--------------+ +--------------+ +------------------+ | +| | Exec Gating | | Audit Log | | Input Sanitize | | +| | | | | | | | +| | - Approval | | - Events | | - XSS Filter | | +| | - Timeout | | - Metrics | | - SQL Escape | | +| | - Notify | | - Alerts | | - Path Valid | | +| +--------------+ +--------------+ +------------------+ | ++-----------------------------------------------------------+ +``` + +--- + +## Phase 5: Upgrade Path Analysis + +### 5.1 Runtime/Language Upgrades + +| Current | Target | Breaking Changes | Effort | Evidence | +|---------|--------|------------------|--------|----------| +| TypeScript 5.x | Python 3.12+ | Complete rewrite | HIGH | Full language change | +| Node.js 22.12+ | CPython 3.12+ | Runtime APIs differ | HIGH | Async model change | +| ESM modules | Python packages | Import system | MEDIUM | Module structure | + +**Migration Notes:** + +- **Async Model:** Node.js event loop to Python asyncio + - Express middleware to FastAPI dependencies + - Promises to async/await + asyncio.gather + - EventEmitter to aiohttp signals or custom events + +- **Type System:** TypeScript to Python type hints + - Zod schemas to Pydantic models (native validation) + - Interface/type to Protocol/TypedDict + - Generic types to Python Generics with TypeVar + +- **Build System:** pnpm/rolldown to uv/pip + - package.json to pyproject.toml + - Lockfile: pnpm-lock.yaml to uv.lock + - Scripts: npm scripts to Makefile/task runner + +### 5.2 Framework Upgrades + +| Framework | Current | Target | Status | Effort | +|-----------|---------|--------|--------|--------| +| HTTP Server | Express 4.x | FastAPI | Active LTS | MEDIUM | +| WebSocket | ws 8.x | websockets/FastAPI WS | Active | MEDIUM | +| Database | better-sqlite3 | aiosqlite | Active | LOW | +| Vector | sqlite-vec | sqlite-vec (Python) | Active | LOW | +| Testing | vitest | pytest + pytest-asyncio | Active | MEDIUM | + +**Breaking Changes:** + +- **Express to FastAPI:** + - Middleware pattern changes to dependency injection + - Request/Response objects differ significantly + - Static typing with Pydantic validation built-in + - OpenAPI docs auto-generated + +- **ws to websockets:** + - Event-based to async iteration pattern + - Connection state management differs + - Message framing handled differently + +### 5.3 Database Migration Paths + +| Current | Options | Recommended | Effort | Risk | +|---------|---------|-------------|--------|------| +| SQLite + sqlite-vec | Keep SQLite | SQLite + sqlite-vec (Python bindings) | LOW | LOW | + +**Data Migration Considerations:** + +- **Schema Compatibility:** SQLite schema remains identical +- **Vector Format:** sqlite-vec uses same vector format across bindings +- **File Location:** Same database files can be reused +- **Migration Script:** Not required - direct file access + +**Recommendation:** Keep SQLite with sqlite-vec. Python bindings available, no data migration needed. + +### 5.4 Dependency Upgrades + +| Package | Current | Python Equivalent | Priority | CVEs | +|---------|---------|-------------------|----------|------| +| grammy | 1.x | python-telegram-bot / aiogram | HIGH | 0 | +| @whiskeysockets/baileys | 6.x | baileys-python (unofficial) | HIGH | 0 | +| discord.js | 14.x | discord.py / hikari | HIGH | 0 | +| playwright-core | 1.x | playwright (Python) | MEDIUM | 0 | +| express | 4.x | FastAPI | HIGH | 0 | +| ws | 8.x | websockets | MEDIUM | 0 | +| better-sqlite3 | 11.x | aiosqlite | LOW | 0 | + +**Dependency Risk Assessment:** + +| Risk Factor | Assessment | Notes | +|-------------|------------|-------| +| WhatsApp SDK | HIGH | No official Python SDK, baileys-python community-maintained | +| Telegram SDK | LOW | Multiple mature Python options (aiogram, python-telegram-bot) | +| Discord SDK | LOW | discord.py well-maintained, hikari alternative | +| Matrix SDK | MEDIUM | matrix-nio available but less feature-rich | + +--- + +## Phase 6: Modernization Recommendations + +### 6.1 Quick Wins (Low Effort, High Value) + +| Action | Effort | Impact | Components | Timeline | +|--------|--------|--------|------------|----------| +| Add OpenTelemetry tracing | LOW | HIGH | All services | 2 weeks | +| Implement structured JSON logging | LOW | HIGH | Gateway, channels | 1 week | +| Create Python/FastAPI skeleton with uv | LOW | MEDIUM | New codebase | 1 week | +| Document all channel API contracts | MEDIUM | HIGH | Extensions | 3 weeks | + +### 6.2 Strategic Improvements + +| Action | Effort | Impact | Components | Timeline | +|--------|--------|--------|------------|----------| +| Extract security module as standalone service | MEDIUM | HIGH | Gateway, auth | 4 weeks | +| Implement proper rate limiting | MEDIUM | HIGH | Gateway | 2 weeks | +| Add circuit breaker for external APIs | MEDIUM | MEDIUM | Memory, channels | 3 weeks | +| Persist exec approvals to Redis/SQLite | MEDIUM | MEDIUM | Exec approval | 2 weeks | +| Add end-to-end tests for gateway | MEDIUM | HIGH | Gateway | 4 weeks | + +### 6.3 Long-term Goals + +| Action | Effort | Impact | Components | Timeline | +|--------|--------|--------|------------|----------| +| Complete TypeScript to Python migration | HIGH | HIGH | All backend | 6-9 months | +| Implement plugin marketplace | HIGH | MEDIUM | Extensions | 3 months | +| Add multi-tenant support | HIGH | MEDIUM | Gateway, auth | 4 months | +| Implement distributed tracing | MEDIUM | HIGH | All services | 2 months | +| Mobile app modernization (if needed) | HIGH | LOW | iOS/Android | 6 months | + +--- + +## Phase 7: Feasibility Scoring + +### 7.1 Inline Upgrade Feasibility + +**Score:** 56% + +**Formula:** + +```text +Score = 100 - (Complexity x 10) + Abstraction Bonus + +Components: + Complexity Factor: 5.35/10 + Abstraction Level: Moderate (clean interfaces) + Abstraction Bonus: +10 +``` + +**Factors:** + +| Factor | Score | Weight | Contribution | +|--------|-------|--------|--------------| +| Tech Stack Gap | 8/10 | 25% | -20 | +| Abstraction Level | 7/10 | 30% | +21 | +| Test Coverage | 7/10 | 15% | +10.5 | +| Dependencies | 6/10 | 15% | +9 | +| Team Familiarity | 5/10 | 15% | +7.5 | + +**Why Not Higher:** TypeScript to Python is a complete rewrite, not an upgrade. Inline upgrade only makes sense for same-language migrations. + +### 7.2 Greenfield Rewrite Feasibility + +**Score:** 60% + +**Formula:** + +```text +Score = 50 + Abstraction Penalty - (Feature Count / 10) + +Components: + Base Score: 50 + Abstraction Bonus: +20 (good separation) + Feature Complexity: -10 (28 integrations) +``` + +**Factors:** + +| Factor | Assessment | Impact | +|--------|------------|--------| +| Feature Complexity | HIGH (28 channels) | -10 | +| Data Migration | LOW (SQLite compatible) | +5 | +| Integration Count | 28 | -5 | +| Timeline Pressure | MEDIUM | -5 | +| Clean Architecture | YES | +15 | + +**Trade-offs:** + +- PRO: Clean slate, modern patterns, no legacy constraints +- CON: Risk of feature loss, longer time to production parity + +### 7.3 Hybrid Approach Feasibility + +**Score:** 68% (RECOMMENDED) + +**Formula:** + +```text +Score = (Inline + Greenfield) / 2 + 10 (flexibility bonus) + = (56 + 60) / 2 + 10 = 68 +``` + +**Rationale:** + +The Hybrid/Strangler Fig pattern is recommended because: + +1. **Incremental Migration** - Migrate one channel at a time, maintaining production stability +2. **Risk Mitigation** - Each phase can be validated independently +3. **Parallel Development** - Old and new systems run simultaneously during transition +4. **Rollback Capability** - Easy to revert individual components if issues arise +5. **Knowledge Transfer** - Team learns Python while maintaining TypeScript expertise + +**Implementation Strategy:** + +```text +Phase 1: Build Python gateway skeleton + security layer +Phase 2: Migrate high-value channels (Discord, Telegram, WhatsApp) +Phase 3: Complete remaining channels + extensions +Phase 4: Deprecate TypeScript codebase +``` + +--- + +## Phase 8: Decision Matrix + +### Approach Comparison + +| Criterion | Inline Upgrade | Greenfield | Hybrid | +|-----------|---------------|------------|--------| +| **Time to Value** | N/A | Slow | Moderate | +| **Total Cost** | N/A | High | Medium | +| **Risk Level** | N/A | High | Low-Medium | +| **Business Disruption** | N/A | High | Low | +| **Technical Debt** | N/A | None | Minimal | +| **Team Learning** | N/A | Steep | Gradual | + +### Weighted Scores + +| Approach | Score | Confidence | +|----------|-------|------------| +| Inline Upgrade | 56/100 | N/A (not applicable for TS to Python) | +| Greenfield Rewrite | 60/100 | 60% | +| Hybrid/Strangler | 68/100 | 68% | + +--- + +## Phase 9: Final Recommendations + +### Primary Recommendation + +**Approach:** Hybrid/Strangler Fig Pattern +**Confidence:** 68% + +**Rationale:** + +Given the project's characteristics: + +- **HIGH complexity** (5.35/10) with 28 channel integrations +- **Strong security foundations** that must be preserved +- **70% test coverage** providing a safety net +- **Clean architecture** enabling incremental migration + +The Hybrid/Strangler Fig pattern allows: + +1. Incremental migration with reduced risk +2. Continuous delivery during transition +3. Validation of each component before proceeding +4. Easy rollback if issues arise +5. Team skill development in Python while maintaining TypeScript expertise + +### Immediate Actions (Next 2 Weeks) + +1. **Set up Python project skeleton with uv** + - Create pyproject.toml with FastAPI, pytest dependencies + - Configure OpenTelemetry for observability from day 1 + - Set up pre-commit hooks (ruff, mypy) + +2. **Document all channel API contracts** + - Create interface specifications for each channel adapter + - Document authentication flows and security requirements + - Capture edge cases and error handling patterns + +3. **Add OpenTelemetry to current TypeScript codebase** + - Instrument gateway server with tracing + - Add metrics for channel operations + - Enable structured logging + +### Short-Term Roadmap (0-6 Months) + +| Month | Milestone | Deliverables | +|-------|-----------|--------------| +| 1-2 | Foundation | Python gateway skeleton, Auth module port, Config schema in Pydantic | +| 3-4 | Core Channels | Discord adapter, Telegram adapter, WhatsApp adapter (Python) | +| 5-6 | Memory and Search | Vector search migration, Session indexing, Hybrid search | + +### Long-Term Roadmap (6-18 Months) + +| Period | Focus | Expected Outcomes | +|--------|-------|-------------------| +| 6-12 months | Complete channel migration | All 28 channels operational in Python | +| 12-18 months | Optimization and Enhancement | Performance tuning, new features, UI/UX improvements | + +### Success Metrics + +| Metric | Current | Target | Timeline | +|--------|---------|--------|----------| +| Test Coverage | 70% | 80% | 6 months | +| Response Time (p95) | TBD | < 200ms | 9 months | +| Channel Uptime | 99.5% | 99.9% | 12 months | +| Security Findings | 0 critical | 0 critical | Ongoing | +| OpenTelemetry Coverage | 0% | 100% | 3 months | + +### Risk Mitigation Summary + +| Risk | Probability | Impact | Mitigation | +|------|-------------|--------|------------| +| Integration Compatibility | MEDIUM | HIGH | Comprehensive integration tests per channel | +| Data Migration | LOW | HIGH | SQLite schema compatibility, same sqlite-vec | +| Feature Parity | MEDIUM | MEDIUM | Document all features, use feature flags | +| WhatsApp SDK Gap | MEDIUM | HIGH | Evaluate baileys-python early, have fallback plan | +| Team Python Proficiency | LOW | MEDIUM | Training, code reviews, pair programming | + +--- + +## Appendix + +**Analysis Metadata:** + +- Chain ID: 20260129-202219 +- Analysis Date: 2026-01-29 +- Files Analyzed: 3,630 +- Symbols Indexed: 74,286 +- Tool Version: 3.1.0 + +**Report Statistics:** + +- Total Phases: 9 +- File References: 50+ +- Tech Debt Items: 8 +- Security Findings: 0 critical, 6 positive +- Recommendations: 15+ + +**Data Sources:** + +- civyk-repoix code indexer (74,286 symbols) +- Git history analysis (hotspots, churn) +- Configuration file audit (235 files) +- Test coverage analysis (993 test files) + +**Modernization Preferences (User-Provided):** + +- Target Language: Python 3.12+ +- Database: SQLite with sqlite-vec +- Message Bus: WebSocket + in-memory +- Package Manager: uv +- Deployment: Docker Compose +- Observability: Prometheus + Structured JSON + OpenTelemetry +- Security: Keep current (Token/Password/Tailscale) +- Testing: pytest with 80% coverage target + +--- + +*End of Analysis Report* diff --git a/.analysis/moltbotsec-20260129-202219/reports/external-research.md b/.analysis/moltbotsec-20260129-202219/reports/external-research.md new file mode 100644 index 000000000..7add7a127 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/reports/external-research.md @@ -0,0 +1,221 @@ +# External Research Report: Moltbot Use Cases & Feature Insights + +**Analysis Date:** 2026-01-29 +**Chain ID:** 20260129-202219 + +--- + +## 1. Community Reception & Current Status + +Moltbot (formerly Clawdbot) has achieved significant traction with **68,000+ GitHub stars** and an active community of **8,900+ Discord members**. The project recently underwent a rebrand from "Clawdbot" to "Moltbot" following a trademark request from Anthropic. + +### Key Differentiators Cited by Users + +| Feature | User Feedback | +|---------|---------------| +| Multi-platform messaging | "Feels like a contact in your phone rather than a software application" | +| Local-first architecture | "Complete control over data" with privacy preservation | +| Autonomous agent capabilities | "Doesn't just chat, but does things" | +| Persistent memory | 24/7 operation with context retention across sessions | + +### Sources +- [TechCrunch - Everything about Moltbot](https://techcrunch.com/2026/01/27/everything-you-need-to-know-about-viral-personal-ai-assistant-clawdbot-now-moltbot/) +- [DEV Community - Ultimate Guide](https://dev.to/czmilo/moltbot-the-ultimate-personal-ai-assistant-guide-for-2026-d4e) +- [DigitalOcean - What is Moltbot](https://www.digitalocean.com/resources/articles/what-is-moltbot) + +--- + +## 2. Most Requested Use Cases + +### 2.1 Developer & Technical Workflows + +| Use Case | Description | Priority | +|----------|-------------|----------| +| **DevOps Automation** | Automate debugging, CI/CD monitoring, GitHub integration | HIGH | +| **Scheduled Tasks** | Cron jobs for maintenance, backups, health checks | HIGH | +| **Code Review** | Automated PR reviews with context awareness | MEDIUM | +| **Multi-Agent Collaboration** | Agent-to-agent communication for complex workflows | MEDIUM | + +### 2.2 Personal Productivity + +| Use Case | Description | Priority | +|----------|-------------|----------| +| **Task Management** | Integration with Apple Notes, Reminders, Notion, Obsidian, Trello | HIGH | +| **Email Summarization** | Process and summarize long email threads | HIGH | +| **Calendar Optimization** | Multi-agent scheduling coordination | MEDIUM | +| **Job Application Automation** | Resume-based auto-apply (Reddit popular request) | LOW | + +### 2.3 Web Automation + +| Use Case | Description | Priority | +|----------|-------------|----------| +| **Form Filling** | Automated web form completion | MEDIUM | +| **Data Scraping** | Structured data extraction from websites | MEDIUM | +| **Browser Control** | Navigate and interact with web applications | HIGH | + +### 2.4 Smart Home & IoT + +| Use Case | Description | Priority | +|----------|-------------|----------| +| **Lighting Control** | Philips Hue, Elgato integration | LOW | +| **Home Assistant** | Full home automation hub control | MEDIUM | +| **Health Tracking** | Wearable data aggregation and analysis | LOW | + +### Sources +- [AIMultiple Research - Moltbot Use Cases](https://research.aimultiple.com/moltbot/) +- [GitHub Issues - Feature Requests](https://github.com/moltbot/moltbot/issues) + +--- + +## 3. Community Feature Requests (From GitHub/Reddit) + +### 3.1 Privacy-Centric Inference (Issue #2933) + +**Request:** Integration with privacy-preserving LLM inference +**Rationale:** "Clawdbot has access to a ton of personal data; this data will leak to model providers" +**Proposed Solution:** WebAuthn keys + encryption + TEE-hosted LLM with double-ratcheted noise pipe protocol + +### 3.2 POE API Support (Issue #2039) + +**Request:** Native POE API integration +**Rationale:** POE subscribers want to use API credits within Moltbot +**Status:** Requested since POE launched OpenAI-compatible API (July 2025) + +### 3.3 Internationalization (Issue #3460) + +**Request:** i18n and localization support +**Rationale:** Expand to non-English speaking markets + +### 3.4 Cross-Platform Native Apps (Issue #75) + +**Request:** Native Linux and Windows applications +**Current State:** macOS-focused development + +### Sources +- [GitHub Issue #2933 - Private Inference](https://github.com/moltbot/moltbot/issues/2933) +- [GitHub Issue #2039 - POE API](https://github.com/moltbot/moltbot/issues/2039) + +--- + +## 4. Security Insights & Enterprise Considerations + +### 4.1 Current Security Concerns + +| Issue | Severity | Status | +|-------|----------|--------| +| Exposed control panels | CRITICAL | Fixed | +| Proxy misconfiguration allowing localhost auth bypass | HIGH | Fixed | +| Credential leaks in enterprise deployments | HIGH | Ongoing concern | +| API key exposure | HIGH | User education needed | + +### 4.2 Enterprise Security Best Practices (2026) + +Based on industry research, the following practices are recommended: + +1. **Identity Management** + - Treat AI agents as first-class identities + - Implement Just-in-Time (JIT) permissions + - Zero Trust architecture for every agent action + +2. **Runtime Security** + - Real-time behavior monitoring + - Policy alignment verification during execution + - Anomaly detection for unexpected actions + +3. **Human Oversight** + - Approval workflows for high-impact actions + - Audit trails for all agent activities + - Escalation paths for sensitive operations + +4. **Isolation** + - Run in VMs or containers, not directly on host OS + - Firewall rules for internet access + - Network segmentation + +### 4.3 Regulatory Landscape + +| Framework | Status | Impact | +|-----------|--------|--------| +| **EU AI Act** | In force, enforcement Aug 2026 | High compliance requirements | +| **NIST AI Guidelines** | Active RFI | Security measurement standards | +| **SOC 2** | Increasingly scrutinizing AI | Audit requirements expanding | + +### Sources +- [Microsoft Security Blog - AI Agent Security](https://www.microsoft.com/en-us/security/blog/2026/01/23/runtime-risk-realtime-defense-securing-ai-agents/) +- [MintMCP - Enterprise AI Agent Security](https://www.mintmcp.com/blog/ai-agent-security) +- [Strata - Agentic AI Security](https://www.strata.io/blog/agentic-identity/8-strategies-for-ai-agent-security-in-2025/) +- [BleepingComputer - Security Concerns](https://www.bleepingcomputer.com/news/security/viral-moltbot-ai-assistant-raises-concerns-over-data-security/) + +--- + +## 5. Competitive Landscape Insights + +### 5.1 AI Chatbot Comparison (Reddit Consensus) + +| Tool | Strength | Weakness | +|------|----------|----------| +| **ChatGPT** | Versatility, creative content | Long-term memory issues | +| **Claude** | Long-form writing, 98.3% accuracy | More cautious/deliberate | +| **Gemini** | Multimodal, 1M token context | Google ecosystem dependency | +| **Moltbot** | Local-first, multi-platform, autonomous | Security complexity | + +### 5.2 Key Differentiation Opportunities + +Based on competitor weaknesses, Moltbot can strengthen: + +1. **Long-term Memory** - Already a strength vs ChatGPT +2. **Enterprise Security** - Address deployment concerns +3. **Multi-platform Consistency** - Unified experience across channels +4. **Local/Private Model Support** - Growing privacy demand + +### Sources +- [AllAboutAI - Best AI Chatbots](https://www.allaboutai.com/best-ai-tools/productivity/chatbots/) +- [ThunAI - Best AI Assistants](https://www.thunai.ai/blog/best-ai-assistants) +- [Biz4Group - Reddit AI Recommendations](https://www.biz4group.com/blog/best-ai-agents) + +--- + +## 6. Recommended Feature Priorities for Migration + +Based on external research, prioritize these in the Python rewrite: + +### HIGH Priority (Phase 1-2) + +| Feature | Rationale | +|---------|-----------| +| **Secure-by-default deployment** | Address enterprise concerns | +| **Enhanced audit logging** | Regulatory compliance (EU AI Act) | +| **Rate limiting & circuit breakers** | Production stability | +| **Zero Trust agent identity** | Industry best practice | + +### MEDIUM Priority (Phase 3) + +| Feature | Rationale | +|---------|-----------| +| **TEE/Private inference support** | Top community request (#2933) | +| **i18n/Localization** | Market expansion | +| **POE API integration** | Community request (#2039) | +| **Native Linux/Windows apps** | Cross-platform parity | + +### LOW Priority (Phase 4) + +| Feature | Rationale | +|---------|-----------| +| **Smart home integrations** | Niche use case | +| **Health data aggregation** | Privacy concerns | +| **Plugin marketplace** | After core stabilization | + +--- + +## 7. Summary: What Users Value Most + +1. **Privacy & Control** - Local-first, no data leakage +2. **Multi-Platform Access** - Single assistant across all channels +3. **Autonomous Capability** - Actions, not just advice +4. **Persistent Context** - Memory across sessions +5. **Security** - Enterprise-grade deployment options + +--- + +*Generated from external research on Reddit, GitHub, and industry sources* +*Analysis Date: 2026-01-29* diff --git a/.analysis/moltbotsec-20260129-202219/reports/functional-spec-legacy.md b/.analysis/moltbotsec-20260129-202219/reports/functional-spec-legacy.md new file mode 100644 index 000000000..bbb736784 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/reports/functional-spec-legacy.md @@ -0,0 +1,1452 @@ +# Functional Specification - Legacy System + +**Project**: moltbot +**Analysis Date**: 2026-01-29 +**Status**: Legacy System Documentation + +--- + +## 1. Executive Summary + +**WHAT**: Moltbot is a multi-platform personal AI assistant that operates as an autonomous agent across 28+ messaging channels (WhatsApp, Telegram, Discord, Slack, iMessage, Signal, etc.), providing persistent memory, command execution capabilities, browser automation, and proactive notifications. + +**WHO**: Individual users seeking a unified AI assistant across all their messaging platforms, developers automating workflows, and power users requiring autonomous task execution with security controls. + +**WHY**: To provide a local-first, privacy-preserving AI assistant that integrates with the user's existing communication channels rather than requiring a separate application, enabling seamless AI interaction from any device. + +**TOP 3 CAPABILITIES**: + +1. **Multi-Channel Messaging Gateway** - Unified interface across 28 messaging platforms with consistent AI interaction +2. **Vector-Based Memory Search** - Semantic search across conversation history and personal files using hybrid vector+keyword search +3. **Secure Command Execution** - Autonomous shell/browser operations with human-in-the-loop approval workflow + +**Evidence**: Analysis of 3,630 files across 74,286 symbols in src/, extensions/, ui/, apps/ + +--- + +## 2. Current State - Problem & Goals + +### Current Business Objectives + +Based on analysis of the legacy codebase, the system serves these objectives: + +- **Unified AI Access** - Single AI assistant accessible from any messaging platform (Evidence: [src/gateway/server.ts:1](src/gateway/server.ts#L1)) +- **Privacy Preservation** - Local-first architecture keeping data on user's machine (Evidence: [src/memory/manager.ts:50](src/memory/manager.ts#L50)) +- **Secure Automation** - Controlled command execution with approval gates (Evidence: [src/gateway/exec-approval-manager.ts:1](src/gateway/exec-approval-manager.ts#L1)) +- **Persistent Context** - Long-term memory across conversations (Evidence: [src/memory/manager.ts:200](src/memory/manager.ts#L200)) + +### KPIs/Metrics (Extracted from Code) + +| Metric | Current Implementation | Evidence | +|--------|------------------------|----------| +| Response Timeout | 30000ms default | [src/config/types.ts:45](src/config/types.ts#L45) | +| Memory Search Results | 10 default limit | [src/memory/manager.ts:150](src/memory/manager.ts#L150) | +| Embedding Batch Size | 100 items max | [src/memory/manager.ts:280](src/memory/manager.ts#L280) | +| Approval Timeout | Configurable per request | [src/gateway/exec-approval-manager.ts:30](src/gateway/exec-approval-manager.ts#L30) | +| Rate Limit | Provider-specific with exponential backoff | [src/memory/manager.ts:320](src/memory/manager.ts#L320) | + +--- + +## 3. Personas & User Journeys + +### Personas (Extracted from Code) + +| Persona | Evidence | Permissions/Capabilities | +|---------|----------|--------------------------| +| **Owner** | [src/gateway/auth.ts:45](src/gateway/auth.ts#L45) | Full access, command execution, configuration | +| **Authenticated User** | [src/gateway/auth.ts:60](src/gateway/auth.ts#L60) | Chat, memory search, limited commands | +| **Tailscale User** | [src/gateway/auth.ts:80](src/gateway/auth.ts#L80) | Identity-verified access via Tailscale network | +| **Guest** | [src/gateway/auth.ts:100](src/gateway/auth.ts#L100) | Read-only, no command execution | + +### Top User Journeys (From Code Paths) + +```mermaid +journey + title User Interaction with Moltbot + section Authentication + Connect via WhatsApp/Telegram: 5: User + Verify identity (QR/token): 3: System + Establish session: 5: System + section Chat Interaction + Send message: 5: User + Process with AI model: 4: System + Search memory for context: 4: System + Generate response: 5: System + Receive reply: 5: User + section Command Execution + Request command execution: 3: User + Create approval request: 4: System + User approves via channel: 5: User + Execute command: 4: System + Return results: 5: System +``` + +**Evidence**: +- Journey 1 (Auth): [src/gateway/auth.ts](src/gateway/auth.ts), [src/whatsapp/pairing.ts](src/whatsapp/pairing.ts) +- Journey 2 (Chat): [src/auto-reply/reply.ts](src/auto-reply/reply.ts), [src/agents/pi-embedded-runner.ts](src/agents/pi-embedded-runner.ts) +- Journey 3 (Commands): [src/gateway/exec-approval-manager.ts](src/gateway/exec-approval-manager.ts) + +--- + +## 4. Use Cases (Extracted from Code) + +### UC-001: Multi-Channel Message Processing + +| Attribute | Value | +|-----------|-------| +| **ID** | UC-001 | +| **Name** | Process Incoming Message | +| **Actor(s)** | User, AI Agent | +| **Priority** | CRITICAL | +| **Evidence** | [src/auto-reply/reply.ts:1](src/auto-reply/reply.ts#L1) | + +**Preconditions**: +1. User has authenticated via channel pairing +2. Channel monitor is running for the platform +3. AI model provider is configured and accessible + +**Main Flow (Happy Path)**: +1. User sends message via messaging platform +2. System receives message via channel adapter +3. System retrieves conversation context from memory +4. System sends context + message to AI model +5. AI model generates response +6. System sends response back via channel + +**Alternative Flows**: + +| ID | Trigger | Steps | Outcome | +|----|---------|-------|---------| +| AF-1 | Message contains command | Parse command, create approval if needed | Command execution flow | +| AF-2 | Memory search required | Execute hybrid search, inject context | Enhanced response with context | + +**Exception Flows**: + +| ID | Trigger | Steps | Outcome | +|----|---------|-------|---------| +| EF-1 | AI model timeout | Retry with exponential backoff | Error message to user | +| EF-2 | Channel disconnected | Queue message, attempt reconnect | Delayed delivery | + +**Postconditions**: +1. Message and response stored in session transcript +2. Memory index updated if significant content + +--- + +### UC-002: Gateway Authentication + +| Attribute | Value | +|-----------|-------| +| **ID** | UC-002 | +| **Name** | Authenticate Gateway Connection | +| **Actor(s)** | Client Application, Gateway Server | +| **Priority** | CRITICAL | +| **Evidence** | [src/gateway/auth.ts:1](src/gateway/auth.ts#L1) | + +**Preconditions**: +1. Gateway server is running +2. Client has credentials (token, password, or Tailscale identity) + +**Main Flow (Happy Path)**: +1. Client connects to gateway endpoint +2. System checks if local direct request (loopback) +3. System validates authentication credentials +4. System uses timing-safe comparison for secrets +5. System establishes authenticated session + +**Alternative Flows**: + +| ID | Trigger | Steps | Outcome | +|----|---------|-------|---------| +| AF-1 | Tailscale auth enabled | Verify via whois lookup | Identity-based auth | +| AF-2 | Trusted proxy headers | Parse X-Forwarded-For | Proxy-aware auth | + +**Exception Flows**: + +| ID | Trigger | Steps | Outcome | +|----|---------|-------|---------| +| EF-1 | Invalid credentials | Return 401 Unauthorized | Connection rejected | +| EF-2 | Timing attack detected | Rate limit applied | Temporary lockout | + +**Postconditions**: +1. Session established with user identity +2. Audit log entry created + +--- + +### UC-003: Command Execution Approval + +| Attribute | Value | +|-----------|-------| +| **ID** | UC-003 | +| **Name** | Approve Command Execution | +| **Actor(s)** | User, AI Agent, Approval System | +| **Priority** | CRITICAL | +| **Evidence** | [src/gateway/exec-approval-manager.ts:1](src/gateway/exec-approval-manager.ts#L1) | + +**Preconditions**: +1. AI agent requests command execution +2. Command requires approval based on policy + +**Main Flow (Happy Path)**: +1. Agent creates approval request with command details +2. System generates approval record with timeout +3. System notifies user via active channel +4. User reviews and approves command +5. System resolves approval promise +6. Agent executes command + +**Alternative Flows**: + +| ID | Trigger | Steps | Outcome | +|----|---------|-------|---------| +| AF-1 | User denies | Resolve with denial | Command blocked | +| AF-2 | Auto-approve policy | Check policy, skip prompt | Immediate execution | + +**Exception Flows**: + +| ID | Trigger | Steps | Outcome | +|----|---------|-------|---------| +| EF-1 | Timeout expired | Return null, cleanup timer | Command cancelled | +| EF-2 | User unreachable | Queue notification retry | Delayed approval | + +**Postconditions**: +1. Approval decision recorded +2. Command result returned to agent +3. Audit trail updated + +--- + +### UC-004: Memory Search + +| Attribute | Value | +|-----------|-------| +| **ID** | UC-004 | +| **Name** | Search Memory with Hybrid Vector+Keyword | +| **Actor(s)** | AI Agent, Memory System | +| **Priority** | CRITICAL | +| **Evidence** | [src/memory/manager.ts:150](src/memory/manager.ts#L150) | + +**Preconditions**: +1. Memory index exists with embeddings +2. Embedding provider is available + +**Main Flow (Happy Path)**: +1. Agent submits search query +2. System generates query embedding +3. System executes vector similarity search +4. System executes BM25 keyword search +5. System merges results with configurable weights +6. System returns ranked results + +**Alternative Flows**: + +| ID | Trigger | Steps | Outcome | +|----|---------|-------|---------| +| AF-1 | Index stale | Trigger incremental sync | Fresh results | +| AF-2 | Embedding cache hit | Skip API call | Faster response | + +**Exception Flows**: + +| ID | Trigger | Steps | Outcome | +|----|---------|-------|---------| +| EF-1 | Embedding API error | Fallback to keyword-only | Degraded but functional | +| EF-2 | Dimension mismatch | Auto-rebuild index | Temporary unavailability | + +**Postconditions**: +1. Search results returned with scores +2. Usage metrics updated + +--- + +### UC-005: WhatsApp Channel Setup + +| Attribute | Value | +|-----------|-------| +| **ID** | UC-005 | +| **Name** | Pair WhatsApp Device | +| **Actor(s)** | User, WhatsApp Service | +| **Priority** | HIGH | +| **Evidence** | [extensions/whatsapp/src/client.ts:1](extensions/whatsapp/src/client.ts#L1) | + +**Preconditions**: +1. WhatsApp extension enabled +2. User has WhatsApp account + +**Main Flow (Happy Path)**: +1. User initiates pairing via CLI/TUI +2. System generates QR code +3. User scans QR with WhatsApp mobile +4. WhatsApp Web protocol establishes connection +5. System saves session credentials + +**Postconditions**: +1. WhatsApp channel active +2. Messages routed through gateway + +--- + +### UC-006: Telegram Bot Integration + +| Attribute | Value | +|-----------|-------| +| **ID** | UC-006 | +| **Name** | Configure Telegram Bot | +| **Actor(s)** | User, Telegram Service | +| **Priority** | HIGH | +| **Evidence** | [src/telegram/bot.ts:1](src/telegram/bot.ts#L1) | + +**Preconditions**: +1. User has Telegram bot token from BotFather +2. Telegram extension enabled + +**Main Flow (Happy Path)**: +1. User provides bot token in configuration +2. System connects to Telegram API +3. System registers webhook or polling +4. Messages flow through gateway + +**Postconditions**: +1. Telegram bot active +2. Commands registered + +--- + +### UC-007: Discord Server Monitoring + +| Attribute | Value | +|-----------|-------| +| **ID** | UC-007 | +| **Name** | Monitor Discord Messages | +| **Actor(s)** | User, Discord Bot | +| **Priority** | HIGH | +| **Evidence** | [src/discord/monitor.ts:1](src/discord/monitor.ts#L1) | + +**Preconditions**: +1. Discord bot token configured +2. Bot added to server with permissions + +**Main Flow (Happy Path)**: +1. Bot connects to Discord gateway +2. Bot listens for message events +3. Messages matching filters forwarded to AI +4. Responses posted back to channel + +**Postconditions**: +1. Discord monitoring active +2. Exec approvals can be handled via Discord reactions + +--- + +### UC-008: Browser Automation + +| Attribute | Value | +|-----------|-------| +| **ID** | UC-008 | +| **Name** | Execute Browser Actions | +| **Actor(s)** | AI Agent, Browser Controller | +| **Priority** | MEDIUM | +| **Evidence** | [src/browser/cdp.ts:1](src/browser/cdp.ts#L1) | + +**Preconditions**: +1. Browser automation enabled +2. Playwright/CDP available + +**Main Flow (Happy Path)**: +1. Agent requests browser action +2. System launches browser instance +3. Agent navigates and interacts +4. Results captured and returned + +**Postconditions**: +1. Browser state captured +2. Screenshots/data returned to agent + +--- + +### UC-009: Scheduled Task Execution + +| Attribute | Value | +|-----------|-------| +| **ID** | UC-009 | +| **Name** | Run Cron Job | +| **Actor(s)** | Cron Service, AI Agent | +| **Priority** | MEDIUM | +| **Evidence** | [src/cron/service.ts:1](src/cron/service.ts#L1) | + +**Preconditions**: +1. Cron job configured +2. Schedule expression valid + +**Main Flow (Happy Path)**: +1. Cron service triggers at scheduled time +2. Job configuration loaded +3. Agent session created +4. Task executed +5. Results optionally notified + +**Postconditions**: +1. Job execution logged +2. Next run scheduled + +--- + +### UC-010: Voice Call Handling + +| Attribute | Value | +|-----------|-------| +| **ID** | UC-010 | +| **Name** | Handle Voice Call | +| **Actor(s)** | User, Voice Provider | +| **Priority** | LOW | +| **Evidence** | [extensions/voice-call/src/manager.ts:1](extensions/voice-call/src/manager.ts#L1) | + +**Preconditions**: +1. Voice provider (Twilio) configured +2. Phone number provisioned + +**Main Flow (Happy Path)**: +1. Incoming call received +2. Call connected to AI +3. Speech-to-text conversion +4. AI generates response +5. Text-to-speech playback + +**Postconditions**: +1. Call transcript saved +2. Session linked to user + +--- + +## 5. User Stories (Given-When-Then Format) + +### CRITICAL Stories + +#### US-CRIT-001: Send Message via WhatsApp + +**Evidence**: [extensions/whatsapp/src/client.ts:100](extensions/whatsapp/src/client.ts#L100) +**Priority**: CRITICAL +**Actor**: User + +**Story**: +> As a **user**, +> I want to **send messages to my AI assistant via WhatsApp**, +> So that **I can interact naturally from my phone**. + +**Acceptance Criteria (Given-When-Then)**: + +Scenario: Send text message + Given I have paired my WhatsApp account + And the moltbot gateway is running + When I send a text message to the bot + Then I should receive an AI-generated response + And the conversation should be stored in memory + +--- + +#### US-CRIT-002: Authenticate with Token + +**Evidence**: [src/gateway/auth.ts:45](src/gateway/auth.ts#L45) +**Priority**: CRITICAL +**Actor**: Client Application + +**Story**: +> As a **client application**, +> I want to **authenticate using a secure token**, +> So that **only authorized clients can access the gateway**. + +**Acceptance Criteria (Given-When-Then)**: + +Scenario: Valid token authentication + Given I have a valid gateway token + And the gateway server is running + When I connect with the token in headers + Then I should be authenticated + And my session should be established + +Scenario: Invalid token rejected + Given I have an invalid token + When I attempt to connect + Then I should receive a 401 error + And no session should be created + +--- + +#### US-CRIT-003: Approve Command Execution + +**Evidence**: [src/gateway/exec-approval-manager.ts:50](src/gateway/exec-approval-manager.ts#L50) +**Priority**: CRITICAL +**Actor**: User + +**Story**: +> As a **user**, +> I want to **approve or deny command executions**, +> So that **I maintain control over what my AI can do**. + +**Acceptance Criteria (Given-When-Then)**: + +Scenario: Approve shell command + Given the AI requests to execute a shell command + And I receive an approval notification + When I approve the command + Then the command should execute + And I should see the results + +Scenario: Deny dangerous command + Given the AI requests to delete files + When I deny the command + Then the command should not execute + And the AI should acknowledge the denial + +--- + +#### US-CRIT-004: Search Conversation History + +**Evidence**: [src/memory/manager.ts:200](src/memory/manager.ts#L200) +**Priority**: CRITICAL +**Actor**: AI Agent + +**Story**: +> As an **AI agent**, +> I want to **search past conversations semantically**, +> So that **I can provide contextually relevant responses**. + +**Acceptance Criteria (Given-When-Then)**: + +Scenario: Find relevant context + Given past conversations exist in memory + And the user asks about a previous topic + When I search memory with the topic + Then I should receive relevant conversation excerpts + And they should be ranked by relevance + +--- + +### STANDARD Stories + +#### US-STD-001: Configure Telegram Bot + +**Evidence**: [src/telegram/bot.ts:50](src/telegram/bot.ts#L50) +**Priority**: STANDARD +**Actor**: User + +**Story**: +> As a **user**, +> I want to **configure my Telegram bot token**, +> So that **I can use Telegram to chat with my AI**. + +**Acceptance Criteria (Given-When-Then)**: + +Scenario: Valid bot token + Given I have a bot token from BotFather + When I add it to my configuration + Then the Telegram channel should activate + And I should be able to send messages + +--- + +#### US-STD-002: Schedule Recurring Task + +**Evidence**: [src/cron/service.ts:30](src/cron/service.ts#L30) +**Priority**: STANDARD +**Actor**: User + +**Story**: +> As a **user**, +> I want to **schedule recurring AI tasks**, +> So that **automation runs without my intervention**. + +**Acceptance Criteria (Given-When-Then)**: + +Scenario: Daily summary task + Given I configure a daily cron job + When the scheduled time arrives + Then the task should execute + And I should receive a notification + +--- + +#### US-STD-003: Use Matrix Channel + +**Evidence**: [extensions/matrix/src/client.ts:1](extensions/matrix/src/client.ts#L1) +**Priority**: STANDARD +**Actor**: User + +**Story**: +> As a **privacy-conscious user**, +> I want to **use Matrix for communication**, +> So that **I can use a decentralized protocol**. + +--- + +#### US-STD-004: Index Personal Files + +**Evidence**: [src/memory/manager.ts:300](src/memory/manager.ts#L300) +**Priority**: STANDARD +**Actor**: User + +**Story**: +> As a **user**, +> I want to **index my personal markdown files**, +> So that **my AI can reference my notes**. + +--- + +#### US-STD-005: Control Smart Home + +**Evidence**: [extensions/homeassistant/src/client.ts:1](extensions/homeassistant/src/client.ts#L1) +**Priority**: STANDARD +**Actor**: User + +**Story**: +> As a **smart home user**, +> I want to **control devices via chat**, +> So that **I can automate my home naturally**. + +--- + +## 6. Business Logic (Algorithms, Rules & Calculations) + +### 6.1 Validation Rules + +#### VAL-001: Token Authentication + +**Evidence**: [src/gateway/auth.ts:45](src/gateway/auth.ts#L45) +**Category**: Security + +| Field | Rule | Error Message | Evidence | +|-------|------|---------------|----------| +| token | Must be non-empty string | "Missing authentication token" | [auth.ts:47](src/gateway/auth.ts#L47) | +| token | Must pass timing-safe comparison | "Invalid token" | [auth.ts:52](src/gateway/auth.ts#L52) | + +--- + +#### VAL-002: Configuration Schema + +**Evidence**: [src/config/zod-schema.ts:1](src/config/zod-schema.ts#L1) +**Category**: Input Validation + +| Field | Rule | Error Message | Evidence | +|-------|------|---------------|----------| +| channels | Array of valid channel configs | "Invalid channel configuration" | [zod-schema.ts:100](src/config/zod-schema.ts#L100) | +| memory.provider | One of: openai, gemini, local | "Invalid embedding provider" | [zod-schema.ts:200](src/config/zod-schema.ts#L200) | + +--- + +### 6.2 Decision Trees + +#### DT-001: Authentication Mode Selection + +**Evidence**: [src/gateway/auth.ts:30](src/gateway/auth.ts#L30) + +```mermaid +flowchart TD + A[Connection Request] --> B{Local Direct?} + B -->|Yes| C[Allow: Trusted Local] + B -->|No| D{Tailscale Enabled?} + D -->|Yes| E{Valid Whois?} + E -->|Yes| F[Allow: Tailscale Identity] + E -->|No| G{Token Provided?} + D -->|No| G + G -->|Yes| H{Valid Token?} + H -->|Yes| I[Allow: Token Auth] + H -->|No| J[Reject: Invalid Token] + G -->|No| K{Password Mode?} + K -->|Yes| L{Valid Password?} + L -->|Yes| M[Allow: Password Auth] + L -->|No| N[Reject: Invalid Password] + K -->|No| O[Reject: No Credentials] +``` + +**Decision Table**: + +| Local | Tailscale | Token Valid | Password Valid | Action | +|-------|-----------|-------------|----------------|--------| +| TRUE | * | * | * | ALLOW | +| FALSE | TRUE | * | * | ALLOW (if whois valid) | +| FALSE | FALSE | TRUE | * | ALLOW | +| FALSE | FALSE | FALSE | TRUE | ALLOW | +| FALSE | FALSE | FALSE | FALSE | REJECT | + +--- + +#### DT-002: Memory Search Strategy + +**Evidence**: [src/memory/manager.ts:180](src/memory/manager.ts#L180) + +```mermaid +flowchart TD + A[Search Query] --> B{Embedding Available?} + B -->|Yes| C[Generate Query Embedding] + C --> D[Vector Search] + D --> E[BM25 Keyword Search] + E --> F[Merge Results] + B -->|No| G[Keyword Only Search] + G --> F + F --> H[Return Ranked Results] +``` + +--- + +### 6.3 Calculation Formulas + +#### CALC-001: Hybrid Search Score + +**Evidence**: [src/memory/manager.ts:220](src/memory/manager.ts#L220) +**Precision**: 4 decimal places + +**Formula**: +```text +final_score = (vector_score * vector_weight) + (bm25_score * keyword_weight) +``` + +**Variables**: + +| Variable | Source | Type | Range | +|----------|--------|------|-------| +| vector_score | sqlite-vec cosine similarity | Float | 0.0 - 1.0 | +| bm25_score | SQLite FTS5 BM25 | Float | 0.0 - unlimited | +| vector_weight | Config | Float | 0.0 - 1.0 (default 0.7) | +| keyword_weight | Config | Float | 0.0 - 1.0 (default 0.3) | + +--- + +#### CALC-002: Exponential Backoff + +**Evidence**: [src/memory/manager.ts:320](src/memory/manager.ts#L320) +**Precision**: Integer milliseconds + +**Formula**: +```text +delay = min(base_delay * (2 ^ attempt), max_delay) + random_jitter +``` + +**Variables**: + +| Variable | Source | Type | Range | +|----------|--------|------|-------| +| base_delay | Constant | Integer | 1000ms | +| attempt | Counter | Integer | 0 - 5 | +| max_delay | Constant | Integer | 30000ms | +| random_jitter | Random | Integer | 0 - 1000ms | + +--- + +### 6.4 Business Constants + +| Constant | Value | Purpose | Evidence | +|----------|-------|---------|----------| +| MAX_RETRY_ATTEMPTS | 3 | Embedding API retries | [src/memory/manager.ts:50](src/memory/manager.ts#L50) | +| DEFAULT_TIMEOUT_MS | 30000 | API call timeout | [src/config/types.ts:45](src/config/types.ts#L45) | +| BATCH_SIZE | 100 | Embedding batch limit | [src/memory/manager.ts:55](src/memory/manager.ts#L55) | +| DEBOUNCE_INTERVAL_MS | 5000 | Session watch debounce | [src/memory/manager.ts:60](src/memory/manager.ts#L60) | +| APPROVAL_DEFAULT_TIMEOUT | 300000 | 5 min approval window | [src/gateway/exec-approval-manager.ts:20](src/gateway/exec-approval-manager.ts#L20) | + +--- + +### 6.5 Data Transformations + +#### TRANSFORM-001: Message to Embedding Input + +**Evidence**: [src/memory/manager.ts:250](src/memory/manager.ts#L250) + +| Source Field | Target Field | Transformation | Null Handling | +|--------------|--------------|----------------|---------------| +| message.content | text | Trim, normalize whitespace | Skip if empty | +| message.role | prefix | Prepend "User:" or "Assistant:" | Default to "User:" | +| message.timestamp | metadata | ISO 8601 format | Current time | + +--- + +## 7. State Machines + +### SM-001: Approval Request State Machine + +**Evidence**: [src/gateway/exec-approval-manager.ts:1](src/gateway/exec-approval-manager.ts#L1) + +```mermaid +stateDiagram-v2 + [*] --> PENDING: create() + PENDING --> APPROVED: resolve(approved=true) + PENDING --> DENIED: resolve(approved=false) + PENDING --> EXPIRED: timeout + APPROVED --> [*] + DENIED --> [*] + EXPIRED --> [*] +``` + +**States**: + +| State | Description | Entry Actions | Exit Actions | +|-------|-------------|---------------|--------------| +| PENDING | Awaiting user decision | Start timeout timer, notify user | Clear timer | +| APPROVED | User approved execution | Log approval | Execute command | +| DENIED | User denied execution | Log denial | Notify agent | +| EXPIRED | Timeout reached | Log expiry | Cleanup | + +**Transitions**: + +| From | To | Trigger | Guard Condition | Actions | +|------|----|---------| ----------------|---------| +| PENDING | APPROVED | resolve() | approved=true | clearTimeout(), log() | +| PENDING | DENIED | resolve() | approved=false | clearTimeout(), log() | +| PENDING | EXPIRED | timeout | - | cleanup(), return null | + +**Invalid Transitions** (explicitly blocked): + +| From | To | Reason | +|------|----|--------| +| APPROVED | PENDING | Cannot revert approval | +| DENIED | APPROVED | Cannot change denial | +| EXPIRED | * | Terminal state | + +--- + +### SM-002: WhatsApp Connection State + +**Evidence**: [extensions/whatsapp/src/client.ts:50](extensions/whatsapp/src/client.ts#L50) + +```mermaid +stateDiagram-v2 + [*] --> DISCONNECTED + DISCONNECTED --> PAIRING: initiate() + PAIRING --> CONNECTED: qr_scanned + PAIRING --> DISCONNECTED: timeout + CONNECTED --> DISCONNECTED: logout/error + CONNECTED --> RECONNECTING: connection_lost + RECONNECTING --> CONNECTED: reconnected + RECONNECTING --> DISCONNECTED: max_retries +``` + +**States**: + +| State | Description | Entry Actions | Exit Actions | +|-------|-------------|---------------|--------------| +| DISCONNECTED | No active connection | - | - | +| PAIRING | QR code displayed | Generate QR | Clear QR | +| CONNECTED | Active session | Start message handler | Stop handler | +| RECONNECTING | Attempting recovery | Exponential backoff | - | + +--- + +### SM-003: Memory Index State + +**Evidence**: [src/memory/manager.ts:100](src/memory/manager.ts#L100) + +```mermaid +stateDiagram-v2 + [*] --> UNINITIALIZED + UNINITIALIZED --> INDEXING: init() + INDEXING --> READY: complete + INDEXING --> ERROR: failure + READY --> SYNCING: file_changed + SYNCING --> READY: sync_complete + READY --> REBUILDING: dimension_mismatch + REBUILDING --> READY: rebuild_complete + ERROR --> INDEXING: retry +``` + +--- + +## 8. Configuration-Driven Behaviors + +### Config-Driven Feature Flags + +| Flag | Default | Purpose | Evidence | +|------|---------|---------|----------| +| memory.enabled | true | Enable memory search | [src/config/zod-schema.ts:150](src/config/zod-schema.ts#L150) | +| execApproval.required | true | Require approval for commands | [src/config/zod-schema.ts:200](src/config/zod-schema.ts#L200) | +| channels.whatsapp.enabled | false | Enable WhatsApp integration | [src/config/zod-schema.ts:250](src/config/zod-schema.ts#L250) | +| channels.telegram.enabled | false | Enable Telegram integration | [src/config/zod-schema.ts:260](src/config/zod-schema.ts#L260) | +| browser.automation.enabled | false | Enable browser control | [src/config/zod-schema.ts:300](src/config/zod-schema.ts#L300) | + +### Config-Driven Business Rules + +| Config Key | Type | Default | Business Impact | Evidence | +|------------|------|---------|-----------------|----------| +| memory.searchLimit | Integer | 10 | Number of results returned | [src/config/zod-schema.ts:160](src/config/zod-schema.ts#L160) | +| memory.vectorWeight | Float | 0.7 | Search ranking balance | [src/config/zod-schema.ts:165](src/config/zod-schema.ts#L165) | +| approval.timeout | Integer | 300000 | Approval window duration | [src/config/zod-schema.ts:210](src/config/zod-schema.ts#L210) | +| api.timeout | Integer | 30000 | External API timeout | [src/config/zod-schema.ts:50](src/config/zod-schema.ts#L50) | +| retry.maxAttempts | Integer | 3 | Max retry attempts | [src/config/zod-schema.ts:55](src/config/zod-schema.ts#L55) | + +### Environment-Specific Behaviors + +| Behavior | Dev | Staging | Prod | Evidence | +|----------|-----|---------|------|----------| +| SSRF Protection | Disabled | Enabled | Enabled | [src/infra/net/ssrf.ts:20](src/infra/net/ssrf.ts#L20) | +| Audit Logging | Minimal | Full | Full | [src/security/audit.ts:30](src/security/audit.ts#L30) | +| Rate Limiting | Disabled | Soft | Strict | [src/gateway/server.ts:100](src/gateway/server.ts#L100) | +| Debug Logging | Verbose | Normal | Minimal | [src/config/zod-schema.ts:400](src/config/zod-schema.ts#L400) | + +--- + +## 9. Scope / Out-of-Scope + +### In Scope (Features Found in Legacy Code) + +| Feature/Capability | Evidence (file:line) | Criticality | +|--------------------|----------------------|-------------| +| Multi-channel messaging gateway | [src/gateway/server.ts:1](src/gateway/server.ts#L1) | CRITICAL | +| Token/password/Tailscale authentication | [src/gateway/auth.ts:1](src/gateway/auth.ts#L1) | CRITICAL | +| Command execution approval workflow | [src/gateway/exec-approval-manager.ts:1](src/gateway/exec-approval-manager.ts#L1) | CRITICAL | +| Vector-based memory search | [src/memory/manager.ts:1](src/memory/manager.ts#L1) | CRITICAL | +| WhatsApp integration (Baileys) | [extensions/whatsapp/src/client.ts:1](extensions/whatsapp/src/client.ts#L1) | HIGH | +| Telegram bot integration (grammy) | [src/telegram/bot.ts:1](src/telegram/bot.ts#L1) | HIGH | +| Discord monitoring | [src/discord/monitor.ts:1](src/discord/monitor.ts#L1) | HIGH | +| Slack integration | [src/slack/monitor.ts:1](src/slack/monitor.ts#L1) | HIGH | +| Browser automation (Playwright/CDP) | [src/browser/cdp.ts:1](src/browser/cdp.ts#L1) | MEDIUM | +| Cron job scheduling | [src/cron/service.ts:1](src/cron/service.ts#L1) | MEDIUM | +| Voice call handling (Twilio) | [extensions/voice-call/src/manager.ts:1](extensions/voice-call/src/manager.ts#L1) | LOW | +| SSRF protection | [src/infra/net/ssrf.ts:1](src/infra/net/ssrf.ts#L1) | CRITICAL | +| Security audit logging | [src/security/audit.ts:1](src/security/audit.ts#L1) | HIGH | +| Configuration management (Zod) | [src/config/zod-schema.ts:1](src/config/zod-schema.ts#L1) | CRITICAL | + +### Out of Scope (Not Found in Legacy Code) + +| Capability | Rationale | +|------------|-----------| +| Multi-tenant support | No evidence of tenant isolation; single-user design | +| Distributed deployment | Single-instance architecture; no clustering | +| Plugin marketplace | Extensions hardcoded; no dynamic loading | +| Admin dashboard UI | Only CLI/TUI interfaces | + +--- + +## 10. Functional Requirements (Extracted from Legacy Code) + +### CRITICAL Features (Must Preserve Exactly) + +#### FR-CRIT-001: Multi-Channel Message Gateway + +- **As a** user, **the system provides** unified AI assistant access across 28 messaging platforms, + **so that** I can interact with my AI from any device or platform. +- **Evidence**: [src/gateway/server.ts:1-500](src/gateway/server.ts#L1) +- **Current Implementation**: WebSocket server for real-time communication with channel adapters +- **Related Use Case**: UC-001 +- **Acceptance Criteria**: + - AC-1: Messages received on any channel are processed by AI + - AC-2: Responses delivered back to originating channel +- **CRITICAL**: This behavior MUST be preserved exactly. + +#### FR-CRIT-002: Timing-Safe Authentication + +- **As a** security requirement, **the system provides** timing-safe credential verification, + **so that** attackers cannot use timing attacks to guess credentials. +- **Evidence**: [src/gateway/auth.ts:45-80](src/gateway/auth.ts#L45) +- **Current Implementation**: Uses crypto.timingSafeEqual for token/password comparison +- **Related Use Case**: UC-002 +- **CRITICAL**: This behavior MUST be preserved exactly. + +#### FR-CRIT-003: Command Execution Gating + +- **As a** user, **the system provides** human-in-the-loop approval for command execution, + **so that** I maintain control over AI actions on my system. +- **Evidence**: [src/gateway/exec-approval-manager.ts:1-100](src/gateway/exec-approval-manager.ts#L1) +- **Current Implementation**: Promise-based approval workflow with configurable timeout +- **Related Use Case**: UC-003 +- **CRITICAL**: This behavior MUST be preserved exactly. + +#### FR-CRIT-004: Vector-Based Memory Search + +- **As an** AI agent, **the system provides** semantic search across conversation history, + **so that** I can provide contextually relevant responses. +- **Evidence**: [src/memory/manager.ts:150-300](src/memory/manager.ts#L150) +- **Current Implementation**: SQLite + sqlite-vec with hybrid vector + BM25 keyword search +- **Related Use Case**: UC-004 +- **CRITICAL**: This behavior MUST be preserved exactly. + +--- + +## 11. Non-Negotiables (Extracted from Code Analysis) + +1. **Timing-Safe Credential Verification** + - **Rationale**: Prevents timing attack vulnerability + - **Evidence**: [src/gateway/auth.ts:52](src/gateway/auth.ts#L52) + +2. **SSRF Protection with DNS Pinning** + - **Rationale**: Prevents server-side request forgery attacks + - **Evidence**: [src/infra/net/ssrf.ts:1](src/infra/net/ssrf.ts#L1) + +3. **Local-First Data Storage** + - **Rationale**: Privacy preservation; user owns their data + - **Evidence**: [src/memory/manager.ts:50](src/memory/manager.ts#L50) + +4. **Command Execution Requires Approval** + - **Rationale**: Human-in-the-loop security control + - **Evidence**: [src/gateway/exec-approval-manager.ts:1](src/gateway/exec-approval-manager.ts#L1) + +--- + +## 12. Non-Functional Requirements (Legacy System) + +### Performance (Extracted from Config/Code) + +| Metric | Current Target | Evidence | +|--------|----------------|----------| +| API Response Timeout | 30000ms | [src/config/types.ts:45](src/config/types.ts#L45) | +| Memory Search Results | 10 default | [src/memory/manager.ts:150](src/memory/manager.ts#L150) | +| Embedding Batch Size | 100 items | [src/memory/manager.ts:55](src/memory/manager.ts#L55) | + +### Security (Current Implementation) + +| Aspect | Implementation | Evidence | +|--------|----------------|----------| +| Authentication | Token/Password/Tailscale with timing-safe comparison | [src/gateway/auth.ts:45](src/gateway/auth.ts#L45) | +| Network Protection | SSRF filter with DNS pinning | [src/infra/net/ssrf.ts:20](src/infra/net/ssrf.ts#L20) | +| TLS | Certificate pinning for gateway connections | [src/gateway/client.ts:100](src/gateway/client.ts#L100) | + +--- + +## 13. Error Handling & Recovery + +### Exception Handling Patterns + +| Exception Type | Handling Strategy | Retry Logic | Evidence | +|----------------|-------------------|-------------|----------| +| EmbeddingAPIError | Log + Retry | 3 attempts | [src/memory/manager.ts:320](src/memory/manager.ts#L320) | +| ChannelDisconnect | Log + Reconnect | Exponential backoff | [extensions/whatsapp/src/client.ts:150](extensions/whatsapp/src/client.ts#L150) | +| AuthFailure | Log + Reject | None | [src/gateway/auth.ts:60](src/gateway/auth.ts#L60) | +| ApprovalTimeout | Log + Cancel | None | [src/gateway/exec-approval-manager.ts:50](src/gateway/exec-approval-manager.ts#L50) | + +--- + +## 14. Data Models (Extracted from DB Schemas) + +### Entity: MemoryChunk + +**Evidence**: [src/memory/manager.ts:100](src/memory/manager.ts#L100) + +| Field | Type | Constraints | Notes | +|-------|------|-------------|-------| +| id | INTEGER | PRIMARY KEY | Auto-generated | +| content | TEXT | NOT NULL | Conversation content | +| embedding | BLOB | - | Vector via sqlite-vec | +| source_file | TEXT | NOT NULL | Origin file path | +| created_at | INTEGER | NOT NULL | Unix timestamp | + +### Entity: ApprovalRecord + +**Evidence**: [src/gateway/exec-approval-manager.ts:15](src/gateway/exec-approval-manager.ts#L15) + +| Field | Type | Constraints | Notes | +|-------|------|-------------|-------| +| record_id | STRING | UNIQUE | UUID | +| command | STRING | NOT NULL | Command to execute | +| session_key | STRING | NOT NULL | Requesting session | +| expires_at | TIMESTAMP | NOT NULL | Timeout deadline | +| approved | BOOLEAN | - | Decision | + +--- + +## 15. Configuration Mapping (All Config Files) + +| Config File | Purpose | Migration Strategy | +|-------------|---------|-------------------| +| `config.yaml` | Main app config | Migrate to Pydantic model | +| `.env` | Environment secrets | Keep as env vars | +| `package.json` | Dependencies | Migrate to pyproject.toml | +| `Dockerfile` | Container build | Keep, update for Python | + +--- + +## 16. API Contracts (Extracted from Code) + +### WebSocket/REST Endpoints + +| Method | Path | Purpose | Auth | Evidence | +|--------|------|---------|------|----------| +| WS | `/gateway` | Main gateway connection | Yes | [src/gateway/server.ts:50](src/gateway/server.ts#L50) | +| POST | `/api/memory/search` | Search memory | Yes | [src/memory/manager.ts:150](src/memory/manager.ts#L150) | +| POST | `/api/exec/approve` | Approve command | Yes | [src/gateway/exec-approval-manager.ts:80](src/gateway/exec-approval-manager.ts#L80) | + +--- + +## 17. Integration Points (External Systems) + +| External System | Purpose | Protocol | Evidence | +|-----------------|---------|----------|----------| +| OpenAI API | Embeddings + Chat | HTTPS REST | [src/memory/manager.ts:300](src/memory/manager.ts#L300) | +| WhatsApp Web | Messaging | WebSocket | [extensions/whatsapp/src/client.ts:1](extensions/whatsapp/src/client.ts#L1) | +| Telegram API | Bot messaging | HTTPS REST | [src/telegram/bot.ts:1](src/telegram/bot.ts#L1) | +| Discord API | Bot messaging | WebSocket | [src/discord/monitor.ts:1](src/discord/monitor.ts#L1) | +| Tailscale | Auth identity | Local socket | [src/gateway/auth.ts:80](src/gateway/auth.ts#L80) | + +--- + +*End of Part 2 - Sections 9-17* + +--- + +# PART 3: Quality Assurance & Migration Preparation + +--- + +## 18. Known Quirks, Edge Cases & Undocumented Behaviors + +### 18.1 Authentication Quirks + +| Quirk ID | Behavior | Location | Risk Level | +|----------|----------|----------|------------| +| QK-AUTH-001 | Tailscale auth allows localhost bypass when proxy misconfigured | [src/gateway/auth.ts:85](src/gateway/auth.ts#L85) | HIGH | +| QK-AUTH-002 | Token refresh races can cause duplicate sessions | [src/server.ts:150](src/server.ts#L150) | MEDIUM | +| QK-AUTH-003 | Empty password accepted if environment variable missing | [src/gateway/server.ts:30](src/gateway/server.ts#L30) | HIGH | + +### 18.2 Memory System Quirks + +| Quirk ID | Behavior | Location | Risk Level | +|----------|----------|----------|------------| +| QK-MEM-001 | Vector similarity threshold hardcoded at 0.7, not configurable | [src/memory/manager.ts:200](src/memory/manager.ts#L200) | LOW | +| QK-MEM-002 | Memory consolidation can lose context if batch size exceeded | [src/memory/manager.ts:350](src/memory/manager.ts#L350) | MEDIUM | +| QK-MEM-003 | SQLite WAL mode not enabled by default, causing lock contention | [src/memory/manager.ts:50](src/memory/manager.ts#L50) | MEDIUM | + +### 18.3 Channel-Specific Quirks + +| Quirk ID | Channel | Behavior | Impact | +|----------|---------|----------|--------| +| QK-TEL-001 | Telegram | Empty reply array silently ignored until recent fix | Message loss | +| QK-WA-001 | WhatsApp | QR code session expires every 14 days requiring re-auth | UX friction | +| QK-DISC-001 | Discord | Rate limits not exponentially backed off | API bans | +| QK-SLACK-001 | Slack | Thread replies don't maintain conversation context | Context loss | + +### 18.4 Command Execution Quirks + +| Quirk ID | Behavior | Evidence | Mitigation Needed | +|----------|----------|----------|-------------------| +| QK-EXEC-001 | `shell: true` bypasses argument sanitization | [src/tools/common/computer-use.ts:180](src/tools/common/computer-use.ts#L180) | Input validation | +| QK-EXEC-002 | Approval timeout hardcoded to 5 minutes | [src/gateway/exec-approval-manager.ts:20](src/gateway/exec-approval-manager.ts#L20) | Make configurable | +| QK-EXEC-003 | Background commands not tracked after server restart | Memory persistence | + +--- + +## 19. Risks, Assumptions & Decisions (RAD Log) + +### 19.1 Assumptions Made During Analysis + +| ID | Assumption | Confidence | Impact if Wrong | +|----|------------|------------|-----------------| +| A-001 | SQLite + sqlite-vec sufficient for production scale | 80% | Need PostgreSQL migration | +| A-002 | TypeScript → Python migration preserves all behavior | 70% | Regression bugs | +| A-003 | 28 channel adapters can be migrated incrementally | 85% | Parallel operation needed | +| A-004 | Memory system behavior is deterministic | 75% | Race condition bugs | +| A-005 | MCP protocol stable enough for 18-month migration | 90% | Protocol version issues | + +### 19.2 Key Decisions Required + +| ID | Decision | Options | Recommendation | Deadline | +|----|----------|---------|----------------|----------| +| D-001 | Migration strategy | Clean rewrite vs Hybrid | Hybrid (Strangler Fig) | Before Phase 1 | +| D-002 | Authentication mechanism | Keep Tailscale vs OAuth2 | Support both | Phase 2 | +| D-003 | Database migration | SQLite only vs Postgres option | SQLite + migration path | Phase 1 | +| D-004 | Channel adapter priority | All 28 vs Core 8 first | Core 8 (Telegram, WhatsApp, Discord, Slack, iMessage, Signal, Email, Web) | Phase 1 | +| D-005 | Python framework | FastAPI vs Litestar | FastAPI (ecosystem) | Phase 1 | + +### 19.3 Risk Register + +| ID | Risk | Probability | Impact | Mitigation | +|----|------|-------------|--------|------------| +| R-001 | Security vulnerabilities in exec workflow | HIGH | CRITICAL | Sandbox + allowlist | +| R-002 | Memory leak from long-running connections | MEDIUM | HIGH | Connection pooling | +| R-003 | Data loss during migration | LOW | CRITICAL | Dual-write period | +| R-004 | Channel API breaking changes | MEDIUM | MEDIUM | Adapter versioning | +| R-005 | Performance regression in Python | MEDIUM | MEDIUM | Benchmark suite | +| R-006 | Community resistance to rewrite | LOW | MEDIUM | Incremental delivery | + +--- + +## 20. Value Proposition & Business Case + +### 20.1 Current Value Delivered + +| Value Category | Current State | Evidence | +|----------------|---------------|----------| +| **Multi-platform reach** | 28 channel integrations | extensions/ directory | +| **Privacy** | Local-first, self-hosted | No cloud dependency | +| **Autonomy** | Executes actions, not just advice | Computer use, shell tools | +| **Memory** | Persistent context across sessions | SQLite + embeddings | +| **Community** | 68,000+ GitHub stars, 8,900+ Discord | External research | + +### 20.2 Migration Value Add + +| Enhancement | Business Value | User Impact | +|-------------|----------------|-------------| +| **Security hardening** | Enterprise adoption, compliance | Trust | +| **Python ecosystem** | Larger contributor pool | More features | +| **Better observability** | Faster debugging | Reliability | +| **Improved testing** | Fewer regressions | Stability | +| **Modern architecture** | Easier extension | Innovation speed | + +### 20.3 Cost-Benefit Analysis + +| Factor | Current (TypeScript) | Target (Python) | +|--------|----------------------|-----------------| +| Security posture | 6/10 (tech debt) | 9/10 (secure-by-default) | +| Maintainability | 5/10 (complexity) | 8/10 (patterns) | +| Test coverage | ~40% estimated | 80% target | +| Deployment complexity | Medium | Low (Docker Compose) | +| Community contribution barrier | Medium (TS) | Low (Python) | + +--- + +## 21. Traceability Matrix + +### 21.1 Requirements → Code Mapping + +| Requirement | Source Files | Test Coverage | +|-------------|--------------|---------------| +| FR-CORE-001: Multi-channel messaging | src/*/bot.ts, extensions/*/src/*.ts | Partial | +| FR-CORE-002: Memory persistence | src/memory/manager.ts | Unit tests exist | +| FR-CORE-003: Command execution | src/tools/common/*.ts | Integration tests | +| FR-CORE-004: Authentication | src/gateway/auth.ts | Manual testing | +| NFR-SEC-001: Input validation | Scattered across files | Incomplete | +| NFR-PERF-001: Response latency | src/server.ts, src/gateway/*.ts | No benchmarks | + +### 21.2 User Stories → Features Mapping + +| User Story | Features Implemented | Gaps | +|------------|---------------------|------| +| US-001: Multi-platform access | 28 channels | Sync inconsistent | +| US-002: Remember context | Memory manager | No explicit forget | +| US-003: Execute commands | Computer use tools | No audit trail | +| US-004: Secure authentication | Tailscale + password | No MFA | +| US-005: Conversation threading | Per-channel threads | Cross-channel lost | + +### 21.3 Security Requirements → Controls + +| Security Req | Current Control | Gap | +|--------------|-----------------|-----| +| SR-001: Prevent injection | Basic sanitization | Incomplete coverage | +| SR-002: Authenticate users | Tailscale/password | Timing attacks possible | +| SR-003: Authorize actions | Human approval | No role-based | +| SR-004: Audit activities | Logging exists | No centralized trail | +| SR-005: Protect secrets | Environment vars | No vault integration | + +--- + +## 22. Next Steps for Migration + +### 22.1 Pre-Migration Checklist + +- [ ] **Document all 28 channel behaviors** with integration tests +- [ ] **Capture memory search edge cases** in test fixtures +- [ ] **Record exact authentication flows** including error states +- [ ] **Map all environment variables** to configuration schema +- [ ] **Create golden file outputs** for regression testing +- [ ] **Document all WebSocket message formats** with examples + +### 22.2 Migration Phase 1 Priorities + +| Priority | Item | Rationale | +|----------|------|-----------| +| P0 | Security core (auth, input validation) | Foundation for everything | +| P0 | Memory system (SQLite + embeddings) | Critical data layer | +| P1 | Gateway server (WebSocket) | Core communication | +| P1 | Core 8 channel adapters | 95% of usage | +| P2 | Computer use tools | High-value feature | +| P2 | MCP server implementation | Extensibility | + +### 22.3 Recommended Test Strategy + +| Layer | Approach | Target Coverage | +|-------|----------|-----------------| +| Unit tests | pytest with fixtures | 80% line coverage | +| Integration tests | Docker Compose test environment | All API endpoints | +| E2E tests | Playwright for web UI | Critical user journeys | +| Security tests | OWASP ZAP + custom scripts | All input vectors | +| Performance tests | Locust load testing | Baseline + regression | + +--- + +## 23. Business Logic Preservation Checklist + +### 23.1 Memory System Preservation + +| Logic | Current Implementation | Migration Notes | +|-------|------------------------|-----------------| +| Embedding generation | OpenAI API, text-embedding-3-small | Keep same model | +| Similarity search | sqlite-vec cosine similarity | Preserve threshold 0.7 | +| Memory consolidation | Batch of 100, summarize older | Keep batch size | +| Conversation threading | Thread ID based | Preserve exact logic | +| Context window management | Truncate at token limit | Same algorithm | + +### 23.2 Authentication Preservation + +| Logic | Current Implementation | Migration Notes | +|-------|------------------------|-----------------| +| Tailscale identity | Local socket whois | Preserve fallback behavior | +| Password verification | crypto.timingSafeEqual | Use secrets.compare_digest | +| Session management | In-memory, not persisted | Consider persistence | +| Token refresh | Background interval | Match timing | + +### 23.3 Channel Adapter Preservation + +| Logic | Current Implementation | Migration Notes | +|-------|------------------------|-----------------| +| Message normalization | Per-adapter transform | Define interface contract | +| Rate limiting | Per-channel backoff | Preserve exact timings | +| Reconnection | Exponential backoff | Same parameters | +| Error handling | Retry 3x then fail | Keep retry count | +| Media handling | Download → process → respond | Same flow | + +### 23.4 Command Execution Preservation + +| Logic | Current Implementation | Migration Notes | +|-------|------------------------|-----------------| +| Approval workflow | WebSocket notification → wait → proceed | Same state machine | +| Timeout handling | 5 minute default | Make configurable | +| Output capture | Streaming stdout/stderr | Preserve streaming | +| Exit code handling | Return to AI for next action | Same behavior | + +--- + +## 24. Output Validation Checklist + +### 24.1 Functional Parity Tests + +| Test Category | Validation Method | Pass Criteria | +|---------------|-------------------|---------------| +| Message processing | Golden file comparison | Byte-identical output | +| Memory retrieval | Same queries, same results | Result ordering matches | +| Authentication | Same credentials, same outcome | Timing within 10% | +| Command execution | Same commands, same output | Exit codes match | +| Error messages | Error scenario replay | Message text matches | + +### 24.2 Performance Baseline + +| Metric | Current Value | Acceptable Range | +|--------|---------------|------------------| +| Message latency (p50) | TBD - measure | ±20% | +| Message latency (p99) | TBD - measure | ±30% | +| Memory search latency | TBD - measure | ±20% | +| Connection startup | TBD - measure | ±50% | +| Memory usage (idle) | TBD - measure | ±25% | + +### 24.3 Security Validation + +| Security Test | Expected Outcome | Tool | +|---------------|------------------|------| +| SQL injection attempts | All blocked | sqlmap | +| XSS payloads | All sanitized | Custom suite | +| Command injection | All blocked | Custom suite | +| SSRF attempts | All blocked | Custom suite | +| Auth bypass attempts | All rejected | Custom suite | +| Timing attacks | Constant time | timing-safe tests | + +--- + +## Appendix A: Configuration Variable Catalog + +### A.1 Required Environment Variables + +| Variable | Purpose | Default | Sensitive | +|----------|---------|---------|-----------| +| `OPENAI_API_KEY` | Embeddings + chat | None | YES | +| `ANTHROPIC_API_KEY` | Claude API access | None | YES | +| `DATABASE_PATH` | SQLite file location | ./data/moltbot.db | NO | +| `GATEWAY_PORT` | WebSocket server port | 3000 | NO | +| `AUTH_PASSWORD` | Gateway authentication | None | YES | + +### A.2 Optional Configuration + +| Variable | Purpose | Default | +|----------|---------|---------| +| `LOG_LEVEL` | Logging verbosity | info | +| `MEMORY_BATCH_SIZE` | Consolidation batch | 100 | +| `EMBEDDING_MODEL` | OpenAI model name | text-embedding-3-small | +| `MAX_CONTEXT_TOKENS` | Context window limit | 8000 | +| `EXEC_TIMEOUT_MS` | Command timeout | 300000 | + +### A.3 Channel-Specific Configuration + +| Channel | Required Variables | Optional Variables | +|---------|-------------------|-------------------| +| Telegram | `TELEGRAM_BOT_TOKEN` | `TELEGRAM_WEBHOOK_URL` | +| Discord | `DISCORD_BOT_TOKEN` | `DISCORD_GUILD_ID` | +| WhatsApp | None (QR auth) | `WHATSAPP_SESSION_PATH` | +| Slack | `SLACK_BOT_TOKEN`, `SLACK_APP_TOKEN` | `SLACK_SIGNING_SECRET` | +| Email | `IMAP_*`, `SMTP_*` credentials | `EMAIL_POLL_INTERVAL` | + +--- + +## Appendix B: Error Code Catalog + +### B.1 Authentication Errors + +| Code | Message | Cause | Resolution | +|------|---------|-------|------------| +| AUTH_001 | "Authentication required" | Missing credentials | Provide password/token | +| AUTH_002 | "Invalid credentials" | Wrong password | Check AUTH_PASSWORD | +| AUTH_003 | "Session expired" | Token timeout | Re-authenticate | +| AUTH_004 | "Tailscale identity not found" | Not on Tailscale | Use password auth | + +### B.2 Memory Errors + +| Code | Message | Cause | Resolution | +|------|---------|-------|------------| +| MEM_001 | "Embedding generation failed" | OpenAI API error | Check API key/quota | +| MEM_002 | "Database locked" | Concurrent access | Enable WAL mode | +| MEM_003 | "Memory search timeout" | Large dataset | Optimize query | + +### B.3 Channel Errors + +| Code | Message | Cause | Resolution | +|------|---------|-------|------------| +| CHAN_001 | "Connection failed" | Network/API issue | Retry with backoff | +| CHAN_002 | "Rate limited" | Too many requests | Wait for reset | +| CHAN_003 | "Authentication failed" | Invalid bot token | Reconfigure channel | +| CHAN_004 | "Message too long" | Exceeds platform limit | Truncate/split | + +--- + +## Appendix C: Glossary of Domain Terms + +| Term | Definition | Context | +|------|------------|---------| +| **Adapter** | Channel-specific integration module | Gateway pattern | +| **Consolidation** | Process of summarizing old memories | Memory management | +| **Gateway** | Central WebSocket server for all channels | Architecture | +| **Human-in-the-loop** | Approval workflow for sensitive actions | Security | +| **MCP** | Model Context Protocol for tool extension | Anthropic standard | +| **Memory fragment** | Single stored context unit with embedding | Storage model | +| **Thread** | Conversation context within a channel | Messaging | +| **Tool** | Executable capability exposed to AI | Agent framework | + +--- + +## Appendix D: File-to-Functionality Index + +### D.1 Core System Files + +| File Path | Primary Function | +|-----------|------------------| +| src/server.ts | Main entry point, server initialization | +| src/gateway/server.ts | WebSocket gateway server | +| src/gateway/auth.ts | Authentication logic | +| src/memory/manager.ts | Memory storage and retrieval | +| src/tools/common/*.ts | Shared tool implementations | + +### D.2 Channel Adapter Files + +| File Path | Channel | +|-----------|---------| +| src/telegram/bot.ts | Telegram | +| src/discord/monitor.ts | Discord | +| extensions/whatsapp/src/client.ts | WhatsApp | +| src/imessage/*.ts | iMessage | +| extensions/slack/src/*.ts | Slack | + +### D.3 Configuration Files + +| File Path | Purpose | +|-----------|---------| +| .env.example | Environment variable template | +| config/default.json | Default configuration | +| package.json | Dependencies and scripts | +| tsconfig.json | TypeScript configuration | + +--- + +*End of Functional Specification - Legacy System* +*Document Version: 1.0* +*Generated: 2026-01-29* +*Analysis Chain ID: 20260129-202219* diff --git a/.analysis/moltbotsec-20260129-202219/reports/functional-spec-target.md b/.analysis/moltbotsec-20260129-202219/reports/functional-spec-target.md new file mode 100644 index 000000000..1f59d9a04 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/reports/functional-spec-target.md @@ -0,0 +1,1522 @@ +# Functional Specification - Target System + +**Project**: moltbot +**Analysis Date**: 2026-01-29 +**Status**: Target System Design +**Based On**: functional-spec-legacy.md + +--- + +## 1. Executive Summary + +**WHAT**: The target Moltbot system is a modular, plugin-based personal AI assistant that operates as an autonomous agent across messaging channels. Users install only the capabilities they need. Rebuilt on Python 3.12+ with FastAPI for improved security, maintainability, and a manageable codebase. + +**WHO**: Individual users seeking unified AI across messaging platforms, developers automating workflows, and power users requiring autonomous task execution with security controls (same as legacy). + +**WHY**: To maintain all existing functionality while achieving: +- **Modular architecture**: Install only what you need (no bloated dependencies) +- **Secure-by-default**: Validated inputs, audit trails +- **Maintainable codebase**: Each plugin is independently testable and versionable +- **Enhanced observability**: OpenTelemetry for production debugging + +**MODERNIZATION GOALS**: + +1. **Plugin-based architecture**: Core + installable plugins for channels, AI providers, and extensions +2. Security-first architecture with validated inputs and audit trails +3. 80% test coverage with pytest for regression prevention +4. OpenTelemetry observability for production debugging +5. Simplified deployment via Docker Compose + +**KEY CHANGES FROM LEGACY**: + +| Aspect | Legacy | Target | Rationale | +|--------|--------|--------|-----------| +| Language | TypeScript/Node.js | Q1: Python 3.12+ | Larger contributor pool, better ML ecosystem | +| Database | SQLite + better-sqlite3 | Q2: SQLite + sqlite-vec (unchanged) | Proven, migration-free | +| Message Bus | Express WebSocket | Q3: WebSocket + in-memory | FastAPI native WebSocket | +| Package Manager | npm/pnpm | Q4: uv | Faster, reproducible | +| Deployment | Manual/Docker | Q5: Docker Compose | Standardized orchestration | +| Testing | vitest | Q10: pytest (80% coverage) | Industry standard | +| Observability | Console logging | Q8: OpenTelemetry | Production-grade | +| Architecture | Monolithic (all 28 channels) | Plugin-based (install what you need) | Manageable codebase | + +--- + +## 1.1 Plugin Architecture Overview + +### Design Philosophy + +**Install only what you need.** The core system is minimal; capabilities are added via plugins. + +```mermaid +graph TB + subgraph Core["moltbot (core)"] + GATEWAY["Gateway"] + AUTH["Auth"] + MEMORY["Memory"] + AGENT["Agent"] + SCHEDULER["Scheduler"] + end + + subgraph Channels["Channel Plugins"] + TELEGRAM["moltbot-telegram"] + DISCORD["moltbot-discord"] + SLACK["moltbot-slack"] + WHATSAPP["moltbot-whatsapp"] + SIGNAL["moltbot-signal"] + MORE_CH["... 20+ more"] + end + + subgraph AI["AI Provider Plugins"] + CLAUDE["moltbot-claude"] + OPENAI["moltbot-openai"] + GEMINI["moltbot-gemini"] + LOCAL["moltbot-local"] + end + + subgraph Extensions["Extension Plugins"] + VOICE["moltbot-voice"] + CRON["moltbot-cron"] + WEB["moltbot-web"] + TUI["moltbot-tui"] + end + + Core --> Channels + Core --> AI + Core --> Extensions +``` + +### Plugin Categories + +| Category | Package Pattern | Purpose | Install Example | +|----------|-----------------|---------|-----------------| +| **Core** | `moltbot` | Essential runtime | `uv pip install moltbot` | +| **Channels** | `moltbot-{platform}` | Messaging adapters | `uv pip install moltbot-telegram` | +| **AI Providers** | `moltbot-{provider}` | AI inference | `uv pip install moltbot-claude` | +| **Extensions** | `moltbot-{feature}` | Optional features | `uv pip install moltbot-voice` | + +### Installation Scenarios + +| Use Case | Installation Command | Packages | +|----------|---------------------|----------| +| Minimal personal | `uv pip install moltbot moltbot-telegram moltbot-claude` | 3 | +| Multi-channel personal | `uv pip install "moltbot[telegram,discord,signal,claude]"` | 5 | +| Business (Slack/Teams) | `uv pip install "moltbot[slack,teams,openai,voice]"` | 5 | +| Developer (all) | `uv pip install "moltbot[all]"` | All | + +### User Benefits + +| Benefit | Description | +|---------|-------------| +| **Smaller footprint** | Only install dependencies you need | +| **Faster startup** | Load only required plugins | +| **Simpler updates** | Update individual plugins independently | +| **Easier debugging** | Isolated plugin issues | +| **Custom stacks** | Mix and match channels + AI providers | + +--- + +## 2. Current State - Problem & Goals + +### Modernization Objectives + +Based on user preferences and legacy analysis: + +- **Security Hardening** (Addresses legacy issue: timing attacks, input validation gaps) +- **Test Coverage Improvement** (User preference: Q10 - 80% target) +- **Observability Enhancement** (User preference: Q8 - OpenTelemetry) +- **Maintainability** (Technical improvement: Python type hints + mypy) + +### Target KPIs/Metrics + +| Metric | Legacy Value | Target Value | Improvement | +|--------|--------------|--------------|-------------| +| Response Timeout | 30000ms | 30000ms | EXACT (preserved) | +| Memory Search Results | 10 default | 10 default | EXACT (preserved) | +| Embedding Batch Size | 100 items | 100 items | EXACT (preserved) | +| Test Coverage | ~40% estimated | 80% | +40% | +| Startup Time | N/A | < 10s | Measurable | +| Message Latency (p50) | N/A | < 500ms | Measurable | + +--- + +## 3. Personas & User Journeys + +### Personas (Target System) + +| Persona | Legacy Capabilities | Target Capabilities | Changes | +|---------|---------------------|---------------------|---------| +| **Owner** | Full access, command execution, configuration | Full access, command execution, configuration | EXACT | +| **Authenticated User** | Chat, memory search, limited commands | Chat, memory search, limited commands | EXACT | +| **Tailscale User** | Identity-verified access via Tailscale | Identity-verified access via Tailscale | EXACT | +| **Guest** | Read-only, no command execution | Read-only, no command execution | EXACT | + +### Target User Journeys + +```mermaid +journey + title User Interaction with Moltbot (Target) + section Authentication + Connect via WhatsApp/Telegram: 5: User + Verify identity (QR/token): 3: System + Establish session: 5: System + section Chat Interaction + Send message: 5: User + Process with AI model: 4: System + Search memory for context: 4: System + Generate response: 5: System + Receive reply: 5: User + section Command Execution + Request command execution: 3: User + Create approval request: 4: System + User approves via channel: 5: User + Execute command: 4: System + Return results: 5: System +``` + +**Changes from Legacy**: +- Journey 1 (Auth): EXACT - Same flow, Python implementation +- Journey 2 (Chat): EXACT - Same flow, FastAPI backend +- Journey 3 (Commands): ENHANCED - Better audit logging + +--- + +## 4. Use Cases (Target System) + +### UC-001: Multi-Channel Message Processing + +| Attribute | Legacy | Target | Status | +|-----------|--------|--------|--------| +| **ID** | UC-001 | UC-001 | EXACT | +| **Name** | Process Incoming Message | Process Incoming Message | | +| **Actor(s)** | User, AI Agent | User, AI Agent | | +| **Priority** | CRITICAL | CRITICAL | | + +**Modernization Status**: EXACT + +**Changes from Legacy**: +- Implementation language: TypeScript → Python +- Framework: Express → FastAPI +- All business logic preserved exactly + +**Main Flow (Target)**: +1. User sends message via messaging platform +2. System receives message via channel adapter (Python async) +3. System retrieves conversation context from memory (aiosqlite) +4. System sends context + message to AI model +5. AI model generates response +6. System sends response back via channel + +**Alternative Flows**: Same as legacy +**Exception Flows**: Same as legacy + +--- + +### UC-002: Gateway Authentication + +| Attribute | Legacy | Target | Status | +|-----------|--------|--------|--------| +| **ID** | UC-002 | UC-002 | ENHANCED | +| **Name** | Authenticate Gateway Connection | Authenticate Gateway Connection | | +| **Actor(s)** | Client Application, Gateway Server | Client Application, Gateway Server | | +| **Priority** | CRITICAL | CRITICAL | | + +**Modernization Status**: ENHANCED + +**Changes from Legacy**: +- Timing-safe: crypto.timingSafeEqual → secrets.compare_digest +- Enhanced audit logging for all auth attempts +- Rate limiting with configurable thresholds + +**Main Flow (Target)**: +1. Client connects to gateway endpoint (FastAPI WebSocket) +2. System checks if local direct request (loopback) +3. System validates authentication credentials (Pydantic) +4. System uses timing-safe comparison for secrets (secrets.compare_digest) +5. System establishes authenticated session +6. System logs auth event to audit trail (NEW) + +--- + +### UC-003: Command Execution Approval + +| Attribute | Legacy | Target | Status | +|-----------|--------|--------|--------| +| **ID** | UC-003 | UC-003 | ENHANCED | +| **Name** | Approve Command Execution | Approve Command Execution | | +| **Actor(s)** | User, AI Agent, Approval System | User, AI Agent, Approval System | | +| **Priority** | CRITICAL | CRITICAL | | + +**Modernization Status**: ENHANCED + +**Changes from Legacy**: +- Comprehensive audit trail for all approvals/denials +- Configurable command allowlist validation +- Structured logging for compliance + +**Main Flow (Target)**: +1. Agent creates approval request with command details +2. System validates command against allowlist (NEW) +3. System generates approval record with timeout +4. System notifies user via active channel +5. User reviews and approves command +6. System logs approval decision (ENHANCED) +7. System resolves approval promise +8. Agent executes command in sandbox (ENHANCED) + +--- + +### UC-004: Memory Search + +| Attribute | Legacy | Target | Status | +|-----------|--------|--------|--------| +| **ID** | UC-004 | UC-004 | EXACT | +| **Name** | Search Memory with Hybrid Vector+Keyword | Search Memory with Hybrid Vector+Keyword | | +| **Priority** | CRITICAL | CRITICAL | | + +**Modernization Status**: EXACT + +**Changes from Legacy**: +- Implementation: TypeScript → Python +- Database library: better-sqlite3 → aiosqlite +- Vector search: sqlite-vec (unchanged) + +--- + +### UC-005: WhatsApp Channel Setup + +| Attribute | Legacy | Target | Status | +|-----------|--------|--------|--------| +| **ID** | UC-005 | UC-005 | EXACT | +| **Name** | Pair WhatsApp Device | Pair WhatsApp Device | | +| **Priority** | HIGH | HIGH | | + +**Modernization Status**: EXACT + +**Changes from Legacy**: +- WhatsApp Web protocol implementation in Python +- Same QR code pairing flow + +--- + +### UC-006: Telegram Bot Integration + +| Attribute | Legacy | Target | Status | +|-----------|--------|--------|--------| +| **ID** | UC-006 | UC-006 | EXACT | +| **Name** | Configure Telegram Bot | Configure Telegram Bot | | +| **Priority** | HIGH | HIGH | | + +**Modernization Status**: EXACT + +**Changes from Legacy**: +- Python-telegram-bot library +- Same bot token configuration flow + +--- + +### UC-007: Discord Server Monitoring + +| Attribute | Legacy | Target | Status | +|-----------|--------|--------|--------| +| **ID** | UC-007 | UC-007 | EXACT | +| **Name** | Monitor Discord Messages | Monitor Discord Messages | | +| **Priority** | HIGH | HIGH | | + +**Modernization Status**: EXACT + +**Changes from Legacy**: +- discord.py library +- Same monitoring and response flow + +--- + +### UC-008: Browser Automation + +| Attribute | Legacy | Target | Status | +|-----------|--------|--------|--------| +| **ID** | UC-008 | UC-008 | EXACT | +| **Name** | Execute Browser Actions | Execute Browser Actions | | +| **Priority** | MEDIUM | MEDIUM | | + +**Modernization Status**: EXACT + +**Changes from Legacy**: +- Playwright Python bindings +- Same CDP integration pattern + +--- + +### UC-009: Scheduled Task Execution + +| Attribute | Legacy | Target | Status | +|-----------|--------|--------|--------| +| **ID** | UC-009 | UC-009 | EXACT | +| **Name** | Run Cron Job | Run Cron Job | | +| **Priority** | MEDIUM | MEDIUM | | + +**Modernization Status**: EXACT + +**Changes from Legacy**: +- APScheduler library +- Same cron expression support + +--- + +### UC-010: Voice Call Handling + +| Attribute | Legacy | Target | Status | +|-----------|--------|--------|--------| +| **ID** | UC-010 | UC-010 | EXACT | +| **Name** | Handle Voice Call | Handle Voice Call | | +| **Priority** | LOW | LOW | | + +**Modernization Status**: EXACT + +**Changes from Legacy**: +- Twilio Python SDK +- Same voice flow + +--- + +## 5. User Stories (Target System) + +### CRITICAL Stories + +#### US-CRIT-001: Send Message via WhatsApp + +**Legacy Reference**: US-CRIT-001 (functional-spec-legacy.md) +**Status**: EXACT +**Priority**: CRITICAL +**Actor**: User + +**Story**: +> As a **user**, +> I want to **send messages to my AI assistant via WhatsApp**, +> So that **I can interact naturally from my phone**. + +**Changes from Legacy**: +- None - identical behavior required + +**Acceptance Criteria (Target)**: + +Scenario: Send text message + Given I have paired my WhatsApp account + And the moltbot gateway is running (Python/FastAPI) + When I send a text message to the bot + Then I should receive an AI-generated response + And the conversation should be stored in memory + And the interaction should be logged with correlation ID (NEW) + +--- + +#### US-CRIT-002: Authenticate with Token + +**Legacy Reference**: US-CRIT-002 (functional-spec-legacy.md) +**Status**: ENHANCED +**Priority**: CRITICAL +**Actor**: Client Application + +**Story**: +> As a **client application**, +> I want to **authenticate using a secure token**, +> So that **only authorized clients can access the gateway**. + +**Changes from Legacy**: +- Enhanced: Timing-safe comparison with secrets.compare_digest +- Enhanced: All auth attempts logged to audit trail + +**Acceptance Criteria (Target)**: + +Scenario: Valid token authentication + Given I have a valid gateway token + And the gateway server is running + When I connect with the token in headers + Then I should be authenticated + And my session should be established + And the auth event should be logged (NEW) + +Scenario: Invalid token rejected + Given I have an invalid token + When I attempt to connect + Then I should receive a 401 error + And no session should be created + And the failed attempt should be logged (NEW) + +--- + +#### US-CRIT-003: Approve Command Execution + +**Legacy Reference**: US-CRIT-003 (functional-spec-legacy.md) +**Status**: ENHANCED +**Priority**: CRITICAL +**Actor**: User + +**Story**: +> As a **user**, +> I want to **approve or deny command executions**, +> So that **I maintain control over what my AI can do**. + +**Changes from Legacy**: +- Enhanced: Command allowlist validation +- Enhanced: Full audit trail of all approvals/denials + +**Acceptance Criteria (Target)**: + +Scenario: Approve shell command + Given the AI requests to execute a shell command + And the command is on the allowlist (NEW) + And I receive an approval notification + When I approve the command + Then the command should execute + And I should see the results + And the approval should be recorded in audit log (NEW) + +Scenario: Deny dangerous command + Given the AI requests to delete files + When I deny the command + Then the command should not execute + And the AI should acknowledge the denial + And the denial should be recorded in audit log (NEW) + +--- + +### STANDARD Stories + +#### US-STD-001: Search Memory + +**Legacy Reference**: US-STD-001 (functional-spec-legacy.md) +**Status**: EXACT +**Priority**: STANDARD +**Actor**: AI Agent + +**Story**: +> As an **AI agent**, +> I want to **search the user's memory for relevant context**, +> So that **I can provide informed responses**. + +**Changes from Legacy**: +- None - identical behavior required + +--- + +### NEW Stories (Target Only) + +#### US-NEW-001: View Audit Trail + +**Status**: NEW (no legacy equivalent) +**Rationale**: Required for enterprise compliance and security monitoring + +**Story**: +> As an **administrator**, +> I want to **view the audit trail of all actions**, +> So that **I can monitor for security issues and compliance**. + +**Acceptance Criteria (Target)**: + +Scenario: View recent audit events + Given I am an authenticated administrator + When I query the audit log + Then I should see all recent events with correlation IDs + And each event should include timestamp, user, action, and outcome + +--- + +#### US-NEW-002: Monitor System Health + +**Status**: NEW (no legacy equivalent) +**Rationale**: Required for production observability (Q8 preference) + +**Story**: +> As an **operator**, +> I want to **monitor system health via metrics endpoint**, +> So that **I can detect issues before they impact users**. + +**Acceptance Criteria (Target)**: + +Scenario: Access health metrics + Given the system is running + When I query the /metrics endpoint + Then I should see Prometheus-format metrics + And metrics should include message_count, latency_p50, active_connections + +--- + +## 6. Business Logic (Target System) + +### 6.1 Validation Rules + +#### VAL-001: Authentication Credentials + +**Legacy Reference**: VAL-001 (functional-spec-legacy.md) +**Preservation Status**: EXACT + +| Field | Legacy Rule | Target Rule | Change Reason | +|-------|-------------|-------------|---------------| +| token | Non-empty string | Non-empty string (Pydantic validated) | Framework change | +| password | Timing-safe compare | secrets.compare_digest | Language equivalent | + +--- + +### 6.2 Decision Trees + +#### DT-001: Authentication Method Selection + +**Legacy Reference**: DT-001 +**Preservation Status**: EXACT + +```mermaid +flowchart TD + A[Connection Request] --> B{Is Loopback?} + B -->|Yes| C[Auto-authenticate] + B -->|No| D{Tailscale Enabled?} + D -->|Yes| E{Tailscale Identity?} + E -->|Found| F[Authenticate via Tailscale] + E -->|Not Found| G{Password Auth?} + D -->|No| G + G -->|Valid| H[Authenticate via Password] + G -->|Invalid| I[Reject 401] +``` + +**Changes from Legacy**: +- None - identical decision logic + +--- + +### 6.3 Calculation Formulas + +#### CALC-001: Memory Similarity Score + +**Legacy Reference**: CALC-001 +**Preservation Status**: EXACT +**Precision**: Float, threshold 0.7 + +**Formula (Target)**: +```text +similarity = cosine_similarity(query_embedding, memory_embedding) +include_result = similarity >= 0.7 +``` + +**Changes from Legacy**: +- None - identical calculation + +--- + +### 6.4 Business Constants + +| Constant | Legacy Value | Target Value | Change Reason | +|----------|--------------|--------------|---------------| +| MEMORY_SIMILARITY_THRESHOLD | 0.7 | 0.7 | EXACT | +| APPROVAL_TIMEOUT_MS | 300000 (5 min) | 300000 (5 min) | EXACT | +| EMBEDDING_BATCH_SIZE | 100 | 100 | EXACT | +| MEMORY_SEARCH_LIMIT | 10 | 10 | EXACT | +| RESPONSE_TIMEOUT_MS | 30000 | 30000 | EXACT | + +--- + +### 6.5 Data Transformations + +#### TRANSFORM-001: Message Normalization + +**Legacy Reference**: TRANSFORM-001 +**Preservation Status**: EXACT + +| Source Field | Target Field | Legacy Transform | Target Transform | +|--------------|--------------|------------------|------------------| +| platform_message | normalized_message | Channel adapter | Channel adapter (Python) | +| raw_text | cleaned_text | Trim, sanitize | Trim, sanitize | + +--- + +## 7. State Machines (Target System) + +### SM-001: Approval Request State Machine + +**Legacy Reference**: SM-001 (functional-spec-legacy.md) +**Preservation Status**: EXACT + +```mermaid +stateDiagram-v2 + [*] --> Pending + Pending --> Approved : User approves + Pending --> Denied : User denies + Pending --> Timeout : Timer expires + Approved --> Executing : Start execution + Executing --> Completed : Success + Executing --> Failed : Error + Approved --> [*] + Denied --> [*] + Timeout --> [*] + Completed --> [*] + Failed --> [*] +``` + +**Changes from Legacy**: + +| Aspect | Legacy | Target | Reason | +|--------|--------|--------|--------| +| States | 6 states | 6 states | EXACT | +| Transitions | 8 transitions | 8 transitions | EXACT | +| Implementation | TypeScript Promise | Python asyncio | Language equivalent | + +--- + +### SM-002: Channel Connection State Machine + +**Legacy Reference**: SM-002 +**Preservation Status**: EXACT + +```mermaid +stateDiagram-v2 + [*] --> Disconnected + Disconnected --> Connecting : Connect request + Connecting --> Connected : Success + Connecting --> Disconnected : Max retries + Connected --> Reconnecting : Connection lost + Reconnecting --> Connected : Success + Reconnecting --> Disconnected : Max retries +``` + +**Changes from Legacy**: +- None - identical state machine + +--- + +## 8. Configuration-Driven Behaviors (Target System) + +### Config-Driven Feature Flags + +| Flag | Legacy Default | Target Default | Change Reason | +|------|----------------|----------------|---------------| +| TAILSCALE_AUTH_ENABLED | true | true | EXACT | +| MEMORY_ENABLED | true | true | EXACT | +| EXEC_APPROVAL_REQUIRED | true | true | EXACT | +| AUDIT_LOGGING_ENABLED | N/A | true | NEW - security requirement | + +### Config-Driven Business Rules (Target) + +| Config Key | Type | Legacy | Target | Impact | +|------------|------|--------|--------|--------| +| memory.similarity_threshold | float | 0.7 | 0.7 | EXACT | +| approval.timeout_seconds | int | 300 | 300 | EXACT | +| auth.rate_limit_attempts | int | N/A | 5 | NEW - brute force protection | +| auth.rate_limit_window_seconds | int | N/A | 300 | NEW - brute force protection | + +### Environment-Specific Behaviors (Target) + +Based on Q5 (Deployment: Docker Compose) and Q7 (Container: Docker): + +| Behavior | Dev | Staging | Prod | Target Change | +|----------|-----|---------|------|---------------| +| Log Level | DEBUG | INFO | WARNING | Configurable via LOG_LEVEL | +| Audit Logging | Optional | Required | Required | NEW - compliance | +| Rate Limiting | Disabled | Enabled | Enabled | NEW - security | +| Health Checks | Optional | Required | Required | NEW - Docker healthcheck | + +--- + +*End of Part 1 - Sections 1-8* + +--- + +# PART 2: Requirements & Integration (Sections 9-17) + +--- + +## 9. Scope / Out-of-Scope (Target System) + +### In Scope (Target Features) + +| Feature/Capability | Legacy Status | Target Status | Migration | +|--------------------|---------------|---------------|-----------| +| Multi-channel messaging gateway | Existing | PRESERVE | TypeScript → Python | +| Token/password/Tailscale auth | Existing | PRESERVE | Use secrets.compare_digest | +| Command execution approval | Existing | ENHANCE | Add command allowlist | +| Vector-based memory search | Existing | PRESERVE | Same sqlite-vec | +| WhatsApp integration | Existing | PRESERVE | Python WhatsApp library | +| Telegram bot | Existing | PRESERVE | python-telegram-bot | +| Discord monitoring | Existing | PRESERVE | discord.py | +| Slack integration | Existing | PRESERVE | slack-sdk | +| Browser automation | Existing | PRESERVE | Playwright Python | +| Cron job scheduling | Existing | PRESERVE | APScheduler | +| Voice call handling | Existing | PRESERVE | Twilio Python | +| SSRF protection | Existing | PRESERVE | DNS pinning in Python | +| Security audit logging | Existing | ENHANCE | Structured JSON + OpenTelemetry | +| Configuration management | Existing | PRESERVE | Zod → Pydantic | +| Health/metrics endpoints | NEW | NEW | Prometheus format | +| Rate limiting | NEW | NEW | Brute force protection | + +### Out of Scope (Target System) + +| Capability | Legacy Status | Reason for Exclusion | +|------------|---------------|---------------------| +| Multi-tenant support | Not Found | Single-user design preserved | +| Distributed deployment | Not Found | Local-first philosophy | +| Plugin marketplace | Not Found | Post-stabilization feature | +| Admin dashboard UI | Not Found | CLI/TUI sufficient | + +--- + +## 10. Functional Requirements (Target System) + +### CRITICAL Features (Preserved from Legacy) + +#### FR-CRIT-001: Multi-Channel Message Gateway + +**Legacy Reference**: FR-CRIT-001 (functional-spec-legacy.md) +**Preservation Status**: EXACT + +- **As a** user, **the system provides** unified AI assistant access across 28 messaging platforms, + **so that** I can interact with my AI from any device or platform. +- **Target Implementation**: + - Language: Q1 (Python 3.12+) + - Framework: FastAPI with WebSocket support + - Database: Q2 (SQLite + sqlite-vec) +- **Changes from Legacy**: + - Implementation language: TypeScript → Python + - Framework: Express.js → FastAPI +- **Acceptance Criteria (Target)**: + - AC-1: Messages received on any channel processed by AI within 2s (p95) + - AC-2: Responses delivered back to originating channel + - AC-3: All interactions logged with correlation IDs + +--- + +#### FR-CRIT-002: Timing-Safe Authentication + +**Legacy Reference**: FR-CRIT-002 (functional-spec-legacy.md) +**Preservation Status**: EXACT + +- **As a** security requirement, **the system provides** timing-safe credential verification, + **so that** attackers cannot use timing attacks to guess credentials. +- **Target Implementation**: + - Language: Q1 (Python 3.12+) + - Method: `secrets.compare_digest()` (Python equivalent) + - Security: Q9 (Keep current Token/Password/Tailscale) +- **Changes from Legacy**: + - `crypto.timingSafeEqual` → `secrets.compare_digest` +- **Acceptance Criteria (Target)**: + - AC-1: Credential verification time constant regardless of match position + - AC-2: All auth attempts logged to audit trail + +--- + +#### FR-CRIT-003: Command Execution Gating + +**Legacy Reference**: FR-CRIT-003 (functional-spec-legacy.md) +**Preservation Status**: ENHANCED + +- **As a** user, **the system provides** human-in-the-loop approval for command execution, + **so that** I maintain control over AI actions on my system. +- **Target Implementation**: + - Language: Q1 (Python 3.12+) + - Pattern: asyncio-based approval workflow +- **Changes from Legacy**: + - ADD: Command allowlist validation before approval prompt + - ADD: Comprehensive audit trail for all decisions +- **Acceptance Criteria (Target)**: + - AC-1: Commands not on allowlist blocked without prompting user + - AC-2: All approvals/denials recorded with timestamp, user, reason + - AC-3: Timeout behavior preserved (5 min default) + +--- + +#### FR-CRIT-004: Vector-Based Memory Search + +**Legacy Reference**: FR-CRIT-004 (functional-spec-legacy.md) +**Preservation Status**: EXACT + +- **As an** AI agent, **the system provides** semantic search across conversation history, + **so that** I can provide contextually relevant responses. +- **Target Implementation**: + - Database: Q2 (SQLite + sqlite-vec) - unchanged + - Search: Hybrid vector + BM25 keyword (unchanged) +- **Changes from Legacy**: + - Implementation: TypeScript → Python with aiosqlite + - Same search algorithm and weights +- **Acceptance Criteria (Target)**: + - AC-1: Same search results for identical queries (golden file tests) + - AC-2: Search latency < 100ms + +--- + +### NEW Features (Target Only) + +#### FR-NEW-001: Audit Trail Query + +**Status**: NEW (no legacy equivalent) +**Rationale**: Required for enterprise compliance (EU AI Act) and security monitoring +**Related User Preference**: Q8 (OpenTelemetry), External Research (Enterprise requirements) + +- **As an** administrator, **the system provides** queryable audit trail of all actions, + **so that** I can monitor for security issues and demonstrate compliance. +- **Acceptance Criteria**: + - AC-1: All auth events, command executions, and tool calls logged + - AC-2: Logs include correlation IDs for request tracing + - AC-3: Sensitive data (tokens, passwords) redacted from logs + +--- + +#### FR-NEW-002: Health Monitoring Endpoints + +**Status**: NEW (no legacy equivalent) +**Rationale**: Required for production observability (Q8 preference) +**Related User Preference**: Q5 (Docker Compose), Q8 (Prometheus) + +- **As an** operator, **the system provides** health check and metrics endpoints, + **so that** I can monitor system health and detect issues proactively. +- **Acceptance Criteria**: + - AC-1: /health returns 200 when system operational + - AC-2: /ready returns 200 when all dependencies connected + - AC-3: /metrics returns Prometheus-format metrics + +--- + +#### FR-NEW-003: Rate Limiting + +**Status**: NEW (no legacy equivalent) +**Rationale**: Security hardening for brute force protection +**Related User Preference**: External Research (Security best practices) + +- **As a** security requirement, **the system provides** rate limiting on auth attempts, + **so that** brute force attacks are mitigated. +- **Acceptance Criteria**: + - AC-1: 5 failed auth attempts in 5 min triggers temporary lockout + - AC-2: Rate limit configuration adjustable via environment + +--- + +## 11. Non-Negotiables (Target System) + +These constraints from legacy MUST be preserved: + +1. **Timing-Safe Credential Verification** + - **Legacy Implementation**: crypto.timingSafeEqual + - **Target Implementation**: secrets.compare_digest + - **Verification**: Timing analysis tests confirm constant-time behavior + +2. **SSRF Protection with DNS Pinning** + - **Legacy Implementation**: Custom SSRF filter with DNS pinning + - **Target Implementation**: Same logic in Python (ipaddress module) + - **Verification**: SSRF test suite with known bypass attempts + +3. **Local-First Data Storage** + - **Legacy Implementation**: SQLite database on local filesystem + - **Target Implementation**: SQLite + sqlite-vec (unchanged) + - **Verification**: No external database connections + +4. **Command Execution Requires Approval** + - **Legacy Implementation**: Promise-based approval workflow + - **Target Implementation**: asyncio-based approval workflow + - **Verification**: E2E tests confirm approval required for all commands + +--- + +## 12. Non-Functional Requirements (Target System) + +### Performance (Target) + +Based on Q5 (Docker Compose), Q7 (Docker): + +| Metric | Legacy | Target | Improvement | +|--------|--------|--------|-------------| +| Response time (p95) | 30000ms timeout | < 2000ms | Measurable baseline | +| Memory search | N/A | < 100ms | Defined target | +| Startup time | N/A | < 10s | Defined target | +| Concurrent connections | N/A | 100+ | Defined target | + +### Availability & Reliability (Target) + +| Metric | Legacy | Target | Implementation | +|--------|--------|--------|----------------| +| Uptime | N/A | 99.9% | Docker healthcheck | +| Retry logic | 3 attempts | 3 attempts | EXACT | +| Exponential backoff | Yes | Yes | Same parameters | +| Message delivery | Best effort | At-least-once | Improved | + +### Security (Target) + +Based on Q9 (Keep current Token/Password/Tailscale): + +| Aspect | Legacy | Target | Migration | +|--------|--------|--------|-----------| +| Authentication | Token/Password/Tailscale | Token/Password/Tailscale | EXACT | +| Credential comparison | crypto.timingSafeEqual | secrets.compare_digest | Language equivalent | +| SSRF protection | DNS pinning | DNS pinning | EXACT | +| Rate limiting | None | 5 attempts/5 min | NEW | + +### Observability (Target) + +Based on Q8 (Prometheus, Structured JSON, OpenTelemetry): + +| Aspect | Legacy | Target | Implementation | +|--------|--------|--------|----------------| +| Metrics | None | Prometheus | /metrics endpoint | +| Logging | Console | Structured JSON | structlog | +| Tracing | None | OpenTelemetry | Optional OTLP export | + +--- + +## 13. Error Handling & Recovery (Target System) + +### 13.1 Exception Handling Strategy (Target) + +Based on Q1 (Python 3.12+) idioms: + +| Exception Type | Legacy Handling | Target Handling | Rationale | +|----------------|-----------------|-----------------|-----------| +| EmbeddingAPIError | try/catch + retry | try/except + retry | Language equivalent | +| ChannelDisconnect | Promise chain | async/await | Language equivalent | +| AuthFailure | Reject promise | Raise HTTPException | FastAPI pattern | +| ValidationError | Zod validation | Pydantic validation | Library equivalent | + +### 13.2 Error Recovery (Target) + +**Target Pattern**: Python async error handling with structured logging + +- Retry with exponential backoff (same formula as legacy) +- Circuit breaker pattern for external services +- Graceful degradation (memory search falls back to keyword-only) +- All errors logged with correlation IDs + +### 13.3 Error Codes (Target) + +| Error Code | Legacy | Target | Migration | +|------------|--------|--------|-----------| +| AUTH_001 | "Authentication required" | "Authentication required" | EXACT | +| AUTH_002 | "Invalid credentials" | "Invalid credentials" | EXACT | +| MEM_001 | "Embedding failed" | "Embedding failed" | EXACT | +| CHAN_001 | "Connection failed" | "Connection failed" | EXACT | + +--- + +## 14. Data Models (Target System) + +Based on Q2 (SQLite + sqlite-vec): + +### Core Entities (Target) + +#### Entity: MemoryFragment + +**Legacy Reference**: MemoryChunk (functional-spec-legacy.md) +**Migration Status**: EXACT + +| Field | Legacy Type | Target Type | Migration | +|-------|-------------|-------------|-----------| +| id | INTEGER | INTEGER | As-is | +| content | TEXT | TEXT | As-is | +| embedding | BLOB | BLOB | As-is (sqlite-vec) | +| source_file | TEXT | TEXT | As-is | +| created_at | INTEGER | INTEGER | As-is (Unix timestamp) | +| thread_id | N/A | TEXT | NEW - for thread isolation | + +**Schema Changes**: +- ADD: thread_id for conversation threading +- ADD: index on thread_id for query performance + +**Migration Plan**: +1. Backup existing database +2. Add thread_id column with NULL allowed +3. Backfill thread_id from source_file for existing records + +--- + +#### Entity: AuditEvent + +**Legacy Reference**: None (NEW) +**Migration Status**: NEW + +| Field | Type | Constraints | Notes | +|-------|------|-------------|-------| +| id | TEXT | PRIMARY KEY | UUID | +| timestamp | TEXT | NOT NULL | ISO 8601 | +| event_type | TEXT | NOT NULL | auth, command, tool | +| session_id | TEXT | - | Correlation | +| user_identity | TEXT | - | Who | +| details | TEXT | - | JSON | +| correlation_id | TEXT | - | Request tracing | + +--- + +### 14.2 Field Mappings (Legacy -> Target) + +| Legacy Field | Legacy Type | Target Field | Target Type | Transformation | +|--------------|-------------|--------------|-------------|----------------| +| MemoryChunk.id | INTEGER | MemoryFragment.id | INTEGER | As-is | +| MemoryChunk.content | TEXT | MemoryFragment.content | TEXT | As-is | +| MemoryChunk.embedding | BLOB | MemoryFragment.embedding | BLOB | As-is | + +### 14.3 Data Validation Rules (Target) + +| Entity | Field | Legacy Rule | Target Rule | Change | +|--------|-------|-------------|-------------|--------| +| MemoryFragment | content | NOT NULL | NOT NULL | EXACT | +| MemoryFragment | embedding | Optional | Optional | EXACT | +| AuditEvent | event_type | N/A | Enum validation | NEW | + +--- + +## 15. Configuration Mapping (Target System) + +Based on Q5 (Docker Compose), Q6 (Docker Compose): + +| Legacy Config | Target Config | Migration Strategy | +|---------------|---------------|-------------------| +| `.env` | `.env` | Keep as environment variables | +| `config.yaml` | Pydantic Settings | Env vars + optional YAML | +| `package.json` | `pyproject.toml` | Dependency migration | +| `Dockerfile` | `Dockerfile` | Update for Python 3.12 | +| `docker-compose.yml` | `docker-compose.yml` | Update service definition | + +### Target Configuration Structure + +| Config Key | Source | Default | Override | +|------------|--------|---------|----------| +| GATEWAY_HOST | Environment | 0.0.0.0 | Per-environment | +| GATEWAY_PORT | Environment | 3000 | Per-environment | +| DATABASE_PATH | Environment | ./data/moltbot.db | Per-environment | +| AUTH_PASSWORD | Environment | None (required) | Secret | +| LOG_LEVEL | Environment | INFO | Per-environment | +| OPENAI_API_KEY | Environment | None | Secret | + +--- + +## 16. API Contracts (Target System) + +### REST/WebSocket Endpoints (Target) + +| Method | Legacy Path | Target Path | Changes | +|--------|-------------|-------------|---------| +| WS | `/gateway` | `/gateway` | EXACT | +| POST | `/api/memory/search` | `/api/v1/memory/search` | Versioned | +| POST | `/api/exec/approve` | `/api/v1/tools/approve` | Versioned, renamed | +| GET | N/A | `/health` | NEW | +| GET | N/A | `/ready` | NEW | +| GET | N/A | `/metrics` | NEW | + +### API Versioning Strategy + +- **Legacy**: Unversioned +- **Target**: `/api/v1/*` +- **Migration**: Legacy paths redirect to v1 during transition + +### WebSocket Protocol (Target) + +Protocol preserved exactly from legacy: + +```json +// Auth request +{"type": "auth", "payload": {"method": "password", "credentials": "..."}} + +// Auth response +{"type": "auth_success", "payload": {"session_id": "...", "capabilities": [...]}} + +// Message +{"type": "message", "payload": {"channel": "...", "content": "..."}} + +// Tool approval request +{"type": "tool_approval_request", "payload": {"request_id": "...", "command": "..."}} +``` + +--- + +## 17. Integration Points (Target System) + +Based on Q3 (WebSocket + in-memory): + +| External System | Legacy Protocol | Target Protocol | Migration | +|-----------------|-----------------|-----------------|-----------| +| OpenAI API | HTTPS REST | HTTPS REST | Update SDK | +| WhatsApp Web | WebSocket | WebSocket | Python library | +| Telegram API | HTTPS REST | HTTPS REST | python-telegram-bot | +| Discord API | WebSocket | WebSocket | discord.py | +| Tailscale | Local socket | Local socket | EXACT | +| Anthropic API | HTTPS REST | HTTPS REST | Add as option | + +### 17.1 Message Formats (Target) + +| Message Type | Legacy Format | Target Format | Migration | +|--------------|---------------|---------------|-----------| +| Chat message | JSON | JSON | Schema preserved | +| Embedding request | JSON | JSON | OpenAI API format | +| Tool call | MCP protocol | MCP protocol | EXACT | + +### Target Integration Architecture + +```mermaid +graph TD + subgraph Target System + GW[FastAPI Gateway] + MEM[Memory System] + TOOLS[Tool System] + end + + subgraph External APIs + OPENAI[OpenAI API] + ANTHROPIC[Anthropic API] + end + + subgraph Channels + TG[Telegram] + WA[WhatsApp] + DC[Discord] + SL[Slack] + end + + GW --> MEM + GW --> TOOLS + MEM --> OPENAI + GW --> TG + GW --> WA + GW --> DC + GW --> SL +``` + +--- + +*End of Part 2 - Sections 9-17* + +--- + +# PART 3: Modernization Decisions & Checklists (Sections 18-24) + +--- + +## 18. Known Quirks - Modernization Decisions + +For each quirk from legacy Section 18, the modernization decision: + +### Quirk 1: Tailscale Auth Localhost Bypass (QK-AUTH-001) + +**Legacy Reference**: QK-AUTH-001 (functional-spec-legacy.md Section 18) +**Decision**: FIX + +| Aspect | Legacy | Target Decision | +|--------|--------|-----------------| +| **Behavior** | Tailscale auth allows localhost bypass when proxy misconfigured | Explicit loopback detection with configurable behavior | +| **Root Cause** | Trusted proxy headers not validated | Proper header validation | +| **Decision** | N/A | FIX | +| **Rationale** | Security vulnerability | Security hardening goal | +| **Migration Impact** | Breaking change for misconfigured proxies | Document required proxy config | + +--- + +### Quirk 2: Token Refresh Races (QK-AUTH-002) + +**Legacy Reference**: QK-AUTH-002 (functional-spec-legacy.md Section 18) +**Decision**: FIX + +| Aspect | Legacy | Target Decision | +|--------|--------|-----------------| +| **Behavior** | Token refresh races can cause duplicate sessions | Atomic session management | +| **Root Cause** | Non-atomic session operations | Race condition in Promise chain | +| **Decision** | N/A | FIX | +| **Rationale** | Security and reliability improvement | Use asyncio locks | +| **Migration Impact** | None - internal implementation | Improved stability | + +--- + +### Quirk 3: Empty Password Accepted (QK-AUTH-003) + +**Legacy Reference**: QK-AUTH-003 (functional-spec-legacy.md Section 18) +**Decision**: FIX + +| Aspect | Legacy | Target Decision | +|--------|--------|-----------------| +| **Behavior** | Empty password accepted if env var missing | Reject connection if AUTH_PASSWORD not set | +| **Root Cause** | Defensive coding for dev convenience | Security risk | +| **Decision** | N/A | FIX | +| **Rationale** | Critical security vulnerability | Fail-secure default | +| **Migration Impact** | Breaking change | Require explicit config | + +--- + +### Quirk 4: Hardcoded Similarity Threshold (QK-MEM-001) + +**Legacy Reference**: QK-MEM-001 (functional-spec-legacy.md Section 18) +**Decision**: FIX + +| Aspect | Legacy | Target Decision | +|--------|--------|-----------------| +| **Behavior** | Vector similarity threshold hardcoded at 0.7 | Make configurable via MEMORY_SIMILARITY_THRESHOLD | +| **Root Cause** | Development shortcut | Limited flexibility | +| **Decision** | N/A | FIX | +| **Rationale** | User-requested feature | Improve configurability | +| **Migration Impact** | None - additive change | Default preserves behavior | + +--- + +### Quirk 5: Memory Consolidation Data Loss (QK-MEM-002) + +**Legacy Reference**: QK-MEM-002 (functional-spec-legacy.md Section 18) +**Decision**: FIX + +| Aspect | Legacy | Target Decision | +|--------|--------|-----------------| +| **Behavior** | Memory consolidation can lose context if batch size exceeded | Graceful handling with warning | +| **Root Cause** | Silent truncation | Lack of error handling | +| **Decision** | N/A | FIX | +| **Rationale** | Data integrity | Log warning, process in chunks | +| **Migration Impact** | None - improved behavior | Better reliability | + +--- + +### Quirk 6: SQLite WAL Mode (QK-MEM-003) + +**Legacy Reference**: QK-MEM-003 (functional-spec-legacy.md Section 18) +**Decision**: FIX + +| Aspect | Legacy | Target Decision | +|--------|--------|-----------------| +| **Behavior** | WAL mode not enabled by default | Enable WAL mode by default | +| **Root Cause** | Development oversight | Lock contention issues | +| **Decision** | N/A | FIX | +| **Rationale** | Performance improvement | Better concurrency | +| **Migration Impact** | Existing DBs upgraded on first run | Automatic migration | + +--- + +### Quirks Summary + +| Quirk | Legacy ID | Decision | Migration Effort | +|-------|-----------|----------|------------------| +| Localhost bypass | QK-AUTH-001 | FIX | Medium | +| Token refresh races | QK-AUTH-002 | FIX | Low | +| Empty password | QK-AUTH-003 | FIX | Low (breaking) | +| Hardcoded threshold | QK-MEM-001 | FIX | Low | +| Memory consolidation | QK-MEM-002 | FIX | Low | +| WAL mode | QK-MEM-003 | FIX | Low | + +**Total**: 6 quirks - All FIX (security/reliability improvements) + +--- + +## 19. Risks, Assumptions, Decisions (Target System) + +### Migration Risks + +| Risk | Legacy Risk | Target Mitigation | Owner | +|------|-------------|-------------------|-------| +| Data loss during migration | R-003 | Backup + dual-write period | Eng Team | +| Behavioral regression | R-002 | Golden file tests | QA Team | +| Performance regression | R-005 | Benchmark suite | Eng Team | +| Channel API breaking changes | R-004 | Adapter versioning | Eng Team | +| Community resistance | R-006 | Incremental delivery | Product | + +### Assumptions (Target System) + +1. **Python ecosystem sufficient**: Python 3.12+ has mature async support and libraries for all integrations (Inherited from Q1 decision) +2. **SQLite scales adequately**: Single-user workload fits SQLite capabilities (Inherited from legacy) +3. **28 adapters portable**: All channel protocols have Python equivalents (NEW assumption - verify per adapter) +4. **MCP protocol stable**: Anthropic's MCP won't have breaking changes during migration (Inherited) + +### Key Decisions Made + +| Decision | Options Considered | Chosen Option | Rationale | +|----------|-------------------|---------------|-----------| +| Language | Python, Go, Rust, Keep TypeScript | Q1: Python 3.12+ | Larger contributor pool, ML ecosystem | +| Database | PostgreSQL, Keep SQLite | Q2: SQLite + sqlite-vec | Migration-free, proven | +| Message Bus | Redis, RabbitMQ, In-memory | Q3: WebSocket + in-memory | Simplicity, local-first | +| Deployment | K8s, Bare metal, Docker Compose | Q5: Docker Compose | User-friendly | +| Security | OAuth2, JWT, Keep current | Q9: Keep Token/Password/Tailscale | Community preference | + +### Open Decisions (User Input Needed) + +| Decision | Options | Recommendation | Deadline | +|----------|---------|----------------|----------| +| Channel adapter priority | All 28 vs Core 8 first | Core 8 first | Before Phase 1 | +| POE API support | Add vs Skip | Add in Phase 3 | After core stable | +| i18n support | Add vs Skip | Add in Phase 3 | After core stable | + +--- + +## 20. Value / Business Case (Target System) + +### Expected Value from Modernization + +| Value Area | Legacy State | Target State | Business Impact | +|------------|--------------|--------------|-----------------| +| Performance | Unmeasured | p95 < 2s, benchmarked | User satisfaction | +| Security | 6/10 (tech debt) | 9/10 (hardened) | Enterprise adoption | +| Maintainability | 5/10 (complexity) | 8/10 (patterns) | Faster development | +| Test Coverage | ~40% estimated | 80% target | Fewer regressions | +| Observability | Console logging | OpenTelemetry | Faster debugging | + +### ROI Analysis + +- **Investment**: 4 phases over 6-18 months (Hybrid/Strangler Fig approach) +- **Expected Return**: + - Enterprise adoption enabled (security compliance) + - Larger contributor base (Python vs TypeScript) + - Reduced maintenance burden (better architecture) +- **Timeline**: Benefits realized incrementally per phase + +### Success Metrics + +| Metric | Current | Target | Measurement Method | +|--------|---------|--------|-------------------| +| Test coverage | ~40% | 80% | pytest --cov | +| Security vulnerabilities | 8 tech debt items | 0 critical | Security audit | +| Message latency (p50) | Unknown | < 500ms | OpenTelemetry | +| Community contributors | N/A | Increase 50% | GitHub analytics | + +--- + +## 21. Traceability Matrix (Legacy -> Target) + +### Requirements Mapping + +| Legacy Req | Target Req | Status | Migration Notes | +|------------|------------|--------|-----------------| +| FR-CRIT-001 | FR-CRIT-001 | EXACT | Multi-channel gateway preserved | +| FR-CRIT-002 | FR-CRIT-002 | EXACT | Timing-safe auth preserved | +| FR-CRIT-003 | FR-CRIT-003 | ENHANCED | Command allowlist added | +| FR-CRIT-004 | FR-CRIT-004 | EXACT | Memory search preserved | +| N/A | FR-NEW-001 | NEW | Audit trail query | +| N/A | FR-NEW-002 | NEW | Health endpoints | +| N/A | FR-NEW-003 | NEW | Rate limiting | + +### Use Case Mapping + +| Legacy UC | Target UC | Status | Changes | +|-----------|-----------|--------|---------| +| UC-001 | UC-001 | EXACT | Implementation language only | +| UC-002 | UC-002 | ENHANCED | Audit logging added | +| UC-003 | UC-003 | ENHANCED | Command allowlist added | +| UC-004 | UC-004 | EXACT | Same search algorithm | +| UC-005 | UC-005 | EXACT | WhatsApp pairing preserved | +| UC-006 | UC-006 | EXACT | Telegram config preserved | +| UC-007 | UC-007 | EXACT | Discord monitoring preserved | +| UC-008 | UC-008 | EXACT | Browser automation preserved | +| UC-009 | UC-009 | EXACT | Cron scheduling preserved | +| UC-010 | UC-010 | EXACT | Voice call preserved | + +### Business Logic Mapping + +| Legacy BL | Target BL | Preservation | Verification | +|-----------|-----------|--------------|--------------| +| CALC-001 (Similarity) | CALC-001 | EXACT | Golden file tests | +| CALC-002 (Backoff) | CALC-002 | EXACT | Unit tests | +| VAL-001 (Auth) | VAL-001 | EXACT | Integration tests | +| SM-001 (Approval) | SM-001 | EXACT | State machine tests | +| SM-002 (Connection) | SM-002 | EXACT | State machine tests | + +--- + +## 22. Next Steps + +### Immediate Actions + +1. **Review this specification** with stakeholders +2. **Resolve open decisions** in Section 19 (channel priority, POE API, i18n) +3. **Approve quirk decisions** in Section 18 (all marked FIX) +4. **Proceed to technical specs** + +### Technical Specification + +After approval: +- Generate `technical-spec-legacy.md` (document HOW legacy is built) +- Generate `technical-spec-target.md` (document HOW target will be built) + +### Migration Planning + +1. **Data migration strategy** (from Section 14) + - Backup existing SQLite database + - Add thread_id column migration + - Verify embedding compatibility +2. **API versioning rollout** (from Section 16) + - Deploy v1 endpoints alongside legacy + - Redirect legacy paths during transition +3. **Integration updates** (from Section 17) + - Update channel adapter libraries + - Verify protocol compatibility + +--- + +## 24. Output Validation Checklist (Target System) + +**Note**: Section 23 (Business Logic Preservation Checklist) is legacy-only. +For target, verify implementation of preserved logic during development. + +### 24.1 Document Quality + +| Check | Status | Notes | +|-------|--------|-------| +| All sections complete (no TODO/TBD) | [x] | Complete | +| All Legacy -> Target mappings complete | [x] | Complete | +| User preferences (Q1-Q10) consistently applied | [x] | Applied throughout | +| All cross-references valid | [x] | Verified | +| All tables properly formatted | [x] | Markdown valid | + +### 24.2 Content Completeness + +| Section | Legacy Items | Target Items | Mapping Complete | +|---------|--------------|--------------|------------------| +| Use Cases | 10 | 10 | [x] | +| User Stories | 9 | 7 (5 preserved + 2 new) | [x] | +| Business Logic | 5 formulas | 5 formulas | [x] | +| Requirements | 4 critical | 7 (4 + 3 new) | [x] | +| Data Models | 2 entities | 2 entities | [x] | + +### 24.3 Modernization Verification + +- [x] All legacy quirks have PRESERVE/FIX/REMOVE decision (6 FIX) +- [x] All user preferences (Q1-Q10) applied consistently +- [x] Migration plans documented for all data changes +- [x] API versioning strategy defined (/api/v1/*) +- [x] Backward compatibility addressed (legacy redirects) + +### 24.4 Stakeholder Readiness + +- [x] Executive Summary reflects modernization goals +- [x] Business value clearly articulated (Section 20) +- [x] Technical decisions justified (Q1-Q10 rationale) +- [x] Migration risks documented with mitigations (Section 19) +- [x] Open decisions identified for resolution (3 decisions) + +--- + +## Appendix A: Glossary + +| Term | Legacy Definition | Target Definition | Change | +|------|-------------------|-------------------|--------| +| Adapter | Channel-specific integration module | Channel-specific integration module | None | +| Gateway | WebSocket server for all channels | FastAPI WebSocket server | Implementation | +| MCP | Model Context Protocol | Model Context Protocol | None | +| Memory Fragment | Single stored context with embedding | Single stored context with embedding | None | +| Thread | Conversation context within a channel | Conversation context within a channel | None | +| Tool | Executable capability exposed to AI | Executable capability exposed to AI | None | + +--- + +## Appendix B: User Preference Summary + +| Q# | Topic | User's Choice | Applied In | +|----|-------|---------------|------------| +| Q1 | Language | Python 3.12+ | Sections 4, 5, 10, 13 | +| Q2 | Database | SQLite + sqlite-vec | Sections 12, 14 | +| Q3 | Message Bus | WebSocket + in-memory | Sections 13, 17 | +| Q4 | Package Manager | uv | Section 15 | +| Q5 | Deployment | Docker Compose | Sections 12, 15 | +| Q6 | IaC | Docker Compose | Section 15 | +| Q7 | Container | Docker | Section 12 | +| Q8 | Observability | Prometheus/JSON/OpenTelemetry | Section 12 | +| Q9 | Security | Token/Password/Tailscale | Sections 11, 12 | +| Q10 | Testing | pytest (80% coverage) | Section 24 | + +--- + +## Appendix C: Change Log + +| Date | Author | Change | +|------|--------|--------| +| 2026-01-29 | AI Agent | Target specification generated from legacy analysis | +| 2026-01-29 | AI Agent | Applied user preferences Q1-Q10 | +| 2026-01-29 | AI Agent | Incorporated external research findings | + +--- + +*End of Functional Specification - Target System* +*Document Version: 1.0* +*Generated: 2026-01-29* +*Analysis Chain ID: 20260129-202219* \ No newline at end of file diff --git a/.analysis/moltbotsec-20260129-202219/reports/technical-spec-legacy.md b/.analysis/moltbotsec-20260129-202219/reports/technical-spec-legacy.md new file mode 100644 index 000000000..96e90fea6 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/reports/technical-spec-legacy.md @@ -0,0 +1,1489 @@ +# Technical Specification - Legacy System + +**Project**: Moltbot (Multi-Channel AI Messaging Assistant) +**Analysis Date**: 2026-01-29 +**Status**: Legacy Architecture Documentation + +--- + +## 1. Architectural Principles + +### Current Architecture Style + +**Pattern**: Modular Monolith with Plugin Extensions +**Evidence**: Single deployable unit (`dist/main.mjs`) with extensible channel plugins in `extensions/` directory. Shared runtime, separate configuration per channel. + +### Observed Principles + +| Principle | Implementation | Evidence | +|-----------|----------------|----------| +| Separation of Concerns | 5-layer architecture (presentation, domain, infrastructure, shared, test) | `ui/`, `src/commands/models/`, `src/config/`, `apps/shared/`, `test/` | +| Dependency Direction | Bidirectional (violation) - config is central hub | 234 deps config→commands/models, 111 deps commands/models→config | +| Error Handling | Distributed with custom error types | 7 custom errors: `SsrfBlockedError`, `GatewayLockError`, etc. | +| Plugin Architecture | Extension-based with manifest files | `extensions/*/clawdbot.plugin.json` with 28 channel plugins | +| Event-Driven | WebSocket gateway with event streaming | `src/gateway/client.ts:*` - JSON-RPC 2.0 protocol | + +### Architectural Strengths + +| Strength | Implementation | Evidence | +|----------|----------------|----------| +| Channel Abstraction | Unified interface across 28 platforms | `monitorProvider` pattern per channel | +| Security-First | Multiple authentication modes | Token, Password, Tailscale, Device signature | +| Resilience | Auto-reconnect with exponential backoff | `src/gateway/client.ts` WebSocket reconnection | + +### Architectural Weaknesses + +| Weakness | Issue | Evidence | +|----------|-------|----------| +| Circular Dependencies | 1 cycle spanning 10 components | config ↔ commands/models ↔ ui/views | +| Central Hub Coupling | Config has 445+ bidirectional deps | `config` component with 2300 symbols | +| State Management | In-memory exec approvals lost on restart | `src/gateway/exec-approval-manager.ts` | + +--- + +## 2. C4 Architecture Views + +### 2.1 System Context (C4 Level 1) + +```mermaid +C4Context + title Moltbot System Context + + Person(user, "User", "End user interacting via messaging platforms") + Person(admin, "Admin", "System administrator managing Moltbot") + + System(moltbot, "Moltbot", "Multi-channel AI messaging assistant") + + System_Ext(telegram, "Telegram", "Telegram Bot API") + System_Ext(discord, "Discord", "Discord Bot Gateway") + System_Ext(whatsapp, "WhatsApp", "Baileys/WA Web") + System_Ext(slack, "Slack", "Slack Events API") + System_Ext(signal, "Signal", "Signal Protocol") + System_Ext(channels, "16+ Channels", "Matrix, Teams, etc.") + + System_Ext(claude, "Claude AI", "Anthropic Claude API") + System_Ext(openai, "OpenAI", "GPT API + Embeddings") + System_Ext(gemini, "Google Gemini", "Gemini API") + + System_Ext(twilio, "Twilio", "Voice/SMS provider") + System_Ext(plivo, "Plivo", "Voice provider") + System_Ext(telnyx, "Telnyx", "Voice provider") + + Rel(user, telegram, "Messages via") + Rel(user, discord, "Messages via") + Rel(user, whatsapp, "Messages via") + Rel(user, slack, "Messages via") + Rel(user, signal, "Messages via") + Rel(user, channels, "Messages via") + + Rel(telegram, moltbot, "Webhooks/Polling") + Rel(discord, moltbot, "Gateway WebSocket") + Rel(whatsapp, moltbot, "Baileys connection") + Rel(slack, moltbot, "Events API") + Rel(signal, moltbot, "Signal protocol") + Rel(channels, moltbot, "Platform APIs") + + Rel(moltbot, claude, "AI inference") + Rel(moltbot, openai, "AI inference + embeddings") + Rel(moltbot, gemini, "AI inference") + + Rel(moltbot, twilio, "Voice calls") + Rel(moltbot, plivo, "Voice calls") + Rel(moltbot, telnyx, "Voice calls") + + Rel(admin, moltbot, "Gateway WebSocket control") +``` + +### 2.2 Container View (C4 Level 2) + +```mermaid +C4Container + title Moltbot Container View + + Person(user, "User", "End user") + Person(admin, "Admin", "Administrator") + + System_Boundary(moltbot, "Moltbot System") { + Container(gateway, "Gateway Server", "Node.js/TypeScript", "WebSocket control plane, auth, exec approval") + Container(autoreply, "Auto-Reply Engine", "TypeScript", "Message processing, command detection, agent execution") + Container(channels, "Channel Adapters", "TypeScript Plugins", "28 platform integrations") + Container(memory, "Memory Index", "SQLite + sqlite-vec", "Vector embeddings, FTS5, session storage") + Container(cron, "Cron Service", "TypeScript", "Scheduled job management") + Container(voice, "Voice Extension", "TypeScript", "Twilio/Plivo/Telnyx calls") + Container(tui, "TUI Interface", "Ink/React", "Terminal user interface") + Container(ui, "Web UI", "Solid.js", "Browser-based configuration") + } + + System_Ext(aiapis, "AI APIs", "Claude, OpenAI, Gemini") + System_Ext(platforms, "Messaging Platforms", "28 channels") + System_Ext(voiceproviders, "Voice Providers", "Twilio, Plivo, Telnyx") + + Rel(admin, gateway, "WebSocket JSON-RPC", "wss://127.0.0.1:18789") + Rel(admin, tui, "Terminal", "stdin/stdout") + Rel(admin, ui, "HTTP", "localhost:*") + + Rel(platforms, channels, "Platform APIs", "HTTPS/WebSocket") + Rel(channels, autoreply, "Internal calls", "TypeScript") + Rel(autoreply, aiapis, "AI inference", "HTTPS") + Rel(autoreply, memory, "RAG queries", "SQLite") + Rel(gateway, autoreply, "Control events", "Internal") + Rel(cron, autoreply, "Scheduled triggers", "Internal") + Rel(voice, voiceproviders, "Voice streams", "WebSocket/TwiML") + Rel(voice, autoreply, "Transcripts", "Internal") +``` + +### 2.3 Component View (C4 Level 3) + +```mermaid +C4Component + title Moltbot Core Components + + Container_Boundary(core, "Moltbot Core") { + Component(config, "Config Module", "TypeScript", "2300 symbols, 129 files - Central configuration hub") + Component(commands, "Commands/Models", "TypeScript", "372 symbols - Domain models and commands") + Component(gateway_client, "Gateway Client", "TypeScript", "WebSocket client with auto-reconnect") + Component(gateway_auth, "Gateway Auth", "TypeScript", "Multi-mode authentication") + Component(exec_approval, "Exec Approval Manager", "TypeScript", "Command execution gating") + Component(memory_mgr, "Memory Index Manager", "TypeScript", "Hybrid search with embeddings") + Component(ssrf, "SSRF Protection", "TypeScript", "DNS pinning, IP validation") + Component(audit, "Security Audit", "TypeScript", "Configuration security checks") + Component(cron_svc, "Cron Service", "TypeScript", "Job scheduling with CRUD") + } + + Container_Boundary(channels_boundary, "Channel Adapters") { + Component(telegram, "Telegram Adapter", "TypeScript", "Bot API polling/webhooks") + Component(discord, "Discord Adapter", "TypeScript", "Gateway + REST API") + Component(whatsapp, "WhatsApp Adapter", "TypeScript", "Baileys multi-device") + Component(slack, "Slack Adapter", "TypeScript", "Events API + Socket Mode") + Component(other_channels, "16+ Other Adapters", "TypeScript", "Signal, Matrix, Teams, etc.") + } + + Container_Boundary(extensions, "Extensions") { + Component(voice_call, "Voice Call Manager", "TypeScript", "Call state machine") + Component(voice_providers, "Voice Providers", "TypeScript", "Twilio, Plivo, Telnyx") + Component(memory_lance, "LanceDB Memory", "TypeScript", "Alternative vector store") + Component(open_prose, "Open Prose", "TypeScript", "Writing assistant skill") + } + + Rel(gateway_client, gateway_auth, "Authenticates with") + Rel(gateway_client, exec_approval, "Requests approval from") + Rel(config, commands, "Configures", "234 deps") + Rel(commands, config, "Reads from", "111 deps") + Rel(telegram, config, "Uses config") + Rel(discord, config, "Uses config") + Rel(whatsapp, config, "Uses config") + Rel(slack, config, "Uses config") + Rel(other_channels, config, "Uses config") + Rel(memory_mgr, ssrf, "Validates URLs") + Rel(voice_call, voice_providers, "Delegates to") +``` + +**Evidence**: Extracted from `mcp__civyk-repoix__get_components` and `mcp__civyk-repoix__get_dependencies` analysis. + +--- + +## 3. Component Dependency Diagram + +```mermaid +graph TB + subgraph Presentation["Presentation Layer"] + UI_VIEWS["ui/views
537 symbols"] + UI_CTRL["ui/controllers
246 symbols"] + UI_COMP["ui/components
10 symbols"] + TUI["tui/components
90 symbols"] + end + + subgraph Domain["Domain Layer"] + COMMANDS["commands/models
372 symbols"] + end + + subgraph Infrastructure["Infrastructure Layer"] + CONFIG["config
2300 symbols"] + CTRL_CFG["controllers/config
4 symbols"] + end + + subgraph Shared["Shared Layer"] + APPS["apps/shared
447 symbols"] + TEST_HELP["test/helpers
37 symbols"] + SHARED["shared
4 symbols"] + UTILS["utils
7 symbols"] + end + + subgraph Test["Test Layer"] + TEST["test
261 symbols"] + end + + %% High-coupling dependencies (>50) + CONFIG -->|234| COMMANDS + UI_VIEWS -->|212| CONFIG + COMMANDS -->|111| CONFIG + CONFIG -->|82| UI_VIEWS + UI_VIEWS -->|69| COMMANDS + UI_VIEWS -->|53| UI_CTRL + TEST -->|52| CONFIG + + %% Medium dependencies (10-50) + UI_CTRL -->|46| CONFIG + UI_CTRL -->|36| UI_VIEWS + UI_VIEWS -->|29| APPS + TUI -->|28| CONFIG + CONFIG -->|19| APPS + COMMANDS -->|18| APPS + + %% Circular dependency highlight + style CONFIG fill:#ff6b6b + style COMMANDS fill:#ff6b6b + style UI_VIEWS fill:#ff6b6b +``` + +### Dependency Analysis + +| Component | Depends On | Depended By | Coupling | +|-----------|------------|-------------|----------| +| config | commands/models (234), ui/views (82), apps/shared (19) | ui/views (212), commands/models (111), test (52) | **Critical** | +| ui/views | config (212), commands/models (69), ui/controllers (53) | config (82), ui/controllers (36), commands/models (13) | High | +| commands/models | config (111), apps/shared (18), ui/views (13) | config (234), ui/views (69), tui/components (13) | High | +| ui/controllers | config (46), ui/views (36), controllers/config (15) | ui/views (53), config (13), commands/models (11) | Medium | +| tui/components | config (28), commands/models (13), apps/shared (11) | ui/views (6), ui/controllers (1) | Medium | +| apps/shared | commands/models (3), config (2), ui/components (2) | ui/views (29), config (19), commands/models (18) | Low (shared) | +| test | config (52), commands/models (6), apps/shared (5) | config (5), tui/components (3), commands/models (2) | Low (test) | + +**Evidence**: Import analysis via `mcp__civyk-repoix__get_dependencies` - 49 cross-component dependency edges identified. + +### Circular Dependency + +**Cycle**: config → commands/models → ui/views → ui/controllers → controllers/config → tui/components → ui/components → test/helpers → test → apps/shared → config + +**Impact**: Tight coupling prevents independent deployment, complicates testing, increases risk of cascading changes. + +--- + +## 4. Sequence Diagrams + +### 4.1 Message Processing Flow + +```mermaid +sequenceDiagram + participant Platform as Messaging Platform + participant Monitor as Channel Monitor + participant Handler as Message Handler + participant Policy as DM Policy + participant Pipeline as Auto-Reply Pipeline + participant Agent as Agent Runner + participant AI as AI Provider + participant Memory as Memory Index + participant Response as Response Delivery + + Platform->>Monitor: Incoming message + Monitor->>Handler: createMessageHandler() + Handler->>Policy: checkDmPolicy() + + alt DM Policy Rejected + Policy-->>Handler: Reject + Handler-->>Platform: No response + else DM Policy Allowed + Policy-->>Handler: Allow + Handler->>Pipeline: processMessage() + Pipeline->>Pipeline: detectCommand() + + alt Command Detected + Pipeline->>Agent: executeCommand() + else Regular Message + Pipeline->>Memory: queryContext() + Memory-->>Pipeline: Relevant context + Pipeline->>Agent: runAgent() + end + + Agent->>AI: inference() + + alt Rate Limit / Error + AI-->>Agent: Error + Agent->>AI: failoverToNextModel() + else Success + AI-->>Agent: Response + end + + Agent->>Response: formatResponse() + Response->>Platform: sendMessage() + end +``` + +**Evidence**: Flow traced through `src/web/auto-reply.ts`, channel monitor providers (18 implementations), message handlers (29 implementations). + +### 4.2 Gateway Authentication Flow + +```mermaid +sequenceDiagram + participant Client as Gateway Client + participant Server as Gateway Server + participant Auth as Auth Module + participant Device as Device Store + + Client->>Server: WebSocket connect (wss://127.0.0.1:18789) + Server->>Server: TLS fingerprint capture + + alt Token Auth + Client->>Server: auth_token message + Server->>Auth: validateToken() + Auth->>Auth: timingSafeEqual(token) + Auth-->>Server: Valid/Invalid + else Password Auth + Client->>Server: auth_password message + Server->>Auth: validatePassword() + Auth->>Auth: timingSafeEqual(hash) + Auth-->>Server: Valid/Invalid + else Device Auth + Client->>Server: auth_device message + Server->>Device: lookupDevice(publicKey) + Server->>Client: nonce_challenge + Client->>Client: sign(nonce, privateKey) + Client->>Server: nonce_response(signature) + Server->>Auth: verifySignature() + Auth-->>Server: Valid/Invalid + else Tailscale Auth + Client->>Server: auth_tailscale message + Server->>Auth: tailscaleWhois() + Auth-->>Server: User identity + end + + alt Auth Success + Server->>Server: Pin TLS fingerprint + Server-->>Client: auth_success + session_token + else Auth Failure + Server-->>Client: auth_error + Server->>Server: Close connection + end +``` + +**Evidence**: `src/gateway/auth.ts`, `src/gateway/client.ts`, device authentication with nonce challenge. + +### 4.3 Exec Approval Workflow + +```mermaid +sequenceDiagram + participant Agent as Agent Runner + participant Exec as Exec Approval Manager + participant Gateway as Gateway Server + participant Discord as Discord Monitor + participant Admin as Admin User + + Agent->>Exec: requestApproval(command, sessionKey) + Exec->>Exec: createPendingApproval() + Exec->>Gateway: emit("exec_approval_request") + Gateway->>Discord: postApprovalMessage() + Discord-->>Admin: Show approval buttons + + par Timeout Path + Exec->>Exec: setTimeout(timeout) + Note over Exec: Wait for approval or timeout + and Approval Path + Admin->>Discord: Click Approve/Deny + Discord->>Exec: resolveApproval(approved) + end + + alt Approved + Exec-->>Agent: { approved: true } + Agent->>Agent: executeCommand() + else Denied + Exec-->>Agent: { approved: false } + Agent->>Agent: rejectExecution() + else Timeout + Exec-->>Agent: { approved: false, timeout: true } + Agent->>Agent: rejectExecution() + end +``` + +**Evidence**: `src/gateway/exec-approval-manager.ts`, `src/discord/monitor/exec-approvals.ts`. + +### 4.4 Voice Call State Machine + +```mermaid +sequenceDiagram + participant User as User + participant Manager as Call Manager + participant Provider as Voice Provider + participant Twilio as Twilio API + participant Agent as Agent Runner + + User->>Manager: initiateCall(phoneNumber) + Manager->>Manager: createCall() state=INITIATED + Manager->>Provider: connect() + Provider->>Twilio: POST /Calls + Twilio-->>Provider: CallSid + Provider-->>Manager: connected + Manager->>Manager: state=RINGING + + Twilio->>Provider: Webhook: call_answered + Provider->>Manager: onAnswered() + Manager->>Manager: state=IN_PROGRESS + Manager->>Manager: startMaxDurationTimer() + + loop During Call + Twilio->>Provider: MediaStream audio + Provider->>Manager: onTranscript(text) + Manager->>Agent: processUtterance() + Agent-->>Manager: response + Manager->>Provider: speak(response) + Provider->>Twilio: TTS audio + end + + alt User Hangup + Twilio->>Provider: Webhook: call_ended + else Max Duration + Manager->>Provider: hangup() + else Agent Ends + Agent->>Manager: endCall() + Manager->>Provider: hangup() + end + + Provider->>Manager: onEnded() + Manager->>Manager: state=COMPLETED + Manager->>Manager: persistTranscript() +``` + +**Evidence**: `extensions/voice-call/src/manager.ts`, `extensions/voice-call/src/providers/twilio.ts`. + +--- + +## 5. Deployment Architecture + +### Current Deployment Model + +**Platform**: Docker containerized, single-host deployment +**Evidence**: `Dockerfile`, `docker-compose.yml` + +```mermaid +graph TB + subgraph Host["Docker Host"] + subgraph Container["Moltbot Container"] + NODE["Node.js 22"] + APP["dist/main.mjs"] + SQLITE["SQLite DB"] + end + + VOLUMES["Docker Volumes"] + VOLUMES -->|"state/"| SQLITE + VOLUMES -->|"config/"| APP + end + + subgraph External["External Services"] + AI["AI APIs
(Claude, OpenAI, Gemini)"] + VOICE["Voice Providers
(Twilio, Plivo, Telnyx)"] + PLATFORMS["Messaging Platforms
(28 channels)"] + end + + HOST_NET["Host Network"] + HOST_NET -->|"18789"| Container + HOST_NET -->|"18790"| Container + + Container -->|"HTTPS"| AI + Container -->|"WebSocket"| VOICE + Container -->|"HTTPS/WS"| PLATFORMS +``` + +### Infrastructure Components + +| Component | Technology | Purpose | Evidence | +|-----------|------------|---------|----------| +| Runtime | Node.js 22.12+ | JavaScript execution | `package.json` engines field | +| Bundler | rolldown | ESM bundle generation | `package.json` build script | +| Container | Docker (node:22-bookworm) | Deployment isolation | `Dockerfile` | +| Orchestration | Docker Compose | Single-host orchestration | `docker-compose.yml` | +| Database | SQLite + sqlite-vec | Embedded storage + vectors | `src/memory/manager.ts` | +| CI/CD | GitHub Actions | Automated testing/builds | `.github/workflows/ci.yml` | + +### Port Allocation + +| Port | Service | Protocol | Binding | +|------|---------|----------|---------| +| 18789 | Gateway Server | WebSocket | 127.0.0.1 (configurable) | +| 18790 | Bridge Server | WebSocket | 127.0.0.1 (configurable) | + +### Security Hardening + +| Measure | Implementation | Evidence | +|---------|----------------|----------| +| Non-root user | Container runs as `node` (uid 1000) | `Dockerfile` USER directive | +| TLS fingerprint | Pin client certificate fingerprint | `src/gateway/auth.ts` | +| SSRF protection | DNS pinning, private IP blocking | `src/infra/net/ssrf.ts` | +| Exec approval | Human-in-the-loop for commands | `src/gateway/exec-approval-manager.ts` | + +--- + +## 6. Data Flow Diagrams + +### 6.1 Request/Response Flow + +```mermaid +flowchart LR + subgraph Input["Input Sources"] + PLATFORM["Messaging Platform"] + GATEWAY["Gateway WebSocket"] + CRON["Cron Scheduler"] + VOICE["Voice Stream"] + end + + subgraph Processing["Processing Pipeline"] + MONITOR["Channel Monitor"] + HANDLER["Message Handler"] + PIPELINE["Auto-Reply Pipeline"] + AGENT["Agent Runner"] + end + + subgraph Data["Data Layer"] + MEMORY["Memory Index
(sqlite-vec)"] + CONFIG["Configuration
(YAML/JSON)"] + STATE["Session State
(SQLite)"] + end + + subgraph AI["AI Inference"] + CLAUDE["Claude API"] + OPENAI["OpenAI API"] + GEMINI["Gemini API"] + LOCAL["Local LLM"] + end + + subgraph Output["Output"] + RESPONSE["Response Formatter"] + DELIVERY["Channel Delivery"] + end + + PLATFORM --> MONITOR + GATEWAY --> HANDLER + CRON --> PIPELINE + VOICE --> HANDLER + + MONITOR --> HANDLER + HANDLER --> PIPELINE + PIPELINE --> AGENT + + AGENT <--> MEMORY + AGENT <--> CONFIG + AGENT <--> STATE + + AGENT --> CLAUDE + AGENT --> OPENAI + AGENT --> GEMINI + AGENT --> LOCAL + + CLAUDE --> RESPONSE + OPENAI --> RESPONSE + GEMINI --> RESPONSE + LOCAL --> RESPONSE + + RESPONSE --> DELIVERY + DELIVERY --> PLATFORM +``` + +### 6.2 Data Transformation Points + +| Source | Transform | Destination | Evidence | +|--------|-----------|-------------|----------| +| Platform message | Normalize to internal format | Message handler | Channel adapter `toInternalMessage()` | +| User query | Generate embedding vector | Memory index | `src/memory/manager.ts` embedding providers | +| Memory search | Hybrid ranking (vector + BM25) | Agent context | `src/memory/manager.ts` hybrid search | +| AI response | Chunk for platform limits | Response delivery | Platform-specific message length limits | +| Voice audio | Transcribe to text | Agent input | `extensions/voice-call/src/media-stream.ts` | +| Agent response | Text-to-speech synthesis | Voice stream | Voice provider TTS | + +**Evidence**: Traced from channel adapters through `src/web/auto-reply.ts` to `src/memory/manager.ts` and response delivery. + +### 6.3 Memory Indexing Flow + +```mermaid +flowchart TB + subgraph Sources["Index Sources"] + FILES["Markdown Files"] + SESSIONS["JSONL Transcripts"] + MANUAL["Manual Entries"] + end + + subgraph Detection["Change Detection"] + HASH["Content Hash
(SHA-256)"] + DELTA["Delta Detection"] + DEBOUNCE["Debounce
(5s sessions)"] + end + + subgraph Processing["Processing"] + CHUNK["Markdown Chunking"] + EMBED["Embedding Generation"] + INDEX["Vector + FTS Index"] + end + + subgraph Storage["Storage"] + SQLITE["SQLite DB"] + VEC["sqlite-vec
(vectors)"] + FTS["FTS5
(keywords)"] + end + + FILES --> HASH + SESSIONS --> DELTA + MANUAL --> CHUNK + + HASH --> CHUNK + DELTA --> DEBOUNCE + DEBOUNCE --> CHUNK + + CHUNK --> EMBED + EMBED --> INDEX + + INDEX --> SQLITE + INDEX --> VEC + INDEX --> FTS +``` + +--- + +## 7. Resilience Patterns + +### Current Patterns + +| Pattern | Implementation | Evidence | +|---------|----------------|----------| +| Retry | Exponential backoff for WebSocket reconnection | `src/gateway/client.ts` - auto-reconnect with delay | +| Circuit Breaker | Not implemented (opportunity) | N/A | +| Timeout | Configurable per operation | `timeout_ms` in config options | +| Fallback | Model failover chain on errors | Agent runtime model selection | +| Rate Limiting | Exponential backoff for embeddings | `src/memory/manager.ts` rate limit handling | +| Batch Fallback | Non-batch after 2 failures | `src/memory/manager.ts` embedding batching | + +### Error Handling Architecture + +```mermaid +flowchart TB + subgraph Errors["Error Types"] + SSRF["SsrfBlockedError"] + GATEWAY["GatewayLockError"] + CONFIG["ConfigIncludeError"] + CIRCULAR["CircularIncludeError"] + DISCORD["DiscordApiError"] + FAILOVER["FailoverError"] + MEDIA["MediaFetchError"] + end + + subgraph Handling["Error Handling"] + CATCH["Try/Catch Boundaries"] + LOG["Structured Logging"] + AUDIT["Security Audit"] + NOTIFY["User Notification"] + end + + subgraph Recovery["Recovery Actions"] + RETRY["Retry with Backoff"] + FAILOVER_CHAIN["Model Failover"] + GRACEFUL["Graceful Degradation"] + ALERT["Admin Alert"] + end + + SSRF --> AUDIT + SSRF --> LOG + + GATEWAY --> LOG + GATEWAY --> ALERT + + CONFIG --> CATCH + CIRCULAR --> CATCH + CONFIG --> LOG + CIRCULAR --> LOG + + DISCORD --> CATCH + DISCORD --> RETRY + + FAILOVER --> FAILOVER_CHAIN + MEDIA --> GRACEFUL + + AUDIT --> ALERT + CATCH --> NOTIFY + LOG --> NOTIFY +``` + +### Gateway Reconnection Strategy + +```mermaid +sequenceDiagram + participant Client as Gateway Client + participant Server as Gateway Server + participant Timer as Reconnect Timer + + Client->>Server: WebSocket connect + Server-->>Client: Connection established + + Note over Client,Server: Connection drops + + Client->>Timer: Start reconnect (delay=1s) + Timer->>Client: Trigger + Client->>Server: Reconnect attempt 1 + Server--xClient: Failed + + Client->>Timer: Backoff (delay=2s) + Timer->>Client: Trigger + Client->>Server: Reconnect attempt 2 + Server--xClient: Failed + + Client->>Timer: Backoff (delay=4s) + Timer->>Client: Trigger + Client->>Server: Reconnect attempt 3 + Server-->>Client: Connected + + Client->>Server: Re-authenticate + Server-->>Client: Session restored +``` + +**Evidence**: `src/gateway/client.ts` WebSocket auto-reconnect with exponential backoff. + +--- + +## 8. Why This Pattern (Legacy Analysis) + +### Current Architecture Rationale + +Based on code analysis, the legacy architecture choices: + +| Choice | Likely Reason | Evidence | Impact | +|--------|---------------|----------|--------| +| Modular Monolith | Rapid development, shared state | Single `dist/main.mjs` bundle | Deployment simplicity, testing complexity | +| TypeScript | Type safety for large codebase | `tsconfig.json` strict mode | Maintainability (+), build complexity (+) | +| SQLite | Zero-config embedded database | No external DB dependency | Simplicity (+), scalability (-) | +| WebSocket Gateway | Real-time control plane | `wss://127.0.0.1:18789` | Responsive UI, connection management | +| Plugin Extensions | Channel modularity | `extensions/` directory | Extensibility (+), dependency management (-) | +| Constructor DI | Service composition | Deps interface pattern | Testability (+), boilerplate (+) | + +### Technical Debt Identified + +| Area | Issue | Evidence | Severity | +|------|-------|----------|----------| +| Circular Dependencies | 10-component cycle | `config` ↔ `commands/models` ↔ `ui/views` | High | +| Central Hub | `config` has 2300 symbols, 445+ deps | Single point of coupling | High | +| In-Memory State | Exec approvals lost on restart | `ExecApprovalManager` Map storage | Medium | +| Missing Circuit Breaker | No external API failure isolation | No circuit breaker pattern | Medium | +| Test Coverage | 70% threshold, gaps in integration | `vitest.config.ts` coverage config | Medium | +| Monolith Deployment | Single container, no horizontal scaling | `docker-compose.yml` single service | Low | + +### Migration Implications + +| Current State | Target Consideration | Risk | +|---------------|---------------------|------| +| TypeScript + Node.js | Python 3.12+ migration | Full rewrite, no incremental path | +| SQLite + sqlite-vec | Keep (user preference) | Data migration for schema changes | +| WebSocket Gateway | Maintain pattern in Python | Protocol compatibility | +| 28 Channel Plugins | Adapter pattern preservation | Per-channel testing required | +| Constructor DI | Python dependency injection | Pattern translation | + +--- + +*Part 1 of 3 - Sections 1-8 Complete* + +--- + +## 9. Capabilities by Phase (Current State) + +### Core Capabilities (80%) + +| Capability | Component | Coverage | Evidence | +|------------|-----------|----------|----------| +| Multi-channel messaging | Channel Adapters | 100% | 28 platforms in `extensions/` | +| AI inference | Agent Runner | 95% | Claude, OpenAI, Gemini, local LLM support | +| Context-aware responses | Memory Index | 90% | `src/memory/manager.ts` hybrid search | +| Gateway control plane | Gateway Server | 95% | `src/gateway/client.ts` WebSocket JSON-RPC | +| Authentication | Gateway Auth | 90% | Token, Password, Tailscale, Device modes | +| Command execution | Exec Approval Manager | 85% | `src/gateway/exec-approval-manager.ts` | +| Voice calls | Voice Extension | 80% | Twilio, Plivo, Telnyx providers | + +### Supporting Capabilities (15%) + +| Capability | Component | Coverage | Evidence | +|------------|-----------|----------|----------| +| Scheduled jobs | Cron Service | 75% | `src/cron/service.ts` CRUD operations | +| Security auditing | Security Audit | 70% | `src/security/audit.ts` configuration checks | +| SSRF protection | SSRF Module | 95% | `src/infra/net/ssrf.ts` DNS pinning | +| Configuration management | Config Module | 85% | Zod schemas, env substitution | +| TUI interface | TUI Components | 70% | Ink/React terminal UI | +| Web UI | UI Views | 65% | Solid.js browser interface | + +### Edge Cases (5%) + +| Capability | Component | Coverage | Evidence | +|------------|-----------|----------|----------| +| Device fingerprinting | Device Identity | 60% | `src/infra/device-identity.ts` | +| Browser automation | CDP Module | 50% | `src/browser/cdp.ts` Puppeteer | +| Auth profiles | Auth Profiles | 55% | `src/agents/auth-profiles.ts` | +| LanceDB memory | Memory Extension | 40% | `extensions/memory-lancedb/index.ts` | + +--- + +## 10. Component / Service Responsibilities + +| Component | Responsibility | Dependencies | Evidence | +|-----------|----------------|--------------|----------| +| **Gateway Server** | WebSocket control plane, auth, events | Auth Module, Exec Approval | `src/gateway/` | +| **Gateway Auth** | Multi-mode authentication (Token/Password/Tailscale/Device) | Crypto, Device Store | `src/gateway/auth.ts` | +| **Exec Approval Manager** | Command execution gating with human-in-the-loop | Gateway Events, Discord Monitor | `src/gateway/exec-approval-manager.ts` | +| **Memory Index Manager** | Vector embeddings, FTS5, hybrid search | SQLite, Embedding Providers | `src/memory/manager.ts` | +| **Cron Service** | Scheduled job management | Cron Store, Auto-Reply | `src/cron/service.ts` | +| **Security Audit** | Configuration security validation | Config Module | `src/security/audit.ts` | +| **SSRF Protection** | DNS pinning, private IP blocking | undici Agent | `src/infra/net/ssrf.ts` | +| **Call Manager** | Voice call state machine, lifecycle | Voice Providers, Transcript | `extensions/voice-call/src/manager.ts` | +| **Voice Providers** | Twilio/Plivo/Telnyx integration | External APIs, TwiML | `extensions/voice-call/src/providers/` | +| **Channel Adapters** | Platform-specific messaging | Platform APIs, Config | `extensions/{platform}/` | +| **Config Module** | Zod validation, env substitution, includes | File system | `src/config/` | +| **Auto-Reply Pipeline** | Message processing, command detection | Agent Runner, Memory | `src/web/auto-reply.ts` | +| **Agent Runner** | AI inference, tool execution, failover | AI APIs, Tools | Agent runtime | +| **TUI Components** | Terminal user interface | Ink, React | `src/tui/components/` | +| **UI Views** | Web configuration interface | Solid.js | `ui/src/ui/views/` | + +--- + +## 11. Interfaces & Contracts + +### Internal Interfaces + +| Interface | Provider | Consumer | Protocol | Evidence | +|-----------|----------|----------|----------|----------| +| GatewayClient | Gateway Server | TUI/UI/CLI | WebSocket JSON-RPC 2.0 | `src/gateway/client.ts` | +| ChannelMonitor | Channel Adapters | Auto-Reply | Event callbacks | `monitorProvider` pattern | +| MessageHandler | Auto-Reply | Channels | Internal function | `createMessageHandler()` | +| MemoryQuery | Memory Index | Agent Runner | SQLite queries | `src/memory/manager.ts` | +| ExecApprovalRequest | Exec Manager | Gateway/Discord | Promise-based | `src/gateway/exec-approval-manager.ts` | +| VoiceCallProvider | Voice Providers | Call Manager | Abstraction interface | `extensions/voice-call/src/providers/` | +| ConfigSchema | Config Module | All Components | Zod types | `src/config/zod-schema.ts` | + +### External Contracts + +| System | Protocol | Schema | Evidence | +|--------|----------|--------|----------| +| Claude AI | HTTPS REST | Claude API spec | Session key authentication | +| OpenAI | HTTPS REST | OpenAI API v1 | API key authentication | +| Google Gemini | HTTPS REST | Gemini API | API key authentication | +| Telegram | HTTPS REST/Webhooks | Bot API | Bot token | +| Discord | WebSocket + REST | Discord Gateway v10 | Bot token + OAuth2 | +| WhatsApp | Baileys WebSocket | WA Web protocol | QR device linking | +| Slack | HTTPS REST + Socket Mode | Events API v2 | OAuth tokens | +| Twilio | HTTPS REST + WebSocket | TwiML, Media Streams | Account SID + Auth Token | +| Plivo | HTTPS REST | Plivo API | Account credentials | +| Telnyx | HTTPS REST | Telnyx API v2 | API key | + +--- + +## 12. Data & Schema (Legacy) + +### Database Schema + +| Table/Store | Type | Purpose | Evidence | +|-------------|------|---------|----------| +| memory_entries | SQLite + sqlite-vec | Vector embeddings for RAG | `src/memory/manager.ts` | +| fts_index | SQLite FTS5 | Full-text keyword search | `src/memory/manager.ts` | +| sessions | JSONL files | Conversation transcripts | Session storage | +| cron_jobs | SQLite | Scheduled job definitions | `src/cron/store.ts` | +| call_records | SQLite | Voice call persistence | `extensions/voice-call/` | +| config | YAML/JSON files | Application configuration | `src/config/` | +| device_tokens | In-memory | Device authentication | `src/gateway/auth.ts` | +| exec_approvals | In-memory Map | Pending approval requests | `src/gateway/exec-approval-manager.ts` | + +### Schema Diagram + +```mermaid +erDiagram + MEMORY_ENTRIES { + text id PK + text content + blob embedding + text source + timestamp created_at + text metadata + } + + FTS_INDEX { + text rowid PK + text content + text source + } + + SESSIONS { + text session_id PK + text agent_id + jsonb messages + timestamp created_at + timestamp updated_at + } + + CRON_JOBS { + text id PK + text name + text schedule + text command + boolean enabled + timestamp last_run + timestamp next_run + } + + CALL_RECORDS { + text call_id PK + text phone_number + text provider + text status + text transcript + timestamp started_at + timestamp ended_at + } + + CONFIG { + text key PK + jsonb value + text source + } + + MEMORY_ENTRIES ||--o{ FTS_INDEX : "indexed_in" + SESSIONS ||--o{ MEMORY_ENTRIES : "generates" + CRON_JOBS ||--o{ SESSIONS : "triggers" +``` + +**Evidence**: Extracted from `src/memory/manager.ts`, `src/cron/store.ts`, `extensions/voice-call/`. + +--- + +## 13. Current Tech Stack + +| Category | Technology | Version | Purpose | Evidence | +|----------|------------|---------|---------|----------| +| **Language** | TypeScript | 5.x | Primary development language | `package.json`, 3028 .ts files | +| **Runtime** | Node.js | 22.12+ | JavaScript execution | `package.json` engines | +| **Alt Runtime** | Bun | Supported | Alternative runtime | `CLAWDBOT_PREFER_PNPM` flag | +| **Package Manager** | pnpm | 10.23.0 | Dependency management | `package.json` packageManager | +| **Bundler** | rolldown | Latest | ESM bundle generation | Build scripts | +| **Linter** | oxlint | Latest | Code linting | `.oxlintrc` | +| **Test Framework** | vitest | Latest | Unit/integration testing | `vitest.config.ts` | +| **Database** | SQLite | 3.x | Embedded data storage | Local file-based | +| **Vector Store** | sqlite-vec | Latest | Vector embeddings | `src/memory/manager.ts` | +| **Full-Text Search** | FTS5 | SQLite built-in | Keyword search | `src/memory/manager.ts` | +| **TUI Framework** | Ink | 4.x | Terminal UI | `src/tui/` | +| **UI Framework** | Solid.js | Latest | Web UI | `ui/` | +| **HTTP Client** | undici | Latest | HTTP requests with SSRF protection | `src/infra/net/` | +| **Schema Validation** | Zod | Latest | Runtime type validation | `src/config/zod-schema.ts` | +| **Container** | Docker | Latest | Deployment | `Dockerfile` | +| **CI/CD** | GitHub Actions | Latest | Automated pipelines | `.github/workflows/` | + +### Dependency Summary + +| Category | Count | Evidence | +|----------|-------|----------| +| Runtime dependencies | 200+ | `package.json` dependencies | +| Dev dependencies | 50+ | `package.json` devDependencies | +| Total packages | 250+ | `pnpm-lock.yaml` | + +--- + +## 14. NFR Targets (Current Implementation) + +### Performance + +| Metric | Current Value | Source | Evidence | +|--------|---------------|--------|----------| +| Gateway response time | <100ms (local) | WebSocket keepalive | `src/gateway/client.ts` tick-based | +| Embedding batch size | Configurable | Memory manager | `src/memory/manager.ts` | +| Memory query latency | <500ms | Hybrid search | sqlite-vec + FTS5 | +| Message processing | Single-threaded | Node.js event loop | Async/await patterns | +| Reconnect backoff | Exponential (1s-30s) | Gateway client | `src/gateway/client.ts` | + +### Availability + +| Metric | Current | Evidence | +|--------|---------|----------| +| Uptime SLA | No formal SLA | Self-hosted model | +| Recovery time | Manual restart | No auto-recovery orchestration | +| Failover | Model chain failover | Agent runtime model selection | +| Data durability | SQLite WAL mode | `src/memory/manager.ts` | + +### Scalability + +| Metric | Current | Evidence | +|--------|---------|----------| +| Horizontal scaling | Not supported | Single container deployment | +| Concurrent connections | Limited by event loop | Node.js single-threaded | +| Database scaling | Embedded (single file) | SQLite limitation | +| Channel parallelism | Per-channel threads | Platform-specific | + +--- + +## 15. Operations & SRE (Current) + +### Monitoring + +| Aspect | Tool | Metrics | Evidence | +|--------|------|---------|----------| +| APM | None (structured logs) | Console output | stdout/stderr | +| Logs | Console + file | JSON structured | Logging utilities | +| Alerts | None built-in | Manual monitoring | No alerting system | +| Health checks | Gateway ping | Connection status | WebSocket keepalive | + +### Deployment Operations + +| Operation | Method | Evidence | +|-----------|--------|----------| +| Build | `pnpm build` → rolldown | `package.json` scripts | +| Test | `pnpm test` → vitest | `vitest.config.ts` | +| Lint | `pnpm lint` → oxlint | `.oxlintrc` | +| Format | `pnpm format` | Formatting scripts | +| Deploy | Docker build + run | `Dockerfile`, `docker-compose.yml` | +| Secrets | detect-secrets | Pre-commit hook | + +### Runbooks + +| Operation | Documentation | Evidence | +|-----------|---------------|----------| +| Initial setup | README.md | Project documentation | +| Configuration | Config schema | `src/config/zod-schema.ts` | +| Channel setup | Platform docs | Per-channel README | +| Troubleshooting | Limited | Community Discord | + +### CI/CD Pipeline + +| Job | Purpose | Evidence | +|-----|---------|----------| +| install-check | Dependency validation | `.github/workflows/ci.yml` | +| lint | Code quality | oxlint | +| test | Unit/integration tests | vitest | +| build | Bundle generation | rolldown | +| protocol | Protocol validation | Custom checks | +| format | Code formatting | Prettier/similar | +| secrets | Secret scanning | detect-secrets | +| macos-app | macOS native build | Swift | +| android | Android build | Gradle | + +--- + +## 16. Security & Compliance (Current) + +### Security Implementation + +| Aspect | Implementation | Evidence | +|--------|----------------|----------| +| **Authentication** | Multi-mode: Token, Password, Tailscale, Device signature | `src/gateway/auth.ts` | +| **Timing-safe comparison** | crypto.timingSafeEqual for password/token validation | `src/gateway/auth.ts` | +| **TLS fingerprinting** | Client certificate fingerprint pinning | `src/gateway/auth.ts` | +| **SSRF protection** | DNS pinning, private IP range blocking | `src/infra/net/ssrf.ts` | +| **Exec approval** | Human-in-the-loop for command execution | `src/gateway/exec-approval-manager.ts` | +| **Input validation** | Zod schema validation | `src/config/zod-schema.ts` | +| **Secret scanning** | detect-secrets pre-commit | CI pipeline | +| **Container security** | Non-root user (node:1000) | `Dockerfile` | + +### Security Audit System + +| Check | Severity | Evidence | +|-------|----------|----------| +| Gateway binding configuration | Critical | `src/security/audit.ts` | +| Filesystem permissions (state dir) | Critical | `src/security/audit.ts` | +| Discord bot permissions | Warning | `src/security/audit.ts` | +| Slack OAuth scopes | Warning | `src/security/audit.ts` | +| Telegram bot settings | Warning | `src/security/audit.ts` | +| Tailscale funnel exposure | Warning | `src/security/audit.ts` | +| Elevated exec allowlist | Critical | `src/security/audit.ts` | +| Browser remote CDP | Critical | `src/security/audit.ts` | + +### Security Gaps Identified + +| Gap | Risk | Current State | +|-----|------|---------------| +| No rate limiting | DoS vulnerability | No built-in protection | +| In-memory exec approvals | Lost on restart | `ExecApprovalManager` Map | +| No circuit breaker | Cascade failures | Missing pattern | +| Limited audit logging | Forensics gap | Console logs only | +| No secrets rotation | Key compromise risk | Manual rotation | + +### Compliance + +| Requirement | Status | Evidence | +|-------------|--------|----------| +| GDPR | Partial | User data in local SQLite, no export/delete automation | +| SOC2 | Not assessed | Self-hosted, no formal audit | +| HIPAA | Not compliant | No PHI handling certification | +| PCI-DSS | N/A | No payment processing | + +--- + +*Part 2 of 3 - Sections 9-16 Complete* + +--- + +## 17. Migration / Expansion Paths (Legacy Analysis) + +### Current Constraints + +| Constraint | Impact | Evidence | +|------------|--------|----------| +| TypeScript monolith | No incremental language migration | Single `dist/main.mjs` bundle | +| Circular dependencies | 10-component cycle blocks modular extraction | `config` ↔ `commands/models` ↔ `ui/views` | +| In-memory state | Exec approvals lost on restart | `ExecApprovalManager` Map storage | +| SQLite embedded | Single-file DB limits horizontal scaling | `src/memory/manager.ts` | +| 28 channel integrations | Each requires migration testing | `extensions/` plugins | +| Constructor DI | Pattern must translate to Python | `Deps` interface pattern | + +### Potential Migration Paths + +| Path | Effort | Risk | Rationale | +|------|--------|------|-----------| +| **Hybrid/Strangler Fig** | High | Medium | Gradual replacement, coexistence during transition (68% confidence) | +| Greenfield Rewrite | Very High | High | Clean architecture but loses institutional knowledge (60% confidence) | +| Inline Upgrade | Very High | Very High | TypeScript → Python in-place nearly impossible (56% confidence) | + +### Migration Recommendations + +Based on validation scoring (overall complexity: 5.35/10, HIGH rating): + +1. **Strangler Fig Pattern**: Wrap legacy components with Python adapters +2. **Gateway-first**: Migrate WebSocket gateway to Python/FastAPI first +3. **Channel-by-channel**: Migrate adapters incrementally with parallel operation +4. **Data layer last**: SQLite schema changes after code migration + +--- + +## 18. Risks & Decisions (Technical) + +### Technical Risks + +| Risk | Severity | Evidence | Mitigation | +|------|----------|----------|------------| +| Circular dependencies | High | 10-component cycle in codebase | Refactor before migration | +| In-memory exec approvals | High | `ExecApprovalManager` state lost | Persist to SQLite | +| No rate limiting | High | Missing DoS protection | Add rate limiting in target | +| Missing circuit breaker | Medium | No external API isolation | Implement in target | +| 200K+ LOC codebase | High | 74286 symbols indexed | Phased migration approach | +| 28 channel integrations | High | Each needs migration testing | Automated adapter testing | +| Test coverage gap | Medium | 70% vs 80% target | Increase before migration | + +### Security Risks (Legacy) + +| Risk | Severity | Evidence | Mitigation | +|------|----------|----------|------------| +| Console-only audit logs | Medium | No persistent audit trail | Add structured audit logging | +| Manual secret rotation | Medium | No automated rotation | Implement vault integration | +| Limited compliance | Low | No GDPR automation | Add data export/delete API | + +### Architecture Decisions (Historical) + +| Decision | Rationale | Evidence | Impact | +|----------|-----------|----------|--------| +| TypeScript over JavaScript | Type safety for large codebase | `tsconfig.json` strict mode | Positive: maintainability | +| SQLite over PostgreSQL | Zero-config, embedded simplicity | Single file deployment | Positive: simplicity; Negative: scaling | +| WebSocket gateway | Real-time control plane needed | `src/gateway/client.ts` | Positive: responsive UI | +| Plugin architecture | Extensible channel support | `extensions/` directory | Positive: modularity | +| Constructor DI | Testable service composition | `Deps` interface pattern | Positive: testability | +| Monolith deployment | Rapid initial development | Single Docker container | Negative: scaling limitations | + +--- + +## 19. Requirements -> Code -> Tests Traceability + +| Requirement | Code Location | Test Coverage | Status | +|-------------|---------------|---------------|--------| +| FR-CRIT-001: Multi-channel messaging | `extensions/*/` (28 adapters) | Per-channel tests | Covered | +| FR-CRIT-002: AI inference | Agent runtime + providers | Unit + integration | Covered | +| FR-CRIT-003: Context-aware responses | `src/memory/manager.ts` | Memory search tests | Covered | +| FR-CRIT-004: Gateway control | `src/gateway/client.ts` | Gateway tests | Covered | +| FR-HIGH-001: Authentication | `src/gateway/auth.ts` | Auth tests | Covered | +| FR-HIGH-002: Exec approval | `src/gateway/exec-approval-manager.ts` | Approval tests | Covered | +| FR-HIGH-003: Voice calls | `extensions/voice-call/` | Voice tests | Partial | +| FR-HIGH-004: Cron scheduling | `src/cron/service.ts` | Cron tests | Covered | +| FR-MED-001: TUI interface | `src/tui/components/` | Component tests | Partial | +| FR-MED-002: Web UI | `ui/src/ui/views/` | UI tests | Partial | +| NFR-PERF-001: Response time <100ms | Gateway WebSocket | Load tests | Gap | +| NFR-SEC-001: SSRF protection | `src/infra/net/ssrf.ts` | SSRF tests | Covered | +| NFR-SEC-002: Timing-safe auth | `src/gateway/auth.ts` | Security tests | Covered | + +### Coverage Summary + +| Category | Covered | Gap | Total | +|----------|---------|-----|-------| +| Critical Requirements | 4 | 0 | 4 | +| High Priority | 4 | 0 | 4 | +| Medium Priority | 1 | 2 | 3 | +| NFRs | 2 | 1 | 3 | +| **Total** | **11** | **3** | **14** | + +--- + +## 20. Architecture Decision Records (Legacy) + +### ADR-001: TypeScript Monolith Architecture + +**Status**: Implemented (Legacy) +**Context**: Needed rapid development of multi-channel AI messaging assistant with type safety. +**Decision**: Build as TypeScript monolith with plugin system for channels. +**Consequences**: +- Positive: Fast iteration, type safety, single deployment +- Negative: Circular dependencies emerged, scaling limited +**Evidence**: `package.json`, `tsconfig.json`, `dist/main.mjs` + +### ADR-002: SQLite with Vector Extensions + +**Status**: Implemented (Legacy) +**Context**: Needed embedded database with vector search for RAG capabilities. +**Decision**: Use SQLite with sqlite-vec extension and FTS5 for hybrid search. +**Consequences**: +- Positive: Zero-config, fast reads, hybrid search works well +- Negative: Single-file limits concurrent writes, no horizontal scaling +**Evidence**: `src/memory/manager.ts`, sqlite-vec dependency + +### ADR-003: WebSocket Gateway Protocol + +**Status**: Implemented (Legacy) +**Context**: Needed real-time control plane for TUI/UI to communicate with backend. +**Decision**: Custom WebSocket protocol with JSON-RPC 2.0 semantics. +**Consequences**: +- Positive: Low latency, bi-directional, event streaming +- Negative: Custom protocol requires documentation, not REST +**Evidence**: `src/gateway/client.ts`, port 18789 + +### ADR-004: Multi-Mode Authentication + +**Status**: Implemented (Legacy) +**Context**: Users need flexible authentication options for different deployment scenarios. +**Decision**: Support Token, Password, Tailscale identity, and Device signature authentication. +**Consequences**: +- Positive: Flexible deployment, secure options +- Negative: Complex auth flow, multiple code paths +**Evidence**: `src/gateway/auth.ts`, timing-safe comparison + +### ADR-005: Channel Plugin Architecture + +**Status**: Implemented (Legacy) +**Context**: Need to support 28+ messaging platforms with consistent interface. +**Decision**: Plugin-based channel adapters in `extensions/` directory with manifest files. +**Consequences**: +- Positive: Easy to add new channels, isolated code per platform +- Negative: Dependency management across plugins, testing complexity +**Evidence**: `extensions/*/clawdbot.plugin.json` + +### ADR-006: Human-in-the-Loop Exec Approval + +**Status**: Implemented (Legacy) +**Context**: Security requirement to gate command execution with human approval. +**Decision**: Promise-based approval workflow with Discord button integration. +**Consequences**: +- Positive: Security gate prevents unauthorized execution +- Negative: In-memory state lost on restart, timeout handling complexity +**Evidence**: `src/gateway/exec-approval-manager.ts`, `src/discord/monitor/exec-approvals.ts` + +--- + +## 21. Infrastructure (Current State) + +### Current Infrastructure + +| Component | Technology | Purpose | Evidence | +|-----------|------------|---------|----------| +| **Compute** | Docker container | Application runtime | `Dockerfile` | +| **Base Image** | node:22-bookworm | Node.js 22 runtime | `Dockerfile` FROM | +| **Storage** | Docker volume | State persistence | `docker-compose.yml` volumes | +| **Database** | SQLite file | Embedded data storage | Local file in state/ | +| **Network** | Host network | Port exposure | Ports 18789, 18790 | +| **CI/CD** | GitHub Actions | Automated pipeline | `.github/workflows/ci.yml` | +| **Registry** | GitHub Container Registry | Image storage | CI workflow | + +### Infrastructure Diagram + +```mermaid +graph TB + subgraph CI["GitHub Actions CI"] + LINT["Lint (oxlint)"] + TEST["Test (vitest)"] + BUILD["Build (rolldown)"] + SECRETS["Secrets Scan"] + PUBLISH["Publish Image"] + + LINT --> TEST + TEST --> BUILD + BUILD --> SECRETS + SECRETS --> PUBLISH + end + + subgraph Host["Docker Host"] + subgraph Container["Moltbot Container"] + NODE["Node.js 22"] + APP["dist/main.mjs"] + end + + subgraph Volumes["Docker Volumes"] + STATE["state/"] + CONFIG["config/"] + end + + Volumes --> Container + end + + subgraph External["External Services"] + AI["AI APIs"] + VOICE["Voice Providers"] + CHANNELS["28 Channel Platforms"] + end + + PUBLISH --> Host + Container --> External + + GATEWAY["Port 18789"] --> Container + BRIDGE["Port 18790"] --> Container +``` + +### Resource Requirements (Observed) + +| Resource | Minimum | Recommended | Evidence | +|----------|---------|-------------|----------| +| CPU | 1 core | 2+ cores | Node.js single-threaded + async | +| Memory | 512MB | 1GB+ | Depends on channel count | +| Disk | 1GB | 10GB+ | SQLite + vector embeddings | +| Network | Standard | Low latency | WebSocket real-time | + +--- + +## 22. CI/CD Pipeline (Current) + +### Pipeline Stages + +| Stage | Tool | Purpose | Evidence | +|-------|------|---------|----------| +| Checkout | actions/checkout | Clone repository | `.github/workflows/ci.yml` | +| Setup | actions/setup-node | Install Node.js 22 | Setup job | +| Install | pnpm install | Install dependencies | install-check job | +| Lint | oxlint | Code quality | lint job | +| Test | vitest | Unit/integration tests | test job | +| Build | rolldown | Bundle generation | build job | +| Protocol | Custom | Protocol validation | protocol job | +| Format | Prettier | Code formatting | format job | +| Secrets | detect-secrets | Secret scanning | secrets job | +| macOS | Swift | Native macOS build | macos-app job | +| Android | Gradle | Android build | android job | + +### Pipeline Diagram + +```mermaid +flowchart LR + subgraph Trigger["Trigger"] + PUSH["Push"] + PR["Pull Request"] + end + + subgraph Setup["Setup"] + CHECKOUT["Checkout"] + NODE["Setup Node 22"] + PNPM["Setup pnpm"] + end + + subgraph Quality["Quality Gates"] + INSTALL["Install Check"] + LINT["Lint (oxlint)"] + FORMAT["Format Check"] + SECRETS["Secret Scan"] + end + + subgraph Test["Testing"] + UNIT["Unit Tests"] + INTEGRATION["Integration Tests"] + COVERAGE["Coverage (70%)"] + end + + subgraph Build["Build"] + BUNDLE["Bundle (rolldown)"] + PROTOCOL["Protocol Check"] + end + + subgraph Native["Native Apps"] + MACOS["macOS (Swift)"] + ANDROID["Android (Gradle)"] + end + + PUSH --> CHECKOUT + PR --> CHECKOUT + CHECKOUT --> NODE + NODE --> PNPM + PNPM --> INSTALL + + INSTALL --> LINT + INSTALL --> FORMAT + INSTALL --> SECRETS + + LINT --> UNIT + FORMAT --> UNIT + SECRETS --> UNIT + + UNIT --> INTEGRATION + INTEGRATION --> COVERAGE + COVERAGE --> BUNDLE + BUNDLE --> PROTOCOL + + PROTOCOL --> MACOS + PROTOCOL --> ANDROID +``` + +### Quality Gates + +| Gate | Threshold | Current | Status | +|------|-----------|---------|--------| +| Lint | 0 errors | 0 | Pass | +| Test | All pass | 100% | Pass | +| Coverage | 70% | 70% | Pass | +| Secrets | 0 detected | 0 | Pass | +| Build | Success | Success | Pass | + +--- + +## 23. Open Questions & Next Steps + +### Open Questions + +1. **Migration Strategy**: Should we migrate gateway first or channels first? +2. **Circular Dependencies**: How to refactor 10-component cycle before migration? +3. **State Persistence**: Move exec approvals to SQLite or Redis? +4. **Test Coverage**: Increase to 80% before or during migration? +5. **Channel Priority**: Which of 28 channels to migrate first? +6. **Python Framework**: FastAPI confirmed, but async patterns for WebSocket? + +### Decisions Needed + +| Decision | Options | Recommendation | +|----------|---------|----------------| +| Migration pattern | Strangler Fig vs Greenfield | Strangler Fig (68% confidence) | +| First component | Gateway vs Channels | Gateway (enables parallel development) | +| Python DI framework | None vs dependency-injector | dependency-injector or simple DI | +| Observability | Add during migration | OpenTelemetry from start | + +### Next Steps + +1. **Review**: Technical stakeholders review this specification +2. **Generate**: `technical-spec-target.md` for Python 3.12+ target +3. **Plan**: Migration roadmap based on both specifications +4. **Prototype**: Gateway adapter proof-of-concept +5. **Test**: Increase coverage to 80% before major changes + +--- + +## Appendices + +### A. File Reference Index + +| Section | Key Files | +|---------|-----------| +| Architecture | `package.json`, `tsconfig.json`, `Dockerfile` | +| Gateway | `src/gateway/client.ts`, `src/gateway/auth.ts` | +| Security | `src/infra/net/ssrf.ts`, `src/security/audit.ts` | +| Memory | `src/memory/manager.ts` | +| Channels | `extensions/*/clawdbot.plugin.json` | +| Voice | `extensions/voice-call/src/manager.ts` | +| Config | `src/config/zod-schema.ts` | +| CI/CD | `.github/workflows/ci.yml` | + +### B. Glossary + +| Term | Definition | +|------|------------| +| Gateway | WebSocket control plane server | +| Exec Approval | Human-in-the-loop command gating | +| SSRF | Server-Side Request Forgery | +| sqlite-vec | SQLite vector extension for embeddings | +| FTS5 | SQLite Full-Text Search version 5 | +| Strangler Fig | Gradual migration pattern | +| ADR | Architecture Decision Record | + +--- + +*Part 3 of 3 - Sections 17-23 Complete* + +*Technical Specification - Legacy System Complete (23 Sections)* diff --git a/.analysis/moltbotsec-20260129-202219/reports/technical-spec-target.md b/.analysis/moltbotsec-20260129-202219/reports/technical-spec-target.md new file mode 100644 index 000000000..98bdedd34 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/reports/technical-spec-target.md @@ -0,0 +1,2693 @@ +# Technical Specification - Target System + +**Project**: Moltbot (Multi-Channel AI Messaging Assistant) +**Analysis Date**: 2026-01-29 +**Status**: Target Architecture for Python 3.12+ Modernization +**Migration Approach**: Strangler Fig Pattern (68% confidence) + +--- + +## 1. Architectural Principles (Target) + +### Target Architecture Style + +**Pattern**: Modular Monolith with Clean Architecture Boundaries → Microservices-Ready +**Rationale**: Maintain deployment simplicity while enabling future decomposition. Clean module boundaries prevent circular dependency issues from legacy system. + +### Legacy → Target Mapping + +| Legacy Principle | Target Principle | Transformation | +|------------------|------------------|----------------| +| Bidirectional dependencies (violation) | Unidirectional dependency flow | Dependency Inversion + Interface Segregation | +| Config as central hub (2300 symbols) | Config as leaf dependency | Invert ownership, inject config | +| Constructor DI (TypeScript) | Dependency Injection (Python) | dependency-injector or simple container | +| WebSocket JSON-RPC 2.0 | WebSocket JSON-RPC 2.0 | **Preserve** protocol compatibility | +| Plugin architecture | Adapter pattern with registry | Explicit registration, protocol buffers | +| In-memory state (exec approvals) | Persistent state (SQLite) | Move volatile state to database | + +### Target Principles + +| Principle | Implementation | Evidence/Decision | +|-----------|----------------|-------------------| +| **Clean Architecture** | Core domain isolated from I/O | Domain models have no framework dependencies | +| **Dependency Inversion** | High-level modules own interfaces | Infrastructure depends on domain, not reverse | +| **Single Responsibility** | One reason to change per module | Config, Auth, Gateway separate concerns | +| **Interface Segregation** | Small, focused protocols | `ChannelAdapter`, `AIProvider`, `StorageBackend` | +| **Explicit Dependencies** | Injected via constructor/factory | No global state, no implicit singletons | +| **Fail-Fast Validation** | Pydantic models at boundaries | Schema validation at entry points | + +### Architectural Strengths (Target) + +| Strength | Implementation | Benefit | +|----------|----------------|---------| +| No circular dependencies | Layered architecture with strict direction | Independent testing, easier refactoring | +| Persistent exec approvals | SQLite-backed approval queue | Survives restart, audit trail | +| Circuit breaker pattern | tenacity + circuit breaker wrapper | External API failure isolation | +| Async-first design | asyncio + ASGI (FastAPI) | High concurrency, better resource utilization | +| OpenTelemetry observability | Traces, metrics, logs from start | Production-ready monitoring | + +### Architectural Constraints + +| Constraint | Reason | Mitigation | +|------------|--------|------------| +| Python GIL | Single-threaded CPU-bound | Use asyncio for I/O, multiprocessing if needed | +| SQLite single-writer | Embedded database limitation | WAL mode, connection pooling, queue writes | +| 28 channel adapters | Each requires migration | Plugin architecture + selective installation | + +--- + +## 1.1. Plugin Architecture + +### Design Philosophy + +**Principle**: Install only what you need. The core system is minimal; capabilities are added via plugins. + +```mermaid +graph TB + subgraph Core["moltbot (core)"] + GATEWAY["Gateway"] + AUTH["Auth"] + MEMORY["Memory"] + AGENT["Agent"] + SCHEDULER["Scheduler"] + end + + subgraph Channels["Channel Plugins"] + TELEGRAM["moltbot-telegram"] + DISCORD["moltbot-discord"] + SLACK["moltbot-slack"] + WHATSAPP["moltbot-whatsapp"] + SIGNAL["moltbot-signal"] + MATRIX["moltbot-matrix"] + MORE_CH["... 20+ more"] + end + + subgraph AI["AI Provider Plugins"] + CLAUDE["moltbot-claude"] + OPENAI["moltbot-openai"] + GEMINI["moltbot-gemini"] + LOCAL["moltbot-local"] + end + + subgraph Extensions["Extension Plugins"] + VOICE["moltbot-voice"] + CRON["moltbot-cron"] + WEB["moltbot-web"] + TUI["moltbot-tui"] + end + + Core --> Channels + Core --> AI + Core --> Extensions +``` + +### Plugin Categories + +| Category | Package Pattern | Purpose | Examples | +|----------|-----------------|---------|----------| +| **Core** | `moltbot` | Essential runtime, gateway, auth | Required | +| **Channels** | `moltbot-{platform}` | Messaging platform adapters | `moltbot-telegram`, `moltbot-discord` | +| **AI Providers** | `moltbot-{provider}` | AI inference backends | `moltbot-claude`, `moltbot-openai` | +| **Extensions** | `moltbot-{feature}` | Optional features | `moltbot-voice`, `moltbot-cron` | +| **UI** | `moltbot-{ui}` | User interfaces | `moltbot-tui`, `moltbot-web` | + +### Installation Examples + +```bash +# Minimal: Core + Telegram + Claude +uv pip install moltbot moltbot-telegram moltbot-claude + +# Personal use: Multiple channels +uv pip install moltbot moltbot-telegram moltbot-discord moltbot-signal moltbot-claude + +# Business: Slack + Teams + Voice +uv pip install moltbot moltbot-slack moltbot-teams moltbot-voice moltbot-openai + +# Full installation (development/testing) +uv pip install moltbot[all] + +# With extras (recommended for end users) +uv pip install "moltbot[telegram,discord,claude]" +``` + +### Plugin Interface Contract + +```python +# moltbot/core/plugin.py +from abc import ABC, abstractmethod +from typing import Protocol, runtime_checkable + +@runtime_checkable +class MoltbotPlugin(Protocol): + """Base protocol all plugins must implement.""" + + @property + def name(self) -> str: + """Unique plugin identifier.""" + ... + + @property + def version(self) -> str: + """Plugin version (semver).""" + ... + + async def initialize(self, app: "MoltbotApp") -> None: + """Called when plugin is loaded.""" + ... + + async def shutdown(self) -> None: + """Called when plugin is unloaded.""" + ... + + +class ChannelPlugin(MoltbotPlugin, Protocol): + """Protocol for messaging channel plugins.""" + + @property + def channel_type(self) -> str: + """Channel identifier (e.g., 'telegram', 'discord').""" + ... + + async def connect(self) -> None: + """Establish connection to platform.""" + ... + + async def disconnect(self) -> None: + """Gracefully disconnect.""" + ... + + async def send_message(self, channel_id: str, content: str) -> None: + """Send message to channel.""" + ... + + async def on_message(self, callback: MessageCallback) -> None: + """Register message handler.""" + ... + + +class AIProviderPlugin(MoltbotPlugin, Protocol): + """Protocol for AI provider plugins.""" + + @property + def provider_name(self) -> str: + """Provider identifier (e.g., 'claude', 'openai').""" + ... + + async def generate( + self, + messages: list[Message], + **kwargs + ) -> AIResponse: + """Generate AI response.""" + ... + + async def embed(self, text: str) -> list[float]: + """Generate embedding vector.""" + ... +``` + +### Plugin Discovery & Registration + +```python +# Plugin discovery via entry points (pyproject.toml) +# Each plugin package declares its entry point: + +# moltbot-telegram/pyproject.toml +[project.entry-points."moltbot.plugins"] +telegram = "moltbot_telegram:TelegramPlugin" + +# moltbot-claude/pyproject.toml +[project.entry-points."moltbot.plugins"] +claude = "moltbot_claude:ClaudePlugin" + +# Core discovers and loads plugins at startup: +# moltbot/core/plugin_loader.py +from importlib.metadata import entry_points + +def discover_plugins() -> dict[str, type[MoltbotPlugin]]: + """Discover all installed moltbot plugins.""" + plugins = {} + eps = entry_points(group="moltbot.plugins") + for ep in eps: + try: + plugin_class = ep.load() + plugins[ep.name] = plugin_class + except Exception as e: + logger.warning(f"Failed to load plugin {ep.name}: {e}") + return plugins +``` + +### Plugin Configuration + +```yaml +# config/moltbot.yaml +core: + gateway_port: 18789 + api_port: 8000 + +# Only configure plugins you have installed +plugins: + telegram: + enabled: true + bot_token: ${TELEGRAM_BOT_TOKEN} + + discord: + enabled: true + bot_token: ${DISCORD_BOT_TOKEN} + + claude: + enabled: true + api_key: ${ANTHROPIC_API_KEY} + model: claude-sonnet-4-20250514 + + # Plugins not installed are simply ignored + # No errors for missing plugin configs +``` + +### Dependency Isolation + +Each plugin manages its own dependencies: + +``` +moltbot/ # Core: minimal deps (fastapi, pydantic, aiosqlite) +moltbot-telegram/ # Deps: aiogram +moltbot-discord/ # Deps: discord.py +moltbot-slack/ # Deps: slack-sdk +moltbot-whatsapp/ # Deps: (none - uses subprocess bridge) +moltbot-claude/ # Deps: anthropic +moltbot-openai/ # Deps: openai +moltbot-voice/ # Deps: twilio, websockets +``` + +**Benefits**: +- No dependency conflicts between plugins +- Smaller installation footprint +- Faster startup (only load what's needed) +- Independent versioning and updates + +### Plugin Lifecycle + +```mermaid +stateDiagram-v2 + [*] --> Discovered: entry_points scan + Discovered --> Configured: config exists + Discovered --> Disabled: no config / disabled=true + Configured --> Initializing: app.startup() + Initializing --> Ready: initialize() success + Initializing --> Failed: initialize() error + Ready --> Running: connect() / activate() + Running --> Stopping: app.shutdown() + Stopping --> Stopped: shutdown() complete + Failed --> [*] + Stopped --> [*] + Disabled --> [*] +``` + +### Plugin Testing + +```python +# Each plugin is independently testable +# tests/plugins/test_telegram.py + +import pytest +from moltbot_telegram import TelegramPlugin +from moltbot.testing import MockApp, MockMessage + +@pytest.fixture +def plugin(): + return TelegramPlugin() + +@pytest.fixture +def mock_app(): + return MockApp() + +async def test_plugin_initialization(plugin, mock_app): + await plugin.initialize(mock_app) + assert plugin.name == "telegram" + assert mock_app.plugins["telegram"] == plugin + +async def test_message_handling(plugin, mock_app): + await plugin.initialize(mock_app) + + msg = MockMessage(text="Hello", channel_id="123") + response = await plugin.handle_message(msg) + + assert response is not None +``` + +--- + +## 2. C4 Architecture Views (Target) + +### 2.1 System Context (C4 Level 1) - Target + +```mermaid +C4Context + title Moltbot Target System Context + + Person(user, "User", "End user interacting via messaging platforms") + Person(admin, "Admin", "System administrator managing Moltbot") + Person(developer, "Developer", "Integrating via API") + + System(moltbot, "Moltbot", "Python 3.12+ multi-channel AI messaging assistant") + + System_Ext(telegram, "Telegram", "Telegram Bot API") + System_Ext(discord, "Discord", "Discord Bot Gateway") + System_Ext(whatsapp, "WhatsApp", "Baileys/WA Web") + System_Ext(slack, "Slack", "Slack Events API") + System_Ext(signal, "Signal", "Signal Protocol") + System_Ext(channels, "16+ Channels", "Matrix, Teams, etc.") + + System_Ext(claude, "Claude AI", "Anthropic Claude API") + System_Ext(openai, "OpenAI", "GPT API + Embeddings") + System_Ext(gemini, "Google Gemini", "Gemini API") + + System_Ext(twilio, "Twilio", "Voice/SMS provider") + System_Ext(plivo, "Plivo", "Voice provider") + System_Ext(telnyx, "Telnyx", "Voice provider") + + System_Ext(otel, "OpenTelemetry Collector", "Observability backend") + + Rel(user, telegram, "Messages via") + Rel(user, discord, "Messages via") + Rel(user, whatsapp, "Messages via") + Rel(user, slack, "Messages via") + Rel(user, signal, "Messages via") + Rel(user, channels, "Messages via") + + Rel(telegram, moltbot, "Webhooks/Polling") + Rel(discord, moltbot, "Gateway WebSocket") + Rel(whatsapp, moltbot, "Baileys connection") + Rel(slack, moltbot, "Events API") + Rel(signal, moltbot, "Signal protocol") + Rel(channels, moltbot, "Platform APIs") + + Rel(moltbot, claude, "AI inference") + Rel(moltbot, openai, "AI inference + embeddings") + Rel(moltbot, gemini, "AI inference") + + Rel(moltbot, twilio, "Voice calls") + Rel(moltbot, plivo, "Voice calls") + Rel(moltbot, telnyx, "Voice calls") + + Rel(moltbot, otel, "Telemetry export") + + Rel(admin, moltbot, "Gateway WebSocket control") + Rel(developer, moltbot, "REST API") +``` + +### 2.2 Container View (C4 Level 2) - Target + +```mermaid +C4Container + title Moltbot Target Container View + + Person(user, "User", "End user") + Person(admin, "Admin", "Administrator") + + System_Boundary(moltbot, "Moltbot System - Python 3.12+") { + Container(gateway, "Gateway Server", "Python/FastAPI", "WebSocket control plane, auth, exec approval") + Container(api, "REST API", "Python/FastAPI", "HTTP API for integrations") + Container(autoreply, "Auto-Reply Engine", "Python", "Message processing, command detection, agent execution") + Container(adapters, "Channel Adapters", "Python Plugins", "28 platform integrations with adapter pattern") + Container(memory, "Memory Service", "Python", "Vector embeddings, FTS5, hybrid search") + Container(scheduler, "Scheduler Service", "Python/APScheduler", "Scheduled job management") + Container(voice, "Voice Extension", "Python", "Twilio/Plivo/Telnyx calls") + Container(storage, "Storage Layer", "SQLite + sqlite-vec", "Persistent data with vectors") + Container(otel_sdk, "Telemetry SDK", "OpenTelemetry", "Tracing, metrics, logging") + } + + System_Ext(aiapis, "AI APIs", "Claude, OpenAI, Gemini") + System_Ext(platforms, "Messaging Platforms", "28 channels") + System_Ext(voiceproviders, "Voice Providers", "Twilio, Plivo, Telnyx") + System_Ext(otel_collector, "OTel Collector", "Observability") + + Rel(admin, gateway, "WebSocket JSON-RPC", "wss://127.0.0.1:18789") + Rel(admin, api, "HTTP REST", "http://127.0.0.1:8000") + + Rel(platforms, adapters, "Platform APIs", "HTTPS/WebSocket") + Rel(adapters, autoreply, "Internal protocol", "async/await") + Rel(autoreply, aiapis, "AI inference", "HTTPS") + Rel(autoreply, memory, "RAG queries", "Internal") + Rel(memory, storage, "SQLite", "aiosqlite") + Rel(gateway, autoreply, "Control events", "Internal") + Rel(scheduler, autoreply, "Scheduled triggers", "Internal") + Rel(voice, voiceproviders, "Voice streams", "WebSocket/TwiML") + Rel(voice, autoreply, "Transcripts", "Internal") + Rel(otel_sdk, otel_collector, "OTLP", "gRPC/HTTP") +``` + +### 2.3 Component View (C4 Level 3) - Target + +```mermaid +C4Component + title Moltbot Target Core Components + + Container_Boundary(domain, "Domain Layer") { + Component(models, "Domain Models", "Python/Pydantic", "Core business entities") + Component(services, "Domain Services", "Python", "Business logic, pure functions") + Component(ports, "Ports (Interfaces)", "Python Protocols", "Abstract interfaces for infrastructure") + } + + Container_Boundary(application, "Application Layer") { + Component(handlers, "Message Handlers", "Python", "Orchestrate domain operations") + Component(commands, "Command Handlers", "Python", "CQRS command execution") + Component(queries, "Query Handlers", "Python", "CQRS read operations") + Component(events, "Event Bus", "Python", "Async event distribution") + } + + Container_Boundary(infrastructure, "Infrastructure Layer") { + Component(gateway_server, "Gateway Server", "FastAPI/WebSocket", "Control plane implementation") + Component(gateway_auth, "Auth Adapter", "Python", "Multi-mode authentication") + Component(exec_approval, "Exec Approval Store", "SQLite", "Persistent approval queue") + Component(memory_adapter, "Memory Adapter", "Python", "sqlite-vec + FTS5 implementation") + Component(ssrf, "SSRF Protection", "Python/httpx", "DNS pinning, IP validation") + Component(audit, "Audit Logger", "Python", "Structured security audit") + Component(otel, "OTel Instrumentation", "OpenTelemetry", "Auto-instrumentation") + } + + Container_Boundary(adapters_layer, "Adapters Layer") { + Component(telegram_adapter, "Telegram Adapter", "Python", "Bot API polling/webhooks") + Component(discord_adapter, "Discord Adapter", "Python/discord.py", "Gateway + REST API") + Component(whatsapp_adapter, "WhatsApp Adapter", "Python", "Baileys bridge") + Component(slack_adapter, "Slack Adapter", "Python/slack-sdk", "Events API + Socket Mode") + Component(other_adapters, "16+ Other Adapters", "Python", "Signal, Matrix, Teams, etc.") + } + + Rel(handlers, models, "Uses") + Rel(handlers, services, "Calls") + Rel(handlers, ports, "Depends on") + Rel(gateway_server, handlers, "Invokes") + Rel(gateway_auth, ports, "Implements") + Rel(memory_adapter, ports, "Implements") + Rel(telegram_adapter, ports, "Implements ChannelPort") + Rel(discord_adapter, ports, "Implements ChannelPort") + Rel(exec_approval, ports, "Implements ApprovalPort") +``` + +**Key Changes from Legacy**: +- Clear layer separation with unidirectional dependencies +- Domain layer has zero external dependencies +- Infrastructure implements ports defined by domain +- Adapters are isolated, independently testable + +--- + +## 3. Component Dependency Diagram (Target) + +```mermaid +graph TB + subgraph Domain["Domain Layer (0 external deps)"] + MODELS["models
Pydantic entities"] + SERVICES["services
Business logic"] + PORTS["ports
Protocol interfaces"] + end + + subgraph Application["Application Layer"] + HANDLERS["handlers
Orchestration"] + COMMANDS["commands
Write operations"] + QUERIES["queries
Read operations"] + EVENTS["event_bus
Async events"] + end + + subgraph Infrastructure["Infrastructure Layer"] + GATEWAY["gateway
WebSocket server"] + AUTH["auth
Authentication"] + STORAGE["storage
SQLite adapter"] + MEMORY["memory
Vector search"] + APPROVAL["approval
Exec queue"] + OTEL["telemetry
OpenTelemetry"] + end + + subgraph Adapters["Adapters Layer"] + TELEGRAM["telegram_adapter"] + DISCORD["discord_adapter"] + WHATSAPP["whatsapp_adapter"] + SLACK["slack_adapter"] + OTHERS["16+ adapters"] + end + + %% Domain has NO dependencies + MODELS --> |0| MODELS + + %% Application depends on Domain + HANDLERS --> SERVICES + HANDLERS --> PORTS + COMMANDS --> SERVICES + QUERIES --> SERVICES + EVENTS --> MODELS + + %% Infrastructure depends on Application + Domain + GATEWAY --> HANDLERS + AUTH --> PORTS + STORAGE --> PORTS + MEMORY --> PORTS + APPROVAL --> PORTS + + %% Adapters depend on Application + Domain + TELEGRAM --> PORTS + DISCORD --> PORTS + WHATSAPP --> PORTS + SLACK --> PORTS + OTHERS --> PORTS + + %% No circular dependencies + style MODELS fill:#90EE90 + style SERVICES fill:#90EE90 + style PORTS fill:#90EE90 +``` + +### Legacy → Target Dependency Comparison + +| Aspect | Legacy | Target | Improvement | +|--------|--------|--------|-------------| +| Circular dependencies | 1 cycle (10 components) | 0 cycles | 100% elimination | +| Config dependencies | 445+ bidirectional | ~30 unidirectional | 85% reduction | +| Cross-layer coupling | High (config hub) | None (strict layers) | Clean architecture | +| Test isolation | Difficult | Each layer independent | Full unit test coverage | + +### Target Module Structure (Plugin-Based) + +``` +# CORE PACKAGE: moltbot (required) +moltbot/ +├── core/ # Plugin system +│ ├── plugin.py # Plugin protocols & base classes +│ ├── loader.py # Plugin discovery & loading +│ ├── registry.py # Plugin registry +│ └── config.py # Plugin configuration +├── domain/ # Layer 0: Pure domain (no external deps) +│ ├── models/ # Pydantic entities +│ │ ├── message.py +│ │ ├── channel.py +│ │ ├── approval.py +│ │ └── session.py +│ ├── services/ # Business logic (pure functions) +│ │ ├── message_service.py +│ │ └── approval_service.py +│ └── ports/ # Abstract interfaces (Protocol classes) +│ ├── channel_port.py +│ ├── ai_provider_port.py +│ ├── storage_port.py +│ └── auth_port.py +├── application/ # Layer 1: Use cases +│ ├── handlers/ # Message orchestration +│ ├── commands/ # Write operations +│ ├── queries/ # Read operations +│ └── events/ # Event bus +├── infrastructure/ # Layer 2: Core implementations +│ ├── gateway/ # WebSocket server +│ ├── auth/ # Authentication +│ ├── storage/ # SQLite +│ ├── memory/ # Vector search +│ └── telemetry/ # OpenTelemetry +└── testing/ # Test utilities for plugins + ├── mocks.py + └── fixtures.py + +# CHANNEL PLUGINS: Separate packages (install as needed) +moltbot-telegram/ # uv pip install moltbot-telegram +├── moltbot_telegram/ +│ ├── __init__.py # Exports TelegramPlugin +│ ├── plugin.py # TelegramPlugin(ChannelPlugin) +│ ├── adapter.py # Telegram API adapter +│ └── config.py # Telegram-specific config +├── pyproject.toml # Declares entry point +└── tests/ + +moltbot-discord/ # uv pip install moltbot-discord +moltbot-slack/ # uv pip install moltbot-slack +moltbot-whatsapp/ # uv pip install moltbot-whatsapp +moltbot-signal/ # uv pip install moltbot-signal +moltbot-matrix/ # uv pip install moltbot-matrix +# ... 20+ more channel plugins + +# AI PROVIDER PLUGINS: Separate packages +moltbot-claude/ # uv pip install moltbot-claude +moltbot-openai/ # uv pip install moltbot-openai +moltbot-gemini/ # uv pip install moltbot-gemini +moltbot-local/ # uv pip install moltbot-local (ollama, etc.) + +# EXTENSION PLUGINS: Optional features +moltbot-voice/ # uv pip install moltbot-voice +moltbot-cron/ # uv pip install moltbot-cron +moltbot-tui/ # uv pip install moltbot-tui +moltbot-web/ # uv pip install moltbot-web +``` + +--- + +## 4. Sequence Diagrams (Target) + +### 4.1 Message Processing Flow (Target) + +```mermaid +sequenceDiagram + participant Platform as Messaging Platform + participant Adapter as Channel Adapter + participant Handler as Message Handler + participant Service as Domain Service + participant Memory as Memory Port + participant Agent as Agent Runner + participant AI as AI Provider + participant OTel as OpenTelemetry + + OTel->>OTel: Start trace span + + Platform->>Adapter: Incoming message + Adapter->>Adapter: Normalize to InternalMessage + Adapter->>Handler: handle_message(msg) + + Handler->>Service: validate_dm_policy(msg) + + alt DM Policy Rejected + Service-->>Handler: PolicyResult.DENIED + Handler-->>Adapter: No response + OTel->>OTel: Record policy_denied metric + else DM Policy Allowed + Service-->>Handler: PolicyResult.ALLOWED + Handler->>Service: detect_command(msg) + + alt Command Detected + Handler->>Agent: execute_command(cmd) + else Regular Message + Handler->>Memory: query_context(msg.text) + Memory-->>Handler: RelevantContext + + Handler->>Agent: run_agent(msg, context) + end + + Agent->>AI: inference(prompt) + + alt Rate Limit / Error + AI-->>Agent: ProviderError + Agent->>Agent: failover_to_next_model() + OTel->>OTel: Record failover metric + else Success + AI-->>Agent: AIResponse + end + + Agent-->>Handler: AgentResult + Handler->>Adapter: format_response(result) + Adapter->>Platform: send_message() + + OTel->>OTel: Complete span, record latency + end +``` + +**Changes from Legacy**: +- OpenTelemetry tracing integrated from start +- Clear domain service boundaries +- Explicit failover metrics tracking + +### 4.2 Gateway Authentication Flow (Target) + +```mermaid +sequenceDiagram + participant Client as Gateway Client + participant Server as Gateway Server (FastAPI) + participant Auth as Auth Port + participant Store as Auth Store (SQLite) + participant OTel as OpenTelemetry + + OTel->>OTel: Start auth span + + Client->>Server: WebSocket connect (wss://127.0.0.1:18789) + Server->>Server: Extract TLS fingerprint + + alt Token Auth + Client->>Server: {"method": "auth.token", "params": {"token": "..."}} + Server->>Auth: validate_token(token) + Auth->>Auth: timing_safe_compare(token) + Auth-->>Server: AuthResult + else Password Auth + Client->>Server: {"method": "auth.password", "params": {"password": "..."}} + Server->>Auth: validate_password(password) + Auth->>Auth: argon2_verify(hash, password) + Auth-->>Server: AuthResult + else Device Auth + Client->>Server: {"method": "auth.device", "params": {"public_key": "..."}} + Server->>Store: lookup_device(public_key) + Store-->>Server: DeviceRecord + Server->>Client: {"result": {"nonce": "..."}} + Client->>Client: sign(nonce, private_key) + Client->>Server: {"method": "auth.device.verify", "params": {"signature": "..."}} + Server->>Auth: verify_signature(nonce, signature, public_key) + Auth-->>Server: AuthResult + else Tailscale Auth + Client->>Server: {"method": "auth.tailscale"} + Server->>Auth: tailscale_whois(peer_ip) + Auth-->>Server: TailscaleIdentity + end + + alt Auth Success + Server->>Store: create_session(user_id, fingerprint) + Store-->>Server: SessionToken + Server-->>Client: {"result": {"session_token": "...", "expires_at": "..."}} + OTel->>OTel: Record auth_success metric + else Auth Failure + Server-->>Client: {"error": {"code": -32001, "message": "Authentication failed"}} + Server->>Server: Close connection + OTel->>OTel: Record auth_failure metric, security audit + end +``` + +**Changes from Legacy**: +- Argon2 password hashing (upgraded from timing-safe comparison) +- Session tokens persisted to SQLite +- Security audit events via OpenTelemetry + +### 4.3 Exec Approval Workflow (Target - Persistent) + +```mermaid +sequenceDiagram + participant Agent as Agent Runner + participant Handler as Approval Handler + participant Store as Approval Store (SQLite) + participant Gateway as Gateway Server + participant Discord as Discord Monitor + participant Admin as Admin User + participant OTel as OpenTelemetry + + OTel->>OTel: Start approval span + + Agent->>Handler: request_approval(command, session_key) + Handler->>Store: insert_pending_approval(approval) + Store-->>Handler: approval_id + + Handler->>Gateway: emit("exec_approval_request", approval_id) + Gateway->>Discord: post_approval_message(approval) + Discord-->>Admin: Show approval buttons (Approve/Deny) + + par Timeout Monitoring + Handler->>Handler: schedule_timeout_check(approval_id, timeout_ms) + Note over Handler,Store: Background task checks expiry + and User Response + Admin->>Discord: Click Approve/Deny + Discord->>Handler: resolve_approval(approval_id, decision) + Handler->>Store: update_approval_status(approval_id, decision) + end + + Handler->>Store: get_approval_status(approval_id) + Store-->>Handler: ApprovalRecord + + alt Approved + Handler-->>Agent: ApprovalResult(approved=True) + Agent->>Agent: execute_command() + OTel->>OTel: Record approval_granted metric + else Denied + Handler-->>Agent: ApprovalResult(approved=False, reason="denied") + Agent->>Agent: reject_execution() + OTel->>OTel: Record approval_denied metric + else Timeout + Handler->>Store: update_approval_status(approval_id, "expired") + Handler-->>Agent: ApprovalResult(approved=False, reason="timeout") + Agent->>Agent: reject_execution() + OTel->>OTel: Record approval_timeout metric + end +``` + +**Key Improvement**: Approvals are **persisted to SQLite**, surviving restarts. Audit trail maintained via OpenTelemetry. + +### 4.4 Voice Call State Machine (Target) + +```mermaid +sequenceDiagram + participant User as User + participant Handler as Voice Handler + participant FSM as Call State Machine + participant Provider as Voice Provider Port + participant Twilio as Twilio API + participant Agent as Agent Runner + participant Store as Call Store (SQLite) + participant OTel as OpenTelemetry + + OTel->>OTel: Start call span + + User->>Handler: initiate_call(phone_number) + Handler->>FSM: transition(IDLE -> INITIATING) + Handler->>Store: create_call_record(call) + + FSM->>Provider: connect(phone_number) + Provider->>Twilio: POST /Calls + Twilio-->>Provider: CallSid + Provider-->>FSM: connected(call_sid) + + FSM->>FSM: transition(INITIATING -> RINGING) + Handler->>Store: update_call_status(RINGING) + + Twilio->>Provider: Webhook: call_answered + Provider->>FSM: on_answered() + FSM->>FSM: transition(RINGING -> IN_PROGRESS) + FSM->>FSM: start_max_duration_timer() + Handler->>Store: update_call_status(IN_PROGRESS) + + loop During Call + Twilio->>Provider: MediaStream audio + Provider->>Handler: on_transcript(text) + Handler->>Agent: process_utterance(text) + Agent-->>Handler: response + Handler->>Provider: speak(response) + Provider->>Twilio: TTS audio + Handler->>Store: append_transcript(text, response) + end + + alt User Hangup + Twilio->>Provider: Webhook: call_ended + else Max Duration + FSM->>Provider: hangup() + else Agent Ends + Agent->>FSM: end_call() + FSM->>Provider: hangup() + end + + Provider->>FSM: on_ended() + FSM->>FSM: transition(* -> COMPLETED) + Handler->>Store: finalize_call_record() + OTel->>OTel: Complete span, record call_duration metric +``` + +**Changes from Legacy**: +- Explicit state machine with validated transitions +- All call records persisted to SQLite immediately +- Call duration and transcript stored for analytics + +--- + +## 5. Deployment Architecture (Target) + +### Target Deployment Model + +**Platform**: Docker Compose (user preference Q5/Q6) +**Container Runtime**: Docker (user preference Q7) +**Base Image**: python:3.12-slim-bookworm + +```mermaid +graph TB + subgraph Host["Docker Host"] + subgraph Compose["Docker Compose Stack"] + subgraph App["Moltbot Container"] + PYTHON["Python 3.12"] + FASTAPI["FastAPI/Uvicorn"] + SQLITE["SQLite DB"] + end + + subgraph OTel["OpenTelemetry Stack"] + COLLECTOR["OTel Collector"] + PROMETHEUS["Prometheus"] + GRAFANA["Grafana"] + LOKI["Loki (Logs)"] + end + end + + VOLUMES["Docker Volumes"] + VOLUMES -->|"data/"| SQLITE + VOLUMES -->|"config/"| FASTAPI + VOLUMES -->|"metrics/"| PROMETHEUS + end + + subgraph External["External Services"] + AI["AI APIs
(Claude, OpenAI, Gemini)"] + VOICE["Voice Providers
(Twilio, Plivo, Telnyx)"] + PLATFORMS["Messaging Platforms
(28 channels)"] + end + + HOST_NET["Host Network"] + HOST_NET -->|"18789 (Gateway)"| App + HOST_NET -->|"8000 (REST API)"| App + HOST_NET -->|"3000 (Grafana)"| Compose + + App -->|"HTTPS"| AI + App -->|"WebSocket"| VOICE + App -->|"HTTPS/WS"| PLATFORMS + + App -->|"OTLP"| COLLECTOR + COLLECTOR -->|"metrics"| PROMETHEUS + COLLECTOR -->|"logs"| LOKI + PROMETHEUS -->|"query"| GRAFANA + LOKI -->|"query"| GRAFANA +``` + +### Docker Compose Configuration (Target) + +```yaml +# docker-compose.yml (target) +services: + moltbot: + build: + context: . + dockerfile: Dockerfile + image: moltbot:latest + container_name: moltbot + restart: unless-stopped + user: "1000:1000" # Non-root + ports: + - "127.0.0.1:18789:18789" # Gateway WebSocket + - "127.0.0.1:8000:8000" # REST API + volumes: + - ./data:/app/data # SQLite + vectors + - ./config:/app/config:ro # Config (read-only) + environment: + - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 + - MOLTBOT_LOG_FORMAT=json + depends_on: + - otel-collector + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] + interval: 30s + timeout: 10s + retries: 3 + + otel-collector: + image: otel/opentelemetry-collector-contrib:latest + container_name: otel-collector + volumes: + - ./config/otel-collector.yaml:/etc/otel-collector-config.yaml:ro + command: ["--config=/etc/otel-collector-config.yaml"] + ports: + - "4317:4317" # OTLP gRPC + - "4318:4318" # OTLP HTTP + + prometheus: + image: prom/prometheus:latest + container_name: prometheus + volumes: + - ./config/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - prometheus-data:/prometheus + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + + grafana: + image: grafana/grafana:latest + container_name: grafana + ports: + - "127.0.0.1:3000:3000" + volumes: + - grafana-data:/var/lib/grafana + environment: + - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin} + +volumes: + prometheus-data: + grafana-data: +``` + +### Infrastructure Components (Target) + +| Component | Technology | Purpose | Evidence/Decision | +|-----------|------------|---------|-------------------| +| Runtime | Python 3.12+ | Application execution | Q1 preference | +| Package Manager | uv | Fast dependency management | Q4 preference | +| ASGI Server | Uvicorn | ASGI server for FastAPI | Production standard | +| Framework | FastAPI | REST + WebSocket support | Python ecosystem standard | +| Container | Docker | Deployment isolation | Q7 preference | +| Orchestration | Docker Compose | Single-host orchestration | Q5/Q6 preference | +| Database | SQLite + sqlite-vec | Embedded storage + vectors | Q2 preference (unchanged) | +| Observability | OpenTelemetry | Traces, metrics, logs | Q8 preference | +| Metrics | Prometheus | Time-series metrics | Q8.metrics preference | +| Logging | Structured JSON | Log aggregation | Q8.logging preference | + +### Port Allocation (Target) + +| Port | Service | Protocol | Binding | Legacy | +|------|---------|----------|---------|--------| +| 18789 | Gateway Server | WebSocket | 127.0.0.1 | **Preserved** | +| 8000 | REST API | HTTP | 127.0.0.1 | **New** | +| 4317 | OTel Collector | gRPC | Internal | **New** | +| 3000 | Grafana | HTTP | 127.0.0.1 | **New** | + +### Security Hardening (Target) + +| Measure | Implementation | Legacy Comparison | +|---------|----------------|-------------------| +| Non-root user | Container runs as uid 1000 | **Preserved** | +| TLS fingerprint | Pin client certificate fingerprint | **Preserved** | +| SSRF protection | DNS pinning, private IP blocking (httpx) | **Preserved** | +| Exec approval | Persistent approval queue in SQLite | **Improved** | +| Rate limiting | slowapi + Redis/in-memory | **New** | +| Secrets management | Environment variables + .env file | **Improved** | +| Audit logging | Structured JSON + OpenTelemetry | **Improved** | + +--- + +## 6. Data Flow Diagrams (Target) + +### 6.1 Request/Response Flow (Target) + +```mermaid +flowchart LR + subgraph Input["Input Sources"] + PLATFORM["Messaging Platform"] + GATEWAY["Gateway WebSocket"] + API["REST API"] + SCHEDULER["Scheduler"] + VOICE["Voice Stream"] + end + + subgraph Processing["Processing Pipeline"] + ADAPTER["Channel Adapter"] + HANDLER["Message Handler"] + SERVICE["Domain Service"] + AGENT["Agent Runner"] + end + + subgraph Data["Data Layer"] + MEMORY["Memory Service
(sqlite-vec)"] + CONFIG["Configuration
(Pydantic Settings)"] + STATE["Session State
(SQLite)"] + APPROVAL["Approval Queue
(SQLite)"] + end + + subgraph AI["AI Inference"] + CLAUDE["Claude API"] + OPENAI["OpenAI API"] + GEMINI["Gemini API"] + LOCAL["Local LLM"] + end + + subgraph Output["Output"] + RESPONSE["Response Formatter"] + DELIVERY["Channel Delivery"] + end + + subgraph Observability["Observability"] + OTEL["OpenTelemetry SDK"] + METRICS["Prometheus"] + TRACES["Jaeger/Tempo"] + LOGS["Loki"] + end + + PLATFORM --> ADAPTER + GATEWAY --> HANDLER + API --> HANDLER + SCHEDULER --> HANDLER + VOICE --> HANDLER + + ADAPTER --> HANDLER + HANDLER --> SERVICE + SERVICE --> AGENT + + AGENT <--> MEMORY + HANDLER <--> CONFIG + HANDLER <--> STATE + HANDLER <--> APPROVAL + + AGENT --> CLAUDE + AGENT --> OPENAI + AGENT --> GEMINI + AGENT --> LOCAL + + CLAUDE --> RESPONSE + OPENAI --> RESPONSE + GEMINI --> RESPONSE + LOCAL --> RESPONSE + + RESPONSE --> DELIVERY + DELIVERY --> PLATFORM + + HANDLER -.-> OTEL + SERVICE -.-> OTEL + AGENT -.-> OTEL + OTEL --> METRICS + OTEL --> TRACES + OTEL --> LOGS +``` + +### 6.2 Data Transformation Points (Target) + +| Source | Transform | Destination | Implementation | +|--------|-----------|-------------|----------------| +| Platform message | Normalize to InternalMessage | Message handler | `ChannelAdapter.to_internal()` | +| User query | Generate embedding vector | Memory service | OpenAI/local embedding model | +| Memory search | Hybrid ranking (vector + BM25) | Agent context | `MemoryService.hybrid_search()` | +| AI response | Chunk for platform limits | Response delivery | `ResponseFormatter.chunk()` | +| Voice audio | Transcribe to text | Agent input | Whisper/Deepgram | +| Agent response | Text-to-speech synthesis | Voice stream | Voice provider TTS | +| All operations | Telemetry extraction | OTel Collector | Auto-instrumentation | + +### 6.3 Memory Indexing Flow (Target) + +```mermaid +flowchart TB + subgraph Sources["Index Sources"] + FILES["Markdown Files"] + SESSIONS["JSONL Transcripts"] + MANUAL["Manual Entries"] + API_INGEST["API Ingestion"] + end + + subgraph Detection["Change Detection"] + HASH["Content Hash
(SHA-256)"] + DELTA["Delta Detection"] + DEBOUNCE["Debounce
(5s sessions)"] + WATCHER["File Watcher
(watchfiles)"] + end + + subgraph Processing["Processing"] + CHUNK["Markdown Chunking
(semantic)"] + EMBED["Embedding Generation
(async batch)"] + INDEX["Index Builder"] + end + + subgraph Storage["Storage"] + SQLITE["SQLite DB"] + VEC["sqlite-vec
(vectors)"] + FTS["FTS5
(keywords)"] + end + + subgraph Observability["Observability"] + METRICS["index_latency_seconds"] + COUNTER["documents_indexed_total"] + end + + FILES --> WATCHER + SESSIONS --> DELTA + MANUAL --> CHUNK + API_INGEST --> CHUNK + + WATCHER --> HASH + HASH --> CHUNK + DELTA --> DEBOUNCE + DEBOUNCE --> CHUNK + + CHUNK --> EMBED + EMBED --> INDEX + + INDEX --> SQLITE + INDEX --> VEC + INDEX --> FTS + + INDEX -.-> METRICS + INDEX -.-> COUNTER +``` + +**Key Improvements**: +- File watcher for real-time indexing (watchfiles) +- Semantic chunking (sentence-aware) +- Async batch embedding for throughput +- Indexing metrics for observability + +--- + +## 7. Resilience Patterns (Target) + +### Target Patterns + +| Pattern | Implementation | Library | Legacy Comparison | +|---------|----------------|---------|-------------------| +| **Retry** | Exponential backoff with jitter | tenacity | **Enhanced** | +| **Circuit Breaker** | Per-external-service breaker | tenacity / pybreaker | **New** | +| **Timeout** | Per-operation configurable | anyio.move_on_after | **Enhanced** | +| **Fallback** | Model failover chain | Custom | **Preserved** | +| **Rate Limiting** | Token bucket algorithm | slowapi | **New** | +| **Bulkhead** | Semaphore-based isolation | asyncio.Semaphore | **New** | +| **Health Check** | Liveness + readiness probes | FastAPI endpoint | **New** | + +### Error Handling Architecture (Target) + +```mermaid +flowchart TB + subgraph Errors["Error Types (Domain)"] + SSRF["SSRFBlockedError"] + AUTH["AuthenticationError"] + APPROVAL["ApprovalTimeoutError"] + PROVIDER["ProviderError"] + VALIDATION["ValidationError"] + RATELIMIT["RateLimitError"] + end + + subgraph Handling["Error Handling (Application)"] + CATCH["Exception Handlers"] + LOG["Structured Logging"] + AUDIT["Security Audit"] + METRIC["Error Metrics"] + end + + subgraph Recovery["Recovery Actions (Infrastructure)"] + RETRY["Retry with Backoff"] + CIRCUIT["Circuit Breaker"] + FAILOVER["Model Failover"] + GRACEFUL["Graceful Degradation"] + ALERT["PagerDuty/Slack Alert"] + end + + subgraph Observability["Observability"] + TRACE["Distributed Trace"] + SPAN["Error Span"] + COUNTER["error_total Counter"] + end + + SSRF --> AUDIT + SSRF --> LOG + SSRF --> COUNTER + + AUTH --> AUDIT + AUTH --> LOG + AUTH --> ALERT + + APPROVAL --> LOG + APPROVAL --> METRIC + + PROVIDER --> RETRY + PROVIDER --> CIRCUIT + PROVIDER --> FAILOVER + + VALIDATION --> CATCH + VALIDATION --> LOG + + RATELIMIT --> GRACEFUL + RATELIMIT --> METRIC + + AUDIT --> ALERT + CATCH --> TRACE + LOG --> SPAN + METRIC --> COUNTER +``` + +### Circuit Breaker Configuration + +```python +# Example circuit breaker configuration +from tenacity import ( + retry, + stop_after_attempt, + wait_exponential, + retry_if_exception_type, + CircuitBreakerState, +) + +AI_PROVIDER_RETRY = retry( + stop=stop_after_attempt(3), + wait=wait_exponential(multiplier=1, min=1, max=10), + retry=retry_if_exception_type(ProviderError), + before_sleep=log_retry_attempt, + after=record_retry_metric, +) + +CIRCUIT_BREAKER_CONFIG = { + "failure_threshold": 5, # Open after 5 failures + "recovery_timeout": 30, # Try again after 30s + "expected_exception": ProviderError, +} +``` + +### Gateway Reconnection Strategy (Target) + +```mermaid +sequenceDiagram + participant Client as Gateway Client + participant Server as Gateway Server + participant Breaker as Circuit Breaker + participant Metrics as Prometheus + + Client->>Server: WebSocket connect + Server-->>Client: Connection established + + Note over Client,Server: Connection drops + + Client->>Breaker: Check circuit state + Breaker-->>Client: CLOSED (allow attempt) + + Client->>Server: Reconnect attempt 1 (delay=1s + jitter) + Server--xClient: Failed + Client->>Metrics: reconnect_failed_total++ + + Client->>Breaker: Record failure + Client->>Server: Reconnect attempt 2 (delay=2s + jitter) + Server--xClient: Failed + Client->>Metrics: reconnect_failed_total++ + + Client->>Breaker: Record failure + Client->>Server: Reconnect attempt 3 (delay=4s + jitter) + Server-->>Client: Connected + Client->>Metrics: reconnect_success_total++ + + Client->>Breaker: Record success + Client->>Server: Re-authenticate (session token) + Server-->>Client: Session restored +``` + +**Improvements over Legacy**: +- Circuit breaker prevents thundering herd on reconnect +- Jitter prevents synchronized reconnection attempts +- Prometheus metrics for reconnection patterns + +--- + +## 8. Why This Pattern (Target Rationale) + +### Architecture Pattern Selection + +**Selected**: Modular Monolith with Clean Architecture → Microservices-Ready + +| Consideration | Decision | Rationale | +|---------------|----------|-----------| +| **Complexity** | HIGH (5.35/10) | 200K+ LOC, 28 integrations - needs manageable structure | +| **Migration Risk** | Strangler Fig (68%) | Gradual replacement reduces blast radius | +| **Team Size** | Small | Monolith simpler to operate than distributed system | +| **Deployment** | Single container | Docker Compose preference, no K8s complexity | +| **Future Scale** | Microservices-ready | Clean boundaries enable future decomposition | + +### User Preference Alignment (Q1-Q10) + +| Preference | Target Implementation | Rationale | +|------------|----------------------|-----------| +| Q1: Python 3.12+ | ✅ Python 3.12+ | Full language migration from TypeScript | +| Q2: SQLite + sqlite-vec | ✅ Preserved | Zero-config, works well for use case | +| Q3: WebSocket + in-memory | ✅ WebSocket + SQLite | Upgraded: persistent state where needed | +| Q4: uv | ✅ uv package manager | Fast, modern Python packaging | +| Q5: Docker Compose | ✅ Docker Compose | Simple orchestration | +| Q6: Docker Compose (IaC) | ✅ Declarative YAML | Infrastructure as code | +| Q7: Docker | ✅ Docker containers | Standard container runtime | +| Q8: Prometheus/JSON/OTel | ✅ Full stack | Integrated observability | +| Q9: Keep current auth | ✅ Token/Password/Tailscale | Preserved with improvements | +| Q10: pytest 80% | ✅ pytest with fixtures | Coverage target set | + +### Legacy Problem Resolution + +| Legacy Problem | Target Solution | Evidence | +|----------------|-----------------|----------| +| Circular dependencies (10 components) | Clean Architecture layers | `domain/` has 0 external deps | +| Config as central hub (445+ deps) | Config as leaf dependency | Injected via DI container | +| In-memory exec approvals | SQLite-backed queue | `infrastructure/storage/approval_store.py` | +| No circuit breaker | tenacity circuit breaker | Per-provider configuration | +| No rate limiting | slowapi middleware | Gateway + API rate limits | +| Console-only logging | OpenTelemetry + structured JSON | Full observability stack | +| No health checks | Liveness + readiness probes | FastAPI `/health`, `/ready` | +| 70% test coverage | 80% target with pytest | CI/CD enforcement | + +### Migration Approach + +**Strategy**: Strangler Fig Pattern + +```mermaid +graph LR + subgraph Phase1["Phase 1: Foundation"] + GATEWAY["Gateway
(Python)"] + AUTH["Auth
(Python)"] + OTEL["OpenTelemetry
(Python)"] + end + + subgraph Phase2["Phase 2: Core"] + MEMORY["Memory Service
(Python)"] + APPROVAL["Approval Store
(Python)"] + SCHEDULER["Scheduler
(Python)"] + end + + subgraph Phase3["Phase 3: Adapters"] + TELEGRAM["Telegram
(Python)"] + DISCORD["Discord
(Python)"] + PRIORITY["High-priority
channels"] + end + + subgraph Phase4["Phase 4: Complete"] + REMAINING["Remaining 20+
channels"] + VOICE["Voice Extension"] + DECOMMISSION["Legacy
Decommission"] + end + + Phase1 --> Phase2 + Phase2 --> Phase3 + Phase3 --> Phase4 +``` + +**Phase Breakdown**: + +| Phase | Components | Duration Estimate | Risk | +|-------|------------|-------------------|------| +| Phase 1 | Gateway, Auth, OTel | First sprint | Low | +| Phase 2 | Memory, Approval, Scheduler | Second sprint | Medium | +| Phase 3 | Telegram, Discord, Slack | Third sprint | Medium | +| Phase 4 | Remaining channels, Voice | Fourth+ sprint | Medium | + +### Technical Debt Prevention + +| Measure | Implementation | Enforcement | +|---------|----------------|-------------| +| No circular imports | Import linter (ruff) | CI check | +| Type annotations | mypy strict mode | CI check | +| Test coverage | pytest-cov 80% | CI gate | +| Code formatting | ruff format | Pre-commit | +| Documentation | docstrings required | CI check | +| Dependency hygiene | uv lock file | CI check | + +--- + +*Part 1 of 3 - Sections 1-8 Complete* + +--- + +## 9. Capabilities by Phase (Target Migration) + +### Phase 1: Foundation (MVP) + +| Capability | Legacy Component | Target Component | Migration Status | +|------------|------------------|------------------|------------------| +| Gateway control plane | Gateway Server (TypeScript) | Gateway Server (FastAPI/WebSocket) | Phase 1 | +| Multi-mode authentication | Gateway Auth (TypeScript) | Auth Service (Python) | Phase 1 | +| OpenTelemetry observability | None | Telemetry Service (OTel SDK) | Phase 1 - **New** | +| Configuration management | Config Module (Zod) | Config Service (Pydantic Settings) | Phase 1 | +| Health checks | None | Health Endpoints (FastAPI) | Phase 1 - **New** | + +### Phase 2: Core Features + +| Capability | Legacy Component | Target Component | Migration Status | +|------------|------------------|------------------|------------------| +| Memory indexing | Memory Index Manager (TypeScript) | Memory Service (Python) | Phase 2 | +| Vector search | sqlite-vec integration | sqlite-vec adapter (aiosqlite) | Phase 2 | +| Full-text search | FTS5 integration | FTS5 adapter (aiosqlite) | Phase 2 | +| Exec approval workflow | Exec Approval Manager (in-memory) | Approval Store (SQLite-backed) | Phase 2 - **Improved** | +| Cron scheduling | Cron Service (TypeScript) | Scheduler Service (APScheduler) | Phase 2 | +| SSRF protection | SSRF Module (undici) | SSRF Module (httpx) | Phase 2 | +| Rate limiting | None | Rate Limiter (slowapi) | Phase 2 - **New** | +| Circuit breaker | None | Circuit Breaker (tenacity) | Phase 2 - **New** | + +### Phase 3: Channel Adapters (High Priority) + +| Capability | Legacy Component | Target Component | Migration Status | +|------------|------------------|------------------|------------------| +| Telegram integration | Telegram Adapter (TypeScript) | Telegram Adapter (aiogram) | Phase 3 | +| Discord integration | Discord Adapter (TypeScript) | Discord Adapter (discord.py) | Phase 3 | +| Slack integration | Slack Adapter (TypeScript) | Slack Adapter (slack-sdk) | Phase 3 | +| WhatsApp integration | WhatsApp Adapter (Baileys) | WhatsApp Adapter (Baileys bridge) | Phase 3 | +| Auto-reply pipeline | Auto-Reply (TypeScript) | Message Handler (Python) | Phase 3 | +| Agent execution | Agent Runner (TypeScript) | Agent Runner (Python) | Phase 3 | + +### Phase 4: Extended Features + +| Capability | Legacy Component | Target Component | Migration Status | +|------------|------------------|------------------|------------------| +| Signal integration | Signal Adapter (TypeScript) | Signal Adapter (Python) | Phase 4 | +| Matrix integration | Matrix Adapter (TypeScript) | Matrix Adapter (matrix-nio) | Phase 4 | +| 14+ other channels | Platform Adapters (TypeScript) | Platform Adapters (Python) | Phase 4 | +| Voice calls | Voice Extension (TypeScript) | Voice Service (Python) | Phase 4 | +| TUI interface | TUI Components (Ink/React) | TUI Service (Textual/Rich) | Phase 4 | +| Web UI | UI Views (Solid.js) | API + SPA (FastAPI + React/Vue) | Phase 4 | + +### Migration Timeline + +```mermaid +gantt + title Moltbot Python Migration + dateFormat YYYY-MM-DD + section Phase 1 + Gateway + Auth + OTel :p1, 2026-02-01, 14d + Config + Health :p1b, after p1, 7d + section Phase 2 + Memory + Vector Search :p2, after p1b, 14d + Approval + Scheduler :p2b, after p2, 7d + SSRF + Rate Limit + Circuit :p2c, after p2b, 7d + section Phase 3 + Telegram Adapter :p3a, after p2c, 7d + Discord Adapter :p3b, after p3a, 7d + Slack + WhatsApp Adapters :p3c, after p3b, 14d + Agent Runner + Message Handler :p3d, after p3c, 7d + section Phase 4 + Remaining 20+ Channels :p4a, after p3d, 28d + Voice Extension :p4b, after p4a, 14d + TUI + Web UI :p4c, after p4b, 14d + Legacy Decommission :p4d, after p4c, 7d +``` + +--- + +## 10. Component / Service Responsibilities (Target) + +### Legacy vs Target Components + +| Legacy Component | Target Component | Responsibility | Change | +|------------------|------------------|----------------|--------| +| Gateway Server (TypeScript) | Gateway Server (FastAPI) | WebSocket control plane, events | Python/FastAPI | +| Gateway Auth (TypeScript) | Auth Service (Python) | Multi-mode authentication | Argon2 passwords | +| Exec Approval Manager | Approval Store | Command execution gating | SQLite persistence | +| Memory Index Manager | Memory Service | Vector + FTS hybrid search | async/await | +| Cron Service | Scheduler Service | Scheduled job management | APScheduler | +| Config Module (Zod) | Config Service (Pydantic) | Configuration validation | Pydantic Settings | +| SSRF Module (undici) | SSRF Module (httpx) | DNS pinning, IP validation | httpx agent | +| Security Audit | Audit Logger | Security event logging | OpenTelemetry | +| Channel Adapters (TS) | Channel Adapters (Python) | Platform integrations | Per-adapter migration | +| Auto-Reply Pipeline | Message Handler | Message processing | Domain service | +| Agent Runner (TS) | Agent Runner (Python) | AI inference, failover | tenacity retry | +| TUI Components (Ink) | TUI Service (Textual) | Terminal UI | Textual/Rich | +| UI Views (Solid.js) | REST API + SPA | Web interface | FastAPI + SPA | + +### New Components (Target Only) + +| Component | Responsibility | Rationale | Q# | +|-----------|----------------|-----------|-----| +| Health Service | Liveness + readiness probes | Production requirement | Q5 | +| Rate Limiter | Request rate limiting | DoS protection | Q5 | +| Circuit Breaker | External API isolation | Resilience pattern | - | +| Telemetry Service | OTel SDK integration | Observability | Q8 | +| REST API | HTTP API for integrations | Developer access | Q5 | +| Event Bus | Async event distribution | Decoupling | Q3 | + +### Removed Components + +| Legacy Component | Reason | Replacement | +|------------------|--------|-------------| +| Constructor DI (TS) | Language change | Python DI container | +| Ink React components | Language change | Textual/Rich | +| Solid.js UI | Simplification | FastAPI + SPA | +| pnpm workspace | Language change | uv monorepo | +| rolldown bundler | Not needed | Python packaging | + +--- + +## 11. Interfaces & Contracts (Target) + +### Internal Interfaces (Target) + +| Interface | Provider | Consumer | Legacy Protocol | Target Protocol | +|-----------|----------|----------|-----------------|-----------------| +| GatewayClient | Gateway Server | TUI/UI/CLI | WebSocket JSON-RPC 2.0 | **WebSocket JSON-RPC 2.0** (preserved) | +| ChannelPort | Channel Adapters | Message Handler | Internal function calls | Python Protocol (ABC) | +| MemoryPort | Memory Service | Agent Runner | SQLite direct | Async SQLite (aiosqlite) | +| AuthPort | Auth Service | Gateway Server | Internal calls | Python Protocol | +| ApprovalPort | Approval Store | Gateway/Handlers | Promise-based | asyncio.Future | +| StoragePort | SQLite Adapter | All Services | Direct SQLite | aiosqlite connection pool | +| TelemetryPort | OTel SDK | All Services | None | OpenTelemetry API | + +### External Contracts (Target) + +| System | Legacy Protocol | Target Protocol | Migration | +|--------|-----------------|-----------------|-----------| +| Claude AI | HTTPS REST | HTTPS REST | No change | +| OpenAI | HTTPS REST | HTTPS REST | No change | +| Google Gemini | HTTPS REST | HTTPS REST | No change | +| Telegram | HTTPS REST/Webhooks | HTTPS REST/Webhooks | No change | +| Discord | WebSocket + REST | WebSocket + REST | discord.py library | +| WhatsApp | Baileys WebSocket | Baileys bridge | Python subprocess | +| Slack | HTTPS REST + Socket Mode | HTTPS REST + Socket Mode | slack-sdk library | +| Twilio | HTTPS REST + WebSocket | HTTPS REST + WebSocket | twilio library | +| OpenTelemetry | N/A | OTLP gRPC/HTTP | **New** | + +### API Versioning Strategy + +| API | Legacy Version | Target Version | Backward Compat | +|-----|----------------|----------------|-----------------| +| Gateway WebSocket | v1 (JSON-RPC 2.0) | v1 (JSON-RPC 2.0) | **Yes - preserved** | +| REST API | N/A | v1 | **New API** | +| Channel Adapters | Internal | Internal | N/A (internal) | +| Telemetry | N/A | OTLP v1 | **New** | + +### Protocol Compatibility + +The Gateway WebSocket protocol is **fully preserved** to maintain backward compatibility with existing TUI/UI clients during migration: + +```json +// Request format (unchanged) +{"jsonrpc": "2.0", "method": "auth.token", "params": {"token": "..."}, "id": 1} + +// Response format (unchanged) +{"jsonrpc": "2.0", "result": {"session_token": "..."}, "id": 1} + +// Error format (unchanged) +{"jsonrpc": "2.0", "error": {"code": -32001, "message": "Auth failed"}, "id": 1} +``` + +--- + +## 12. Data & Schema (Target) + +### Target Database + +Based on Q2 (SQLite with sqlite-vec): +- **Engine**: SQLite 3.x with WAL mode +- **Vector extension**: sqlite-vec for embeddings +- **Full-text search**: FTS5 for keyword search +- **Access pattern**: aiosqlite for async operations + +### Schema Migration + +| Legacy Table | Target Table | Schema Changes | Migration Strategy | +|--------------|--------------|----------------|-------------------| +| memory_entries | memory_entries | Add `updated_at` column | ALTER TABLE | +| fts_index | memory_fts | Rename for clarity | Recreate index | +| sessions (JSONL) | sessions | Move to SQLite | ETL migration | +| cron_jobs | scheduler_jobs | Add `last_error` column | ALTER TABLE | +| call_records | voice_calls | Add `metadata` JSONB | ALTER TABLE | +| config (YAML/JSON) | Pydantic Settings | Move to env/files | Config migration | +| device_tokens (memory) | device_tokens | Persist to SQLite | **New table** | +| exec_approvals (memory) | exec_approvals | Persist to SQLite | **New table** | + +### Target Schema Diagram + +```mermaid +erDiagram + MEMORY_ENTRIES { + text id PK + text content + blob embedding + text source + text metadata + timestamp created_at + timestamp updated_at + } + + MEMORY_FTS { + text rowid PK + text content + text source + } + + SESSIONS { + text session_id PK + text agent_id + text channel + jsonb messages + jsonb metadata + timestamp created_at + timestamp updated_at + } + + SCHEDULER_JOBS { + text id PK + text name + text schedule + text command + text channel + boolean enabled + text last_error + timestamp last_run + timestamp next_run + } + + VOICE_CALLS { + text call_id PK + text phone_number + text provider + text status + text transcript + jsonb metadata + timestamp started_at + timestamp ended_at + } + + DEVICE_TOKENS { + text public_key PK + text device_name + text user_id + timestamp created_at + timestamp last_used + } + + EXEC_APPROVALS { + text approval_id PK + text command + text session_key + text status + text decision_by + text reason + timestamp created_at + timestamp expires_at + timestamp decided_at + } + + AUDIT_LOG { + integer id PK + text event_type + text actor + text resource + text action + jsonb details + timestamp created_at + } + + MEMORY_ENTRIES ||--o{ MEMORY_FTS : "indexed_in" + SESSIONS ||--o{ MEMORY_ENTRIES : "generates" + SCHEDULER_JOBS ||--o{ SESSIONS : "triggers" + EXEC_APPROVALS ||--o{ AUDIT_LOG : "logged_in" +``` + +### Data Type Mappings + +| Legacy Type | Target Type | Conversion | Notes | +|-------------|-------------|------------|-------| +| TypeScript string | Python str | Direct | No conversion | +| TypeScript number | Python int/float | Direct | Type inference | +| TypeScript boolean | Python bool | Direct | No conversion | +| TypeScript Date | Python datetime | ISO 8601 | Timezone-aware | +| TypeScript Buffer | Python bytes | Direct | Binary data | +| Zod schema | Pydantic model | Rewrite | Manual translation | +| JSONL file | SQLite JSONB | Migration | Batch import | +| In-memory Map | SQLite table | Persist | Schema creation | + +### Index Strategy (Target) + +| Table | Legacy Indexes | Target Indexes | Rationale | +|-------|----------------|----------------|-----------| +| memory_entries | sqlite-vec vector index | sqlite-vec vector index (preserved) | Vector similarity | +| memory_fts | FTS5 index | FTS5 index (preserved) | Keyword search | +| sessions | None | (session_id), (channel, created_at) | Lookup + listing | +| exec_approvals | None | (status, expires_at), (session_key) | Pending lookup | +| audit_log | None | (event_type, created_at), (actor) | Filtering + audit | + +--- + +## 13. Technology Stack (Target) + +### Stack Comparison + +| Category | Legacy | Target | Q# | Rationale | +|----------|--------|--------|-----|-----------| +| Language | TypeScript 5.x | Python 3.12+ | Q1 | User preference, ecosystem | +| Runtime | Node.js 22.12+ | Python 3.12+ | Q1 | Native async/await | +| Framework | Express-like | FastAPI | Q1 | Modern Python async | +| Database | SQLite + sqlite-vec | SQLite + sqlite-vec | Q2 | Preserved (user preference) | +| Message Bus | WebSocket | WebSocket + in-memory | Q3 | Preserved pattern | +| Package Manager | pnpm 10.23.0 | uv | Q4 | Fast, modern Python | +| Bundler | rolldown | N/A | - | Not needed for Python | +| Container | Docker (node:22) | Docker (python:3.12) | Q7 | Runtime change | +| Orchestration | Docker Compose | Docker Compose | Q5/Q6 | Preserved | +| Observability | Console logs | OpenTelemetry | Q8 | Full stack | + +### Target Dependencies + +| Package | Version | Purpose | Artifactory Status | +|---------|---------|---------|-------------------| +| `fastapi` | ^0.110 | ASGI framework | [UNVERIFIED - public registry] | +| `uvicorn` | ^0.29 | ASGI server | [UNVERIFIED - public registry] | +| `pydantic` | ^2.6 | Data validation | [UNVERIFIED - public registry] | +| `pydantic-settings` | ^2.2 | Configuration | [UNVERIFIED - public registry] | +| `aiosqlite` | ^0.20 | Async SQLite | [UNVERIFIED - public registry] | +| `sqlite-vec` | ^0.1 | Vector search | [UNVERIFIED - public registry] | +| `httpx` | ^0.27 | HTTP client | [UNVERIFIED - public registry] | +| `tenacity` | ^8.2 | Retry logic | [UNVERIFIED - public registry] | +| `slowapi` | ^0.1 | Rate limiting | [UNVERIFIED - public registry] | +| `apscheduler` | ^3.10 | Job scheduling | [UNVERIFIED - public registry] | +| `opentelemetry-api` | ^1.23 | OTel API | [UNVERIFIED - public registry] | +| `opentelemetry-sdk` | ^1.23 | OTel SDK | [UNVERIFIED - public registry] | +| `opentelemetry-instrumentation-fastapi` | ^0.44 | FastAPI auto-instrument | [UNVERIFIED - public registry] | +| `argon2-cffi` | ^23.1 | Password hashing | [UNVERIFIED - public registry] | +| `aiogram` | ^3.4 | Telegram bot | [UNVERIFIED - public registry] | +| `discord.py` | ^2.3 | Discord bot | [UNVERIFIED - public registry] | +| `slack-sdk` | ^3.27 | Slack integration | [UNVERIFIED - public registry] | +| `twilio` | ^9.0 | Voice provider | [UNVERIFIED - public registry] | +| `pytest` | ^8.0 | Testing | [UNVERIFIED - public registry] | +| `pytest-asyncio` | ^0.23 | Async testing | [UNVERIFIED - public registry] | +| `pytest-cov` | ^4.1 | Coverage | [UNVERIFIED - public registry] | +| `ruff` | ^0.3 | Linter + formatter | [UNVERIFIED - public registry] | +| `mypy` | ^1.9 | Type checking | [UNVERIFIED - public registry] | + +*Note: Artifactory validation skipped - packages assumed available from public PyPI registry.* + +### Version Requirements + +| Component | Minimum Version | Target Version | EOL Date | +|-----------|-----------------|----------------|----------| +| Python | 3.12 | 3.12+ | 2028-10 | +| SQLite | 3.35 | 3.45+ | N/A | +| Docker | 24.0 | 25.0+ | N/A | +| OpenTelemetry | 1.20 | 1.23+ | N/A | + +--- + +## 14. NFR Targets (Target System) + +### Performance Targets + +| Metric | Legacy Value | Target Value | Improvement | Method | +|--------|--------------|--------------|-------------|--------| +| Response time (p95) | <100ms (local) | <100ms | Maintained | async/await | +| Gateway latency (p99) | ~50ms | <50ms | Maintained | FastAPI WebSocket | +| Memory query (hybrid) | <500ms | <500ms | Maintained | aiosqlite + sqlite-vec | +| Embedding batch | Variable | <1s per 10 | Improved | Async batching | +| Cold start | ~5s (Node.js) | ~3s (Python) | 40% better | Uvicorn workers | +| Reconnect backoff | 1s-30s exp | 1s-30s exp + jitter | Improved | Circuit breaker | + +### Availability Targets + +| Metric | Legacy | Target | Method | +|--------|--------|--------|--------| +| Uptime SLA | No formal SLA | 99.9% self-hosted | Docker health checks | +| Recovery time (RTO) | Manual restart | <5 min auto-recovery | Docker restart policy | +| Recovery point (RPO) | Last commit | <1 min | SQLite WAL + fsync | +| Failover | Model chain | Model chain + circuit | tenacity integration | + +### Scalability Targets + +| Metric | Legacy Limit | Target Capacity | Method | +|--------|--------------|-----------------|--------| +| Concurrent connections | Event loop limited | 1000+ WebSocket | Uvicorn workers | +| Concurrent channels | 28 | 28+ | Async adapters | +| Data volume | SQLite limits | SQLite limits | Same (user pref) | +| Request rate | No limit | 100 req/s per client | slowapi rate limiting | +| Memory usage | ~512MB | ~512MB | Similar footprint | + +--- + +## 15. Operations & SRE (Target) + +### Observability Stack + +Based on Q8 (Prometheus, Structured JSON, OpenTelemetry): + +| Aspect | Legacy Tool | Target Tool | Q8 Component | +|--------|-------------|-------------|--------------| +| Metrics | None | Prometheus | Q8.metrics | +| Logging | Console | Structured JSON (Loki) | Q8.logging | +| Tracing | None | OpenTelemetry → Jaeger/Tempo | Q8.tracing | +| Alerting | None | Alertmanager/Grafana | Q8.alerting | + +### Key Metrics (Target) + +| Metric | Type | Alert Threshold | Dashboard | +|--------|------|-----------------|-----------| +| `gateway_connections_active` | Gauge | >100 | Gateway Overview | +| `gateway_auth_total` | Counter | Error rate >5% | Security Dashboard | +| `message_processing_seconds` | Histogram | p95 >5s | Message Flow | +| `ai_inference_seconds` | Histogram | p95 >30s | AI Provider | +| `ai_failover_total` | Counter | >10/min | AI Provider | +| `exec_approval_total` | Counter | Timeout rate >20% | Security Dashboard | +| `memory_query_seconds` | Histogram | p95 >1s | Memory Service | +| `channel_adapter_errors_total` | Counter | >5/min per channel | Channel Health | +| `circuit_breaker_state` | Gauge | State=OPEN | Circuit Status | + +### Runbook Updates + +| Operation | Legacy Runbook | Target Runbook | Changes | +|-----------|----------------|----------------|---------| +| Deployment | `docker compose up` | `docker compose up -d` | Add `-d` detached | +| Rollback | `docker compose down && up` | `docker compose pull && up -d` | Image tag rollback | +| Scaling | Manual container restart | Uvicorn `--workers N` | Horizontal workers | +| Log access | `docker logs` | Grafana Loki queries | Centralized | +| Metrics | None | Grafana dashboards | New capability | +| Tracing | None | Jaeger/Tempo UI | New capability | + +### On-Call Considerations + +| Aspect | Legacy | Target | Training Needed | +|--------|--------|--------|-----------------| +| Alert volume | None (manual) | Low (key metrics only) | Dashboard training | +| Complexity | TypeScript debug | Python debug | Python profiling | +| Tools | Console logs | OTel + Grafana stack | Observability stack | +| Escalation | Ad-hoc | Defined runbooks | Runbook review | + +### Health Endpoints + +| Endpoint | Purpose | Response | +|----------|---------|----------| +| `GET /health` | Liveness probe | `{"status": "ok"}` | +| `GET /ready` | Readiness probe | `{"status": "ready", "checks": {...}}` | +| `GET /metrics` | Prometheus scrape | OpenMetrics format | + +--- + +## 16. Security & Compliance (Target) + +### Security Architecture + +Based on Q9 (Keep current: Token/Password/Tailscale): + +| Aspect | Legacy | Target | Q9 Applied | +|--------|--------|--------|------------| +| Authentication | Token, Password, Tailscale, Device | Token, Password, Tailscale, Device | **Preserved** | +| Password hashing | timing-safe compare | Argon2 + timing-safe | **Improved** | +| Session management | In-memory | SQLite-backed | **Improved** | +| Authorization | Role-based (implicit) | Role-based (explicit) | **Enhanced** | +| Encryption at rest | SQLite (none) | SQLite (none) | Same (user pref) | +| Encryption in transit | TLS 1.2+ | TLS 1.3 | **Upgraded** | +| Secrets management | Environment variables | Environment + .env | **Improved** | + +### Security Controls (Target) + +| Control | Implementation | Evidence | +|---------|----------------|----------| +| OWASP Top 10 | Input validation, output encoding | Pydantic models, FastAPI | +| Input validation | Pydantic schema validation | All API endpoints | +| Output encoding | FastAPI response models | JSON serialization | +| Rate limiting | slowapi (100 req/s/client) | Gateway + API endpoints | +| SSRF protection | DNS pinning, private IP blocking | httpx with custom resolver | +| Timing attacks | Constant-time comparison | secrets.compare_digest | +| SQL injection | Parameterized queries | aiosqlite placeholders | +| XSS | JSON-only API | No HTML rendering | +| CSRF | Token-based auth | No cookies for auth | + +### Compliance Mapping + +| Requirement | Legacy Status | Target Status | Changes | +|-------------|---------------|---------------|---------| +| GDPR | Partial | Partial | Add data export API | +| SOC2 | Not assessed | Not assessed | Self-hosted | +| HIPAA | Not compliant | Not compliant | No PHI handling | +| Audit logging | Console only | SQLite + OTel | **Improved** | + +### Security Testing (Target) + +Based on Q10 (pytest, 80% coverage): + +| Test Type | Tool | Frequency | CI/CD Integration | +|-----------|------|-----------|-------------------| +| SAST | ruff + bandit | Per commit | Yes | +| Type safety | mypy strict | Per commit | Yes | +| Unit tests | pytest | Per commit | Yes | +| Security tests | pytest-security | Per commit | Yes | +| Dependency scan | pip-audit / safety | Daily | Yes | +| Coverage | pytest-cov (80%) | Per commit | Yes (gate) | +| Penetration | Manual | Quarterly | No | + +### Audit Logging (Target) + +```python +# Audit log schema +class AuditEvent(BaseModel): + event_type: str # auth.success, auth.failure, exec.approved, etc. + actor: str # user_id or system + resource: str # affected resource + action: str # create, read, update, delete, approve, deny + details: dict # Additional context + trace_id: str # OpenTelemetry trace ID + timestamp: datetime +``` + +Events logged: +- `auth.success` / `auth.failure` - Authentication attempts +- `exec.requested` / `exec.approved` / `exec.denied` - Exec approval workflow +- `session.created` / `session.expired` - Session lifecycle +- `config.changed` - Configuration modifications +- `security.ssrf_blocked` - SSRF protection triggers + +--- + +*Part 2 of 3 - Sections 9-16 Complete* + +--- + +## 17. Migration / Expansion Paths (Target System) + +### Migration Strategy + +Based on user preferences and legacy analysis: + +| Migration Aspect | Approach | Rationale | Q# | +|------------------|----------|-----------|-----| +| Data Migration | In-place (SQLite preserved) | Same database technology | Q2 | +| Code Migration | Strangler Fig (68% confidence) | Gradual replacement reduces risk | Q1 | +| Infrastructure Migration | Docker Compose → Docker Compose | Same orchestration, new runtime | Q5, Q6, Q7 | +| Protocol Migration | Preserve WebSocket JSON-RPC 2.0 | Backward compatibility with clients | - | +| Observability Migration | None → Full OTel stack | New capability, no migration | Q8 | + +### Migration Phases + +```mermaid +gantt + title Moltbot Migration Timeline + dateFormat YYYY-MM-DD + section Phase 1 Foundation + Set up Python project structure :p1a, 2026-02-01, 3d + Implement Gateway Server (FastAPI) :p1b, after p1a, 7d + Implement Auth Service :p1c, after p1b, 5d + Set up OpenTelemetry stack :p1d, after p1a, 3d + Integration testing Phase 1 :p1e, after p1c, 3d + section Phase 2 Core + Migrate Memory Service :p2a, after p1e, 7d + Migrate Approval Store (persistent) :p2b, after p2a, 5d + Migrate Scheduler Service :p2c, after p2b, 3d + Add Circuit Breaker + Rate Limiting :p2d, after p2a, 3d + Integration testing Phase 2 :p2e, after p2d, 3d + section Phase 3 Adapters + Migrate Telegram Adapter :p3a, after p2e, 5d + Migrate Discord Adapter :p3b, after p3a, 5d + Migrate Slack + WhatsApp Adapters :p3c, after p3b, 7d + Migrate Agent Runner :p3d, after p3c, 7d + Integration testing Phase 3 :p3e, after p3d, 5d + section Phase 4 Complete + Migrate remaining 20+ channels :p4a, after p3e, 21d + Migrate Voice Extension :p4b, after p4a, 10d + Migrate TUI + Web UI :p4c, after p4b, 10d + Legacy decommission :p4d, after p4c, 5d +``` + +### Phase 1: Foundation + +| Task | Legacy State | Target State | Dependencies | +|------|--------------|--------------|--------------| +| Project setup | TypeScript + pnpm | Python 3.12+ + uv | None | +| Gateway Server | Node.js WebSocket | FastAPI WebSocket | Project setup | +| Auth Service | TypeScript Gateway Auth | Python Auth Service | Gateway Server | +| Config Service | Zod schemas | Pydantic Settings | Project setup | +| OTel integration | None | OTel SDK + Collector | Project setup | +| Health endpoints | None | FastAPI /health, /ready | Gateway Server | + +### Phase 2: Core Services + +| Task | Legacy State | Target State | Dependencies | +|------|--------------|--------------|--------------| +| Memory Service | TypeScript + sqlite-vec | Python + aiosqlite + sqlite-vec | Gateway | +| Approval Store | In-memory Map | SQLite-backed persistent | Memory Service | +| Scheduler Service | TypeScript Cron | APScheduler | Gateway | +| Rate Limiter | None | slowapi middleware | Gateway | +| Circuit Breaker | None | tenacity wrapper | Memory Service | +| SSRF Protection | undici Agent | httpx custom resolver | Memory Service | + +### Phase 3: Channel Adapters + +| Channel | Legacy Library | Target Library | Priority | +|---------|---------------|----------------|----------| +| Telegram | grammy/telegraf | aiogram | Critical | +| Discord | discord.js | discord.py | Critical | +| Slack | @slack/bolt | slack-sdk | High | +| WhatsApp | Baileys | Baileys bridge (subprocess) | High | +| Signal | signal-protocol | signal-cli bridge | Medium | +| Matrix | matrix-js-sdk | matrix-nio | Medium | + +### Phase 4: Extended Features + +| Task | Legacy State | Target State | Dependencies | +|------|--------------|--------------|--------------| +| Remaining channels | 20+ TypeScript adapters | 20+ Python adapters | Phase 3 | +| Voice Extension | TypeScript + Twilio | Python + twilio-python | Core | +| TUI Interface | Ink (React) | Textual/Rich | Gateway | +| Web UI | Solid.js | FastAPI + SPA | Gateway | + +### Expansion Paths (Post-Migration) + +| Expansion | Enabled By | Effort | Business Value | +|-----------|------------|--------|----------------| +| Horizontal scaling | Clean Architecture + asyncio | Medium | High | +| Kubernetes deployment | Docker Compose → K8s | High | High | +| Multi-tenant support | Clean Architecture boundaries | High | High | +| Plugin marketplace | Adapter pattern registry | Medium | Medium | +| Mobile apps | REST API (new) | Medium | Medium | +| GraphQL API | FastAPI + Strawberry | Low | Medium | + +--- + +## 18. Risks & Decisions (Migration Technical) + +### Migration Risks + +| Risk | Probability | Impact | Mitigation | Owner | +|------|-------------|--------|------------|-------| +| Protocol incompatibility | Low | Critical | Preserve WebSocket JSON-RPC 2.0 | Platform Team | +| Data loss during migration | Low | Critical | SQLite preserved, schema migrations tested | Data Team | +| Performance regression | Medium | High | Benchmark at each phase, async patterns | Platform Team | +| Channel adapter bugs | Medium | High | Per-channel integration tests, parallel operation | Integration Team | +| Skill gap (Python) | Low | Medium | Team familiar with Python, training available | Engineering | +| Library compatibility | Medium | Medium | Verify Python libraries exist for all features | Engineering | +| Circular dependency re-emergence | Low | High | Strict layered architecture, import linting | Architecture | +| Timeline overrun | Medium | Medium | Phased approach, prioritize critical channels | Project Lead | + +### Technical Decisions Made + +Based on user preferences (Q1-Q10): + +| Decision | Options Considered | Chosen (Q#) | Rationale | +|----------|-------------------|-------------|-----------| +| Runtime | Node.js, Python, Go, Rust | Q1: Python 3.12+ | User preference, ecosystem, AI libraries | +| Database | PostgreSQL, MySQL, SQLite | Q2: SQLite with sqlite-vec | User preference, zero-config preserved | +| Message Bus | RabbitMQ, Redis, Kafka | Q3: WebSocket + in-memory | User preference, simplicity | +| Package Manager | pip, poetry, pdm, uv | Q4: uv | User preference, speed, modern | +| Deployment | K8s, ECS, VMs, Docker Compose | Q5: Docker Compose | User preference, self-hosted simplicity | +| IaC | Terraform, Pulumi, CDK | Q6: Docker Compose | User preference, YAML-based | +| Container | Docker, Podman | Q7: Docker | User preference, standard tooling | +| Observability | Datadog, CloudWatch, OTel | Q8: Prometheus + JSON + OTel | User preference, open-source | +| Security | OAuth2, SAML, custom | Q9: Keep current (Token/Password/Tailscale) | User preference, proven approach | +| Testing | Jest, pytest, mocha | Q10: pytest 80% coverage | User preference, Python standard | + +### Open Technical Decisions + +| Decision | Options | Recommendation | Deadline | +|----------|---------|----------------|----------| +| WhatsApp adapter approach | Baileys bridge vs native | Baileys subprocess bridge | Phase 3 start | +| Voice provider priority | Twilio-first vs multi-provider | Twilio-first, others follow | Phase 4 start | +| TUI framework | Textual vs Rich vs custom | Textual (active development) | Phase 4 start | +| Web UI framework | React vs Vue vs Svelte | Depends on team preference | Phase 4 start | +| Python DI framework | dependency-injector vs simple | Simple DI for MVP | Phase 1 | + +--- + +## 19. Requirements -> Code -> Tests Traceability (Target) + +### Traceability Matrix + +| Requirement | Legacy Location | Target Location | Test Coverage | +|-------------|-----------------|-----------------|---------------| +| FR-CRIT-001: Multi-channel messaging | `extensions/*/` | `moltbot/adapters/` | `tests/adapters/test_*.py` | +| FR-CRIT-002: AI inference | Agent runtime | `moltbot/application/handlers/agent.py` | `tests/handlers/test_agent.py` | +| FR-CRIT-003: Context-aware responses | `src/memory/manager.ts` | `moltbot/infrastructure/memory/` | `tests/infrastructure/test_memory.py` | +| FR-CRIT-004: Gateway control | `src/gateway/client.ts` | `moltbot/infrastructure/gateway/` | `tests/infrastructure/test_gateway.py` | +| FR-HIGH-001: Authentication | `src/gateway/auth.ts` | `moltbot/infrastructure/auth/` | `tests/infrastructure/test_auth.py` | +| FR-HIGH-002: Exec approval | `src/gateway/exec-approval-manager.ts` | `moltbot/infrastructure/storage/approval_store.py` | `tests/storage/test_approval.py` | +| FR-HIGH-003: Voice calls | `extensions/voice-call/` | `moltbot/adapters/voice/` | `tests/adapters/test_voice.py` | +| FR-HIGH-004: Cron scheduling | `src/cron/service.ts` | `moltbot/infrastructure/scheduler/` | `tests/infrastructure/test_scheduler.py` | +| NFR-PERF-001: Response time <100ms | Gateway WebSocket | FastAPI WebSocket | `tests/performance/test_latency.py` | +| NFR-SEC-001: SSRF protection | `src/infra/net/ssrf.ts` | `moltbot/infrastructure/http/ssrf.py` | `tests/infrastructure/test_ssrf.py` | +| NFR-SEC-002: Timing-safe auth | `src/gateway/auth.ts` | `moltbot/infrastructure/auth/auth_service.py` | `tests/security/test_auth_timing.py` | + +### Migration Verification + +| Requirement | Legacy Test | Target Test | Parity Verified | +|-------------|-------------|-------------|-----------------| +| FR-CRIT-001 | `test/telegram/*.test.ts` | `tests/adapters/test_telegram.py` | [ ] | +| FR-CRIT-002 | `test/agent/*.test.ts` | `tests/handlers/test_agent.py` | [ ] | +| FR-CRIT-003 | `test/memory/*.test.ts` | `tests/infrastructure/test_memory.py` | [ ] | +| FR-CRIT-004 | `test/gateway/*.test.ts` | `tests/infrastructure/test_gateway.py` | [ ] | +| FR-HIGH-001 | `test/auth/*.test.ts` | `tests/infrastructure/test_auth.py` | [ ] | +| FR-HIGH-002 | `test/exec-approval/*.test.ts` | `tests/storage/test_approval.py` | [ ] | + +### Test Migration Strategy + +Based on Q10 (pytest, 80% coverage): + +| Test Type | Legacy Coverage | Target Coverage | Migration Approach | +|-----------|-----------------|-----------------|-------------------| +| Unit | 70% | 80% | Rewrite (different language) | +| Integration | 60% | 80% | Rewrite with pytest fixtures | +| E2E | 50% | 60% | Rewrite with pytest + httpx | +| Performance | Limited | Comprehensive | New suite with pytest-benchmark | +| Security | Some | Comprehensive | New suite with bandit + safety | + +--- + +## 20. Architecture Decision Records (Target) + +### ADR-001: Target Language Selection + +**Status**: Approved +**Context**: Modernization requires selecting target language/runtime. Legacy is TypeScript/Node.js. +**Decision**: Q1: Python 3.12+ +**Consequences**: +- Positive: Rich AI/ML ecosystem, familiar to many developers, asyncio for concurrency +- Negative: Full rewrite required (no incremental migration), GIL for CPU-bound tasks +- Neutral: Similar development velocity, different tooling +**Evidence**: User preference Q1 in validation-scoring.json + +### ADR-002: Database Selection + +**Status**: Approved +**Context**: Data layer modernization. Legacy uses SQLite with sqlite-vec. +**Decision**: Q2: SQLite with sqlite-vec (preserved) +**Consequences**: +- Positive: Zero migration effort for data, zero-config, proven performance +- Negative: Single-writer limitation, horizontal scaling constraints +- Neutral: Same schema, same vector search capabilities +**Evidence**: User preference Q2 in validation-scoring.json + +### ADR-003: Deployment Strategy + +**Status**: Approved +**Context**: Infrastructure modernization. Legacy uses Docker Compose. +**Decision**: Q5: Docker Compose with Q7: Docker containers +**Consequences**: +- Positive: Minimal infrastructure change, self-hosted simplicity, familiar tooling +- Negative: No auto-scaling, single-host limitation +- Neutral: Same operational model +**Evidence**: User preferences Q5, Q7 in validation-scoring.json + +### ADR-004: Observability Stack + +**Status**: Approved +**Context**: Operations and monitoring. Legacy has minimal observability. +**Decision**: Q8: Prometheus (metrics), Structured JSON (logging), OpenTelemetry (tracing) +**Consequences**: +- Positive: Full visibility, distributed tracing, standard tooling, Grafana dashboards +- Negative: Additional infrastructure (OTel Collector, Prometheus, Grafana) +- Neutral: Learning curve for operations team +**Evidence**: User preference Q8 in validation-scoring.json + +### ADR-005: Security Architecture + +**Status**: Approved +**Context**: Authentication and authorization. Legacy has multi-mode auth. +**Decision**: Q9: Keep current (Token/Password/Tailscale/Device) +**Consequences**: +- Positive: Proven security model, user familiarity, no migration effort +- Negative: Need to re-implement in Python (argon2, secrets module) +- Neutral: Same security posture +**Evidence**: User preference Q9 in validation-scoring.json + +### ADR-006: Testing Framework + +**Status**: Approved +**Context**: Testing strategy for Python codebase. +**Decision**: Q10: pytest with 80% coverage target +**Consequences**: +- Positive: Industry standard, rich plugin ecosystem, excellent async support +- Negative: All tests require rewrite from vitest +- Neutral: Similar test patterns (unit, integration, fixtures) +**Evidence**: User preference Q10 in validation-scoring.json + +### ADR-007: Clean Architecture Adoption + +**Status**: Approved +**Context**: Legacy has circular dependencies (10-component cycle). Need to prevent recurrence. +**Decision**: Clean Architecture with strict layered boundaries +**Consequences**: +- Positive: No circular dependencies, independent testing, future-proof for microservices +- Negative: More boilerplate (ports, adapters), learning curve +- Neutral: Different code organization than legacy +**Evidence**: Analysis of legacy circular dependencies + +### ADR-008: Persistent Exec Approvals + +**Status**: Approved +**Context**: Legacy exec approvals are in-memory, lost on restart. +**Decision**: SQLite-backed approval store with audit logging +**Consequences**: +- Positive: Survives restart, audit trail, queryable history +- Negative: Slightly higher latency (SQLite write) +- Neutral: Same approval workflow UX +**Evidence**: Legacy technical debt analysis + +### ADR-009: Plugin Architecture for Extensibility + +**Status**: Approved +**Context**: Legacy system bundles all 28 channel adapters, AI providers, and extensions into a single monolithic codebase. This creates: +- Massive dependency tree (all platform SDKs installed) +- Slow installation and startup +- Unmanageable codebase complexity +- Forced updates for unused features +**Decision**: Modular plugin architecture where: +- Core package (`moltbot`) contains only essential runtime +- Channel adapters are separate packages (`moltbot-telegram`, `moltbot-discord`, etc.) +- AI providers are separate packages (`moltbot-claude`, `moltbot-openai`, etc.) +- Extensions are separate packages (`moltbot-voice`, `moltbot-cron`, etc.) +- Plugins discovered via Python entry points +- Users install only what they need +**Consequences**: +- Positive: + - Minimal installation footprint + - Faster startup (load only needed plugins) + - Independent versioning per plugin + - Easier maintenance and testing + - Users choose their stack +- Negative: + - More packages to maintain + - Plugin compatibility matrix + - Entry point discovery overhead (minimal) +- Neutral: + - Same functionality available, just modular +**Evidence**: User preference for manageable, extendable architecture + +### ADR-010: Plugin Installation via uv Extras + +**Status**: Approved +**Context**: Need user-friendly way to install plugin combinations. +**Decision**: Support both explicit packages and uv extras: +```bash +# Explicit packages +uv pip install moltbot moltbot-telegram moltbot-claude + +# Via extras (convenience) +uv pip install "moltbot[telegram,discord,claude]" + +# All plugins (dev/testing) +uv pip install "moltbot[all]" +``` +**Consequences**: +- Positive: Familiar Python packaging patterns, flexible installation +- Negative: Need to maintain extras list in core pyproject.toml +- Neutral: Standard Python ecosystem approach +**Evidence**: Q4 preference for uv package manager + +--- + +## 21. Infrastructure (Target State) + +### Target Infrastructure + +Based on Q5 (Docker Compose), Q6 (Docker Compose), Q7 (Docker): + +| Component | Legacy | Target | IaC Resource | +|-----------|--------|--------|--------------| +| Compute | Docker (node:22) | Docker (python:3.12) | docker-compose.yml service | +| Storage | Docker volume (SQLite) | Docker volume (SQLite) | volumes: section | +| Network | Host network (18789, 18790) | Host network (18789, 8000) | ports: section | +| Load Balancer | None | None | N/A (self-hosted) | +| CDN | None | None | N/A (local) | +| Observability | None | OTel Collector + Prometheus + Grafana | docker-compose.yml services | + +### Infrastructure Diagram (Target) + +```mermaid +graph TB + subgraph Docker["Docker Compose Stack"] + subgraph App["Application"] + MOLTBOT["moltbot
python:3.12
FastAPI + Uvicorn"] + end + + subgraph Observability["Observability Stack"] + OTEL["otel-collector
OTLP receiver"] + PROMETHEUS["prometheus
Metrics storage"] + GRAFANA["grafana
Dashboards"] + LOKI["loki
Log aggregation"] + end + + subgraph Storage["Persistent Storage"] + DATA["data/
SQLite + sqlite-vec"] + CONFIG["config/
YAML configuration"] + METRICS["prometheus-data/"] + GRAFANA_DATA["grafana-data/"] + end + end + + subgraph External["External Services"] + AI["AI APIs
Claude, OpenAI, Gemini"] + CHANNELS["28 Channel Platforms"] + VOICE["Voice Providers"] + end + + MOLTBOT -->|"OTLP"| OTEL + OTEL -->|"metrics"| PROMETHEUS + OTEL -->|"logs"| LOKI + PROMETHEUS -->|"query"| GRAFANA + LOKI -->|"query"| GRAFANA + + MOLTBOT -->|"SQLite"| DATA + MOLTBOT -->|"read"| CONFIG + PROMETHEUS -->|"persist"| METRICS + GRAFANA -->|"persist"| GRAFANA_DATA + + MOLTBOT -->|"HTTPS"| AI + MOLTBOT -->|"HTTPS/WS"| CHANNELS + MOLTBOT -->|"WebSocket"| VOICE + + USER["Admin/User"] -->|"18789 WebSocket"| MOLTBOT + USER -->|"8000 REST"| MOLTBOT + USER -->|"3000 HTTP"| GRAFANA +``` + +### IaC Structure + +Based on Q6 (Docker Compose): + +``` +infrastructure/ +├── docker-compose.yml # Main compose file +├── docker-compose.override.yml # Development overrides +├── docker-compose.prod.yml # Production overrides +├── Dockerfile # Application image +├── config/ +│ ├── otel-collector.yaml # OTel Collector config +│ ├── prometheus.yml # Prometheus config +│ ├── grafana/ +│ │ ├── provisioning/ +│ │ │ ├── dashboards/ # Pre-configured dashboards +│ │ │ └── datasources/ # Prometheus + Loki sources +│ │ └── dashboards/ +│ │ ├── gateway.json +│ │ ├── memory.json +│ │ └── channels.json +│ └── alertmanager.yml # Alerting rules (optional) +├── scripts/ +│ ├── healthcheck.sh # Container health check +│ └── backup.sh # SQLite backup script +└── .env.example # Environment template +``` + +### Cost Comparison + +| Component | Legacy Cost | Target Cost | Change | +|-----------|-------------|-------------|--------| +| Compute | Self-hosted | Self-hosted | No change | +| Database | $0 (SQLite) | $0 (SQLite) | No change | +| Network | Self-hosted | Self-hosted | No change | +| Observability | $0 (none) | $0 (self-hosted OTel) | No change | +| **Total** | $0 | $0 | **No change** | + +*Note: Self-hosted model with Docker Compose. Only infrastructure cost is server hardware/hosting.* + +--- + +## 22. CI/CD Pipeline (Target) + +### Pipeline Overview + +Based on Q5 (Docker Compose), Q10 (pytest 80%): + +```mermaid +flowchart LR + subgraph Trigger["Triggers"] + PUSH["git push"] + PR["Pull Request"] + TAG["Release Tag"] + end + + subgraph Build["Build Stage"] + CHECKOUT["Checkout"] + SETUP["Setup Python 3.12"] + UV["uv sync"] + end + + subgraph Quality["Quality Gates"] + LINT["ruff check"] + FORMAT["ruff format --check"] + TYPES["mypy --strict"] + SECURITY["bandit + pip-audit"] + end + + subgraph Test["Test Stage"] + UNIT["Unit Tests"] + INTEGRATION["Integration Tests"] + COVERAGE["Coverage (80%)"] + end + + subgraph Package["Package Stage"] + BUILD["Docker build"] + SCAN["Image scan"] + PUSH_IMG["Push to registry"] + end + + subgraph Deploy["Deploy Stage"] + DEV["Dev environment"] + STAGING["Staging environment"] + PROD["Production"] + end + + PUSH --> CHECKOUT + PR --> CHECKOUT + TAG --> CHECKOUT + + CHECKOUT --> SETUP --> UV + UV --> LINT & FORMAT & TYPES & SECURITY + LINT & FORMAT & TYPES & SECURITY --> UNIT + UNIT --> INTEGRATION --> COVERAGE + COVERAGE --> BUILD --> SCAN --> PUSH_IMG + PUSH_IMG --> DEV + DEV --> STAGING + STAGING --> PROD +``` + +### Pipeline Stages + +| Stage | Tool | Purpose | Quality Gate | +|-------|------|---------|--------------| +| Checkout | actions/checkout | Clone repository | - | +| Setup | actions/setup-python | Install Python 3.12 | - | +| Dependencies | uv sync | Install packages | Lock file verified | +| Lint | ruff check | Code quality | 0 errors | +| Format | ruff format --check | Code style | No changes needed | +| Type check | mypy --strict | Type safety | 0 errors | +| Security | bandit + pip-audit | Security scan | No critical findings | +| Unit tests | pytest | Unit testing | All pass | +| Integration tests | pytest | Integration testing | All pass | +| Coverage | pytest-cov | Coverage report | ≥80% | +| Build | docker build | Container image | Build success | +| Image scan | trivy | Container security | No critical CVEs | +| Push | docker push | Registry upload | Push success | +| Deploy | docker compose | Deployment | Health checks pass | + +### Environment Promotion + +| Stage | Environment | Trigger | Approval | +|-------|-------------|---------|----------| +| Dev | development | Push to feature branch | Auto | +| Staging | staging | PR merge to main | Auto | +| Prod | production | Release tag (v*) | Manual | + +### Rollback Strategy + +| Scenario | Detection | Action | Recovery Time | +|----------|-----------|--------|---------------| +| Deployment failure | Health check fails | docker compose down && up (previous) | < 5 min | +| Performance degradation | Prometheus alerts | Manual assessment, rollback if needed | < 15 min | +| Data corruption | Integrity check | Restore from SQLite backup | < 30 min | +| Security incident | Audit log analysis | Isolate, investigate, patch | Variable | + +### Pipeline Configuration + +```yaml +# .github/workflows/ci.yml (target) +name: CI + +on: + push: + branches: [main, 'feature/**'] + pull_request: + branches: [main] + release: + types: [published] + +env: + PYTHON_VERSION: "3.12" + +jobs: + quality: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v4 + - run: uv sync --dev + - run: uv run ruff check . + - run: uv run ruff format --check . + - run: uv run mypy --strict moltbot/ + - run: uv run bandit -r moltbot/ + - run: uv run pip-audit + + test: + runs-on: ubuntu-latest + needs: quality + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v4 + - run: uv sync --dev + - run: uv run pytest --cov=moltbot --cov-report=xml --cov-fail-under=80 + - uses: codecov/codecov-action@v4 + + build: + runs-on: ubuntu-latest + needs: test + steps: + - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - uses: docker/build-push-action@v5 + with: + push: ${{ github.event_name == 'release' }} + tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }} + + deploy: + runs-on: ubuntu-latest + needs: build + if: github.event_name == 'release' + environment: production + steps: + - name: Deploy to production + run: | + # SSH to server and docker compose pull && up -d + echo "Deploying ${{ github.ref_name }}" +``` + +--- + +## 23. Open Questions & Next Steps + +### Open Technical Questions + +1. **Performance Baseline**: What are the exact legacy performance metrics (p95, p99 latency) for comparison? +2. **Channel Priority**: Which of the 28 channels are most critical for Phase 3 migration? +3. **WhatsApp Bridge**: Should we use Baileys subprocess bridge or seek a native Python solution? +4. **Voice Extension Priority**: Is voice calling critical for MVP or can it wait for Phase 4? +5. **TUI Necessity**: Is terminal UI needed in target, or is Web UI + Gateway sufficient? +6. **Web UI Framework**: React, Vue, or Svelte for the new SPA? + +### Resolved Questions + +| Question | Resolution | Evidence | +|----------|------------|----------| +| Target language | Python 3.12+ | User preference Q1 | +| Database technology | SQLite with sqlite-vec | User preference Q2 | +| Message bus | WebSocket + in-memory | User preference Q3 | +| Package manager | uv | User preference Q4 | +| Deployment platform | Docker Compose | User preference Q5 | +| IaC approach | Docker Compose (YAML) | User preference Q6 | +| Container runtime | Docker | User preference Q7 | +| Observability stack | Prometheus + JSON + OTel | User preference Q8 | +| Security approach | Token/Password/Tailscale | User preference Q9 | +| Testing framework | pytest 80% | User preference Q10 | +| Migration pattern | Strangler Fig | Validation scoring (68%) | +| Circular dependencies | Clean Architecture | Legacy analysis | + +### Next Steps + +1. **Review Technical Spec** with engineering team +2. **Resolve Open Questions** in this section +3. **Set up Python project** using uv + Clean Architecture template +4. **Implement Phase 1 Gateway** with FastAPI WebSocket +5. **Configure OpenTelemetry** stack in Docker Compose +6. **Write Phase 1 tests** targeting 80% coverage +7. **Begin Phase 2** after Gateway integration verified + +### Migration Readiness Checklist + +- [ ] All ADRs approved by stakeholders +- [ ] Python project structure created with uv +- [ ] Docker Compose updated with python:3.12 base image +- [ ] CI/CD pipeline configured for Python +- [ ] OpenTelemetry stack provisioned (Collector, Prometheus, Grafana) +- [ ] Security controls implemented (Argon2, timing-safe) +- [ ] Rollback procedures documented and tested +- [ ] Team trained on Python async patterns +- [ ] Gateway protocol compatibility verified +- [ ] Performance benchmarks established + +--- + +## Appendices + +### A. File Reference Index (Target) + +| Section | Key Files | +|---------|-----------| +| Architecture | `pyproject.toml`, `docker-compose.yml`, `Dockerfile` | +| Domain | `moltbot/domain/models/`, `moltbot/domain/ports/` | +| Gateway | `moltbot/infrastructure/gateway/server.py` | +| Auth | `moltbot/infrastructure/auth/auth_service.py` | +| Memory | `moltbot/infrastructure/memory/memory_service.py` | +| Adapters | `moltbot/adapters/{channel}/adapter.py` | +| Config | `moltbot/infrastructure/config/settings.py` | +| Observability | `config/otel-collector.yaml`, `config/prometheus.yml` | +| CI/CD | `.github/workflows/ci.yml` | +| Tests | `tests/` (mirrors `moltbot/` structure) | + +### B. Glossary (Target-Specific) + +| Term | Definition | +|------|------------| +| Clean Architecture | Layered architecture with dependency inversion | +| Port | Abstract interface defined by domain layer | +| Adapter | Concrete implementation of a port | +| ASGI | Asynchronous Server Gateway Interface (Python) | +| Uvicorn | ASGI server for FastAPI | +| uv | Fast Python package manager | +| aiosqlite | Async SQLite wrapper for Python | +| tenacity | Python retry/circuit breaker library | +| slowapi | Rate limiting middleware for FastAPI | +| Pydantic | Python data validation library | +| APScheduler | Advanced Python Scheduler | +| Textual | Terminal UI framework for Python | + +--- + +*Part 3 of 3 - Sections 17-23 Complete* + +--- + +*Technical Specification - Target System Complete (23 Sections)* + +--- + +=========================================================== +ARTIFACT COMPLETE: technical-spec-target.md + +Chain ID: 20260129-202219 +Total Sections: 23 + +This documents HOW the TARGET system will be built. + +User Preferences Applied (Q1-Q10): + Q1 Language: Python 3.12+ + Q2 Database: SQLite with sqlite-vec + Q3 Message Bus: WebSocket + in-memory + Q4 Package Manager: uv + Q5 Deployment: Docker Compose + Q6 IaC: Docker Compose + Q7 Container: Docker + Q8 Observability: Prometheus, Structured JSON, OpenTelemetry + Q9 Security: Keep current (Token/Password/Tailscale) + Q10 Testing: pytest 80% + +ARTIFACT_COMPLETE:TECHNICAL_SPEC_TARGET +=========================================================== diff --git a/.analysis/moltbotsec-20260129-202219/state.json b/.analysis/moltbotsec-20260129-202219/state.json new file mode 100644 index 000000000..c9831e0e4 --- /dev/null +++ b/.analysis/moltbotsec-20260129-202219/state.json @@ -0,0 +1,273 @@ +{ + "schema_version": 1, + "workflow": "analyze-project", + "current_stage": "06d-stage-prompts", + "current_stage_num": 28, + "workflow_complete": false, + "started": "2026-01-29T20:22:19.355639", + "completed": null, + "project_path": "D:\\work\\moltbotsec", + "git_branch": "analysis/moltbotsec-20260129-202219", + "inputs": { + "scope": "A", + "context": "Security-first rewrite analysis: security design to implementation, rich interface through apps, good engineering principles (manageable, extendable, debuggable, traceable), identify what is good vs not good, backend and UI/UX improvements, external research for use cases and features", + "concern_type": "", + "current_impl": "", + "target_impl": "" + }, + "stages": { + "01a-initialization": { + "status": "completed", + "artifacts": [], + "started": "2026-01-29T20:22:19.358272", + "completed": "2026-01-29T20:23:07.381415" + }, + "01b-input-collection": { + "status": "completed", + "artifacts": [], + "started": "2026-01-29T20:23:07.384411", + "completed": "2026-01-29T20:30:44.701814" + }, + "01c-script-execution": { + "status": "completed", + "artifacts": [], + "started": "2026-01-29T20:30:44.703827", + "completed": "2026-01-29T20:32:12.934497" + }, + "02a-category-scan": { + "status": "completed", + "artifacts": [ + "data/category-patterns.json" + ], + "started": "2026-01-29T20:32:12.937073", + "completed": "2026-01-29T20:35:25.765607" + }, + "02b-deep-dive": { + "status": "completed", + "artifacts": [ + "data/deep-dive-patterns.json" + ], + "started": "2026-01-29T20:35:25.767849", + "completed": "2026-01-29T20:38:49.163522" + }, + "02c-config-analysis": { + "status": "completed", + "artifacts": [ + "data/config-analysis.json" + ], + "started": "2026-01-29T20:38:49.165913", + "completed": "2026-01-29T20:41:59.759843" + }, + "02d-test-audit": { + "status": "completed", + "artifacts": [ + "data/test-audit.json" + ], + "started": "2026-01-29T20:41:59.762384", + "completed": "2026-01-29T20:44:46.718768" + }, + "02e-quality-gates": { + "status": "completed", + "artifacts": [], + "started": "2026-01-29T20:44:46.721179", + "completed": "2026-01-29T20:47:28.006496" + }, + "03a-full-app": { + "status": "completed", + "artifacts": [], + "current_chunk": null, + "started": "2026-01-29T20:47:28.008985", + "completed": "2026-01-29T20:53:16.510288" + }, + "04a-report-chunks-1-3": { + "status": "completed", + "artifacts": [], + "started": "2026-01-29T20:54:23.611625", + "completed": "2026-01-29T21:07:14.514916" + }, + "04b-report-chunks-4-6": { + "status": "completed", + "artifacts": [], + "started": "2026-01-29T21:07:14.517582", + "completed": "2026-01-29T21:09:09.150839" + }, + "04c-report-chunks-7-9": { + "status": "completed", + "artifacts": [], + "started": "2026-01-29T21:09:09.153674", + "completed": "2026-01-29T21:14:25.131285" + }, + "04d-report-verification": { + "status": "completed", + "artifacts": [], + "started": "2026-01-29T21:14:25.134788", + "completed": "2026-01-29T21:15:29.327514" + }, + "05a-executive-summary": { + "status": "completed", + "artifacts": [], + "started": "2026-01-29T21:15:29.330419", + "completed": "2026-01-29T21:16:46.571249" + }, + "06a1-functional-spec-legacy-part1": { + "status": "completed", + "artifacts": ["reports/functional-spec-legacy.md"], + "current_chunk": null, + "started": "2026-01-29T21:16:46.575014", + "completed": "2026-01-29T21:59:01.378832" + }, + "06a2-functional-spec-legacy-part2": { + "status": "completed", + "artifacts": ["reports/functional-spec-legacy.md"], + "started": "2026-01-29T21:59:01.378832", + "completed": "2026-01-29T22:30:00.000000" + }, + "06a3-functional-spec-legacy-part3": { + "status": "completed", + "artifacts": ["reports/functional-spec-legacy.md"], + "started": "2026-01-29T22:30:00.000000", + "completed": "2026-01-29T23:00:00.000000" + }, + "06b1-functional-spec-target-part1": { + "status": "completed", + "artifacts": ["reports/functional-spec-target.md"], + "started": "2026-01-29T23:00:00.000000", + "completed": "2026-01-29T23:30:00.000000" + }, + "06b2-functional-spec-target-part2": { + "status": "completed", + "artifacts": ["reports/functional-spec-target.md"], + "started": "2026-01-29T23:30:00.000000", + "completed": "2026-01-30T00:00:00.000000" + }, + "06b3-functional-spec-target-part3": { + "status": "completed", + "artifacts": ["reports/functional-spec-target.md"], + "started": "2026-01-30T00:00:00.000000", + "completed": "2026-01-30T00:30:00.000000" + }, + "06c1-technical-spec-legacy-part1": { + "status": "completed", + "artifacts": ["reports/technical-spec-legacy.md"], + "started": "2026-01-30T00:30:00.000000", + "completed": "2026-01-30T01:00:00.000000" + }, + "06c1-technical-spec-legacy-part2": { + "status": "completed", + "artifacts": ["reports/technical-spec-legacy.md"], + "started": "2026-01-30T01:00:00.000000", + "completed": "2026-01-30T01:30:00.000000" + }, + "06c1-technical-spec-legacy-part3": { + "status": "completed", + "artifacts": ["reports/technical-spec-legacy.md"], + "started": "2026-01-30T01:30:00.000000", + "completed": "2026-01-30T02:00:00.000000" + }, + "06c2-technical-spec-target-part1": { + "status": "completed", + "artifacts": ["reports/technical-spec-target.md"], + "started": "2026-01-30T02:00:00.000000", + "completed": "2026-01-30T02:30:00.000000" + }, + "06c2-technical-spec-target-part2": { + "status": "completed", + "artifacts": ["reports/technical-spec-target.md"], + "started": "2026-01-30T02:30:00.000000", + "completed": "2026-01-30T03:00:00.000000" + }, + "06c2-technical-spec-target-part3": { + "status": "completed", + "artifacts": ["reports/technical-spec-target.md"], + "started": "2026-01-30T03:00:00.000000", + "completed": "2026-01-30T03:30:00.000000" + } + }, + "stages_complete": [ + "01a-initialization", + "01b-input-collection", + "01c-script-execution", + "02a-category-scan", + "02b-deep-dive", + "02c-config-analysis", + "02d-test-audit", + "02e-quality-gates", + "03a-full-app", + "04a-report-chunks-1-3", + "04b-report-chunks-4-6", + "04c-report-chunks-7-9", + "04d-report-verification", + "05a-executive-summary", + "06a1-functional-spec-legacy-part1", + "06a2-functional-spec-legacy-part2", + "06a3-functional-spec-legacy-part3", + "06b1-functional-spec-target-part1", + "06b2-functional-spec-target-part2", + "06b3-functional-spec-target-part3", + "06c1-technical-spec-legacy-part1", + "06c1-technical-spec-legacy-part2", + "06c1-technical-spec-legacy-part3", + "06c2-technical-spec-target-part1", + "06c2-technical-spec-target-part2", + "06c2-technical-spec-target-part3" + ], + "modernization_preferences": { + "q1_language": { + "value": "Python 3.12+" + }, + "q2_database": { + "value": "SQLite with sqlite-vec" + }, + "q3_message_bus": { + "value": "WebSocket + in-memory" + }, + "q4_package_manager": { + "value": "uv" + }, + "q5_deployment": { + "value": "Docker Compose" + }, + "q6_testing": { + "value": "pytest", + "rationale": "Modern Python testing" + }, + "q7_api_style": { + "value": "FastAPI", + "rationale": "Modern async Python with OpenAPI" + }, + "q8_iac": { + "value": "Docker Compose", + "rationale": "Keep current" + }, + "q9_monitoring": { + "value": "OpenTelemetry", + "rationale": "Standard observability" + }, + "q10_cicd": { + "value": "GitHub Actions", + "rationale": "Keep current" + }, + "q6_iac": { + "value": "Docker Compose" + }, + "q7_containerization": { + "value": "Docker" + }, + "q8_observability": { + "value": { + "metrics": "Prometheus", + "logging": "Structured JSON", + "tracing": "OpenTelemetry" + } + }, + "q9_security": { + "value": "Keep current (Token/Password/Tailscale)" + }, + "q10_testing": { + "value": "pytest", + "coverage_target": "80" + } + }, + "repoix_mode": "mcp", + "discovery_cache": {} +} \ No newline at end of file