feat(queue): queue a message with everything the composer had attached

Queueing captured only the text and files. Context chips (inline comments,
terminal selections, browser annotations, PR comments and checks, quotes,
linked issue/PR/Linear references, pending synthetic parts) stayed in the
composer and only left with the next manual send, so a queued message the
server delivered went out without them and the chips rode an unrelated
message later.

A queued message now carries what the composer would have sent: the text
with its agent mention stripped and file mentions resolved into
attachments, the attached context as structured parts, and the skill
instruction derived from the text. The server delivers those parts in the
composer's order, the VS Code auto-send does the same, and editing a queued
message puts the chips and linked references back. A failed queue restores
the composer completely. Snapshots and broadcasts omit the captured
context like attachment payloads; a take returns it.

Claude-Session: https://claude.ai/code/session_01HB9wdLQoZX2vfyDjwv6Rso
This commit is contained in:
Bohdan Triapitsyn
2026-09-04 22:56:27 +03:00
parent ce5c0c068e
commit 34bf631157
17 changed files with 823 additions and 285 deletions
@@ -5,7 +5,7 @@ import { useSelectionStore } from '@/sync/selection-store';
import { useConfigStore } from '@/stores/useConfigStore';
import { useContextStore } from '@/stores/contextStore';
import { useAutoReviewStore } from '@/stores/useAutoReviewStore';
import { parseAgentMentions } from '@/lib/messages/agentMentions';
import { queuedContextToParts } from '@/components/chat/composer/submit/buildOutgoingMessage';
import { getDirectoryState } from '@/sync/sync-refs';
import { useDirectorySync } from '@/sync/sync-context';
import { getRuntimeKey } from '@/lib/runtime-switch';
@@ -82,14 +82,14 @@ export const buildQueuedAutoSendPayload = (queue: QueuedMessage[]) => {
return null;
}
const agents = useConfigStore.getState().getVisibleAgents();
const { sanitizedText, mention } = parseAgentMentions(queued.content, agents);
// A queued message is delivered as captured: mention already stripped,
// file mentions resolved, and the context it was queued with following it.
return {
queuedMessageId: queued.id,
primaryText: sanitizedText,
primaryText: queued.text,
primaryAttachments: queued.attachments ?? [],
agentMentionName: mention?.name,
agentMentionName: queued.agentMention,
additionalParts: queuedContextToParts(queued.context ?? []),
sendConfig: queued.sendConfig,
};
};
@@ -114,7 +114,7 @@ export const sendQueuedAutoSendPayload = (
resolved.agent,
payload.primaryAttachments,
payload.agentMentionName,
undefined,
payload.additionalParts.length > 0 ? payload.additionalParts : undefined,
resolved.variant,
'normal',
{ target },