diff --git a/src/main/services/team/CrossTeamService.ts b/src/main/services/team/CrossTeamService.ts index 327cefd6..6ddbcfaa 100644 --- a/src/main/services/team/CrossTeamService.ts +++ b/src/main/services/team/CrossTeamService.ts @@ -76,7 +76,7 @@ export class CrossTeamService { const formattedText = `[Cross-team from ${from} | depth:${chainDepth}]\n${text}`; const messageId = randomUUID(); - // 5. Inbox write (TeamInboxWriter handles file lock + in-process lock internally) + // 5. Inbox write to TARGET team (TeamInboxWriter handles file lock + in-process lock internally) await this.inboxWriter.sendMessage(toTeam, { member: leadName, text: formattedText, @@ -85,7 +85,24 @@ export class CrossTeamService { source: 'cross_team', }); - // 6. Best-effort relay (if online) + // 6. Write "sent" copy to SENDER's inbox so the message appears in their activity + const senderLeadName = (await this.dataService.getLeadMemberName(fromTeam)) ?? 'team-lead'; + void this.inboxWriter + .sendMessage(fromTeam, { + member: senderLeadName, + text, + from: 'user', + to: `${toTeam}.${leadName}`, + summary: summary ?? `Cross-team message to ${toTeam}`, + source: 'cross_team_sent', + }) + .catch((e: unknown) => { + logger.warn( + `Failed to write sender copy for ${fromTeam}: ${e instanceof Error ? e.message : String(e)}` + ); + }); + + // 7. Best-effort relay (if online) if (this.provisioning?.isTeamAlive(toTeam)) { void this.provisioning.relayLeadInboxMessages(toTeam).catch((e: unknown) => { logger.warn(`Cross-team relay to ${toTeam}: ${e instanceof Error ? e.message : String(e)}`); diff --git a/src/main/services/team/TeamInboxWriter.ts b/src/main/services/team/TeamInboxWriter.ts index e267b220..c8e55f07 100644 --- a/src/main/services/team/TeamInboxWriter.ts +++ b/src/main/services/team/TeamInboxWriter.ts @@ -23,7 +23,7 @@ export class TeamInboxWriter { const payload: InboxMessage = { from: request.from ?? 'user', - to: request.member, + to: request.to ?? request.member, text: request.text, timestamp: new Date().toISOString(), read: false, diff --git a/src/renderer/components/team/TeamDetailView.tsx b/src/renderer/components/team/TeamDetailView.tsx index a5f13521..905c35f6 100644 --- a/src/renderer/components/team/TeamDetailView.tsx +++ b/src/renderer/components/team/TeamDetailView.tsx @@ -215,6 +215,7 @@ export const TeamDetailView = ({ teamName }: TeamDetailViewProps): React.JSX.Ele updateTaskStatus, updateTaskOwner, sendTeamMessage, + sendCrossTeamMessage, requestReview, createTeamTask, startTask, @@ -255,6 +256,7 @@ export const TeamDetailView = ({ teamName }: TeamDetailViewProps): React.JSX.Ele updateTaskStatus: s.updateTaskStatus, updateTaskOwner: s.updateTaskOwner, sendTeamMessage: s.sendTeamMessage, + sendCrossTeamMessage: s.sendCrossTeamMessage, requestReview: s.requestReview, createTeamTask: s.createTeamTask, startTask: s.startTask, @@ -1567,6 +1569,15 @@ export const TeamDetailView = ({ teamName }: TeamDetailViewProps): React.JSX.Ele }); }); }} + onCrossTeamSend={(toTeam, text, summary) => { + void sendCrossTeamMessage({ + fromTeam: teamName, + fromMember: 'user', + toTeam, + text, + summary, + }); + }} />
+ + +
+ {/* Current team option */} + + + {/* Separator */} +
+ + {/* Other teams */} + {crossTeamTargets.map((target) => { + const isSelected = selectedTeam === target.teamName; + return ( + + ); + })} +
+ + + ) : null} + +