fix(team): require revision notice before editing

This commit is contained in:
777genius 2026-05-25 20:57:04 +03:00
parent 7e0520cb4c
commit 86e700f031
2 changed files with 84 additions and 6 deletions

View file

@ -733,12 +733,21 @@ export const MessagesPanel = memo(function MessagesPanel({
}, []);
const handleReviseMessage = useCallback(
(message: InboxMessage) => {
async (message: InboxMessage) => {
if (!isRevisableUserSentMessage(message, memberNames)) return;
const originalMessageId = trimString(message.messageId);
if (originalMessageId !== revisionMessageId) return;
const recipient = trimString(message.to);
const originalText = getRevisableMessageText(message);
try {
await sendTeamMessage(teamName, {
member: recipient,
text: buildRevisionNoticeText(originalMessageId, originalText),
summary: `${REVISION_NOTICE_PREFIX} ${originalMessageId}`,
});
} catch {
return;
}
setRevisionRequest({
requestId: `${originalMessageId}:${Date.now()}`,
originalMessageId,
@ -747,11 +756,6 @@ export const MessagesPanel = memo(function MessagesPanel({
actionMode: message.actionMode,
});
composerTextareaRef.current?.focus();
void sendTeamMessage(teamName, {
member: recipient,
text: buildRevisionNoticeText(originalMessageId, originalText),
summary: `${REVISION_NOTICE_PREFIX} ${originalMessageId}`,
}).catch(() => undefined);
},
[memberNames, revisionMessageId, sendTeamMessage, teamName]
);

View file

@ -868,6 +868,80 @@ describe('MessagesPanel idle summary invariants', () => {
});
});
it('does not enter revision mode when the revision notice fails to send', async () => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
storeState.sendTeamMessage.mockRejectedValueOnce(new Error('send failed'));
const host = document.createElement('div');
document.body.appendChild(host);
const root = createRoot(host);
await act(async () => {
storeState.teamMessagesByName['atlas-hq'] = {
canonicalMessages: [
makeMessage({
messageId: 'latest-user-send',
from: 'user',
to: 'bob',
source: 'user_sent',
timestamp: '2026-04-08T12:05:00.000Z',
text: 'raw transport text',
summary: 'restore this text',
}),
],
optimisticMessages: [],
feedRevision: 'rev-1',
nextCursor: null,
hasMore: false,
lastFetchedAt: Date.now(),
loadingHead: false,
loadingOlder: false,
headHydrated: true,
};
root.render(
React.createElement(MessagesPanel, {
teamName: 'atlas-hq',
position: 'sidebar',
onPositionChange: vi.fn(),
members: [
{
agentType: 'developer',
currentTaskId: null,
lastActiveAt: null,
messageCount: 0,
name: 'bob',
role: 'Developer',
status: 'idle',
taskCount: 0,
},
],
tasks: [],
timeWindow: null,
pendingRepliesByMember: {},
onPendingReplyChange: vi.fn(),
})
);
await Promise.resolve();
});
const editButtons = Array.from(host.querySelectorAll('button')).filter(
(button) => button.textContent === 'Edit message'
);
expect(editButtons).toHaveLength(1);
await act(async () => {
editButtons[0].click();
await Promise.resolve();
});
expect(storeState.sendTeamMessage).toHaveBeenCalledOnce();
expect(host.textContent).not.toContain('composer revision:latest-user-send:restore this text');
await act(async () => {
root.unmount();
await Promise.resolve();
});
});
it('clears stale OpenCode runtime diagnostics once the member reply is visible', async () => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
const host = document.createElement('div');