UNPKG

consortium

Version:

Remote control and session sharing CLI for AI coding agents

61 lines (58 loc) • 2.44 kB
'use strict'; const DEFAULT_MIN_LINES = 20; const DEFAULT_MIN_CHARS = 600; const FENCE_RE = /```([\w.+-]*)[ \t]*\r?\n([\s\S]*?)```/g; function classify(langRaw, content) { const lang = langRaw.trim().toLowerCase(); if (lang === "html" || lang === "htm") return { kind: "html" }; if (lang === "svg") return { kind: "svg" }; if (lang === "mermaid") return { kind: "mermaid" }; if (lang === "jsx" || lang === "tsx" || lang === "react") return { kind: "react", language: lang === "tsx" ? "tsx" : "jsx" }; if (lang === "md" || lang === "markdown") return { kind: "markdown" }; if (!lang) { const head = content.trimStart().slice(0, 120).toLowerCase(); if (head.startsWith("<svg")) return { kind: "svg" }; if (head.startsWith("<!doctype html") || head.startsWith("<html")) return { kind: "html" }; } return { kind: "code", language: lang || void 0 }; } function titleFor(kind, language, precedingLine) { const heading = precedingLine.replace(/^#+\s*/, "").replace(/[*_`]/g, "").trim(); if (heading && heading.length <= 60) return heading; switch (kind) { case "html": return "HTML page"; case "svg": return "SVG image"; case "mermaid": return "Diagram"; case "react": return "React component"; case "markdown": return "Document"; default: return language ? `${language} snippet` : "Code snippet"; } } function scanForArtifacts(text, opts = {}) { if (!text) return []; const minLines = opts.minCodeLines ?? DEFAULT_MIN_LINES; const minChars = opts.minCodeChars ?? DEFAULT_MIN_CHARS; const out = []; FENCE_RE.lastIndex = 0; let match; while ((match = FENCE_RE.exec(text)) !== null) { const content = match[2].replace(/\s+$/, ""); if (!content.trim()) continue; const { kind, language } = classify(match[1] ?? "", content); const lineCount = content.split("\n").length; const alwaysPromote = kind === "html" || kind === "svg" || kind === "mermaid" || kind === "react"; const meetsThreshold = lineCount >= minLines || content.length >= minChars; if (!alwaysPromote && !meetsThreshold) continue; const before = text.slice(0, match.index).split("\n").filter((l) => l.trim()); const precedingLine = before.length ? before[before.length - 1] : ""; out.push({ kind, language, title: titleFor(kind, language, precedingLine), content }); } return out; } exports.scanForArtifacts = scanForArtifacts;