consortium
Version:
Remote control and session sharing CLI for AI coding agents
59 lines (57 loc) • 2.41 kB
JavaScript
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;
}
export { scanForArtifacts };