/ src / utils / directMemberMessage.ts
directMemberMessage.ts
 1  import type { AppState } from '../state/AppState.js'
 2  
 3  /**
 4   * Parse `@agent-name message` syntax for direct team member messaging.
 5   */
 6  export function parseDirectMemberMessage(input: string): {
 7    recipientName: string
 8    message: string
 9  } | null {
10    const match = input.match(/^@([\w-]+)\s+(.+)$/s)
11    if (!match) return null
12  
13    const [, recipientName, message] = match
14    if (!recipientName || !message) return null
15  
16    const trimmedMessage = message.trim()
17    if (!trimmedMessage) return null
18  
19    return { recipientName, message: trimmedMessage }
20  }
21  
22  export type DirectMessageResult =
23    | { success: true; recipientName: string }
24    | {
25        success: false
26        error: 'no_team_context' | 'unknown_recipient'
27        recipientName?: string
28      }
29  
30  type WriteToMailboxFn = (
31    recipientName: string,
32    message: { from: string; text: string; timestamp: string },
33    teamName: string,
34  ) => Promise<void>
35  
36  /**
37   * Send a direct message to a team member, bypassing the model.
38   */
39  export async function sendDirectMemberMessage(
40    recipientName: string,
41    message: string,
42    teamContext: AppState['teamContext'],
43    writeToMailbox?: WriteToMailboxFn,
44  ): Promise<DirectMessageResult> {
45    if (!teamContext || !writeToMailbox) {
46      return { success: false, error: 'no_team_context' }
47    }
48  
49    // Find team member by name
50    const member = Object.values(teamContext.teammates ?? {}).find(
51      t => t.name === recipientName,
52    )
53  
54    if (!member) {
55      return { success: false, error: 'unknown_recipient', recipientName }
56    }
57  
58    await writeToMailbox(
59      recipientName,
60      {
61        from: 'user',
62        text: message,
63        timestamp: new Date().toISOString(),
64      },
65      teamContext.teamName,
66    )
67  
68    return { success: true, recipientName }
69  }