Treat attachment-free Feishu rich-text posts containing bot commands like ordinary text commands instead of forwarding them to the Harness.
Co-authored-by: OpenClaw Agent <agent@openclaw.ai>
- Move preset/model/archive controls from settings card to main menu
- Arrange 4 dropdowns in 2x2 grid with external icons
- Align steer and archive side by side
- Replace #showSettingsCard with #sendMenuCard for preset/model/archive updates
- Add #sendMenuCard after 'new' button action for consistency
- Update help card to reflect current menu layout (12 items)
- Clean up duplicate sessionlist entries in menuHelpText
- Add missing English dictionary entries
Wrap all user-facing chat text in src/channels with a host-side t()
translator (Chinese is the identity default, so untranslated text is
always sent verbatim in Chinese). English is selected via the host
plugin config `language: en` or the DSH_IM_LANGUAGE environment
variable, and the settings UI keeps following the DSH web locale.
- add src/channels/shared/i18n.mjs with setImHostLanguage/t() and a
Chinese-key -> English dictionary split by area (shared + channels)
- complete the English dictionary for every t() key in src/channels,
including the feishu channel (welcome/help, repair flow, interactive
cards, watch flow) and the shared command/approval/stream text
- wrap previously untranslated chat-facing strings in feishu bridge,
feishu runtime, editable-message-stream, harness-client,
connection-test and image-prompt
- dedupe dictionary entries that existed in multiple channel files and
canonicalize conflicting translations into the shared dictionaries
- extend the i18n unit test to decode string-literal escapes so keys
containing \n are checked correctly
- document the language switch in README.md, README.en.md and
CHANGELOG.md, and rebuild lib/index.js
Added English support for bot chat messages across all nine IM
channels and AI Office without changing any Chinese output.
The menu card renders the repair fallback as **5**<emoji>修复, so the two assertions that matched **5**修复 are broadened to tolerate the marker emoji. The number-reply on a later session page now reads the last text confirmation instead of assuming the last outgoing message is text, since #bindSession refreshes the menu card after binding. Rebuild bundle.
- read form data from action.form_value (Card 2.0) instead of formValue
- wrap custom steer input and submit in a form container with submit button
- reuse runModelCommand for dropdown model picks so IDs with multiple / keep working
- pass key when sending the help card so back-to-menu stays valid
- compute initial_index from {value} option arrays
- add in-flight tests for menu stop, steer dropdown, and steer form
Add stop/compact/settings/watchlist buttons to the hub menu card, route repair through the numeric fallback (reply 6) without an extra button, and sync the menu help and card-structure test assertions. Rebuild the lib bundle so the published artifact carries the changes.
Replace the flat button-only command menu with an information-architected
assistant center: status summary header, session dropdown (current session
pre-selected), workspace/model/preset dropdowns with current value shown,
archive toggle, task control (stop/compact/steer), watch multi-select, and a
collapsed settings panel. All commands expose card or dropdown entry points.
Each session row is a column_set with a fixed 90px watch-toggle column
(⭐关注/⭐取关 for already-watched sessions) and a weighted session button
carrying the number label; number replies bind the session. Replaces the
stacked button pair; also honors the per-bot archived-session policy.
The session list (and the numeric /watch index) honors a per-bot persisted
policy: /archived off hides archived sessions from cards and index
resolution, /archived on restores them. Defaults to on.
- /watch resolves the target READ-ONLY: sessions are validated against
registered workspace listings (current or any other) without binding the
conversation or switching workspaces. /unwatch and /watchlist round out
the command set; the watchlist card supports button and number-reply
unwatching.
- Watches persist in the state store (sessionId + title + chatId + lastSeq)
and resume at runtime start: the bridge starts the global event-mux
watcher in its constructor when the harness supports it.
- Completion pushes fire on turn/end, deduped by sessionId + turn id, with
the seq watermark persisted per watch. After a mux reconnect the bridge
replays each watched session's recent history (session.history) through
the normal handler, so missed turn/end events are compensated without
duplicates.
- Bound-session push targets are persisted (chatTargets) instead of living
only in memory, and refresh on every accepted message.
- Watch failures map to safe user-facing messages.
- /m (or /menu) opens a card menu; /sessionlist and /workspacelist render
cards with bind/switch buttons; number replies stay usable as a fallback
when the app does not subscribe card.action.trigger.
- card.action.trigger callbacks validate the operator's open_id against the
allowed senders: group members outside the allowlist can never drive
binding, workspace switches or other card actions.
- Session-list pagination uses page numbers everywhere (buttons carry
sessions:<page>), fixing the previous double page-size scaling that
skipped pages past 20 sessions.
- Bind/workspace failures map to safe user-facing messages instead of raw
error details.
- Apps registered after this change subscribe card.action.trigger during
the scan flow.