Table cells already containing **bold** markers got double-wrapped,
creating ****text**** which produced overlapping <b><i> tags rejected
by Telegram's HTML parser.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Telegram bot is handled entirely by the Gateway
(apps/gateway/telegram/). The Desktop channel plugin was never
registered (commented out in initChannels) and is dead code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of silently discarding tool narration or spamming separate
messages, send a single editable Telegram message that updates in-place
as the agent works. First tool narration sends a reply; subsequent
narrations edit the same message. The final answer is sent as a new
message.
- Add replyTextEditable/editText to ChannelOutboundAdapter interface
- Implement editFormatted + editable methods in Telegram plugin
- Track statusMessageId in ChannelManager, clear on agent_end/error
- Add sendOrEditStatus to Gateway TelegramService with same behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the agent uses tools (web search, etc.), it generates intermediate
narration text like "Let me search..." before each tool call. These were
being sent as separate Telegram messages, causing message spam. Now we
detect tool_use blocks in the message content and skip sending those
intermediate messages — only the final answer reaches the user.
Applied to both Desktop channel plugin and Gateway Telegram service.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Telegram doesn't support HTML tables, so pipe-delimited Markdown tables
were rendered as hard-to-read plain text on mobile. This converts tables
to a vertical "Header: Value" format with bold first column before
sending to Telegram.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract useQRToken and useCountdown hooks to qr-hooks.ts so qr-code.tsx
only exports components (fixes react-refresh/only-export-components)
- Remove unused useRef import from connect-step.tsx
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cleanupPendingRequests() iterated the service-wide pendingRequests Map
and rejected every entry. Since it was called from connectUser's catch
block (a per-user error path), one user's connection failure would
spuriously reject other users' in-flight verify RPCs.
The call was also redundant: sendVerifyRpc already cleans up its own
entry in all failure paths (timeout, RPC error, route failure).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DeviceConfirmDialog only exists in the main Layout, so verify
requests were timing out during onboarding. Since the user is
actively generating the QR code, auto-approve and show a success
state instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces in-memory Map with file-backed store at
~/.super-multica/gateway/telegram-users.json so user bindings
survive gateway restarts during local development.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add short code store, bot commands (/start, /status, /help), and
POST /telegram/connect-code endpoint for Desktop to create QR codes.
Users scan a QR → Telegram opens → /start {code} → auto-connects.
- ShortCodeStore: in-memory Map with TTL for connection info
- Bot commands registered via setMyCommands
- Refactor handleConnectionLink into shared connectUser method
- Fetch bot username via getMe() for deep link URL
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When TELEGRAM_WEBHOOK_URL is not set, the bot automatically starts in
long-polling mode (bot.start()) instead of waiting for webhook calls.
This allows local development without ngrok or a public URL.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the user-facing ability to create custom Telegram bots via BotFather.
Non-technical users should only need to message @multica_bot on Telegram.
- Disable telegramChannel plugin registration in initChannels()
- Remove ConnectStep from onboarding flow (Privacy → Provider → Start)
- Replace TelegramCard with simple text pointing to @multica_bot
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- store.test.ts: use baseDir option instead of mocking paths.js
- session-file-repair.test.ts: remove write-lock mock, assert behavior
- announce-findings.test.ts: use real storage with temp dirs
- sessions-list.test.ts: use real registry with seed helper
- compaction.test.ts: mock only third-party pi-coding-agent, use real
context-window internals
All tests exercise real code paths, improving confidence in actual
behavior per the strict mock policy.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add AuthStoreOptions with baseDir to auth-profiles/store.ts functions,
add baseDir option to announce.ts readLatestAssistantReply, and add
seedSubagentRunForTests helper to registry.ts. These enable tests to
use real implementations with temp directories instead of mocking
internal modules.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Group chats have unresolved issues in the Gateway context:
- Per-user deviceId causes context overwrites across groups
- Reply chains across users route to wrong Hubs
- Welcome messages are noisy in groups
Restrict to private chats only until a proper group model is designed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port all 7 features from the Desktop long-polling Telegram channel plugin
to the Gateway webhook-based Telegram bot:
- Markdown → Telegram HTML formatting with parse-error fallback
- Text chunking for messages >4096 chars (paragraph-boundary split)
- Reply-to original message + 👀 ack reaction lifecycle
- Group chat support (mention/reply filtering, @mention stripping)
- Per-chat message serialization (prevents race conditions)
- Inbound media handling (voice/audio/photo/video/document)
with transcription (Whisper) and description (Vision API)
- Outbound file captions with HTML formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scans test files at startup and warns when vi.mock() targets internal
modules (relative paths or @multica/* packages). Reports file paths
and line numbers for all violations without interfering with test
execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Establish "external-only mock" rule: only third-party dependencies
may be mocked in tests. Internal modules must use real implementations
with temp directories, reset functions, or dependency injection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce a RunLog system that records agent execution events as
structured JSONL to ~/.super-multica/sessions/{id}/run-log.jsonl.
Enable via MULTICA_RUN_LOG=1 env var or AgentOptions.enableRunLog.
Logs: run lifecycle, LLM calls, tool execution timing, context
overflow recovery, auth profile rotation, error classification,
and compaction events.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prefer markdown responses from servers that support Cloudflare's Markdown
for Agents feature, reducing token usage by ~80% when available. Non-supporting
servers fall back to HTML as before.
- Update Accept header to prefer text/markdown in web_fetch requests
- Add text/markdown content-type handling to skip HTML parsing pipeline
- Capture x-markdown-tokens response header in WebFetchResult
- Add extractMarkdownTitle() helper for native markdown title extraction
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix publish repo from "multica" to "super-multica"
- Add zip to mac targets (required for electron-updater auto-updates)
- Enable hardenedRuntime (required for notarization)
- Add notarize config with teamId placeholder
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add optional context parameter to getAuthHeaders() so callers can
provide feature-specific suffixes (e.g. "to use web search") in the
not-logged-in error message, restoring the original behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace duplicated getLocalAuth() + manual header construction in
finance/api.ts and web-search.ts with the shared getAuthHeaders()
and API_BASE_URL from hub/api-client.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract API_BASE_URL and getAuthHeaders() into a reusable module
so that tools don't duplicate base URL and auth header construction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Route all financial data requests through api-dev.copilothub.ai/api/v1/financial
proxy and authenticate via sid/device-id/os-type headers instead of X-API-KEY.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate web_search tool from HMAC-SHA256 reqId signing to
sid/device-id/os-type auth headers, matching the desktop API client
pattern. Update endpoint to /api/v1/web-search.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reads sid and deviceId from ~/.super-multica/auth.json for use by
tools that need authenticated API access.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add common generateEncryptedId() utility in @multica/utils
- All Device IDs now use same encryption algorithm (40 hex chars)
- Web: store encrypted format directly in localStorage
- Desktop: use shared utility, accept encrypted ID from Web
- Hub: use shared utility for hub-id generation
- Telegram: use shared utility for device ID generation
- Gateway hook: use encrypted format for client connections
Algorithm: sha256(sha256(uuid).slice(0,32)).slice(0,8) + sha256(uuid).slice(0,32)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>