5.8.2 Work-item reference token + parse/resolve helper (`lib/mentions`)
Type: code · Executor: coding_agent · Repo: motir-core · Foundation — no blockers.
Define the work-item reference vocabulary and the pure helper everything else parses through — the parallel of the shipped user-mention authority lib/mentions/parse.ts (MENTION_TOKEN_RE = /\[@([^\]]*)\]\(mention:([A-Za-z0-9_-]+)\)/g, parseMentionIds).
Token format. A work-item reference serializes to [MOTIR-11](motir:<workItemId>) — same Markdown-link shape as the user token but the motir: scheme + a work-item id payload (not a user id). Chosen to ride the EXISTING round-trip: tiptap-markdown / markdown-it already allow custom link schemes, and the render layer (lib/markdown/render.tsx) already gates an allowed scheme (mention:) in both urlTransform and the rehype-sanitize schema — so motir: is added the same way (5.8.6).
Helper (add to lib/mentions/, e.g. lib/mentions/workItemRefs.ts).
WORKITEM_TOKEN_RE—/\[[^\]]*\]\(motir:([A-Za-z0-9_-]+)\)/g(captures the id).WORKITEM_KEY_RE— bare project-key patternMOTIR-<n>(word-boundaried, case-insensitive on the prefix; the prefix comes from the project, not hard-coded "MOTIR" — read the project's key so this works for any tenant).parseWorkItemRefs(text): { ids: string[], keys: string[] }— extract token ids AND bare keys from any Markdown/plain string, deduped, first-seen order, malformed tokens silently skipped (the same forgiving contract asparseMentionIds). Title is plain text → onlykeysapply there; rich-text fields yield both.- Pure string functions only — no DB (key->id resolution is the service's job, 5.8.3, because it needs the workspace/project + permission scope).
Acceptance criteria
parseWorkItemRefsextracts ids frommotir:tokens and bareMOTIR-Nkeys; mixed input returns both arrays; duplicates collapse first-seen; malformed (motir:with empty/illegal id, an unmatched bracket) are skipped, never thrown.- The key regex is built from a passed-in project key (no literal "MOTIR"); a key for a DIFFERENT project's prefix is NOT matched by this project's regex (resolution scope is enforced later, but the pattern is prefix-specific).
- Does not match inside code spans/fenced blocks if
parseMentionIdsdoesn't either — match the shipped helper's behaviour exactly (read it first; keep parity). - Unit tests (vitest) cover every branch above; co-located with the existing
lib/mentionstests. - No change to
parseMentionIdsbehaviour (user mentions untouched).
Context refs: lib/mentions/parse.ts (the pattern to mirror), lib/markdown/render.tsx (MENTION_HREF_RE, scheme allow-listing — the consumer in 5.8.6).