Skip to content

feat: add /update and /doctor to TG bot menu#75

Open
changhansung wants to merge 268 commits into
suzuke:mainfrom
songsid:feat/tg-update-doctor-commands
Open

feat: add /update and /doctor to TG bot menu#75
changhansung wants to merge 268 commits into
suzuke:mainfrom
songsid:feat/tg-update-doctor-commands

Conversation

@changhansung

Copy link
Copy Markdown
Contributor

Adds /update and /doctor to forum bot commands. /doctor executes agend doctor and returns stripped ANSI results to chat.

AgEnD Dev and others added 30 commits April 18, 2026 22:47
…all users

Discord adapter now emits all messages. Fleet-manager checks access:
- Classic channels: all users allowed (for chat logging)
- Topic/general: only allowed_users pass
- Remove guildId filter from messageCreate — messages from any server pass through
- Fleet-manager access control + routing handles which channels are valid
- Fixes: messages from non-primary server were silently dropped
- Restore .kiro/settings/mcp.json to .gitignore (machine-specific)
- Remove ~/Projects/ from .gitignore (local path)
- Remove plugin package-lock.json (managed by root workspaces)
… stale drop

- Reduce waitForIdle timeout to 10s for lightweight (classic) instances
- Add queue depth counter with warning at depth > 3
- Drop stale user messages (>60s in queue), preserve cross-instance messages
- Apply sanitizeInstanceName in ClassicChannelManager.load() to match
  handleClassicStart registration path, preventing workspace directory
  drift after rebase/restart
- Allow bare attachments (images without /chat prefix) to be forwarded
  to classic channel agents
- Include attachment info in classic channel chat logs
restartInstances() killed classic tmux windows during orphan cleanup
but never restarted them. Only reregisterClassicChannels() was called
(routing only). Add the same startup logic from startAll() to restart
classic instances with concurrency 3.
capture-pane leaks 'can't find window' to stderr when instances
are still starting up. Pipe stderr to suppress.
…bare attachments

- Bare image (no /chat): download to ~/.agend/workspaces/<instance>/inbox/,
  log path in chat-log, react 📸, don't forward to agent
- /chat + image: download to workspace inbox, forward to agent with
  correct workspace path in image_path and text
- Topic mode image handling unchanged (still uses processAttachments directly)
Strip photo from attachments before processAttachments when already
saved to workspace inbox, preventing orphan file in daemon inbox.
P0: Discord adapter security hardening
- messageCreate: reject messages from other guilds
- interactionCreate: reject interactions from other guilds

P1: setup-wizard Discord channel type support
- Add channel type selection step (Telegram / Discord)
- Discord flow: token verification, guild selection, user ID input
- buildFleetConfig generates correct Discord config (type: discord,
  bot_token_env: AGEND_DISCORD_TOKEN, guild_id)
- WizardAnswers extended with channelType and guildId fields
- Telegram flow unchanged
Adds optional general_channel_id prompt after User ID step.
Written to fleet.yaml under channel.options when provided.
After Discord flow completion, both setup-wizard and quickstart now
display: 'Classic Bot Mode: Use /start in any Discord channel to start
an agent. Use /chat to talk.'
…ugh guildId check

messageCreate, interactionCreate, and channelDelete handlers now check
openChannels set before rejecting messages from non-primary guilds.
This allows classic bot channels registered across multiple servers to
continue functioning while still blocking unregistered channels.

Added debug logging for non-primary guild classic channel events.
…dcoded 1

Telegram General Topic has thread_id=1 by convention, but Discord
channels have snowflake IDs. When general_channel_id is set in
fleet.yaml options, use it as the general instance's topic_id.
Fixes 'Unknown Channel' error on fleet start with Discord.
- ClassicBotYaml.defaults gains allowed_guilds?: string[]
- isGuildAllowed(): empty/unset list allows all guilds (backward compat)
- Discord adapter slash_command events now include guildId
- handleClassicStart checks guild whitelist before registering channel
After fleet.yaml is written, Discord quickstart now asks:
- Set up ClassicBot? (allows /start in any channel) [Y/n]
- If yes: collects allowed_guilds (primary guild pre-filled, can add more)
- Asks default backend (defaults to fleet backend)
- Writes ~/.agend/classicBot.yaml matching ClassicBotYaml interface
When fleet.yaml exists, quickstart now offers 3 options:
1. Add allowed users - load existing config, show current users,
   collect new IDs, append and write back
2. Overwrite - start fresh (previous behavior)
3. Skip - skip fleet.yaml changes

After fleet.yaml handling, if classicBot.yaml exists, offers to
add allowed guilds (load/show/collect/append/write back).
If classicBot.yaml doesn't exist and Discord, runs the existing
creation flow.
…apter

/start in a non-primary guild was silently dropped because the channel
wasn't in openChannels yet (chicken-and-egg: /start creates the classic
channel, but the channel must exist to pass the openChannels check).

Fix: let slash commands (isChatInputCommand) through regardless of guild.
The guild whitelist check in fleet-manager's handleClassicStart handles
authorization. Only block non-slash interactions (buttons) from unknown
channels.
Covers setup, slash commands, server whitelist (allowed_guilds),
per-channel backend override, and quickstart supplement mode.
Previously any local process knowing AGEND_PORT could POST to /agent with
any instance name and impersonate that instance. Now each spawn writes a
fresh 32-byte token to <instanceDir>/agent.token (mode 0600); agent-cli
reads it and sends it in X-Agend-Instance-Token; the endpoint verifies
with timingSafeEqual against the on-disk value for the claimed instance.

Also propagates AGEND_HOME to the child so agent-cli finds the token
file when the daemon uses a non-default data dir.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
POST /ui/tasks, /ui/schedules, /ui/teams, /ui/config and /ui/send
previously cast fields out of JSON with `body.x as string`, which allowed
unknown-field injection and unchecked types. outbound-handlers already
validates agent-facing calls via zod; web-api now follows the same pattern
with strict, public-only schemas:

  - TaskCreateSchema / TaskUpdateSchema
  - ScheduleCreateSchema
  - TeamCreateSchema (name restricted to [A-Za-z0-9._-])
  - ConfigUpdateSchema (.strict() at every level)
  - SendMessageSchema (caps message length at 16 KB; early-aborts oversized bodies)

Unknown fields now return 400 instead of silently passing through into
internal structures. Added tests/web-api.test.ts covering the reject cases.

Addresses ultrareview Phase 1 item P1.3.
changhansung and others added 30 commits June 12, 2026 13:27
In topic mode, daemon should not block reply when lastChatId is unset.
Fleet-manager has the classicBot channelId fallback to route correctly.
allowed_guilds: {} (object instead of array) caused all groups to be
rejected. Now uses Array.isArray check — non-array values treated as
'allow all'.
/stop@other_bot was being stripped to /stop and executed by all bots
in the group. Now checks if the @suffix matches our bot username —
if not, ignores the command entirely.
…fore start()

Two bugs:
1. Primary adapter's 'started' handler never set world.botUsername
   (only secondary adapter did). This caused isBotMentioned to always
   be false for TG classic mode on the primary adapter.
2. adapter.start() was called BEFORE event listeners were attached,
   so if 'started' fired synchronously it would be missed.

Fix: set botUsername in primary handler + move start() after all
event registrations.
- /start in groups: requires admin after isGroupAllowed passes
- /stop: requires admin
- /raw via @mention: requires admin
- Regular @mention conversation remains open to all users
- systemd: Restart=on-failure + RestartSec=5 (auto-restart on crash)
- launchd: already has KeepAlive=true (no change needed)
- Startup priority: general_topic instances start first and wait,
  then remaining instances start with staggered concurrency
- Both initial start and restart paths use same priority logic
- General instance failures logged but don't block other startups
TG: /status, /restart, /sysinfo → [Fleet]
TG: /start, /stop, /chat → [ClassicBot]
DC: all slash commands → [ClassicBot]
1. Daily update check: fleet daemon checks npm for new versions every
   24h (first check after 1h). Notifies general topic if update available.
   Beta instances also check @beta tag.

2. /update detached restart: after npm install, spawns a detached shell
   that sleeps 2s then restarts the service. Prevents the restart from
   killing the update response.

3. agend doctor expansion: adds fleet-level checks for fleet.yaml syntax,
   port 19280 availability, stale MCP sockets, service ExecStart mismatch,
   kiro-cli auth, and working_directory existence.
feat: daily update check, /update detached restart, doctor expansion
feat: doctor checks for service Restart policy and daemon-reload
1. sd-notify: READY=1 after generals start, WATCHDOG=1 every 30s,
   STOPPING=1 on shutdown. Zero dependencies (uses net.createConnection).

2. systemd template: Type=notify, NotifyAccess=main, WatchdogSec=60.
   systemd kills+restarts fleet if no watchdog ping for 60s.

3. General instance startup failure now sends notification to the
   general topic channel with error details.
feat: systemd watchdog + general startup failure notification
…ollab log

- Replace all user-facing 'agend fleet start' with 'agend start'
- Collab mode: skip logging empty bot messages (no text, no attachments)
fix: update message uses 'agend start' + skip empty bot messages in collab log
- Upgrade grammy to 1.44.0
- Auto-detect rich content (tables, code blocks, headings, HR, details)
- Use sendRichMessage API for rich content, fallback to sendText on failure
feat: Telegram Rich Messages support (Bot API 10.1)
docs: add tmux Ctrl+C unstick procedure to fleet-health skill
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants