feat(session): add cross-session references
This commit is contained in:
@@ -7,7 +7,7 @@ import {
|
||||
} from "@/components/InlineTokenHighlight";
|
||||
import { useLogoFallback } from "@/hooks/useLogoFallback";
|
||||
import { logoFallbackUrls } from "@/lib/provider-brand";
|
||||
import type { CliAppInfo, McpPresetInfo } from "@/lib/types";
|
||||
import type { CliAppInfo, McpPresetInfo, SessionMention } from "@/lib/types";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type CliAppMentionSegment =
|
||||
@@ -16,7 +16,8 @@ type CliAppMentionSegment =
|
||||
|
||||
export type CapabilityMentionSegment =
|
||||
| CliAppMentionSegment
|
||||
| { kind: "mcp"; text: string; preset: McpPresetInfo };
|
||||
| { kind: "mcp"; text: string; preset: McpPresetInfo }
|
||||
| { kind: "session"; text: string; mention: SessionMention };
|
||||
|
||||
export function cliAppInitials(app: CliAppInfo): string {
|
||||
const value = app.display_name || app.name;
|
||||
@@ -44,8 +45,9 @@ export function splitCapabilityMentionSegments(
|
||||
value: string,
|
||||
cliApps: CliAppInfo[],
|
||||
mcpPresets: McpPresetInfo[] = [],
|
||||
sessionMentions: SessionMention[] = [],
|
||||
): CapabilityMentionSegment[] {
|
||||
if (!value || (cliApps.length === 0 && mcpPresets.length === 0)) {
|
||||
if (!value || (cliApps.length === 0 && mcpPresets.length === 0 && sessionMentions.length === 0)) {
|
||||
return value ? [{ kind: "text", text: value }] : [];
|
||||
}
|
||||
const cliAppsByName = new Map(
|
||||
@@ -58,12 +60,15 @@ export function splitCapabilityMentionSegments(
|
||||
.filter((preset) => preset.installed && preset.configured)
|
||||
.map((preset) => [preset.name.toLowerCase(), preset]),
|
||||
);
|
||||
if (cliAppsByName.size === 0 && mcpPresetsByName.size === 0) {
|
||||
const sessionsByName = new Map(
|
||||
sessionMentions.map((mention) => [mention.name.toLowerCase(), mention]),
|
||||
);
|
||||
if (cliAppsByName.size === 0 && mcpPresetsByName.size === 0 && sessionsByName.size === 0) {
|
||||
return [{ kind: "text", text: value }];
|
||||
}
|
||||
|
||||
const segments: CapabilityMentionSegment[] = [];
|
||||
const mentionRe = /(^|[\s([{])@([a-z0-9_-]+)\b/gi;
|
||||
const mentionRe = /(^|[\s([{])@([\p{L}\p{N}_-]+)(?=$|[^\p{L}\p{N}_-])/giu;
|
||||
let cursor = 0;
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = mentionRe.exec(value)) !== null) {
|
||||
@@ -72,7 +77,8 @@ export function splitCapabilityMentionSegments(
|
||||
const key = name.toLowerCase();
|
||||
const app = cliAppsByName.get(key);
|
||||
const preset = app ? null : mcpPresetsByName.get(key);
|
||||
if (!app && !preset) continue;
|
||||
const session = app || preset ? null : sessionsByName.get(key);
|
||||
if (!app && !preset && !session) continue;
|
||||
|
||||
const mentionStart = match.index + prefix.length;
|
||||
const mentionEnd = mentionStart + name.length + 1;
|
||||
@@ -83,6 +89,12 @@ export function splitCapabilityMentionSegments(
|
||||
segments.push({ kind: "cli", text: value.slice(mentionStart, mentionEnd), app });
|
||||
} else if (preset) {
|
||||
segments.push({ kind: "mcp", text: value.slice(mentionStart, mentionEnd), preset });
|
||||
} else if (session) {
|
||||
segments.push({
|
||||
kind: "session",
|
||||
text: value.slice(mentionStart, mentionEnd),
|
||||
mention: session,
|
||||
});
|
||||
}
|
||||
cursor = mentionEnd;
|
||||
}
|
||||
@@ -96,13 +108,15 @@ export function CliAppMentionText({
|
||||
text,
|
||||
cliApps,
|
||||
mcpPresets = [],
|
||||
sessionMentions = [],
|
||||
}: {
|
||||
text: string;
|
||||
cliApps: CliAppInfo[];
|
||||
mcpPresets?: McpPresetInfo[];
|
||||
sessionMentions?: SessionMention[];
|
||||
}) {
|
||||
const segments = splitCapabilityMentionSegments(text, cliApps, mcpPresets);
|
||||
if (!segments.some((segment) => segment.kind === "cli" || segment.kind === "mcp")) return <>{text}</>;
|
||||
const segments = splitCapabilityMentionSegments(text, cliApps, mcpPresets, sessionMentions);
|
||||
if (!segments.some((segment) => segment.kind !== "text")) return <>{text}</>;
|
||||
return (
|
||||
<>
|
||||
{segments.map((segment, index) => {
|
||||
@@ -117,7 +131,7 @@ export function CliAppMentionText({
|
||||
variant="message"
|
||||
/>
|
||||
);
|
||||
return (
|
||||
if (segment.kind === "mcp") return (
|
||||
<McpPresetMentionToken
|
||||
key={`mcp-${segment.preset.name}-${index}`}
|
||||
preset={segment.preset}
|
||||
@@ -125,11 +139,40 @@ export function CliAppMentionText({
|
||||
variant="message"
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<SessionMentionToken
|
||||
key={`session-${segment.mention.session_key}-${index}`}
|
||||
mention={segment.mention}
|
||||
label={segment.text}
|
||||
variant="message"
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function SessionMentionToken({
|
||||
mention,
|
||||
label,
|
||||
variant,
|
||||
}: {
|
||||
mention: SessionMention;
|
||||
label: string;
|
||||
variant: "composer" | "message";
|
||||
}) {
|
||||
const testIdPrefix = variant === "composer" ? "composer" : "message";
|
||||
return (
|
||||
<InlineTokenHighlight
|
||||
testId={`${testIdPrefix}-session-mention-${mention.name}`}
|
||||
title={`Session: ${mention.title || mention.name}`}
|
||||
color={INLINE_TOKEN_HIGHLIGHT_COLOR}
|
||||
>
|
||||
{label}
|
||||
</InlineTokenHighlight>
|
||||
);
|
||||
}
|
||||
|
||||
export function CliAppMentionToken({
|
||||
app,
|
||||
label,
|
||||
|
||||
Reference in New Issue
Block a user