supermemory/apps/web/lib/plugin-space.ts
ved015 4e607f9fd7 fix: Add plugin document rendering and MCP preview support (#938)
<h3>Implement comprehensive plugin document rendering support including MCP previews and plugin specific content handling.</h3>
<br>
<br>

<img width="1680" height="471" alt="Screenshot 2026-05-12 at 8 24 49 PM" src="https://github.com/user-attachments/assets/f1294bc2-2841-4833-9f01-ac47b8c52c01" />

<br>
<br>

<img width="1680" height="963" alt="Screenshot 2026-05-12 at 8 28 25 PM" src="https://github.com/user-attachments/assets/9436c7ab-3b9b-4366-86fd-1465407ff0f9" />
2026-05-15 18:26:37 +00:00

167 lines
4.1 KiB
TypeScript

export type PluginSpaceInfo = {
pluginId: "claude-code" | "openclaw" | "opencode" | "codex" | "amp"
label: string
iconSrc: string | null
projectId?: string
}
type PluginDef = {
id: PluginSpaceInfo["pluginId"]
label: string
iconSrc: string | null
prefixes: string[]
}
const PLUGINS: PluginDef[] = [
{
id: "claude-code",
label: "Claude Code",
iconSrc: "/images/plugins/claude-code.svg",
prefixes: ["claudecode"],
},
{
id: "openclaw",
label: "OpenClaw",
iconSrc: "/images/plugins/openclaw.svg",
prefixes: ["openclaw"],
},
{
id: "opencode",
label: "OpenCode",
iconSrc: "/images/plugins/opencode.svg",
prefixes: ["opencode"],
},
{
id: "codex",
label: "Codex",
iconSrc: "/images/plugins/codex.png",
prefixes: ["codex"],
},
{
id: "amp",
label: "Amp",
iconSrc: null,
prefixes: ["amp"],
},
]
function parsePluginRest(rest: string): { projectId?: string } {
if (!rest || rest === "default" || rest === "global") {
return { projectId: "Global" }
}
const userMatch = rest.match(/^user[_-]([0-9a-f]{6,64})$/i)
if (userMatch?.[1]) return { projectId: `User · ${userMatch[1].slice(0, 6)}` }
const projectMatch = rest.match(/^project[_-]([0-9a-f]{6,64})$/i)
if (projectMatch?.[1]) return { projectId: projectMatch[1].slice(0, 6) }
const hexOnly = rest.match(/^([0-9a-f]{6,64})$/i)
if (hexOnly?.[1]) return { projectId: hexOnly[1].slice(0, 6) }
return { projectId: rest.slice(0, 24) }
}
const PLUGIN_ICON_BY_LABEL: Record<string, string> = {
"Claude Code": "/images/plugins/claude-code.svg",
OpenClaw: "/images/plugins/openclaw.svg",
OpenCode: "/images/plugins/opencode.svg",
Codex: "/images/plugins/codex.png",
}
export function pluginIconByLabel(
label: string | null | undefined,
): string | null {
if (!label) return null
return PLUGIN_ICON_BY_LABEL[label] ?? null
}
export function pluginInitial(label: string | null | undefined): string {
if (!label) return "?"
return label.trim().charAt(0).toUpperCase() || "?"
}
export type PluginDocSource = {
pluginId: "claude-code"
label: string
iconSrc: string
projectName?: string
formatLabel: string
type: "session_turn" | "project-knowledge" | "manual" | "unknown"
}
function formatLabelForType(t: string | undefined): {
formatLabel: string
type: PluginDocSource["type"]
} {
switch (t) {
case "session_turn":
return { formatLabel: "Session", type: "session_turn" }
case "project-knowledge":
return { formatLabel: "Project knowledge", type: "project-knowledge" }
case "manual":
return { formatLabel: "Note", type: "manual" }
default:
return { formatLabel: "Note", type: "unknown" }
}
}
export function detectPluginSource(
metadata: Record<string, unknown> | null | undefined,
documentSource?: string | null,
): PluginDocSource | null {
const sourceFromMeta =
metadata && typeof metadata.sm_source === "string"
? metadata.sm_source
: null
const source = documentSource ?? sourceFromMeta
if (source !== "claude-code-plugin") return null
const md = metadata ?? {}
const project =
typeof md.project === "string" && md.project.trim()
? md.project.trim()
: undefined
const t = typeof md.type === "string" ? md.type : undefined
const { formatLabel, type } = formatLabelForType(t)
return {
pluginId: "claude-code",
label: "Claude Code",
iconSrc: "/images/plugins/claude-code.svg",
projectName: project,
formatLabel,
type,
}
}
export function detectPluginSpace(
containerTag: string,
): PluginSpaceInfo | null {
if (!containerTag) return null
for (const plugin of PLUGINS) {
for (const prefix of plugin.prefixes) {
if (containerTag === prefix) {
return {
pluginId: plugin.id,
label: plugin.label,
iconSrc: plugin.iconSrc,
projectId: "Global",
}
}
const separator = containerTag[prefix.length]
if (
containerTag.startsWith(prefix) &&
(separator === "_" || separator === "-")
) {
const rest = containerTag.slice(prefix.length + 1)
const parsed = parsePluginRest(rest)
return {
pluginId: plugin.id,
label: plugin.label,
iconSrc: plugin.iconSrc,
projectId: parsed.projectId,
}
}
}
}
return null
}