Files
multica/packages/core/permissions
Jiayuan Zhang 3bd69bdaa2 MUL-4432: add DM button on agent detail page (#5289)
* feat(agents): add DM button on agent detail page

The header gains a DM action next to Assign work. It shares the MUL-3963
invocation gate with assignment: allowed users land on the Chat tab with a
fresh compose bound to the agent via a new one-shot ?agent=<id> deep link
(consumed once the permission-filtered agent list resolves, then stripped);
denied users get an explanatory toast instead of a hidden affordance.

Closes MUL-4432

Co-authored-by: multica-agent <github@multica.ai>

* fix(chat): harden the ?agent= deep link against races and undetermined permissions

Review follow-up for the DM button (PR #5289):

- An explicit user action (thread select, archive, manual new chat) now
  supersedes a still-pending ?agent= intent, so an intent deferred by slow
  agent/member queries can no longer fire late and clobber that choice.
- The composingNew reset reads the live store value; under StrictMode's
  effect replay the render-captured snapshot re-closed the compose pane the
  intent had just opened (one-shot guard rightly refuses to re-fire).
- A settled miss (revoked access, archived agent, bad id) now toasts and
  strips the param instead of silently keeping a re-fireable intent; still-
  loading queries keep the intent pending. Query errors never settle.
- useAgentPermissions exposes isLoading: the detail page disables DM while
  membership resolves instead of toasting a false not_member deny at a
  legitimate member.

The chat store test mock is now reactive (useSyncExternalStore) — with a
plain mutable ref React bails out of committing post-effect re-renders and
the StrictMode regression cannot reproduce. Both new regression tests fail
against the pre-fix code.

Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: Lambda <lambda@multica.ai>
Co-authored-by: multica-agent <github@multica.ai>
2026-07-12 13:56:31 +08:00
..