Refresh missing/forced group titles via groupMetadata and participating catalog so cards show real names instead of bare JIDs.
Co-authored-by: Cursor <cursoragent@cursor.com>
Fetch groupMetadata.subject on @mentions for group cards; render contact pushName under phone rows so admins are not staring at bare numbers.
Co-authored-by: Cursor <cursoragent@cursor.com>
Suggestions only open while focused and hide exact matches; nested group admins/members drop extra frames; pending and actions show group names.
Co-authored-by: Cursor <cursoragent@cursor.com>
Settings button only forwarded accessPolicy, so the graded ACL page always opened empty; also refresh grant from connection.status on mount.
Co-authored-by: Cursor <cursoragent@cursor.com>
Client normalizeBot dropped accessGrant/groupSessionScope, so pending, contacts, and group cards never appeared. Also record contacts only on DM/@, auto-create group buckets on @, and add one-click grant buttons.
Co-authored-by: Cursor <cursoragent@cursor.com>
Row keys included the phone value, so each character remounted the input; also sync draft from serialized grant content, not object identity.
Co-authored-by: Cursor <cursoragent@cursor.com>
Mention triggers leave opaque LID digits in the body; remove those only,
without injecting sender identity (use context enhancement when needed).
Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve LID to phone aliases before allowlist and @mention checks so
group prompts are not silently dropped after a working direct chat.
Co-authored-by: Cursor <cursoragent@cursor.com>
Ops bots now isolate per-speaker Harness sessions in groups, with a
settings/RPC toggle to restore shared chat sessions when needed.
Co-authored-by: Cursor <cursoragent@cursor.com>
GitHub installs still shipped the upstream @xmanrui/dsh-im client id, so the web shell loaded the bundle without registering the plugin.
Co-authored-by: Cursor <cursoragent@cursor.com>
Keep all IM channels; rename package/cordis id for local profile install without colliding with the community plugin. Document fork intent in FORK.md.
Co-authored-by: Cursor <cursoragent@cursor.com>
Support current DSH Session.snapshotEvents while retaining the legacy session.events and apiProxy paths. Add regression coverage and record the nine-channel rollout and live verification for issue #70.
Resolve the current main conflict, treat reply timeouts as inactivity windows, and confirm liveness through Harness instead of sticky interaction ownership.
Add chatId and threadId source fields across all nine IM channels, update UI/docs/tests, reconcile the latest main branch, and credit @Chan-0312 as a contributor.
Address review feedback on the interaction cards:
1. Bind card decisions to the initiating actor. The card-action operator
(operatorOpenId) is now passed into the approval and question handlers:
- submitByApprovalId receives { actor } so another allowed group member
cannot approve/reject someone else's approval;
- the answer branch requires pending.actor === operator.
2. Include the question index in the answer button action and validate it
against the current pending question, so a stale card from an earlier
question in a multi-question interaction cannot be applied to the next one.
3. When both the card send and the plain-text fallback fail, the error is no
longer swallowed: it propagates so the interaction is not marked as
presented and the existing retry/reconnect behaviour can run.
Adds regression tests for all three cases.
Render Harness approval and single-choice question interactions as
interactive Feishu cards with approve/reject and answer buttons,
matching the already-available interactionCards behaviour. Cards are now
the default; set DSH_IM_INTERACTION_CARDS=0 (or interactionCards=false)
to keep the plain-text reply flow.
- bridge.mjs: approve:/reject:/answer: card actions, interactionCards
option, gated approval render hook, interactive question presentation,
and operationArguments/printableText helpers; refactor the inline
question answer into #submitQuestionAnswer so both text replies and
card buttons share one path.
- feishu-cards.mjs: approvalCard (approve/reject) and questionCard
(option buttons) templates.
- feishu-runtime.mjs: default interactionCards from env (on).
- harness-approval.mjs: optional channel render hook + submitByApprovalId.
- i18n-en: add the new card t() keys.
- Tests: pin the plain-text reply flow in state-machine suites that
drive it, and add dedicated card tests for the default approve/reject,
answer buttons, and the text fallback. Full suite shows no new
failures versus upstream.
A long-running Harness task was falsely reported as MODEL_REPLY_TIMEOUT
after the fixed 10-minute deadline even though the backend was still
working. Replace the hard wall-clock deadline with an activity-based
stall window: the wait renews whenever the turn produces new events, the
control ownership is active, or (mid-turn with no new events) Harness
still reports the session as running. Only a genuine stall with no
progress for the whole timeoutMs window fails fast.
This is the shared harness-client layer, exercised end-to-end by the
Feishu channel (which already exposes HARNESS_REPLY_TIMEOUT_MS); other
channels inherit the same fix.
Adds two regression tests: a long-running turn with periodic activity
completes instead of timing out, and a genuinely stalled turn still
fails with harness-reply-timeout.
- CHANGELOG: keep the image-fallback entry under Unreleased alongside the new 4.5.0 section
- harness-client: upstream renameSession coexists with the image-rejection fallback retry path
- lib/index.js rebuilt from merged sources