fix: TG ClassicBot chat-log text + classic instance notifications#90
Open
changhansung wants to merge 324 commits into
Open
fix: TG ClassicBot chat-log text + classic instance notifications#90changhansung wants to merge 324 commits into
changhansung wants to merge 324 commits into
Conversation
changhansung
commented
Jun 17, 2026
Contributor
- Non-@mention messages now log rawText (not empty string) to chat-log
- notifyInstanceTopic falls back to routing table for classic instances
Document attachments were only passed as file_id for manual download, unlike photos which are auto-downloaded. Now documents are downloaded to inbox with attachment_path in extraMeta and a [📎 File] prefix, falling back to file_id on download failure.
Extend saveClassicAttachment() to download both photo and document
attachments to workspace inbox. Returns { path, kind } so the caller
can set the correct extraMeta (image_path vs attachment_path) and use
appropriate emoji reactions (📸 for photos, 📎 for documents).
- New classicBot creation: collect admin_users after backend (pre-filled with quickstart userId, can add more) - Patch mode: renamed maybeAddClassicBotGuilds → maybeUpdateClassicBot, now also asks 'Add admin users? [y/N]' with show/collect/append - Output format includes defaults.admin_users alongside allowed_guilds
… /raw Part 1: ClassicChannelManager - defaults.admin_users?: string[] in classicBot.yaml - isAdmin(userId): empty/unset = no admins (secure default) Part 2: Discord adapter - Register /compact, /save (filename + force), /load (filename) slash commands - Extract interaction options as key-value pairs in slash_command event Part 3: Fleet manager - Handle /compact, /save, /load with admin check - pasteRawToClassicInstance: send raw_paste IPC to bypass [user:] wrapping - /save supports force option (appends -f flag) Part 4: Daemon - raw_paste IPC handler: paste directly to CLI - /raw prefix in pushChannelMessage: topic mode users can paste raw text (protected by allowed_users access control upstream)
…paste 1. Classic channel /chat /raw bypass: users could send '/chat /raw /compact' to bypass admin check. Now handleClassicChannelMessage blocks messages starting with /raw after stripping /chat prefix. 2. raw_paste IPC handler now uses pasteLock + deliverMessage instead of direct tmux.pasteText, preventing race conditions with concurrent message deliveries and respecting idle wait.
C1: /update authorization — empty allowed_users now disables /update
(was: empty = anyone can update). Matches upstream/main behavior.
C2: /save /load filename injection — validate filename against [\w.-]+
to prevent newline injection via tmux paste.
C3: Restore shellQuote for AGEND_HOME and AGEND_INSTANCE_NAME in
daemon env prefix. JSON.stringify uses double quotes which allow
$ and backtick interpretation in bash.
- daemon.ts: emit message_queued (when pasteQueueDepth > 0) and message_delivered (after deliverMessage) with chatId + messageId - instance-lifecycle.ts: listen for both events, call ctx.reactMessageStatus - fleet-manager.ts: reactMessageStatus reacts on the user's message, gated to Discord adapter only
- /chat respond now returns the bot reply message ID - Pass channelId as chatId + reply messageId to daemon meta - Optimize react() to try chatId as channelId first (fast path) - Fixes: ⏳/✅ reactions not showing because messageId was empty
…sy TUI When multiple messages are queued and the TUI is busy outputting, the first send-keys Enter after paste-buffer can be swallowed. Add a retry Enter after 1s delay. All supported CLIs (kiro-cli, claude-code, gemini-cli, codex, opencode) ignore Enter on empty input, making the retry safe.
…allow Root cause: with 10s/30s timeout, waitForIdle expires while the agent is still outputting. The forced paste succeeds but Enter is swallowed by the busy TUI. With 120s, paste only happens when the CLI has been silent for 2s (truly idle), so Enter is reliably accepted. The retry Enter in pasteText remains as a safety net for the rare case where the 120s timeout expires.
Part 1: restart_instance MCP tool - outbound-schemas.ts: RestartInstanceArgs (name only) - outbound-handlers.ts: restartInstance handler calling ctx.restartSingleInstance - OutboundContext: add restartSingleInstance method - mcp-tools.ts: register restart_instance tool - daemon.ts: add to CROSS_INSTANCE_TOOLS set Part 2: lightweight waitForIdle - deliverMessage: lightweight 30s, normal 120s (was 120s for both)
After /start registers a new classic channel, setOpenChannels on the adapter wasn't updated. Messages from non-primary guilds to the new channel were silently dropped because the channel wasn't in openChannels. This also affected attachment URL storage — images couldn't be downloaded.
1. handleClassicStop: add reregisterClassicChannels() after unregister to remove stopped channel from adapter openChannels. 2. reregisterClassicChannels: always call setOpenChannels even when channels list is empty, so the last /stop properly clears all stale entries from the adapter.
No admin required. Reads context from statusline.json first, falls back to tmux capture-pane with kiro-cli regex parser. Shows context percentage, backend, and instance name.
OpenCode shows 'Permission required' when accessing external directories, followed by a 'confirm' prompt. Add getRuntimeDialogs to auto-press Enter on both layers.
Runtime dialogs (Permission required, confirm) need fast response. 30s meant each prompt waited up to 30s before auto-dismiss. 5s keeps CPU impact minimal (single capture-pane per cycle).
Select 'Allow always' instead of 'Allow once' so the same directory won't prompt again. Added Right/Left to sendSpecialKey and dialog handler SPECIAL_KEYS set.
Kiro CLI 2.0 TUI mode uses ~1.1GB per instance. Classic mode uses ~300MB. Add --classic flag to kiro-cli chat command.
1. classic-channel-manager.ts:
- ClassicChannel.collab field (persisted to classicBot.yaml)
- toggleCollab(channelId): toggle + save, returns new state
- isCollab(channelId): check collab status
2. discord-adapter.ts:
- Register /collab slash command
- Only block own messages (not all bots) — let fleet-manager decide
- Pass isBotMessage flag in message emit
- Emit bot user ID with 'started' event
3. channel/types.ts:
- InboundMessage.isBotMessage?: boolean
4. fleet-manager.ts:
- /collab handler: admin-only toggle, responds with new state
- handleInboundMessage: bot messages only pass through to collab channels
- handleClassicChannelMessage collab mode:
- Log all messages (including bots) to chat-logs
- Trigger on exact @mention (<@BOT_USER_ID>) only
- @everyone/@here/@ROLE don't trigger (not <@id> format)
- Strip @mention, forward clean text to agent
- Store botUserId from adapter 'started' event
Part 1: pre_task_command - types.ts: InstanceConfig.pre_task_command?: string - classic-channel-manager.ts: ClassicChannel.preTaskCommand, load/save, getPreTaskCommand(channelId) - daemon.ts: in pasteLock, deliverMessage(pre_task_command) before the actual message (waits for idle between both) - fleet-manager.ts: startClassicInstance passes preTaskCommand from classicChannels config into InstanceConfig Part 2: General steering - GENERAL_INSTRUCTIONS: add 'Instance Configuration Tips' section with reviewer pre_task_command, collab mode, and cost_guard suggestions
feat: memory layering best practice in fleet steering
fix: memory best practice - add guards against hallucination
Previously only triggered when NO general existed at all. Now detects each channel adapter without a bound general and auto-creates one. Uses new channel_id field for explicit binding. findGeneralInstance prefers channel_id match over name heuristic.
fix: auto-create general per adapter in multi-channel setup
docs: multi-channel skill (dual platform setup)
- Removed fleet.pid blocker for 'add users' and 'add platform' actions - Add platform: detached spawn 'agend fleet restart --reload' (avoids SIGUSR1 exit(0) + Restart=on-failure bug) - Add users: SIGHUP hot-reload - Only 'Overwrite' still requires fleet to be stopped
feat: quickstart supports adding platform while fleet is running
… for platform detection
…assign fix: quickstart systemd restart + assignTopicIds channel_id platform detection
…ates When adding a second platform, existing general without channel_id was not recognized as belonging to any adapter. Auto-create spawned duplicates. Fix: 3-phase approach: 1. Match unbound generals by topic_id (TG general has topic_id=1, DC has general_channel_id) 2. Adopt remaining unbound generals first-come 3. Only create new instances if no unbound generals left This correctly handles: existing TG general + add DC → general gets channel_id=telegram, new general-discord created for DC.
fix: adopt existing general when adding second platform
Without it, General has no valid topic_id and routing breaks. Loop until user provides a value with explanation why it's needed.
fix: Discord general_channel_id required in quickstart
On machines without D-Bus user session (root, SSH without linger, containers), systemctl --user fails. Now falls back to fleet.pid kill like agend fleet stop does.
fix: agend stop fallback to PID kill when systemd unavailable
…lable Same D-Bus issue as agend stop. When startService() fails or no service is installed, spawns 'agend fleet start' in background instead of giving up.
fix: agend start fallback to direct fleet start when systemd unavailable
docs: complete configuration and commands reference
fix: add admin check to /restart + correct docs permissions
fix: add version to /sysinfo + improve kiro-cli context parser
fix: /status adds tmux capture fallback for context percentage
fix: remove /chat from TG ClassicBot menu
…reach classic instances
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.