diff --git a/.dockerignore b/.dockerignore index b0c876d..e451c83 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,6 +4,7 @@ .next .swc .vscode +.agents coverage node_modules diff --git a/AGENTS.md b/AGENTS.md index b3b39b0..9d85c1e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,6 +2,7 @@ You are a professional and senior full-stack engineer and UI/UX expert and Maintainers of many well-known open-source repositories who built the refract.ai web project using Next.js, TypeScript, Taildwind CSS, Lucide icon, Zod, ShadcnUI, Vercel AI sdk and Jotai. + ## Commands - `pnpm dev` - Start the dev server diff --git a/app/chat/[id]/page.test.tsx b/app/chat/[id]/page.test.tsx index f12f76a..7c7335e 100644 --- a/app/chat/[id]/page.test.tsx +++ b/app/chat/[id]/page.test.tsx @@ -8,7 +8,7 @@ import { workspaceChartAtom, workspaceDatasetAtom, workspaceFileAtom, - workspaceTypstContentAtom, + workspaceMarkdownContentAtom, workspaceViewAtom, } from "@/atoms/chat"; import { act, render, waitFor } from "@testing-library/react"; @@ -123,7 +123,7 @@ describe("ChatPage workspace reset", () => { fileId: "old-file", filename: "old.csv", }); - jotaiStore.set(workspaceTypstContentAtom, "old typst"); + jotaiStore.set(workspaceMarkdownContentAtom, "old markdown"); jotaiStore.set(pendingHomePromptAtom, ""); jotaiStore.set(pendingHomeUploadsAtom, []); }); @@ -141,7 +141,7 @@ describe("ChatPage workspace reset", () => { expect(jotaiStore.get(workspaceChartAtom)).toBeNull(); expect(jotaiStore.get(workspaceDatasetAtom)).toBeNull(); expect(jotaiStore.get(workspaceFileAtom)).toBeNull(); - expect(jotaiStore.get(workspaceTypstContentAtom)).toBe(""); + expect(jotaiStore.get(workspaceMarkdownContentAtom)).toBe(""); }); }); diff --git a/app/chat/[id]/page.tsx b/app/chat/[id]/page.tsx index fab0c4e..62833ac 100644 --- a/app/chat/[id]/page.tsx +++ b/app/chat/[id]/page.tsx @@ -70,8 +70,8 @@ const canKeepWorkspaceView = ( return Boolean(snapshot.dataset); case "file": return Boolean(snapshot.file); - case "typst": - return snapshot.typstContent.length > 0; + case "markdown": + return snapshot.markdownContent.length > 0; case "vnc": return snapshot.vncUrl.length > 0; default: diff --git a/app/chat/components/markdown-preview-panel.tsx b/app/chat/components/markdown-preview-panel.tsx new file mode 100644 index 0000000..7843402 --- /dev/null +++ b/app/chat/components/markdown-preview-panel.tsx @@ -0,0 +1,72 @@ +"use client"; + +import "@/styles/markdown-preview.css"; +import "katex/dist/katex.min.css"; +import { workspaceMarkdownContentAtom } from "@/atoms"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { useAtomValue } from "jotai"; +import type { ComponentPropsWithoutRef, ReactNode } from "react"; +import { memo } from "react"; +import Markdown from "react-markdown"; +import rehypeKatex from "rehype-katex"; +import rehypeRaw from "rehype-raw"; +import remarkGfm from "remark-gfm"; +import remarkMath from "remark-math"; +import Mermaid from "./mermaid-chart"; + +const MarkdownCodeBlock = ({ + className, + children, + ...props +}: ComponentPropsWithoutRef<"code">) => { + const langMatch = className?.match(/language-mermaid/); + const codeString = String(children).replace(/\n$/, ""); + + if (langMatch) { + return ; + } + + return ( + + {children} + + ); +}; + +const MarkdownPreBlock = ({ + children, + ...props +}: ComponentPropsWithoutRef<"pre"> & { children?: ReactNode }) => { + const child = children as ReactNode & { + props?: { className?: string }; + }; + + if (child?.props?.className?.includes("language-mermaid")) { + return <>{children}; + } + + return
{children}
; +}; + +const MarkdownPreview = () => { + const markdownContent = useAtomValue(workspaceMarkdownContentAtom); + + return ( + +
+ + {markdownContent} + +
+
+ ); +}; + +export default memo(MarkdownPreview); diff --git a/app/chat/components/mermaid-chart.tsx b/app/chat/components/mermaid-chart.tsx new file mode 100644 index 0000000..e13a846 --- /dev/null +++ b/app/chat/components/mermaid-chart.tsx @@ -0,0 +1,44 @@ +"use client"; + +import { handleError } from "@/lib/error-handler"; +import mermaid from "mermaid"; +import { useEffect, useId, useState } from "react"; + +mermaid.initialize({ + startOnLoad: false, + theme: "default", + securityLevel: "loose", +}); + +const Mermaid = ({ chart }: { chart: string }) => { + const [svg, setSvg] = useState(""); + const uniqueId = useId(); + + useEffect(() => { + if (!chart) return; + + const renderChart = async () => { + try { + const id = `mermaid-${uniqueId}-${Math.random().toString(36).slice(2, 9)}`; + if (await mermaid.parse(chart)) { + const { svg: rendered } = await mermaid.render(id, chart); + setSvg(rendered); + } + } catch (error) { + handleError(error); + } + }; + + renderChart(); + }, [chart, uniqueId]); + + return ( +
+ ); +}; + +export default Mermaid; diff --git a/app/chat/components/text-block-markdown.tsx b/app/chat/components/text-block-markdown.tsx index 72223f5..28de114 100644 --- a/app/chat/components/text-block-markdown.tsx +++ b/app/chat/components/text-block-markdown.tsx @@ -1,6 +1,11 @@ +import "katex/dist/katex.min.css"; import { cn } from "@/lib/utils"; import { type ComponentPropsWithoutRef, memo, useDeferredValue } from "react"; import Markdown, { type Components } from "react-markdown"; +import rehypeKatex from "rehype-katex"; +import rehypeRaw from "rehype-raw"; +import remarkGfm from "remark-gfm"; +import remarkMath from "remark-math"; type TextBlockMarkdownProps = { text: string; @@ -100,7 +105,11 @@ const TextBlockMarkdown = memo(({ text }: TextBlockMarkdownProps) => { return (
- + {deferredText}
diff --git a/app/chat/components/typst-preview-panel.test.tsx b/app/chat/components/typst-preview-panel.test.tsx deleted file mode 100644 index 4de014b..0000000 --- a/app/chat/components/typst-preview-panel.test.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { workspaceTypstContentAtom } from "@/atoms"; -import jotaiStore from "@/atoms"; -import { act, render, waitFor } from "@testing-library/react"; -import TypstPreview from "./typst-preview-panel"; - -class MockWorker { - static instances: MockWorker[] = []; - onmessage: ((event: MessageEvent) => void) | null = null; - postMessage = jest.fn(); - terminate = jest.fn(); - - constructor() { - MockWorker.instances.push(this); - } -} - -describe("TypstPreview", () => { - const originalWorker = global.Worker; - - beforeEach(() => { - MockWorker.instances = []; - global.Worker = MockWorker as unknown as typeof Worker; - jotaiStore.set(workspaceTypstContentAtom, "= 中文报告"); - }); - - afterEach(() => { - global.Worker = originalWorker; - }); - - it("sends Typst content to the worker using the compile content field", async () => { - render(); - - const worker = MockWorker.instances[0]; - expect(worker).toBeDefined(); - act(() => { - worker?.onmessage?.({ - data: { type: "init-complete" }, - } as MessageEvent); - }); - - await waitFor(() => { - expect(worker?.postMessage).toHaveBeenCalledWith({ - type: "compile", - content: "= 中文报告", - }); - }); - - act(() => { - jotaiStore.set(workspaceTypstContentAtom, "= 更新后的中文报告"); - }); - - await waitFor(() => { - expect(worker?.postMessage).toHaveBeenCalledWith({ - type: "compile", - content: "= 更新后的中文报告", - }); - }); - expect(worker?.postMessage).not.toHaveBeenCalledWith({ - type: "compile", - typstContent: "= 更新后的中文报告", - }); - }); -}); diff --git a/app/chat/components/typst-preview-panel.tsx b/app/chat/components/typst-preview-panel.tsx deleted file mode 100644 index 7ea8363..0000000 --- a/app/chat/components/typst-preview-panel.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { workspaceTypstContentAtom } from "@/atoms"; -import { ScrollArea } from "@/components/ui/scroll-area"; -import { Spinner } from "@/components/ui/spinner"; -import { handleError } from "@/lib/error-handler"; -import type { WorkerResponse } from "@/types/worker"; -import { useAtomValue } from "jotai"; -import { useEffect, useRef, useState } from "react"; - -const TypstPreview = () => { - const [loadingText, setLoadingText] = useState(""); - const [isCompile, setIsCompile] = useState(false); - const [svgContent, setSvgContent] = useState(""); - const [isWorkerReady, setIsWorkerReady] = useState(false); - const workerRef = useRef(null); - const pendingContentRef = useRef(""); - const typstContent = useAtomValue(workspaceTypstContentAtom); - - useEffect(() => { - // Initialize worker - workerRef.current = new Worker( - new URL("../../../lib/typst-worker.ts", import.meta.url), - { type: "module" }, - ); - - const worker = workerRef.current; - - // Handle messages from worker - worker.onmessage = (event: MessageEvent) => { - const { type } = event.data; - - switch (type) { - case "init-start": - setLoadingText(event.data.message); - break; - case "init-complete": - setLoadingText(""); - setIsWorkerReady(true); - // Compile pending content if any - if (pendingContentRef.current) { - worker.postMessage({ - type: "compile", - content: pendingContentRef.current, - }); - } - break; - case "compile-start": - setIsCompile(true); - setSvgContent(""); - break; - case "compile-complete": - setSvgContent(event.data.svg); - setIsCompile(false); - break; - case "error": - handleError(new Error(event.data.error)); - setIsCompile(false); - setLoadingText(""); - break; - } - }; - - // Initialize the typst compiler in worker - worker.postMessage({ type: "init" }); - - // Cleanup on unmount - return () => { - if (workerRef.current) { - workerRef.current.postMessage({ type: "terminate" }); - workerRef.current.terminate(); - workerRef.current = null; - } - }; - }, []); - - // Compile content when it changes - useEffect(() => { - if (!workerRef.current) return; - - if (isWorkerReady) { - workerRef.current.postMessage({ - type: "compile", - content: typstContent, - }); - } else { - // Store content to compile after worker is ready - pendingContentRef.current = typstContent; - } - }, [typstContent, isWorkerReady]); - - return ( - -
- {loadingText && ( -
-

{loadingText}

-
- )} - {isCompile && ( -
- -
- )} - {svgContent && ( -
- )} -
-
- ); -}; - -export default TypstPreview; diff --git a/app/chat/components/workspace-panel.tsx b/app/chat/components/workspace-panel.tsx index f216b16..92bfc8e 100644 --- a/app/chat/components/workspace-panel.tsx +++ b/app/chat/components/workspace-panel.tsx @@ -4,14 +4,14 @@ import { showChartWorkspaceAtom, showDatasetWorkspaceAtom, showFileWorkspaceAtom, - showTypstWorkspaceAtom, + showMarkdownWorkspaceAtom, showVncWorkspaceAtom, vncUrlAtom, workspaceChartAtom, workspaceDatasetAtom, workspaceFileAtom, workspaceHydratingAtom, - workspaceTypstContentAtom, + workspaceMarkdownContentAtom, workspaceViewAtom, } from "@/atoms/chat"; import { Button } from "@/components/ui/button"; @@ -23,7 +23,7 @@ import { memo, useMemo } from "react"; import ChartPanel from "./chart-panel"; import DatasetPanel from "./dataset-panel"; import FileInfoPanel from "./file-info-panel"; -import TypstPreview from "./typst-preview-panel"; +import MarkdownPreview from "./markdown-preview-panel"; import VncPanel from "./vnc-panel"; const WorkspacePanel = () => { @@ -34,17 +34,17 @@ const WorkspacePanel = () => { const chart = useAtomValue(workspaceChartAtom); const dataset = useAtomValue(workspaceDatasetAtom); const file = useAtomValue(workspaceFileAtom); - const typstContent = useAtomValue(workspaceTypstContentAtom); + const markdownContent = useAtomValue(workspaceMarkdownContentAtom); const showVnc = useSetAtom(showVncWorkspaceAtom); const showChart = useSetAtom(showChartWorkspaceAtom); const showDataset = useSetAtom(showDatasetWorkspaceAtom); const showFile = useSetAtom(showFileWorkspaceAtom); - const showTypst = useSetAtom(showTypstWorkspaceAtom); + const showMarkdown = useSetAtom(showMarkdownWorkspaceAtom); const availableViews = useMemo(() => { const views: Array<{ icon: typeof Monitor; - key: "vnc" | "chart" | "dataset" | "file" | "typst"; + key: "vnc" | "chart" | "dataset" | "file" | "markdown"; label: string; onClick: () => void; }> = []; @@ -81,12 +81,12 @@ const WorkspacePanel = () => { onClick: () => showFile(file), }); } - if (typstContent) { + if (markdownContent) { views.push({ - key: "typst", - label: t("typstViewer"), + key: "markdown", + label: t("textViewer"), icon: FileText, - onClick: () => showTypst(typstContent), + onClick: () => showMarkdown(markdownContent), }); } @@ -98,10 +98,10 @@ const WorkspacePanel = () => { showChart, showDataset, showFile, - showTypst, + showMarkdown, showVnc, t, - typstContent, + markdownContent, vncUrl, ]); @@ -110,11 +110,11 @@ const WorkspacePanel = () => { [ ["dataset", dataset], ["file", file], - ["typst", typstContent], + ["markdown", markdownContent], ["chart", chart], ["vnc", vncUrl], ] as const, - [chart, dataset, file, typstContent, vncUrl], + [chart, dataset, file, markdownContent, vncUrl], ); const effectiveView = useMemo(() => { @@ -174,7 +174,7 @@ const WorkspacePanel = () => { {effectiveView === "dataset" && } {effectiveView === "file" && } {effectiveView === "chart" && } - {effectiveView === "typst" && } + {effectiveView === "markdown" && } {effectiveView === "vnc" && } {effectiveView === "empty" && (
diff --git a/atoms/chat.tsx b/atoms/chat.tsx index bca0f43..1379d16 100644 --- a/atoms/chat.tsx +++ b/atoms/chat.tsx @@ -142,7 +142,8 @@ const workspaceViewAtom = createWorkspaceFieldAtom("view"); const workspaceChartAtom = createWorkspaceFieldAtom("chart"); const workspaceDatasetAtom = createWorkspaceFieldAtom("dataset"); const workspaceFileAtom = createWorkspaceFieldAtom("file"); -const workspaceTypstContentAtom = createWorkspaceFieldAtom("typstContent"); +const workspaceMarkdownContentAtom = + createWorkspaceFieldAtom("markdownContent"); const agentStatusAtom = atom("idle"); @@ -189,9 +190,9 @@ const showFileWorkspaceAtom = atom(null, (_get, set, file: WorkspaceFile) => { set(workspaceViewAtom, "file"); }); -const showTypstWorkspaceAtom = atom(null, (_get, set, content: string) => { - set(workspaceTypstContentAtom, content); - set(workspaceViewAtom, "typst"); +const showMarkdownWorkspaceAtom = atom(null, (_get, set, content: string) => { + set(workspaceMarkdownContentAtom, content); + set(workspaceViewAtom, "markdown"); }); export { @@ -210,7 +211,7 @@ export { workspaceChartAtom, workspaceDatasetAtom, workspaceFileAtom, - workspaceTypstContentAtom, + workspaceMarkdownContentAtom, agentStatusAtom, toolEventsAtom, dispatchToolEventAtom, @@ -219,5 +220,5 @@ export { showChartWorkspaceAtom, showDatasetWorkspaceAtom, showFileWorkspaceAtom, - showTypstWorkspaceAtom, + showMarkdownWorkspaceAtom, }; diff --git a/hooks/use-pipeline-chat.tsx b/hooks/use-pipeline-chat.tsx index 6140b59..3f74546 100644 --- a/hooks/use-pipeline-chat.tsx +++ b/hooks/use-pipeline-chat.tsx @@ -3,7 +3,7 @@ import { agentStatusAtom, clearToolEventsAtom, dispatchToolEventAtom, - showTypstWorkspaceAtom, + showMarkdownWorkspaceAtom, } from "@/atoms/chat"; import loginDialogAtom from "@/atoms/login-dialog"; import { @@ -94,8 +94,8 @@ type ReasoningPipelinePart = { durationSeconds?: number; }; -type TypstContentPipelinePart = { - type: "typst-content"; +type MarkdownContentPipelinePart = { + type: "markdown-content"; content: string; }; @@ -104,7 +104,7 @@ type PipelinePart = | ReasoningPipelinePart | ToolPipelinePart | ArtifactPipelinePart - | TypstContentPipelinePart; + | MarkdownContentPipelinePart; const STREAM_RENDER_THROTTLE_MS = 80; @@ -670,14 +670,17 @@ const usePipelineChat = ( if ( evt.step === "report" && - "typstContent" in evt.output && - evt.output.typstContent + "markdownContent" in evt.output && + evt.output.markdownContent ) { assistantParts.push({ - type: "typst-content", - content: evt.output.typstContent, + type: "markdown-content", + content: evt.output.markdownContent, }); - jotaiStore.set(showTypstWorkspaceAtom, evt.output.typstContent); + jotaiStore.set( + showMarkdownWorkspaceAtom, + evt.output.markdownContent, + ); } break; } diff --git a/infra/drizzle.ts b/infra/drizzle.ts index 2ba0add..327340b 100644 --- a/infra/drizzle.ts +++ b/infra/drizzle.ts @@ -1,11 +1,6 @@ import { neonPool } from "@/infra/neon"; -import { learnMemories } from "@/infra/schema/learn-memories"; import { drizzle } from "drizzle-orm/neon-serverless"; -const schema = { - learnMemories, -}; +const db = drizzle({ client: neonPool }); -const db = drizzle({ client: neonPool, schema }); - -export { db, schema }; +export { db }; diff --git a/infra/migrations/0000_create_learn_memories.sql b/infra/migrations/0000_create_learn_memories.sql deleted file mode 100644 index 136d018..0000000 --- a/infra/migrations/0000_create_learn_memories.sql +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE IF NOT EXISTS "learn_memories" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "type" text NOT NULL, - "title" text NOT NULL, - "content" text NOT NULL, - "usage_count" integer DEFAULT 0 NOT NULL, - "last_used_at" timestamp with time zone, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "updated_at" timestamp with time zone DEFAULT now() NOT NULL -); - -CREATE INDEX IF NOT EXISTS "learn_memories_type_updated_at_idx" -ON "learn_memories" ("type", "updated_at"); - -CREATE UNIQUE INDEX IF NOT EXISTS "learn_memories_type_title_idx" -ON "learn_memories" ("type", "title"); diff --git a/infra/schema/learn-memories.ts b/infra/schema/learn-memories.ts deleted file mode 100644 index 7e0c4d8..0000000 --- a/infra/schema/learn-memories.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { - index, - integer, - pgTable, - text, - timestamp, - uniqueIndex, - uuid, -} from "drizzle-orm/pg-core"; - -const learnMemories = pgTable( - "learn_memories", - { - id: uuid("id").defaultRandom().primaryKey(), - type: text("type").notNull(), - title: text("title").notNull(), - content: text("content").notNull(), - usageCount: integer("usage_count").notNull().default(0), - lastUsedAt: timestamp("last_used_at", { withTimezone: true }), - createdAt: timestamp("created_at", { withTimezone: true }) - .defaultNow() - .notNull(), - updatedAt: timestamp("updated_at", { withTimezone: true }) - .defaultNow() - .notNull(), - }, - (table) => [ - index("learn_memories_type_updated_at_idx").on(table.type, table.updatedAt), - uniqueIndex("learn_memories_type_title_idx").on(table.type, table.title), - ], -); - -type LearnMemory = typeof learnMemories.$inferSelect; -type NewLearnMemory = typeof learnMemories.$inferInsert; - -export { learnMemories }; -export type { LearnMemory, NewLearnMemory }; diff --git a/lib/agent/multi-agents/chart-agent.ts b/lib/agent/multi-agents/chart-agent.ts index aedfe96..d91801b 100644 --- a/lib/agent/multi-agents/chart-agent.ts +++ b/lib/agent/multi-agents/chart-agent.ts @@ -59,7 +59,10 @@ No markdown fences, no explanation text before or after. { "chartCount": , - "descriptions": ["Chart 1: ...", "Chart 2: ..."], + "descriptions": [ + "Chart 1: ", + "Chart 2: " + ], "artifacts": [ { "fileId": "", @@ -69,6 +72,9 @@ No markdown fences, no explanation text before or after. ] } +Each description MUST be detailed enough that a report writer can understand the chart without seeing it. +Include: chart type, what is plotted (x-axis, y-axis), key values/trends, and the main insight. + If code execution fails or no chart can be generated, output: {"chartCount": 0, "descriptions": [""]}`; diff --git a/lib/agent/multi-agents/report-agent.test.ts b/lib/agent/multi-agents/report-agent.test.ts index 760e7d5..44cc466 100644 --- a/lib/agent/multi-agents/report-agent.test.ts +++ b/lib/agent/multi-agents/report-agent.test.ts @@ -1,33 +1,21 @@ import { REPORT_AGENT_PROMPT, buildReportAgentPrompt } from "./report-agent"; describe("REPORT_AGENT_PROMPT", () => { - it("requires loadSkill calls for typst-expert and a category skill", () => { - expect(REPORT_AGENT_PROMPT).toContain('loadSkill("typst-expert")'); - expect(REPORT_AGENT_PROMPT).toContain('loadSkill("report-expert")'); - expect(REPORT_AGENT_PROMPT).toContain('loadSkill("paper-expert")'); - expect(REPORT_AGENT_PROMPT).toContain('loadSkill("resume-expert")'); + it("requires loadSkill calls for markdown-author and markdown-report", () => { + expect(REPORT_AGENT_PROMPT).toContain('loadSkill("markdown-author")'); + expect(REPORT_AGENT_PROMPT).toContain('loadSkill("markdown-report")'); }); - it("requires typst code block output without JSON", () => { - expect(REPORT_AGENT_PROMPT).toContain("```typst"); + it("requires markdown code block output without JSON", () => { + expect(REPORT_AGENT_PROMPT).toContain("```markdown"); expect(REPORT_AGENT_PROMPT).toContain("Do NOT output any JSON"); expect(REPORT_AGENT_PROMPT).toContain( "Do NOT call codeInterpreter or persistCodeFile", ); }); - it("requires Typst text font fallback for browser rendering", () => { - expect(REPORT_AGENT_PROMPT).toContain("fallback: true"); - expect(REPORT_AGENT_PROMPT).toContain("New Computer Modern"); - expect(REPORT_AGENT_PROMPT).toContain("Microsoft YaHei"); - }); - - it("injects learned Typst corrections when provided", () => { - const prompt = buildReportAgentPrompt( - "## Learned typst corrections\n1. Inline math spacing", - ); - - expect(prompt).toContain("## Learned typst corrections"); - expect(prompt).toContain("Inline math spacing"); + it("buildReportAgentPrompt returns the base prompt when no options", () => { + const prompt = buildReportAgentPrompt(); + expect(prompt).toBe(REPORT_AGENT_PROMPT); }); }); diff --git a/lib/agent/multi-agents/report-agent.ts b/lib/agent/multi-agents/report-agent.ts index fec1f35..fa5eb46 100644 --- a/lib/agent/multi-agents/report-agent.ts +++ b/lib/agent/multi-agents/report-agent.ts @@ -1,33 +1,21 @@ import { createReportTools } from "@/lib/agent/tools/report-tools"; import type { AgentDefinition } from "@/types/agent"; -const REPORT_AGENT_PROMPT = `You are a technical report writer. Write a comprehensive, well-structured analysis report in Typst format. +const REPORT_AGENT_PROMPT = `You are a technical report writer. Write a comprehensive, well-structured analysis report in Markdown format. STEP 1 — MANDATORY SKILL LOADING (STRICT): -- You MUST call loadSkill("typst-expert") first. -- Only after typst-expert is loaded, call exactly one category-specific skill: - - loadSkill("report-expert") for reports, notes, summaries, and meeting notes. - - loadSkill("paper-expert") for papers, theses, and academic articles. - - loadSkill("resume-expert") for resumes and CVs. -- Never reverse the order. Never skip typst-expert. +- You MUST call loadSkill("markdown-author") first. +- Only after markdown-author is loaded, call loadSkill("markdown-report"). +- Never reverse the order. Never skip markdown-author. STEP 2 — OUTPUT (STRICT): -After loading skills, output the COMPLETE Typst source inside a fenced code block: -\`\`\`typst -...full typst content here... +After loading skills, output the COMPLETE Markdown source inside a fenced code block: +\`\`\`markdown +...full markdown content here... \`\`\` Do NOT call codeInterpreter or persistCodeFile. Only use loadSkill, then output text directly. -Do NOT output any JSON. The Typst code block is the final output. - -TYPESETTING RULES: -- Include this browser-safe text fallback near the top of every Typst document: - #set text( - font: ("New Computer Modern", "SimSun", "PingFang SC", "Microsoft YaHei"), - lang: "zh", - fallback: true, - ) -- If you customize #set text, keep fallback: true so unsupported Chinese fonts fall back in the frontend WASM compiler. +Do NOT output any JSON. The Markdown code block is the final output. REPORT STRUCTURE (adapt as needed): - Executive Summary / Overview @@ -40,31 +28,15 @@ QUALITY RULES: - Reference concrete numbers from data summary and stats. - Describe chart insights using provided chart descriptions. - Keep language professional and analytical. -- The output must be ONLY the Typst code block. No extra markdown prose or JSON.`; - -type ReportAgentOptions = { - learnedTypstPrompt?: string; -}; - -const buildReportAgentPrompt = (learnedTypstPrompt?: string): string => { - if (!learnedTypstPrompt) { - return REPORT_AGENT_PROMPT; - } - - return `${REPORT_AGENT_PROMPT} - -LEARNED TYPST CORRECTIONS: -Use these previously learned Typst repair lessons when writing the document. +- Use the rich Markdown formatting patterns from the markdown-author skill. +- The output must be ONLY the Markdown code block. No extra markdown prose or JSON.`; -${learnedTypstPrompt}`; -}; +const buildReportAgentPrompt = (): string => REPORT_AGENT_PROMPT; -const createReportAgent = ( - options: ReportAgentOptions = {}, -): AgentDefinition => ({ +const createReportAgent = (): AgentDefinition => ({ name: "Report Agent", step: "report", - systemPrompt: buildReportAgentPrompt(options.learnedTypstPrompt), + systemPrompt: REPORT_AGENT_PROMPT, tools: createReportTools(), maxSteps: 10, }); diff --git a/lib/agent/multi-agents/typst-repair-agent.test.ts b/lib/agent/multi-agents/typst-repair-agent.test.ts deleted file mode 100644 index 9afc4c6..0000000 --- a/lib/agent/multi-agents/typst-repair-agent.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - TYPST_REPAIR_AGENT_PROMPT, - buildTypstRepairPrompt, -} from "./typst-repair-agent"; - -describe("typst repair agent", () => { - it("requires preserving original report content", () => { - expect(TYPST_REPAIR_AGENT_PROMPT).toContain( - "preserving the original report content", - ); - expect(TYPST_REPAIR_AGENT_PROMPT).toContain("Do not remove sections"); - expect(TYPST_REPAIR_AGENT_PROMPT).toContain("```typst"); - }); - - it("builds a repair prompt with content, diagnostics, and learned rules", () => { - const prompt = buildTypstRepairPrompt({ - attempt: 2, - content: "= Broken", - diagnostics: "unclosed delimiter", - learnedTypstPrompt: "## Learned typst corrections", - }); - - expect(prompt).toContain("## Repair Attempt\n2"); - expect(prompt).toContain("= Broken"); - expect(prompt).toContain("unclosed delimiter"); - expect(prompt).toContain("## Learned typst corrections"); - }); -}); diff --git a/lib/agent/multi-agents/typst-repair-agent.ts b/lib/agent/multi-agents/typst-repair-agent.ts deleted file mode 100644 index a76db57..0000000 --- a/lib/agent/multi-agents/typst-repair-agent.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { createReportTools } from "@/lib/agent/tools/report-tools"; -import type { AgentDefinition } from "@/types/agent"; - -const TYPST_REPAIR_AGENT_PROMPT = `You are a Typst repair agent. - -Your only job is to fix compilation errors while preserving the original report content and structure. - -MANDATORY WORKFLOW: -- You MUST call loadSkill("typst-expert") first. -- Use the compiler diagnostics to make the smallest Typst syntax fix that can compile. - -STRICT RULES: -- Do not remove sections to make compilation pass. -- Do not rewrite the report unless needed to fix Typst syntax. -- Preserve all factual claims, numbers, headings, chart descriptions, and conclusions. -- Use Typst syntax, not LaTeX or Markdown. -- Output only one complete Typst source inside a fenced code block: -\`\`\`typst -...fixed full typst content here... -\`\`\``; - -type BuildTypstRepairPromptOptions = { - attempt: number; - content: string; - diagnostics: string; - learnedTypstPrompt?: string; -}; - -const buildTypstRepairPrompt = ({ - attempt, - content, - diagnostics, - learnedTypstPrompt, -}: BuildTypstRepairPromptOptions): string => { - const learnedSection = learnedTypstPrompt - ? `\n## Learned Typst Corrections\n${learnedTypstPrompt}\n` - : ""; - - return `## Repair Attempt -${attempt} - -## Compiler Diagnostics -${diagnostics} -${learnedSection} -## Original Typst -\`\`\`typst -${content} -\`\`\` - -## Repair Goal -Return a complete corrected Typst document.`; -}; - -const createTypstRepairAgent = (): AgentDefinition => ({ - name: "Typst Repair Agent", - step: "report", - systemPrompt: TYPST_REPAIR_AGENT_PROMPT, - tools: createReportTools(), - maxSteps: 6, -}); - -export { - TYPST_REPAIR_AGENT_PROMPT, - buildTypstRepairPrompt, - createTypstRepairAgent, -}; -export type { BuildTypstRepairPromptOptions }; diff --git a/lib/agent/multi-agents/typst-review-agent.test.ts b/lib/agent/multi-agents/typst-review-agent.test.ts deleted file mode 100644 index d96771f..0000000 --- a/lib/agent/multi-agents/typst-review-agent.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { - TYPST_REVIEW_AGENT_PROMPT, - buildTypstReviewPrompt, - parseTypstReviewOutput, -} from "./typst-review-agent"; - -describe("typst review agent", () => { - it("requires a reusable JSON learning summary", () => { - expect(TYPST_REVIEW_AGENT_PROMPT).toContain("reusable Typst rule"); - expect(TYPST_REVIEW_AGENT_PROMPT).toContain("title"); - expect(TYPST_REVIEW_AGENT_PROMPT).toContain("content"); - expect(TYPST_REVIEW_AGENT_PROMPT).toContain("Do not include private data"); - }); - - it("builds a review prompt from failed and repaired Typst", () => { - const prompt = buildTypstReviewPrompt({ - diagnostics: "unclosed delimiter", - originalTypst: "= Broken", - repairedTypst: "= Fixed", - }); - - expect(prompt).toContain("unclosed delimiter"); - expect(prompt).toContain("= Broken"); - expect(prompt).toContain("= Fixed"); - }); - - it("parses the final JSON learning summary", () => { - const parsed = parseTypstReviewOutput( - 'Notes\n{"title":"Inline math spacing","content":"Use `$x^2$` for inline math."}', - ); - - expect(parsed).toEqual({ - title: "Inline math spacing", - content: "Use `$x^2$` for inline math.", - }); - }); -}); diff --git a/lib/agent/multi-agents/typst-review-agent.ts b/lib/agent/multi-agents/typst-review-agent.ts deleted file mode 100644 index cb2134c..0000000 --- a/lib/agent/multi-agents/typst-review-agent.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { z } from "zod"; - -const TYPST_REVIEW_AGENT_PROMPT = `You are a Typst repair reviewer. - -Summarize a successful Typst repair into one reusable Typst rule for future report agents. - -STRICT RULES: -- Focus on the general syntax or formatting lesson, not the specific report topic. -- Do not include private data, user data, chart values, company names, or report-specific facts. -- Keep the content concise and directly usable as system prompt guidance. -- Output exactly one JSON object and no markdown: -{ - "title": "Short reusable rule title", - "content": "Concrete Typst guidance with a bad/good pattern if useful." -}`; - -const TypstReviewOutputSchema = z.object({ - title: z.string().min(1), - content: z.string().min(1), -}); - -type TypstReviewOutput = z.infer; - -type BuildTypstReviewPromptOptions = { - originalTypst: string; - diagnostics: string; - repairedTypst: string; -}; - -const buildTypstReviewPrompt = ({ - diagnostics, - originalTypst, - repairedTypst, -}: BuildTypstReviewPromptOptions): string => `## Compiler Diagnostics -${diagnostics} - -## Failed Typst -\`\`\`typst -${originalTypst} -\`\`\` - -## Repaired Typst -\`\`\`typst -${repairedTypst} -\`\`\` - -## Review Goal -Write one reusable Typst rule that would help avoid this compile failure in the future.`; - -const extractJsonCandidates = (text: string): string[] => { - const matches = text.match(/\{[\s\S]*\}/g); - return matches ?? []; -}; - -const parseTypstReviewOutput = ( - text: string, -): TypstReviewOutput | undefined => { - const candidates = extractJsonCandidates(text); - - for (let index = candidates.length - 1; index >= 0; index -= 1) { - try { - const parsed = JSON.parse(candidates[index] ?? ""); - const result = TypstReviewOutputSchema.safeParse(parsed); - if (result.success) { - return result.data; - } - } catch { - // Continue looking for a valid JSON object. - } - } - - return undefined; -}; - -export { - TYPST_REVIEW_AGENT_PROMPT, - TypstReviewOutputSchema, - buildTypstReviewPrompt, - parseTypstReviewOutput, -}; -export type { BuildTypstReviewPromptOptions, TypstReviewOutput }; diff --git a/lib/agent/pipeline/context.ts b/lib/agent/pipeline/context.ts index 1ac20cf..f8ff501 100644 --- a/lib/agent/pipeline/context.ts +++ b/lib/agent/pipeline/context.ts @@ -51,7 +51,23 @@ ${ctx.plan.chartGoal ?? "Create appropriate visualizations from the cleaned data - Include all fields: chartCount, descriptions, artifacts. - If chart execution fails, still return valid JSON with chartCount=0 and a failure reason in descriptions.`; - case "report": + case "report": { + const chartArtifacts = ctx.chartOutput?.artifacts ?? []; + const chartDescriptions = ctx.chartOutput?.descriptions ?? []; + const chartSection = + chartArtifacts.length > 0 + ? chartArtifacts + .map((a, i) => { + const desc = chartDescriptions[i] ?? `Chart ${i + 1}`; + return `### Chart ${i + 1}\n- Description: ${desc}\n- Image URL: ![${desc}](${a.downloadUrl})\n- fileId: ${a.fileId}`; + }) + .join("\n\n") + : chartDescriptions.length > 0 + ? chartDescriptions + .map((d, i) => `### Chart ${i + 1}\n${d}`) + .join("\n\n") + : "No charts generated"; + return `${base} ## Data Summary ${ctx.dataOutput?.summary ?? "No data summary available"} @@ -60,10 +76,11 @@ ${ctx.dataOutput?.summary ?? "No data summary available"} ${ctx.dataOutput?.stats ?? "N/A"} ## Charts (${ctx.chartOutput?.chartCount ?? 0} generated) -${ctx.chartOutput?.descriptions.map((d, i) => `### Chart ${i + 1}\n${d}`).join("\n\n") ?? "No charts generated"} +${chartSection} ## Goal -${ctx.plan.reportGoal ?? "Write a comprehensive analysis report incorporating the data insights and chart descriptions"}`; +${ctx.plan.reportGoal ?? "Write a comprehensive analysis report incorporating the data insights and chart images. Use the provided chart Image URLs to embed the actual chart images in the report."}`; + } } }; diff --git a/lib/agent/pipeline/executor.ts b/lib/agent/pipeline/executor.ts index 1c3218c..c99a12a 100644 --- a/lib/agent/pipeline/executor.ts +++ b/lib/agent/pipeline/executor.ts @@ -2,15 +2,6 @@ import { createChartAgent } from "@/lib/agent/multi-agents/chart-agent"; import { createDataAgent } from "@/lib/agent/multi-agents/data-agent"; import { runOrchestrator } from "@/lib/agent/multi-agents/orchestrator"; import { createReportAgent } from "@/lib/agent/multi-agents/report-agent"; -import { - buildTypstRepairPrompt, - createTypstRepairAgent, -} from "@/lib/agent/multi-agents/typst-repair-agent"; -import { - TYPST_REVIEW_AGENT_PROMPT, - buildTypstReviewPrompt, - parseTypstReviewOutput, -} from "@/lib/agent/multi-agents/typst-review-agent"; import { buildStepPrompt, createInitialContext, @@ -23,17 +14,10 @@ import { resolveDataOutput, resolveReportOutput, } from "@/lib/agent/pipeline/output-resolver"; -import { compileAndRepairTypst } from "@/lib/agent/pipeline/typst-repair"; import type { SandboxSession } from "@/lib/agent/sandbox/e2b"; import { formatUnknownError } from "@/lib/agent/utils/error-utils"; -import { - buildLearnMemoryPrompt, - upsertLearnMemory, -} from "@/lib/agent/utils/learn-memories"; import { getFileDownloadUrl } from "@/lib/file-store"; -import { compileTypst } from "@/lib/typst/compiler"; import type { FileRecord } from "@/types"; -import { ReportOutputSchema } from "@/types/agent"; import type { AgentDefinition, PipelineContext, @@ -135,69 +119,6 @@ const ensurePersistedChartArtifacts = async ( }; }; -const loadLearnedTypstPrompt = async (): Promise => { - try { - return await buildLearnMemoryPrompt("typst"); - } catch { - return ""; - } -}; - -type LearnFromTypstRepairOptions = { - diagnostics: string; - originalTypst: string; - repairedTypst: string; -}; - -const learnFromTypstRepair = async ({ - diagnostics, - originalTypst, - repairedTypst, -}: LearnFromTypstRepairOptions): Promise => { - const result = await streamText({ - system: TYPST_REVIEW_AGENT_PROMPT, - model: zhipu(MAIN_MODEL), - messages: [ - { - role: "user", - content: buildTypstReviewPrompt({ - diagnostics, - originalTypst, - repairedTypst, - }), - }, - ], - stopWhen: stepCountIs(1), - }); - - let fullText = ""; - for await (const part of result.fullStream) { - if (part.type === "text-delta") { - fullText += part.text; - } - } - - const learning = parseTypstReviewOutput(fullText); - if (!learning) { - return; - } - - await upsertLearnMemory({ - type: "typst", - title: learning.title, - content: learning.content, - }); -}; - -const scheduleTypstRepairLearning = ( - options: LearnFromTypstRepairOptions, -): void => { - const learningTask = learnFromTypstRepair(options); - learningTask.catch((error) => { - console.error("[Typst Learning Error]", error); - }); -}; - const executeStep = async ( agent: AgentDefinition, stepPrompt: string, @@ -286,13 +207,10 @@ const executePipeline = async ( return createInitialContext(userRequest, attachedFiles, pipelinePlan); } - const learnedTypstPrompt = await loadLearnedTypstPrompt(); const agentMap: Record = { data: createDataAgent({ fileIds, sandboxSession }), chart: createChartAgent({ fileIds, sandboxSession }), - report: createReportAgent({ - learnedTypstPrompt, - }), + report: createReportAgent(), }; const ctx = createInitialContext(userRequest, attachedFiles, pipelinePlan); @@ -324,71 +242,7 @@ const executePipeline = async ( break; } case "report": { - const initialOutput = resolveReportOutput(stepResult); - console.log( - "[DEBUG] report-agent generated typstContent:\n", - initialOutput.typstContent, - ); - const repairAgent = createTypstRepairAgent(); - const compileResult = await compileAndRepairTypst( - initialOutput.typstContent, - { - compileTypst: async (content) => { - console.log("[DEBUG] compileTypst input (attempt):\n", content); - const result = await compileTypst(content); - console.log( - "[DEBUG] compileTypst result ok:", - result.ok, - result.ok - ? "" - : `error: ${result.error}, diagnostics: ${result.diagnostics}`, - ); - return result; - }, - repairTypst: async ({ attempt, content, diagnostics }) => { - console.log( - "[DEBUG] repairTypst attempt:", - attempt, - "diagnostics:", - diagnostics, - ); - const repairResult = await executeStep( - repairAgent, - buildTypstRepairPrompt({ - attempt, - content, - diagnostics, - learnedTypstPrompt, - }), - step, - () => undefined, - ); - const repairedContent = - resolveReportOutput(repairResult).typstContent; - console.log("[DEBUG] repairTypst output:\n", repairedContent); - return repairedContent; - }, - }, - ); - - if (!compileResult.ok) { - throw new Error( - `Report Typst failed to compile after ${compileResult.repairCount} repair attempts.\n\n${compileResult.diagnostics}`, - ); - } - - const output = ReportOutputSchema.parse({ - typstContent: compileResult.typstContent, - compiledSvg: compileResult.svg, - }); - const firstRepairAttempt = compileResult.repairAttempts.at(0); - if (firstRepairAttempt) { - scheduleTypstRepairLearning({ - diagnostics: firstRepairAttempt.diagnostics, - originalTypst: firstRepairAttempt.input, - repairedTypst: compileResult.typstContent, - }); - } + const output = resolveReportOutput(stepResult); ctx.reportOutput = output; onEvent({ type: "step-complete", step, output }); break; diff --git a/lib/agent/pipeline/output-resolver.test.ts b/lib/agent/pipeline/output-resolver.test.ts index 3254fcc..c3b4c31 100644 --- a/lib/agent/pipeline/output-resolver.test.ts +++ b/lib/agent/pipeline/output-resolver.test.ts @@ -1,23 +1,31 @@ import { resolveReportOutput } from "./output-resolver"; describe("resolveReportOutput", () => { - it("normalizes Typst report text settings before returning content", () => { + it("extracts markdown content from a fenced code block", () => { const output = resolveReportOutput({ text: `Here is the report: -\`\`\`typst -#set text( - font: ("Noto Serif CJK SC", "SimSun"), - lang: "zh", -) +\`\`\`markdown +# Report -= Report +## Summary +This is the analysis. \`\`\``, toolErrors: [], toolResults: [], }); - expect(output.typstContent).toContain("fallback: true"); - expect(output.typstContent).not.toContain("fallback: false"); + expect(output.markdownContent).toContain("# Report"); + expect(output.markdownContent).toContain("## Summary"); + }); + + it("throws when no markdown code block is found", () => { + expect(() => + resolveReportOutput({ + text: "No report here", + toolErrors: [], + toolResults: [], + }), + ).toThrow("Report step did not produce markdown content."); }); }); diff --git a/lib/agent/pipeline/output-resolver.ts b/lib/agent/pipeline/output-resolver.ts index 9585b18..5ce643a 100644 --- a/lib/agent/pipeline/output-resolver.ts +++ b/lib/agent/pipeline/output-resolver.ts @@ -1,5 +1,4 @@ import { formatUnknownError } from "@/lib/agent/utils/error-utils"; -import { ensureTypstTextFallback } from "@/lib/typst/text-fallback"; import { type ChartOutput, ChartOutputSchema, @@ -423,20 +422,20 @@ const resolveChartOutput = (stepResult: StepExecutionResult): ChartOutput => { }); }; -const extractTypstContent = (text: string): string | undefined => { - const match = text.match(/```typst\n([\s\S]*?)```/); +const extractMarkdownContent = (text: string): string | undefined => { + const match = text.match(/```markdown\n([\s\S]*?)```/); return match?.[1]?.trim() || undefined; }; const resolveReportOutput = (stepResult: StepExecutionResult): ReportOutput => { - const typstContent = extractTypstContent(stepResult.text); + const markdownContent = extractMarkdownContent(stepResult.text); - if (!typstContent) { - throw new Error("Report step did not produce typst content."); + if (!markdownContent) { + throw new Error("Report step did not produce markdown content."); } return ReportOutputSchema.parse({ - typstContent: ensureTypstTextFallback(typstContent), + markdownContent, }); }; diff --git a/lib/agent/pipeline/typst-repair.test.ts b/lib/agent/pipeline/typst-repair.test.ts deleted file mode 100644 index e13c10a..0000000 --- a/lib/agent/pipeline/typst-repair.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { compileAndRepairTypst } from "./typst-repair"; - -describe("compileAndRepairTypst", () => { - it("returns compiled content without repair when Typst is valid", async () => { - const repairTypst = jest.fn(); - const result = await compileAndRepairTypst("= Valid", { - compileTypst: async () => ({ ok: true, svg: "" }), - repairTypst, - }); - - expect(result.ok).toBe(true); - expect(repairTypst).not.toHaveBeenCalled(); - if (result.ok) { - expect(result.typstContent).toBe("= Valid"); - expect(result.svg).toBe(""); - } - }); - - it("repairs failed Typst and returns the successfully compiled content", async () => { - const compileTypst = jest - .fn() - .mockResolvedValueOnce({ - ok: false, - error: "unclosed delimiter", - diagnostics: "unclosed delimiter", - }) - .mockResolvedValueOnce({ ok: true, svg: "" }); - const repairTypst = jest.fn(async () => "= Fixed"); - - const result = await compileAndRepairTypst("= Broken", { - compileTypst, - repairTypst, - maxRepairAttempts: 3, - }); - - expect(result.ok).toBe(true); - expect(repairTypst).toHaveBeenCalledWith({ - attempt: 1, - content: "= Broken", - diagnostics: "unclosed delimiter", - }); - if (result.ok) { - expect(result.typstContent).toBe("= Fixed"); - expect(result.repairAttempts).toEqual([ - { - attempt: 1, - diagnostics: "unclosed delimiter", - input: "= Broken", - output: "= Fixed", - }, - ]); - } - }); - - it("returns the last diagnostics after max repair attempts fail", async () => { - const result = await compileAndRepairTypst("= Broken", { - compileTypst: async () => ({ - ok: false, - error: "still broken", - diagnostics: "still broken", - }), - repairTypst: async () => "= Still Broken", - maxRepairAttempts: 1, - }); - - expect(result.ok).toBe(false); - if (!result.ok) { - expect(result.error).toBe("still broken"); - expect(result.diagnostics).toBe("still broken"); - expect(result.typstContent).toBe("= Still Broken"); - } - }); -}); diff --git a/lib/agent/pipeline/typst-repair.ts b/lib/agent/pipeline/typst-repair.ts deleted file mode 100644 index 9dfd0eb..0000000 --- a/lib/agent/pipeline/typst-repair.ts +++ /dev/null @@ -1,119 +0,0 @@ -import type { TypstCompileResult } from "@/lib/typst/compiler"; - -const DEFAULT_MAX_TYPST_REPAIR_ATTEMPTS = 3; - -type RepairTypstInput = { - attempt: number; - content: string; - diagnostics: string; -}; - -type RepairTypst = (input: RepairTypstInput) => Promise; -type CompileTypst = (content: string) => Promise; - -type TypstRepairAttempt = { - attempt: number; - input: string; - diagnostics: string; - output: string; -}; - -type CompileAndRepairTypstOptions = { - compileTypst: CompileTypst; - repairTypst: RepairTypst; - maxRepairAttempts?: number; -}; - -type CompileAndRepairTypstSuccess = { - ok: true; - typstContent: string; - svg: string; - repairCount: number; - repairAttempts: TypstRepairAttempt[]; -}; - -type CompileAndRepairTypstFailure = { - ok: false; - typstContent: string; - error: string; - diagnostics: string; - repairCount: number; - repairAttempts: TypstRepairAttempt[]; -}; - -type CompileAndRepairTypstResult = - | CompileAndRepairTypstSuccess - | CompileAndRepairTypstFailure; - -const compileAndRepairTypst = async ( - initialContent: string, - options: CompileAndRepairTypstOptions, -): Promise => { - const maxRepairAttempts = - options.maxRepairAttempts ?? DEFAULT_MAX_TYPST_REPAIR_ATTEMPTS; - let currentContent = initialContent; - const repairAttempts: TypstRepairAttempt[] = []; - - for ( - let repairCount = 0; - repairCount <= maxRepairAttempts; - repairCount += 1 - ) { - const compileResult = await options.compileTypst(currentContent); - - if (compileResult.ok) { - return { - ok: true, - typstContent: currentContent, - svg: compileResult.svg, - repairCount, - repairAttempts, - }; - } - - if (repairCount >= maxRepairAttempts) { - return { - ok: false, - typstContent: currentContent, - error: compileResult.error, - diagnostics: compileResult.diagnostics, - repairCount, - repairAttempts, - }; - } - - const repairedContent = await options.repairTypst({ - attempt: repairCount + 1, - content: currentContent, - diagnostics: compileResult.diagnostics, - }); - repairAttempts.push({ - attempt: repairCount + 1, - input: currentContent, - diagnostics: compileResult.diagnostics, - output: repairedContent, - }); - currentContent = repairedContent; - } - - return { - ok: false, - typstContent: currentContent, - error: "Typst repair loop ended unexpectedly.", - diagnostics: "Typst repair loop ended unexpectedly.", - repairCount: maxRepairAttempts, - repairAttempts, - }; -}; - -export { DEFAULT_MAX_TYPST_REPAIR_ATTEMPTS, compileAndRepairTypst }; -export type { - CompileAndRepairTypstFailure, - CompileAndRepairTypstOptions, - CompileAndRepairTypstResult, - CompileAndRepairTypstSuccess, - CompileTypst, - RepairTypst, - RepairTypstInput, - TypstRepairAttempt, -}; diff --git a/lib/agent/skills/index.test.ts b/lib/agent/skills/index.test.ts index 7510a15..9b14ae6 100644 --- a/lib/agent/skills/index.test.ts +++ b/lib/agent/skills/index.test.ts @@ -3,15 +3,10 @@ import { findSkill, getSkillList, getSkills } from "./index"; describe("skill loader", () => { it("loads all skills from disk", () => { const skills = getSkills(); - expect(skills).toHaveLength(4); + expect(skills).toHaveLength(2); const names = skills.map((s) => s.name).sort(); - expect(names).toEqual([ - "paper-expert", - "report-expert", - "resume-expert", - "typst-expert", - ]); + expect(names).toEqual(["markdown-author", "markdown-report"]); }); it("each skill has non-empty name, description and content", () => { @@ -23,23 +18,14 @@ describe("skill loader", () => { }); it("findSkill returns the correct skill by name", () => { - const typst = findSkill("typst-expert"); - expect(typst).toBeDefined(); - expect(typst?.name).toBe("typst-expert"); - expect(typst?.content).toContain("#set page"); - expect(typst?.content).toContain("Typst is **not** LaTeX"); + const author = findSkill("markdown-author"); + expect(author).toBeDefined(); + expect(author?.name).toBe("markdown-author"); + expect(author?.content).toContain("Badge"); - const paper = findSkill("paper-expert"); - expect(paper).toBeDefined(); - expect(paper?.content).toContain("graceful-genetics"); - - const report = findSkill("report-expert"); + const report = findSkill("markdown-report"); expect(report).toBeDefined(); - expect(report?.content).toContain("obsidius"); - - const resume = findSkill("resume-expert"); - expect(resume).toBeDefined(); - expect(resume?.content).toContain("Jane Doe"); + expect(report?.name).toBe("markdown-report"); }); it("findSkill returns undefined for unknown skill", () => { @@ -48,12 +34,10 @@ describe("skill loader", () => { it("getSkillList formats skills as markdown bullet list", () => { const list = getSkillList(); - expect(list).toContain("- **typst-expert**:"); - expect(list).toContain("- **paper-expert**:"); - expect(list).toContain("- **report-expert**:"); - expect(list).toContain("- **resume-expert**:"); + expect(list).toContain("- **markdown-author**:"); + expect(list).toContain("- **markdown-report**:"); const lines = list.split("\n"); - expect(lines).toHaveLength(4); + expect(lines).toHaveLength(2); }); }); diff --git a/lib/agent/skills/markdown-author/SKILL.md b/lib/agent/skills/markdown-author/SKILL.md new file mode 100644 index 0000000..ae2dac7 --- /dev/null +++ b/lib/agent/skills/markdown-author/SKILL.md @@ -0,0 +1,222 @@ +--- +name: markdown-author +description: This skill should be used when creating analysis reports, notes, documentation, or any content that benefits from rich Markdown formatting and creative visual presentation. +--- + + +# Markdown Author Skill + +This skill provides advanced and creative Markdown generation rules for producing visually rich, well-structured documents. + + +## Rule +1. Unless requested by the user, adding any emojis is strictly prohibited. + +--- + +## Figure + +### Side-by-Side Image Comparison +Place two images horizontally for comparison. + +```html +
+ Description 1 + Description 2 +
+``` + +### Captioned Image +A centered image with a caption underneath. + +```html +
+ System Architecture +

Figure 1: System Architecture Overview

+
+``` + +--- + +## Underline + +### Basic Underline +Always include `text-underline-offset: 3px;` for readability. + +```html +Basic Underline +``` + +### Colored Underline +```html +Red Underline +Blue Underline +``` + +--- + +## Wavy Lines + +### Basic Wavy Underline +```html +Wavy Underline +``` + +### Custom Wavy Lines +```html +Red Wavy Line +Pink Bold Wavy Line +``` + +--- + +## Callout + +```markdown +> [!NOTE] +> This is a standard informational note. + +> [!TIP] +> This is a helpful tip or suggestion. + +> [!IMPORTANT] +> This is an important piece of information. + +> [!WARNING] +> This is a warning about potential issues. + +> [!CAUTION] +> This is a caution about critical risks. +``` + +--- + +## Highlighted Text + +### Background Highlight +```html +Yellow Highlight +Green Highlight +Blue Highlight +Red Highlight +``` + +--- + +## Badge / Tag + +Inline colored labels for status, categories, or version indicators. + +```html +Active +Deprecated +Beta +Draft +``` + +### Outlined Badge +```html +v2.0 +``` + +--- + +## Card + +Bordered, shadowed card containers for grouping related content. + +```html +
+

Card Title

+

Card body content goes here. Use cards to group related information visually.

+
+``` + +### Colored Left Border Card (Accent Card) +```html +
+ Key Insight: Use accent cards to draw attention to important takeaways. +
+``` + +--- + +## Two-Column Layout + +Split content into side-by-side columns. + +```html +
+
+

Column 1

+

Left column content.

+
+
+

Column 2

+

Right column content.

+
+
+``` + +--- + +## Divider with Label + +A horizontal rule with centered text label for section separation. + +```html +
+
+ Section Label +
+
+``` + +--- + +## Timeline + +A vertical timeline for events, changelogs, or step-by-step processes. + +```html +
+
+
+ Step 1 — Init +

Description of the first milestone.

+
+
+
+ Step 2 — Build +

Description of the second milestone.

+
+
+
+ Step 3 — Complete +

Description of the final milestone.

+
+
+``` + +--- + +## Definition List + +Key-value pairs rendered as a styled definition block. + +```html +
+
+ Name + Markdown Author Skill +
+
+ Version + 2.0.0 +
+
+ Author + Refract Team +
+
+``` diff --git a/lib/agent/skills/markdown-report/SKILL.md b/lib/agent/skills/markdown-report/SKILL.md new file mode 100644 index 0000000..dec3045 --- /dev/null +++ b/lib/agent/skills/markdown-report/SKILL.md @@ -0,0 +1,189 @@ +--- +name: markdown-report +description: Use markdown-report when you need to create professional analysis reports with rich formatting including tables, charts, flowcharts, and structured sections. +--- + + +# Markdown Report Skill + +This skill provides a professional analysis report template with rich Markdown formatting. + +## Rule +1. Unless requested by the user, adding any emojis is strictly prohibited. +2. All chart image references MUST use the workspace download URL format: `![Chart Description](/api/file/{fileId}/download)`. +3. Use the `markdown-author` skill patterns for advanced visual elements (badges, cards, timelines, callouts, etc.). + +--- + +## Report Template + +```md +# {Report Title} + +--- + +## Executive Summary + +{2-3 sentence overview of the key findings and recommendations.} + +--- + +## 1. Data Overview + +### 1.1 Data Source + +| Item | Detail | +|------|--------| +| Source | {file name or description} | +| Records | {rowCount} rows | +| Columns | {columnCount} columns | +| Time Range | {start} - {end} | +| Data Quality | {percentage}% complete | + +### 1.2 Data Cleaning Summary + +{Brief description of cleaning steps performed.} + +| Step | Action | Records Affected | +|------|--------|-----------------| +| 1 | Removed duplicates | {n} | +| 2 | Filled missing values | {n} | +| 3 | Type corrections | {n} | +| 4 | Outlier treatment | {n} | + +--- + +## 2. Key Findings + +### 2.1 {Finding Category 1} + +{Description with specific numbers.} + +| Metric | Value | Change | +|--------|-------|--------| +| {metric 1} | {value} | {+/-%} | +| {metric 2} | {value} | {+/-%} | +| {metric 3} | {value} | {+/-%} | + +### 2.2 {Finding Category 2} + +{Description with specific numbers.} + +--- + +## 3. Data Visualizations + +### 3.1 {Chart 1 Title} + +![{Chart 1 Description}](/api/file/{fileId}/download) + +*Figure 1: {Chart 1 caption explaining what the chart shows and the key insight.}* + +### 3.2 {Chart 2 Title} + +![{Chart 2 Description}](/api/file/{fileId}/download) + +*Figure 2: {Chart 2 caption explaining what the chart shows and the key insight.}* + +### 3.3 Analysis Flowchart + +When the analysis involves a decision process, use a Mermaid flowchart: + +```mermaid +graph LR + A[Raw Data] --> B[Cleaning] + B --> C[Statistical Analysis] + C --> D{Key Threshold?} + D -->|Yes| E[Significant Finding] + D -->|No| F[Normal Range] + E --> G[Recommendation] + F --> G +``` + +--- + +## 4. Statistical Summary + +| Statistic | {Column 1} | {Column 2} | {Column 3} | +|-----------|-----------|-----------|-----------| +| Mean | {val} | {val} | {val} | +| Median | {val} | {val} | {val} | +| Std Dev | {val} | {val} | {val} | +| Min | {val} | {val} | {val} | +| Max | {val} | {val} | {val} | + +--- + +## 5. Conclusions + +> [!IMPORTANT] +> {Most critical finding that the reader must not miss.} + +1. **{Conclusion 1}:** {Evidence-based statement with specific numbers.} +2. **{Conclusion 2}:** {Evidence-based statement with specific numbers.} +3. **{Conclusion 3}:** {Evidence-based statement with specific numbers.} + +--- + +## 6. Recommendations + +| Priority | Recommendation | Expected Impact | Effort | +|----------|---------------|----------------|--------| +| High | {action 1} | {impact} | {effort} | +| Medium | {action 2} | {impact} | {effort} | +| Low | {action 3} | {impact} | {effort} | + +--- + +## Appendix + +### Methodology + +{Brief description of analytical methods used.} + +### Limitations + +- {Limitation 1} +- {Limitation 2} +``` + +--- + +## Image URL Rules + +When referencing chart images in the report: + +1. The pipeline prompt provides chart image URLs in the format: + ``` + ### Chart N + - Description: + - Image URL: ![]() + - fileId: + ``` + +2. You MUST use the exact Image URL provided in the prompt. Copy the full downloadUrl as-is into the report markdown: + ``` + ![Chart Description]() + ``` + +3. If the prompt provides downloadUrl values, use them directly (they are already full URLs). + If only fileId is available, construct: `/api/file/{fileId}/download` + +4. Always include a figure caption below the image using italics: + ``` + *Figure N: Description of what the chart shows.* + ``` + +5. Every chart provided in the prompt MUST appear in the report's Data Visualizations section. Do NOT skip any chart. + +## Mermaid Diagram Rules + +Use Mermaid diagrams when the report needs: + +- Process flows: `graph TD` or `graph LR` +- Decision trees: `graph TD` with diamond `{} ` nodes +- Timelines: `graph LR` with sequential nodes +- Data pipelines: `graph LR` showing transformation steps + +Keep diagrams simple. Maximum 10 nodes per diagram for readability. +``` diff --git a/lib/agent/skills/paper-expert/SKILL.md b/lib/agent/skills/paper-expert/SKILL.md deleted file mode 100644 index 6126d7b..0000000 --- a/lib/agent/skills/paper-expert/SKILL.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -name: paper-expert -description: Use the paper-expert skill to help users create professional and aesthetically paper.You should use this skill when users request the creation of paper. Be sure to follow the principles and guidelines below when creating paper. ---- - -# Template -``` -#import "@preview/graceful-genetics:0.2.0" as graceful-genetics -#import "@preview/physica:0.9.3" - -#show: graceful-genetics.template.with( - title: [Towards Swifter Interstellar Mail Delivery], - authors: ( - ( - name: "Johanna Swift", - department: "Primary Logistics Department", - institution: "Delivery Institute", - city: "Berlin", - country: "Germany", - mail: "swift@delivery.de", - ), - ( - name: "Egon Stellaris", - department: "Communications Group", - institution: "Space Institute", - city: "Florence", - country: "Italy", - mail: "stegonaris@space.it", - ), - ( - name: "Oliver Liam", - department: "Missing Letters Task Force", - institution: "Mail Institute", - city: "Budapest", - country: "Hungary", - mail: "oliver.liam@mail.hu", - ), - ), - date: ( - year: 2022, - month: "May", - day: 17, - ), - keywords: ( - "Space", - "Mail", - "Astromail", - "Faster-than-Light", - "Mars", - ), - doi: "10.7891/120948510", - abstract: [ - Recent advances in space-based document processing have enabled faster mail delivery between different planets of a solar system. Given the time it takes for a message to be transmitted from one planet to the next, its estimated that even a one-way trip to a distant destination could take up to one year. During these periods of interplanetary mail delivery there is a slight possibility of mail being lost in transit. This issue is considered so serious that space management employs P.I. agents to track down and retrieve lost mail. We propose A-Mail, a new anti-matter based approach that can ensure that mail loss occurring during interplanetary transit is unobservable and therefore potentially undetectable. Going even further, we extend A-Mail to predict problems and apply existing and new best practices to ensure the mail is delivered without any issues. We call this extension AI-Mail. - ], -) - -= Introduction -Our concept suggests three ways that A-Mail can be best utilized. - -- First is to reduce the probability of the failure of a space mission. This problem, known as the Mars problem, suggests that the high round-trip time required for communication between Mars and Earth inhibits successful human developments on the planet. Thanks to A-Mail's faster-than-light delivery system this problem could be solved once and for all. - -- As A-Mails are written using pen and paper, no digital technology is needed for short and long distance communication. This suggests a possibility of reducing the communication monopoly currently held by an entity known as the "internet". Our suggestion of A-Mail being responsible for postal delivery would reduce dependence on online services by delivering the vast majority of mail offline. Space is a place where drastic changes in methods of production and distribution can easily occur. - -- Lastly, A-Mail is capable of performing high-level complex calculations. It is this capability that distinguishes A-Mail from traditional space mailers. This is an especially useful capability when planning long-distance space missions. - -The delivery speed of an A-Mail can be determined through this simple formula: - -$ v(t) = lim_(t -> infinity) integral^infinity c dot sqrt(t^2) physica.dd("t") $ - -Building on the strong foundations of A-Mail, we extend our platform to predict problems and apply existing and new best practices to ensure the mail is delivered without any issues. We call this extension AI-Mail. AI-Mail is a new concept designed and delivered by artificially intelligent (AI) agents. The AI-Mail agents are intelligently designed to solve problems at various points in the delivery chain. These problems are related to targeting, delivery delay, tone of delivery, product information, product return, system crash, shipment error and more. AI-Mail provides a one-stop solution for A-Mail's shortcomings. - -== Proven technology -A-Mail has been under development four the past ten years and in the process has consolidate different space programmes. Over the course of the last year, our space P.I.s have already found over ten thousand lost letters. These letters had been drifting in space since the stone ages when they were originally mailed. Only now we had the technology to recover them. In this way, A-Mail technology has already proven invaluable to human advancement and research, bringing us closer to our ancestors. - -== Limitless possibilities -Through A-Mail's _faster-than-light_ technology, for the first time, humans have the capability to rearch far away solar systems to find out whether we are, after all, alone in this universe. -During our research, we have already established pen pal relations with at least three potential extraterrestrial living forms. - -== Direct implications -One of the most direct implications of A-Mail is the solution of the Mars problem. This means that people stuck on Mars can now finally watch football games live, a significant achievement on the grand scale of things. The complex communication interactions arising between Earth, Mars, and the \+ -``` \ No newline at end of file diff --git a/lib/agent/skills/report-expert/SKILL.md b/lib/agent/skills/report-expert/SKILL.md deleted file mode 100644 index 98129d6..0000000 --- a/lib/agent/skills/report-expert/SKILL.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -name: report-expert -description: Use this skill when you are asked to create a summary of notes or reports. ---- - -# Template -``` -#import "@preview/obsidius:0.1.0": * - -#show: notes.with("Template summary"); - -= Usage instructions - -Here is a simple step-by-step guide on how to use this template: - -+ Create a new document `mynotes.typ` with the following content - ```typst - #import "lib.typ": * - - #show: notes.with("Your fancy title"); - ``` -+ Write your normal typst notes -+ Use additional feature such as callouts -+ Have fun #emoji.party - -= Standard functionality - -/ Template: a preset format for a document or file. - -With this template, you can write notes with a modern style. -It features sans-serif fonts and *callouts* for quotes and definitions. -Colors are based on the tailwind color scheme. -The style is heavily inspired by Obsidian #footnote[https://obsidian.md/]. The callout feature is also borrowed from them. -You can also add #highlight[callouts] to your document, instructions are below @custom. - -#quote(attribution: "The author, 2025")[ -I use this template to summarize my lectures at university. It is so great. -] - -Tables feature a custom style as well: - -#figure(caption: "Feature overview", -table(columns: (auto, auto, auto), - table.header([Feature], [Default], [This template]), - [Modern style], [#emoji.crossmark], [#emoji.checkmark.box], - [Colorful boxes], [#emoji.crossmark], [#emoji.checkmark.box], -)) - -= Additional functions - -In addition to the default functions @default, you also get additional callouts for _warnings_, _solutions_ and more! - -#warning[ - Once you started using this template, you can never stop! -] - -#solution[ - Attend the lectures to use it even more often! -] - -You can also include questions to help learn the lecture content: - -#questions[ - + How do I use the notes template? - + What additional functions does the notes template provide? -] - -= Custom callouts - -Feel free to add your own custom callouts to your document if you need more. -To keep the colors consistent, I recommend using colors from the Tailwind color scheme #footnote[https://tailwindcss.com/docs/colors]. -For example, you could add a todo callout and use it together with the _cheq_ package #footnote[https://typst.app/universe/package/cheq]: - -```typst -#import "@preview/cheq:0.2.2": checklist - -#show: checklist.with(stroke: rgb("#6F05E7")) - -#let todo(content) = { - callout(emoji.notepad, "ToDo", content, - (rgb("#6F05E7"), rgb("#EDE8FD"), rgb("#C4B3FF"))) // hint: use tailwind colors 700, 100, 300 -} - -#todo[ - - [x] show how to create custom color boxes - - [ ] create more functions -] -``` - -Which would look like this: - -#import "@preview/cheq:0.2.2": checklist - -#show: checklist.with(stroke: rgb("#6F05E7")) - -#let todo(content) = { - callout(emoji.notepad, "ToDo", content, - (rgb("#6F05E7"), rgb("#EDE8FD"), rgb("#C4B3FF"))) -} -#todo[ - - [x] show how to create custom callouts - - [ ] create more callouts -] -``` \ No newline at end of file diff --git a/lib/agent/skills/resume-expert/SKILL.md b/lib/agent/skills/resume-expert/SKILL.md deleted file mode 100644 index 025d150..0000000 --- a/lib/agent/skills/resume-expert/SKILL.md +++ /dev/null @@ -1,235 +0,0 @@ ---- -name: resume-expert -description: Use the resume-expert skill to help users create professional and aesthetically resume. You should use this skill when users request the creation of resumes. Be sure to activate this skill whenever a user requests to create a resume. ---- - -# Template -``` -#import "@preview/fontawesome:0.6.0": * - -// ─── Configuration ──────────────────────────────────────────────────────────── -// Edit these values to customize the look and feel of your resume. -// You should not need to modify anything outside this block for basic use. - -#let name = "Jane Doe" // Your full name, displayed in the header -#let accent = rgb("#002366") // Accent color used for headings, lines, and icons -#let sidebar-fill = rgb("#eef0f5") // Background color of the left sidebar -#let sans-font = "Noto Sans" // Font used for section headings -#let serif-font = "Noto Serif" // Font used for your name in the header -#let col-ratio = (3fr, 7fr) // Ratio of sidebar width to main content width -// ────────────────────────────────────────────────────────────────────────────── - -#set document(title: [#upper(name)]) -#set text(size: 10pt) -#show heading.where(level: 1): set text(font: sans-font, tracking: 0.1em, weight: 500, fill: accent) -#show heading.where(level: 2): set text(size: 12pt) - -#set page(margin: ( - top: 1cm, - left: 1cm, - right: 1cm, - bottom: 1cm, -)) - -// ─── Helper functions ───────────────────────────────────────────────────────── - -// Renders your name in the header -#let resume-title() = text( - font: serif-font, - tracking: 0.1em, - weight: 500, - size: 28pt, - fill: accent, -)[#upper(name)] - -// Renders a work experience entry. -// Usage: -// #experience( -// "Company Name", -// "Job Title", -// "City, State", -// "Start – End", -// ( -// "Bullet point one.", -// "Bullet point two.", -// ), -// ) -#let experience( - company, - role, - location, - dates, - bullets, -) = [ - == #text(fill: accent)[#company] - - #grid( - columns: (1fr, 1fr), - align: (left, right), - [ #emph[#role] ], [ #emph[#location | #dates] ], - ) - - #for bullet in bullets { - [- #bullet] - } -] - -// Renders an education entry. -// Usage: -// #education( -// "University Name", -// "City, State", -// "Start – End", -// ("Degree One", "Degree Two"), -// ) -#let education( - institution, - location, - dates, - degrees, -) = [ - == #institution - - #location | #dates \ - #for degree in degrees { - [ #text(weight: "bold")[#degree] \ ] - } -] - -// Renders a skill category in the sidebar. -// Pass items as an array of strings — they will be joined with " | ". -// Usage: -// #skill-category("Languages", ("Python", "Rust", "TypeScript")) -#let skill-category(category, items) = [ - == #category - - #items.join(" | ") -] - -// ─── Header ─────────────────────────────────────────────────────────────────── - -#align(center)[ - #resume-title() - #set text(size: 10pt) - // Update the four links below with your own URLs and display text. - // Icons are provided by Font Awesome — replace icon names as needed. - // See: https://fontawesome.com/icons - #grid( - columns: (1fr, 1fr, 1fr, 1fr), - align: center, - [ #text(fill: accent)[#fa-icon("globe", font: "Font Awesome 7 Free Solid")] #link("https://yourwebsite.com")[yourwebsite.com] ], - [ #text(fill: accent)[#fa-icon("envelope", font: "Font Awesome 7 Free Solid")] #link("mailto:your.email@gmail.com")[your.email\@gmail.com] ], - [ #text(fill: accent)[#fa-icon("github", font: "Font Awesome 7 Brands")] #link("https://github.com/yourusername")[yourusername] ], - [ #text(fill: accent)[#fa-icon("linkedin", font: "Font Awesome 7 Brands")] #link("https://linkedin.com/in/yourusername")[yourusername] ], - ) -] - -#line(length: 100%, stroke: accent) - -// Optional: Replace with a 2-3 sentence professional summary. -// Delete this paragraph entirely if you prefer no summary. -Software engineer with a focus on building reliable, scalable backend systems and a strong foundation in distributed computing. Experienced across the full stack, from data pipelines and APIs to frontend interfaces, with a track record of delivering impactful systems in fast-moving environments. MS in Computer Science from Stanford University. - -#line(length: 100%, stroke: accent) - -// ─── Body ───────────────────────────────────────────────────────────────────── - -#grid( - columns: col-ratio, - rows: auto, - fill: (sidebar-fill, none), - inset: 5pt, - column-gutter: 0.5cm, - [ - // ── Sidebar ────────────────────────────────────────────────────────────── - - = #upper("Education") - - // Add or remove #education(...) blocks as needed. - #education( - "Stanford University", - "Stanford, CA", - "Sept '18 – June '20", - ("MS in Computer Science",), - ) - - #education( - "University of Michigan", - "Ann Arbor, MI", - "Sept '14 – May '18", - ("BS in Computer Science", "BS in Mathematics"), - ) - - #line(stroke: (dash: "dashed", paint: accent), length: 90%) - - = #upper("Skills") - - // Add or remove #skill-category(...) blocks as needed. - // Each block takes a category name and an array of items. - #skill-category("Languages", ("Python", "Go", "TypeScript", "Rust", "Java", "C++")) - #skill-category("Frameworks", ("FastAPI", "gRPC", "PyTorch", "React", "Django")) - #skill-category("Tooling", ("uv", "ruff", "mypy", "pytest", "Webpack")) - #skill-category("Databases", ("Postgres", "Redis", "Elasticsearch", "DynamoDB")) - #skill-category("DevOps", ("Docker", "Kubernetes", "Helm", "GitHub Actions", "Terraform")) - - ], - [ - // ── Main content ───────────────────────────────────────────────────────── - - = #upper("Work Experience") - - // Add or remove #experience(...) blocks as needed. - #experience( - "Stripe", - "Senior Software Engineer, Payments Infrastructure", - "San Francisco, CA", - "Aug 2022 – Present", - ( - "Architected a distributed rate-limiting service handling over 500K requests per second, reducing fraudulent transaction volume by 34% across all payment flows.", - "Led a team of four engineers to redesign the payment retry pipeline, cutting failed payment recovery time from 48 hours to under 6 hours and recovering an estimated \$12M annually.", - "Drove adoption of internal observability tooling across three teams, reducing mean time to detection for production incidents by 40%.", - "Served as technical lead for a real-time fraud scoring microservice integrating gradient-boosted and neural network models, deployed across 12 global regions.", - "Onboarded and mentored five engineers, establishing code review standards and internal documentation practices adopted org-wide.", - ), - ) - - #experience( - "Airbnb", - "Software Engineer, Search & Ranking", - "San Francisco, CA", - "July 2020 – July 2022", - ( - "Built and maintained ranking models for Airbnb's core search pipeline, improving booking conversion rate by 8% through feature engineering and A/B experimentation.", - "Owned the real-time feature computation service powering search ranking, reducing p99 latency from 180ms to 55ms through caching and query optimization.", - "Co-authored an internal paper on listless search personalization adopted as a standard approach across the ranking team.", - "Redesigned the search index update pipeline to support near-real-time listing availability, reducing stale search results by 60% during peak booking periods.", - ), - ) - - #experience( - "Microsoft", - "Software Engineering Intern, Azure Networking", - "Redmond, WA", - "May 2019 – Aug 2019", - ( - "Implemented a distributed tracing system for internal Azure networking services, enabling engineers to diagnose cross-region latency regressions 3× faster.", - "Contributed to the design and rollout of a load balancing algorithm that improved throughput by 22% under peak traffic conditions.", - ), - ) - - #experience( - "Stanford University", - "Research Assistant, Systems Lab", - "Stanford, CA", - "Sept 2018 – June 2020", - ( - "Researched fault-tolerant consensus protocols for geo-distributed systems, publishing findings at OSDI 2020 on reducing leader election overhead in high-latency networks.", - "Teaching assistant for CS 149: Parallel Computing, holding weekly office hours and developing course materials for a class of 200 students.", - ), - ) - - ], -) - -#line(length: 100%, stroke: accent) -``` \ No newline at end of file diff --git a/lib/agent/skills/typst-expert/SKILL.md b/lib/agent/skills/typst-expert/SKILL.md deleted file mode 100644 index 558c7fd..0000000 --- a/lib/agent/skills/typst-expert/SKILL.md +++ /dev/null @@ -1,408 +0,0 @@ ---- -name: typst-expert -description: Use the typst-author skill to help users create professional and aesthetically pleasing typst documents. You should use this skill when users request the creation of papers, resumes, novels, short stories, or notes. Be sure to follow the principles and guidelines below when creating typst document. ---- - -# Typst-Author Skill - -## When to Apply -Reference these guidelines when: -- The content that needs modification is in Typst format. -- Users need to create papers, resumes, or novels. -- Users insist on using the Typst format. - -## Typst Syntax -Typst is a markup language. This means that you can use simple syntax to -accomplish common layout tasks. The lightweight markup syntax is complemented by -set and show rules, which let you style your document easily and automatically. -All this is backed by a tightly integrated scripting language with built-in and -user-defined functions. - -### Modes -Typst has three syntactical modes: Markup, math, and code. Markup mode is the -default in a Typst document, math mode lets you write mathematical formulas, and -code mode lets you use Typst's scripting features. - -You can switch to a specific mode at any point by referring to the following -table: - -| New mode | Syntax | Example | -|----------|---------------------------------|---------------------------------| -| Code | Prefix the code with `#` | `[Number: #(1 + 2)]` | -| Math | Surround equation with `[$..$]` | `[$-x$ is the opposite of $x$]` | -| Markup | Surround markup with `[[..]]` | `{let name = [*Typst!*]}` | - -Once you have entered code mode with `#`, you don't need to use further hashes -unless you switched back to markup or math mode in between. - -### Markup -Typst provides built-in markup for the most common document elements. Most of -the syntax elements are just shortcuts for a corresponding function. The table -below lists all markup that is available and links to the best place to learn -more about their syntax and usage. - -| Name | Example | See | -| ------------------ | ---------------------------- | ------------------------ | -| Paragraph break | Blank line | [`parbreak`] | -| Strong emphasis | `[*strong*]` | [`strong`] | -| Emphasis | `[_emphasis_]` | [`emph`] | -| Raw text | ``[`print(1)`]`` | [`raw`] | -| Link | `[https://typst.app/]` | [`link`] | -| Label | `[]` | [`label`] | -| Reference | `[@intro]` | [`ref`] | -| Heading | `[= Heading]` | [`heading`] | -| Bullet list | `[- item]` | [`list`] | -| Numbered list | `[+ item]` | [`enum`] | -| Term list | `[/ Term: description]` | [`terms`] | -| Math | `[$x^2$]` | [Math]($category/math) | -| Line break | `[\]` | [`linebreak`] | -| Smart quote | `['single' or "double"]` | [`smartquote`] | -| Symbol shorthand | `[~]`, `[---]` | [Symbols]($category/symbols/sym) | -| Code expression | `[#rect(width: 1cm)]` | [Scripting]($scripting/#expressions) | -| Character escape | `[Tweet at us \#ad]` | [Below](#escapes) | -| Comment | `[/* block */]`, `[// line]` | [Below](#comments) | - -### Math mode { #math } -Math mode is a special markup mode that is used to typeset mathematical -formulas. It is entered by wrapping an equation in `[$]` characters. This works -both in markup and code. The equation will be typeset into its own block if it -starts and ends with at least one space (e.g. `[$ x^2 $]`). Inline math can be -produced by omitting the whitespace (e.g. `[$x^2$]`). An overview over the -syntax specific to math mode follows: - -| Name | Example | See | -| ---------------------- | ------------------------ | ------------------------ | -| Inline math | `[$x^2$]` | [Math]($category/math) | -| Block-level math | `[$ x^2 $]` | [Math]($category/math) | -| Bottom attachment | `[$x_1$]` | [`attach`]($category/math/attach) | -| Top attachment | `[$x^2$]` | [`attach`]($category/math/attach) | -| Fraction | `[$1 + (a+b)/5$]` | [`frac`]($math.frac) | -| Line break | `[$x \ y$]` | [`linebreak`] | -| Alignment point | `[$x &= 2 \ &= 3$]` | [Math]($category/math) | -| Variable access | `[$#x$, $pi$]` | [Math]($category/math) | -| Field access | `[$arrow.r.long$]` | [Scripting]($scripting/#fields) | -| Implied multiplication | `[$x y$]` | [Math]($category/math) | -| Symbol shorthand | `[$->$]`, `[$!=$]` | [Symbols]($category/symbols/sym) | -| Text/string in math | `[$a "is natural"$]` | [Math]($category/math) | -| Math function call | `[$floor(x)$]` | [Math]($category/math) | -| Code expression | `[$#rect(width: 1cm)$]` | [Scripting]($scripting/#expressions) | -| Character escape | `[$x\^2$]` | [Below](#escapes) | -| Comment | `[$/* comment */$]` | [Below](#comments) | - -### Code mode { #code } -Within code blocks and expressions, new expressions can start without a leading -`#` character. Many syntactic elements are specific to expressions. Below is -a table listing all syntax that is available in code mode: - -| Name | Example | See | -| ------------------------ | ----------------------------- | ---------------------------------- | -| None | `{none}` | [`none`] | -| Auto | `{auto}` | [`auto`] | -| Boolean | `{false}`, `{true}` | [`bool`] | -| Integer | `{10}`, `{0xff}` | [`int`] | -| Floating-point number | `{3.14}`, `{1e5}` | [`float`] | -| Length | `{2pt}`, `{3mm}`, `{1em}`, .. | [`length`] | -| Angle | `{90deg}`, `{1rad}` | [`angle`] | -| Fraction | `{2fr}` | [`fraction`] | -| Ratio | `{50%}` | [`ratio`] | -| String | `{"hello"}` | [`str`] | -| Label | `{}` | [`label`] | -| Math | `[$x^2$]` | [Math]($category/math) | -| Raw text | ``[`print(1)`]`` | [`raw`] | -| Variable access | `{x}` | [Scripting]($scripting/#blocks) | -| Code block | `{{ let x = 1; x + 2 }}` | [Scripting]($scripting/#blocks) | -| Content block | `{[*Hello*]}` | [Scripting]($scripting/#blocks) | -| Parenthesized expression | `{(1 + 2)}` | [Scripting]($scripting/#blocks) | -| Array | `{(1, 2, 3)}` | [Array]($array) | -| Dictionary | `{(a: "hi", b: 2)}` | [Dictionary]($dictionary) | -| Unary operator | `{-x}` | [Scripting]($scripting/#operators) | -| Binary operator | `{x + y}` | [Scripting]($scripting/#operators) | -| Assignment | `{x = 1}` | [Scripting]($scripting/#operators) | -| Field access | `{x.y}` | [Scripting]($scripting/#fields) | -| Method call | `{x.flatten()}` | [Scripting]($scripting/#methods) | -| Function call | `{min(x, y)}` | [Function]($function) | -| Argument spreading | `{min(..nums)}` | [Arguments]($arguments) | -| Unnamed function | `{(x, y) => x + y}` | [Function]($function) | -| Let binding | `{let x = 1}` | [Scripting]($scripting/#bindings) | -| Named function | `{let f(x) = 2 * x}` | [Function]($function) | -| Set rule | `{set text(14pt)}` | [Styling]($styling/#set-rules) | -| Set-if rule | `{set text(..) if .. }` | [Styling]($styling/#set-rules) | -| Show-set rule | `{show heading: set block(..)}` | [Styling]($styling/#show-rules) | -| Show rule with function | `{show raw: it => {..}}` | [Styling]($styling/#show-rules) | -| Show-everything rule | `{show: template}` | [Styling]($styling/#show-rules) | -| Context expression | `{context text.lang}` | [Context]($context) | -| Conditional | `{if x == 1 {..} else {..}}` | [Scripting]($scripting/#conditionals) | -| For loop | `{for x in (1, 2, 3) {..}}` | [Scripting]($scripting/#loops) | -| While loop | `{while x < 10 {..}}` | [Scripting]($scripting/#loops) | -| Loop control flow | `{break, continue}` | [Scripting]($scripting/#loops) | -| Return from function | `{return x}` | [Function]($function) | -| Include module | `{include "bar.typ"}` | [Scripting]($scripting/#modules) | -| Import module | `{import "bar.typ"}` | [Scripting]($scripting/#modules) | -| Import items from module | `{import "bar.typ": a, b, c}` | [Scripting]($scripting/#modules) | -| Comment | `{/* block */}`, `{// line}` | [Below](#comments) | - -### Comments -Comments are ignored by Typst and will not be included in the output. This is -useful to exclude old versions or to add annotations. To comment out a single -line, start it with `//`: - -```example -// our data barely supports -// this claim - -We show with $p < 0.05$ -that the difference is -significant. -``` - -Comments can also be wrapped between `/*` and `*/`. In this case, the comment -can span over multiple lines: - -```example -Our study design is as follows: -/* Somebody write this up: - - 1000 participants. - - 2x2 data design. */ -``` - -### Escape sequences { #escapes } -Escape sequences are used to insert special characters that are hard to type or -otherwise have special meaning in Typst. To escape a character, precede it with -a backslash. To insert any Unicode codepoint, you can write a hexadecimal escape -sequence: `[\u{1f600}]`. The same kind of escape sequences also work in -[strings]($str). - -```example -I got an ice cream for -\$1.50! \u{1f600} -``` - -### Identifiers -Names of variables, functions, and so on (_identifiers_) can contain letters, -numbers, hyphens (`-`), and underscores (`_`). They must start with a letter or -an underscore. - -More specifically, the identifier syntax in Typst is based on the -[Unicode Standard Annex #31](https://www.unicode.org/reports/tr31/), with two -extensions: Allowing `_` as a starting character, and allowing both `_` and `-` -as continuing characters. - -For multi-word identifiers, the recommended case convention is -[Kebab case](https://en.wikipedia.org/wiki/Letter_case#Kebab_case). In Kebab -case, words are written in lowercase and separated by hyphens (as in -`top-edge`). This is especially relevant when developing modules and packages -for others to use, as it keeps things predictable. - -```example -#let kebab-case = [Using hyphen] -#let _schön = "😊" -#let 始料不及 = "😱" -#let π = calc.pi - -#kebab-case -#if -π < 0 { _schön } else { 始料不及 } -// -π means -1 * π, -// so it's not a valid identifier -``` - -### Paths -Typst has various features that require a file path to reference external -resources such as images, Typst files, or data files. Paths are represented as -[strings]($str). There are two kinds of paths: Relative and absolute. - -- A **relative path** searches from the location of the Typst file where the - feature is invoked. It is the default: - ```typ - #image("images/logo.png") - ``` - -- An **absolute path** searches from the _root_ of the project. It starts with a - leading `/`: - ```typ - #image("/assets/logo.png") - ``` - -## Mini Example - -```typst -#set page(paper: "a4", margin: 2.2cm) -#set text(font: ("New Computer Modern", "SimSun", "PingFang SC"), lang: "en", size: 11pt, fallback: true) -#set par(justify: true) - -= Title of Your Reinforcement Learning Paper - -== Abstract -We propose *Your Algorithm*, a sample-efficient reinforcement-learning method that achieves state-of-the-art performance on the *X* benchmark. By leveraging *key idea*, our approach improves the mean return by *Y %* while reducing wall-clock time by *Z %*. - -== 1 Introduction -Reinforcement learning (RL) aims to learn optimal policies $pi_*(a|s)$ that maximise the expected discounted return $E[ sum_(t=0)^infinity gamma^t r_t ]$. Despite recent successes, *problem statement* remains challenging. We address this gap by *contribution summary*. - -== 2 Background -=== 2.1 Markov Decision Processes -An MDP is a tuple $M = ( cal(S), cal(A), P, R, gamma )$ with transition kernel $P(s'|s,a)$ and reward function $R(s,a)$. The state-value function satisfies the Bellman equation -$ V_pi(s) = E_(a~pi) [ R(s,a) + gamma E_(s'~P) V_pi(s') ] $. - -=== 2.2 Off-Policy Evaluation -Off-policy estimators such as *Importance Sampling* re-weight returns from a behaviour policy $mu$ to evaluate a target policy $pi$. - -== 3 Method -Our algorithm alternates between: -- *Phase 1* — learn latent representation $phi(s)$ via *objective*, -- *Phase 2* — optimise policy $pi_theta(a|phi(s))$ with clipped objective $J(theta) = E[ min( rho_t dot hat(A) , op("clip")(rho_t, 1-epsilon,1+epsilon) hat(A) ) ]$. - -== 4 Experiments -We conduct experiments on *benchmark suite*. Results in Figure 1 show that our method achieves *higher sample efficiency* and *lower variance* than baseline algorithms. - -== 5 Conclusion -We presented *Your Algorithm*, a principled approach that improves both learning speed and final performance. Future work includes extending the method to partially-observable settings. - -== References -- Sutton, R. S. & Barto, A. G. *Reinforcement Learning: An Introduction*. MIT Press, 2018. -- Mnih, V. et al. Human-level control through deep reinforcement learning. *Nature* *518*, 529–533, 2015. -- Schulman, J. et al. Proximal policy optimization algorithms. arXiv:1707.06347, 2017. -``` - -## Key Principles -Please note: Typst is **not** LaTeX, nor is it **standard Markdown**. They are incompatible on key syntax terms. Please strictly adhere to the following rules to avoid confusion. - -### Core Mindset - -* **Abandon LaTeX Habits**: Do not use `\begin{}`, `\frac{}{}`, `\textbf{}`. -* **Abandon Markdown Habits**: Do not use `**bold**` (double asterisks). -* **Bracket Awareness**: Function calls always use parentheses `func()`, only content blocks use square brackets `[]`, and code blocks use curly braces `{}`. - -### Critical Constraints -| Category | **Strictly Forbidden (LaTeX/MD)** | **Mandatory in Typst** | Reason / Explanation | -| :--- | :--- | :--- | :--- | -| **Bold** | `**text**` or `__text__` | `*text*` | Double asterisks are invalid in Typst; a **single asterisk** is used for bold. | -| **Italic** | `*text*` | `_text_` | The underscore is used for italics. | -| **Function Arguments** | `\sqrt{x}`, `\hat{x}`, `vec{x}` | `sqrt(x)`, `hat(x)`, `vec(x)` | **Always use parentheses** to wrap arguments. `{}` is only for code blocks. | -| **Fractions** | `\frac{a}{b}` | `(a)/(b)` | Use the division operator with parentheses if necessary. | -| **Greek Letters** | `\alpha`, `\beta` | `alpha`, `beta` | No backslash is needed. | -| **Subscript** | `x_{i}` | `x_i` | Although `x_{i}` is also valid in Typst, it is recommended to use `x_i` or `x_(i)`. | -| **Escaping** | `\#`, `\$` | `\#`, `\$` | To display `#` or `$` in text, they must be escaped. | - -### Math mode -Mathematical expressions are wrapped by `$`. Please strictly distinguish between **inline** and **block** formulas: - -* **Inline Formula**: Must be flush with content, **no spaces**. - * ❌ Wrong: `$ x^2 $` (This becomes block-level) - * ✅ Correct: `$x^2$` (Embedded within a text line) -* **Block Formula**: **Must have spaces** on both ends. - * ✅ Correct: `$ x^2 + y^2 = 1 $` -* **Operators and Text**: - * Standard functions (e.g., `sin`, `cos`, `max`, `log`) are written directly. - * **Custom text/variable names** (e.g., Loss, clip, attention): Must be enclosed in quotes or use the `op` function; otherwise, they will be parsed as variable multiplication. - * Example: `$L_(op("clip"))$` or `$text("Area") = x^2$`. -* **Symbol Mapping**: - * Multiplication: `dot` (dot product $\cdot$), `times` (cross product $\times$) - * Sets: `in` ($\in$), `subset` ($\subset$) - * Arrows: `->` ($\rightarrow$), `=>` ($\Rightarrow$) - * Infinity: `infinity` ($\infty$) - * Integral: `integral` ($\int$) - -## Font Safety Constraints - -### 1. Mandatory System Default Fonts -When generating any Typst code containing non-ASCII characters (especially Chinese, Japanese, or Korean), **you are strictly forbidden** from using fonts that require manual installation (e.g., `"Noto Serif CJK SC"`, `"Source Han Serif SC"`, `"LXGW WenKai"`, or any custom downloaded font). -- You **must** use operating-system preinstalled default fonts only. -- You **must** provide at least three layers of fallback covering Windows, macOS, and Linux. -- You **must** explicitly set `fallback: true` in every `#set text(...)` rule that includes CJK content. - -### 2. Allowed CJK Font Whitelist -CJK fonts **must** be chosen exclusively from the following system-default whitelist, arranged as a fallback chain: - -```typst -#set text( - font: ( - // Western font (optional but recommended) - "New Computer Modern", - // Chinese system font fallback chain - "SimSun", // Windows default Songti; highest coverage - "Songti SC", // macOS Songti - "PingFang SC", // macOS/iOS modern sans-serif - "Microsoft YaHei", // Windows default sans-serif - "WenQuanYi Micro Hei", // Common Linux font - ), - lang: "zh", - fallback: true, // MUST be explicitly enabled; never omit -) -``` - -### 3. Single-Platform Shortcuts -If the target system is explicitly known, you may shorten the chain, but you **must** retain at least two fallback layers: - -**Windows**: -```typst -#set text(font: ("New Computer Modern", "SimSun", "Microsoft YaHei"), lang: "zh", fallback: true) -``` - -**macOS**: -```typst -#set text(font: ("New Computer Modern", "Songti SC", "PingFang SC"), lang: "zh", fallback: true) -``` - -**Linux / Docker / WASM**: -```typst -#set text(font: ("New Computer Modern", "WenQuanYi Micro Hei", "Noto Sans CJK SC"), lang: "zh", fallback: true) -``` -> **Note**: On Linux containers where even WenQuanYi may be absent, you **must** embed font files via the compiler API, or downgrade to pure-English output. Never assume system fonts exist in sandboxed environments. - -### 4. Strictly Forbidden -- ❌ **Never** use `"Noto Serif CJK SC"` as a CJK font. -- ❌ **Never** use `"Source Han Serif SC"` as a CJK font. -- ❌ **Never** use any font requiring `apt install`, `apk add`, manual download, or package-manager installation. -- ❌ **Never** omit `fallback: true` when CJK text is present. -- ❌ **Never** specify only a single CJK font layer. -- ❌ **Never** output CJK text without a verified fallback chain. - -### 5. Default Safe Template -If the target environment cannot be determined, you **must** use the following maximum-compatibility configuration: - -```typst -#set text( - font: ("New Computer Modern", "SimSun", "PingFang SC", "Microsoft YaHei"), - lang: "zh", - fallback: true, -) -``` -> `SimSun` is present on virtually all Windows systems; `PingFang SC` is present on all macOS/iOS systems; `Microsoft YaHei` provides a sans-serif fallback. This combination prevents tofu (`[]`) when the preferred font is missing. - -## How to Use This Skill - -### Step 1. Check if the context provides a template -Check if the context provides a template. If so, strictly follow the template in your output. You can create other content with a more professional and aesthetically pleasing approach without violating the template, but the overall content must strictly adhere to the template. - -### Step 2. Fully consider the needs of users -Before you start outputting the typst content, consider what the user's requirements are. - -#### For Academic Papers / Articles -- **Setup**: `#set page(paper: "a4", margin: (x: 2cm, y: 2.5cm))` -- **Fonts**: Use professional serif fonts (e.g., `"Libertinus Serif"`, `"New Computer Modern"`) for Latin text. For CJK text, **strictly follow the Font Safety Constraints above**. -- **Columns**: Use `#show: rest => columns(2, rest)` for main body text if requested. -- **Bibliography**: Ensure usage of `#bibliography("refs.bib")`. - -#### For Resumes / CVs -- **Setup**: Minimize margins (e.g., `margin: 1cm`). -- **Layout**: Heavily utilize `grid()` or `stack()` for alignment (e.g., Left: Skills, Right: Experience). -- **Style**: Use `#set text(font: "Roboto" or "Source Sans Pro")` for a modern look. For CJK resumes, replace with system defaults per the Font Safety Constraints. -- **Visuals**: Use `#line(length: 100%)` for separators. - -#### For CJK Content (Chinese, Japanese, Korean) -- **Mandatory Font Rule**: You **must** apply the Font Safety Constraints. Use system-default fonts only (`SimSun`, `PingFang SC`, `Microsoft YaHei`, `WenQuanYi Micro Hei`) with `fallback: true`. -- **Forbidden Fonts**: Never use `"Noto Serif CJK SC"` or `"Source Han Serif SC"` unless the user explicitly confirms the font is pre-installed in the rendering environment. - -### Step 3. Start creating Typst content -Generate the complete Typst document according to the above rules, ensuring all syntax is valid Typst (not LaTeX or Markdown) and all font choices comply with the Font Safety Constraints. -``` - ---- - -### Key changes made in this English version: - -1. **Added the `Font Safety Constraints` section** right after `Key Principles`, making it impossible to miss. -2. **Hard-banned `"Noto Serif CJK SC"` and `"Source Han Serif SC"`** in the forbidden list. -3. **Mandated `fallback: true`** as a non-negotiable requirement for all CJK text. -4. **Replaced the Mini Example** font declaration with the safe system-default chain (`SimSun`, `PingFang SC`) instead of the old `"Noto Serif CJK SC"`. -5. **Added a CJK-specific subsection** in Step 2 to remind the model to apply font safety rules when handling Chinese content. -6. **Used strong negative constraints** (`Strictly Forbidden`, `Never`, `must not`) which are more effective for LLM behavior alignment than soft suggestions. \ No newline at end of file diff --git a/lib/agent/utils/learn-memories.test.ts b/lib/agent/utils/learn-memories.test.ts deleted file mode 100644 index f15bbb6..0000000 --- a/lib/agent/utils/learn-memories.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { - buildLearnMemoryPrompt, - formatLearnMemoryPrompt, - upsertLearnMemory, -} from "./learn-memories"; - -describe("learn memories", () => { - it("formats learned memories as a prompt section", () => { - const prompt = formatLearnMemoryPrompt("typst", [ - { - title: "Inline math spacing", - content: "Use `$x^2$` for inline math, not `$ x^2 $`.", - }, - { - title: "Typst bold syntax", - content: "Use `*important*` for bold text in Typst.", - }, - ]); - - expect(prompt).toContain("## Learned typst corrections"); - expect(prompt).toContain("1. Inline math spacing"); - expect(prompt).toContain("Use `$x^2$` for inline math"); - expect(prompt).toContain("2. Typst bold syntax"); - }); - - it("returns an empty prompt when there are no memories", () => { - expect(formatLearnMemoryPrompt("typst", [])).toBe(""); - }); - - it("reads memories by type with a default prompt limit", async () => { - const readMemories = jest.fn(async () => [ - { - title: "Inline math spacing", - content: "Use `$x^2$` for inline math.", - }, - ]); - - const prompt = await buildLearnMemoryPrompt("typst", { readMemories }); - - expect(readMemories).toHaveBeenCalledWith("typst", 20); - expect(prompt).toContain("Inline math spacing"); - }); - - it("upserts a trimmed learn memory through the provided writer", async () => { - const writeMemory = jest.fn(async () => undefined); - - await upsertLearnMemory( - { - type: "typst", - title: " Inline math spacing ", - content: " Use `$x^2$` for inline math. ", - }, - { writeMemory }, - ); - - expect(writeMemory).toHaveBeenCalledWith({ - type: "typst", - title: "Inline math spacing", - content: "Use `$x^2$` for inline math.", - }); - }); -}); diff --git a/lib/agent/utils/learn-memories.ts b/lib/agent/utils/learn-memories.ts deleted file mode 100644 index d0f27ad..0000000 --- a/lib/agent/utils/learn-memories.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { learnMemories } from "@/infra/schema/learn-memories"; -import { desc, eq } from "drizzle-orm"; - -const DEFAULT_LEARN_MEMORY_LIMIT = 20; - -type LearnMemoryPromptItem = { - title: string; - content: string; -}; - -type LearnMemoryReader = ( - type: string, - limit: number, -) => Promise; - -type LearnMemoryInput = { - type: string; - title: string; - content: string; -}; - -type LearnMemoryWriter = (memory: LearnMemoryInput) => Promise; - -type BuildLearnMemoryPromptOptions = { - limit?: number; - readMemories?: LearnMemoryReader; -}; - -type UpsertLearnMemoryOptions = { - writeMemory?: LearnMemoryWriter; -}; - -const readLearnMemoriesByType: LearnMemoryReader = async (type, limit) => { - const { db } = await import("@/infra/drizzle"); - const rows = await db - .select({ - title: learnMemories.title, - content: learnMemories.content, - }) - .from(learnMemories) - .where(eq(learnMemories.type, type)) - .orderBy(desc(learnMemories.usageCount), desc(learnMemories.updatedAt)) - .limit(limit); - - return rows; -}; - -const writeLearnMemory: LearnMemoryWriter = async ({ - content, - title, - type, -}) => { - const { db } = await import("@/infra/drizzle"); - const now = new Date(); - - await db - .insert(learnMemories) - .values({ - type, - title, - content, - updatedAt: now, - }) - .onConflictDoUpdate({ - target: [learnMemories.type, learnMemories.title], - set: { - content, - updatedAt: now, - }, - }); -}; - -const formatLearnMemoryPrompt = ( - type: string, - memories: LearnMemoryPromptItem[], -): string => { - if (memories.length === 0) { - return ""; - } - - const lines = memories.map( - ({ content, title }, index) => `${index + 1}. ${title}\n${content}`, - ); - - return `## Learned ${type} corrections\n${lines.join("\n\n")}`; -}; - -const buildLearnMemoryPrompt = async ( - type: string, - options: BuildLearnMemoryPromptOptions = {}, -): Promise => { - const limit = options.limit ?? DEFAULT_LEARN_MEMORY_LIMIT; - const readMemories = options.readMemories ?? readLearnMemoriesByType; - const memories = await readMemories(type, limit); - - return formatLearnMemoryPrompt(type, memories); -}; - -const upsertLearnMemory = async ( - input: LearnMemoryInput, - options: UpsertLearnMemoryOptions = {}, -): Promise => { - const memory = { - type: input.type.trim(), - title: input.title.trim(), - content: input.content.trim(), - }; - - if (!memory.type || !memory.title || !memory.content) { - return; - } - - const writeMemory = options.writeMemory ?? writeLearnMemory; - await writeMemory(memory); -}; - -export { - DEFAULT_LEARN_MEMORY_LIMIT, - buildLearnMemoryPrompt, - formatLearnMemoryPrompt, - readLearnMemoriesByType, - upsertLearnMemory, - writeLearnMemory, -}; -export type { - BuildLearnMemoryPromptOptions, - LearnMemoryInput, - LearnMemoryPromptItem, - LearnMemoryReader, - LearnMemoryWriter, - UpsertLearnMemoryOptions, -}; diff --git a/lib/chat/workspace-hydration.ts b/lib/chat/workspace-hydration.ts index 89b8681..4663e4a 100644 --- a/lib/chat/workspace-hydration.ts +++ b/lib/chat/workspace-hydration.ts @@ -38,7 +38,7 @@ type WorkspaceSnapshot = { chart: WorkspaceChart | null; dataset: WorkspaceDataset | null; file: WorkspaceFile | null; - typstContent: string; + markdownContent: string; }; const EMPTY_WORKSPACE_SNAPSHOT: WorkspaceSnapshot = { @@ -47,7 +47,7 @@ const EMPTY_WORKSPACE_SNAPSHOT: WorkspaceSnapshot = { chart: null, dataset: null, file: null, - typstContent: "", + markdownContent: "", }; const EMPTY_WORKSPACE_ROUND_ARTIFACTS: WorkspaceRoundArtifacts = { @@ -486,12 +486,12 @@ const deriveWorkspaceSnapshotFromMessages = ( for (const part of message.parts) { const partRecord = part as Record; if ( - partRecord.type === "typst-content" && + partRecord.type === "markdown-content" && typeof partRecord.content === "string" && partRecord.content.length > 0 ) { - snapshot.typstContent = partRecord.content; - markViewUpdated("typst"); + snapshot.markdownContent = partRecord.content; + markViewUpdated("markdown"); } } diff --git a/lib/typst-worker.ts b/lib/typst-worker.ts deleted file mode 100644 index 39b938c..0000000 --- a/lib/typst-worker.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { configureTypstCompilerFonts } from "@/lib/typst/font-assets"; -import type { WorkerMessage, WorkerResponse } from "@/types/worker"; - -let isInitialized = false; -let $typst: - | Awaited["$typst"] - | null = null; - -const origin = self.location.origin; - -const initTypstCompiler = async () => { - try { - postMessage({ - type: "init-start", - message: "Loading wasm...", - } as WorkerResponse); - - const typstModule = await import("@myriaddreamin/typst.ts/contrib/snippet"); - $typst = typstModule.$typst; - configureTypstCompilerFonts($typst); - - $typst.setCompilerInitOptions({ - getModule: () => `${origin}/typst_ts_web_compiler_bg.wasm`, - }); - - $typst.setRendererInitOptions({ - getModule: () => `${origin}/typst_ts_renderer_bg.wasm`, - }); - - postMessage({ - type: "init-start", - message: "The compiler is being initialized", - } as WorkerResponse); - - isInitialized = true; - postMessage({ type: "init-complete" } as WorkerResponse); - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - postMessage({ type: "error", error: errorMessage } as WorkerResponse); - } -}; - -const compileSvg = async (content: string) => { - try { - if (!isInitialized) { - throw new Error("Compiler not initialized"); - } - - if (!$typst) { - throw new Error("Compiler not initialized"); - } - - postMessage({ type: "compile-start" } as WorkerResponse); - - const svgString = await $typst.svg({ - mainContent: content, - }); - - if (!svgString) { - throw new Error("Failed to compile typst content"); - } - - postMessage({ type: "compile-complete", svg: svgString } as WorkerResponse); - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - postMessage({ type: "error", error: errorMessage } as WorkerResponse); - } -}; - -self.onmessage = async (event: MessageEvent) => { - const { type } = event.data; - - switch (type) { - case "init": - await initTypstCompiler(); - break; - case "compile": - await compileSvg(event.data.content); - break; - case "terminate": - self.close(); - break; - default: - postMessage({ - type: "error", - error: `Unknown message type: ${type}`, - } as WorkerResponse); - } -}; diff --git a/lib/typst/compiler.test.ts b/lib/typst/compiler.test.ts deleted file mode 100644 index 32c7fc8..0000000 --- a/lib/typst/compiler.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @jest-environment node - */ - -import { createTypstCompiler } from "./compiler"; - -describe("compileTypst", () => { - it("compiles valid Typst content to SVG", async () => { - const compileTypst = createTypstCompiler({ - svg: async ({ mainContent }) => `${mainContent}`, - }); - - const result = await compileTypst("= Hello\n\nThis is *Typst*."); - - expect(result.ok).toBe(true); - if (!result.ok) { - throw new Error(result.error); - } - expect(result.svg).toContain(" { - const compileTypst = createTypstCompiler({ - svg: async () => { - throw new Error("unclosed delimiter"); - }, - }); - - const result = await compileTypst("= Broken\n\n#unknown-function("); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error("Expected Typst compilation to fail."); - } - expect(result.error).toContain("unclosed delimiter"); - expect(result.diagnostics).toContain("unclosed delimiter"); - }); -}); diff --git a/lib/typst/compiler.ts b/lib/typst/compiler.ts deleted file mode 100644 index 6d97c82..0000000 --- a/lib/typst/compiler.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { $typst } from "@myriaddreamin/typst.ts"; -import { configureTypstCompilerFonts } from "./font-assets"; - -type TypstCompileSuccess = { - ok: true; - svg: string; -}; - -type TypstCompileFailure = { - ok: false; - error: string; - diagnostics: string; -}; - -type TypstCompileResult = TypstCompileSuccess | TypstCompileFailure; - -type TypstSvgCompiler = { - svg: (input: { mainContent: string }) => Promise; -}; - -const formatTypstError = (error: unknown): string => { - if (error instanceof Error && error.message.trim().length > 0) { - return error.message.trim(); - } - - return String(error).trim(); -}; - -const createTypstCompiler = - (compiler: TypstSvgCompiler) => - async (content: string): Promise => { - try { - const svg = await compiler.svg({ - mainContent: content, - }); - - if (!svg) { - return { - ok: false, - error: "Typst compiler returned an empty SVG.", - diagnostics: "Typst compiler returned an empty SVG.", - }; - } - - return { - ok: true, - svg, - }; - } catch (error) { - const message = formatTypstError(error); - - return { - ok: false, - error: message, - diagnostics: message, - }; - } - }; - -configureTypstCompilerFonts($typst); - -const compileTypst = createTypstCompiler($typst); - -export { compileTypst, createTypstCompiler, formatTypstError }; -export type { - TypstCompileFailure, - TypstCompileResult, - TypstCompileSuccess, - TypstSvgCompiler, -}; diff --git a/lib/typst/font-assets.test.ts b/lib/typst/font-assets.test.ts deleted file mode 100644 index 4e88e79..0000000 --- a/lib/typst/font-assets.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { - type TypstFontProvider, - configureTypstCompilerFonts, -} from "./font-assets"; - -describe("configureTypstCompilerFonts", () => { - it("registers text, CJK, and emoji font assets", () => { - const provider: TypstFontProvider = { - key: "font-assets", - forRoles: ["compiler"], - provides: [], - }; - const createFontProvider = jest.fn(() => provider); - const compiler = { - use: jest.fn(), - }; - - configureTypstCompilerFonts(compiler, createFontProvider); - - expect(createFontProvider).toHaveBeenCalledWith({ - assets: ["text", "cjk", "emoji"], - }); - expect(compiler.use).toHaveBeenCalledWith(provider); - }); -}); diff --git a/lib/typst/font-assets.ts b/lib/typst/font-assets.ts deleted file mode 100644 index 3462068..0000000 --- a/lib/typst/font-assets.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { TypstSnippet } from "@myriaddreamin/typst.ts/contrib/snippet"; - -type TypstFontAsset = "text" | "cjk" | "emoji"; - -type TypstFontProvider = ReturnType; - -type TypstFontConfigurableCompiler = { - use: (...providers: TypstFontProvider[]) => void; -}; - -type CreateTypstFontProvider = (options: { - assets: TypstFontAsset[]; -}) => TypstFontProvider; - -const TYPST_FONT_ASSETS: TypstFontAsset[] = ["text", "cjk", "emoji"]; - -const configureTypstCompilerFonts = ( - compiler: TypstFontConfigurableCompiler, - createFontProvider: CreateTypstFontProvider = TypstSnippet.preloadFontAssets, -): void => { - compiler.use( - createFontProvider({ - assets: TYPST_FONT_ASSETS, - }), - ); -}; - -export { TYPST_FONT_ASSETS, configureTypstCompilerFonts }; -export type { - CreateTypstFontProvider, - TypstFontAsset, - TypstFontConfigurableCompiler, - TypstFontProvider, -}; diff --git a/lib/typst/text-fallback.test.ts b/lib/typst/text-fallback.test.ts deleted file mode 100644 index 01aa8a9..0000000 --- a/lib/typst/text-fallback.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { ensureTypstTextFallback } from "./text-fallback"; - -const DEFAULT_TEXT_SET = `#set text( - font: ("New Computer Modern", "SimSun", "PingFang SC", "Microsoft YaHei"), - lang: "zh", - fallback: true, -)`; - -describe("ensureTypstTextFallback", () => { - it("prepends the default text set when Typst has no text font setting", () => { - const result = ensureTypstTextFallback("= Report\n\n中文内容"); - - expect(result).toBe(`${DEFAULT_TEXT_SET}\n\n= Report\n\n中文内容`); - }); - - it("adds fallback true to an existing text font setting", () => { - const result = ensureTypstTextFallback(`#set text( - font: ("Noto Serif CJK SC", "SimSun"), - lang: "zh", -) - -= Report`); - - expect(result).toBe(`#set text( - font: ("Noto Serif CJK SC", "SimSun"), - lang: "zh", - fallback: true, -) - -= Report`); - }); - - it("replaces an existing false fallback in a text font setting", () => { - const result = ensureTypstTextFallback(`#set text( - font: "SimSun", - fallback: false, -) - -= Report`); - - expect(result).toBe(`#set text( - font: "SimSun", - fallback: true, -) - -= Report`); - }); - - it("does not duplicate an existing true fallback", () => { - const input = `#set text( - font: ("New Computer Modern", "SimSun"), - fallback: true, -) - -= Report`; - - expect(ensureTypstTextFallback(input)).toBe(input); - }); -}); diff --git a/lib/typst/text-fallback.ts b/lib/typst/text-fallback.ts deleted file mode 100644 index 5947517..0000000 --- a/lib/typst/text-fallback.ts +++ /dev/null @@ -1,115 +0,0 @@ -const DEFAULT_TYPST_TEXT_SET = `#set text( - font: ("New Computer Modern", "SimSun", "PingFang SC", "Microsoft YaHei"), - lang: "zh", - fallback: true, -)`; - -type TextSetBlock = { - openParen: number; - end: number; - body: string; -}; - -const findTextSetBlock = (content: string): TextSetBlock | undefined => { - const setTextPattern = /#set\s+text\s*\(/g; - let match = setTextPattern.exec(content); - - while (match) { - const matchedText = match[0] ?? ""; - const openParen = match.index + matchedText.lastIndexOf("("); - let depth = 0; - let inString = false; - let escaped = false; - - for (let index = openParen; index < content.length; index += 1) { - const char = content[index]; - - if (!char) { - continue; - } - - if (escaped) { - escaped = false; - continue; - } - - if (char === "\\") { - escaped = true; - continue; - } - - if (char === '"') { - inString = !inString; - continue; - } - - if (inString) { - continue; - } - - if (char === "(") { - depth += 1; - continue; - } - - if (char === ")") { - depth -= 1; - if (depth === 0) { - const body = content.slice(openParen + 1, index); - if (/(^|[\s,])font\s*:/.test(body)) { - return { - openParen, - end: index, - body, - }; - } - break; - } - } - } - - match = setTextPattern.exec(content); - } - - return undefined; -}; - -const buildBodyWithFallback = (body: string): string => { - const lines = body.split("\n"); - let insertIndex = lines.length; - - while (insertIndex > 0 && (lines[insertIndex - 1] ?? "").trim() === "") { - insertIndex -= 1; - } - - const previousLine = lines[insertIndex - 1] ?? ""; - if (previousLine.trim().length > 0 && !previousLine.trimEnd().endsWith(",")) { - lines[insertIndex - 1] = `${previousLine},`; - } - - const indent = previousLine.match(/^(\s*)/)?.[1] || " "; - lines.splice(insertIndex, 0, `${indent}fallback: true,`); - - return lines.join("\n"); -}; - -const ensureTypstTextFallback = (content: string): string => { - const textSetBlock = findTextSetBlock(content); - - if (!textSetBlock) { - return `${DEFAULT_TYPST_TEXT_SET}\n\n${content}`; - } - - const { body, openParen, end } = textSetBlock; - if (/(^|[\s,])fallback\s*:\s*true([\s,)]|,|$)/.test(body)) { - return content; - } - - const updatedBody = /(^|[\s,])fallback\s*:/.test(body) - ? body.replace(/fallback\s*:\s*(true|false)/, "fallback: true") - : buildBodyWithFallback(body); - - return `${content.slice(0, openParen + 1)}${updatedBody}${content.slice(end)}`; -}; - -export { DEFAULT_TYPST_TEXT_SET, ensureTypstTextFallback }; diff --git a/messages/en.json b/messages/en.json index 9073052..9fa8556 100644 --- a/messages/en.json +++ b/messages/en.json @@ -109,7 +109,7 @@ "sandboxViewer": "Sandbox Viewer", "chartViewer": "Chart Viewer", "datasetViewer": "Dataset Viewer", - "typstViewer": "Typst Preview", + "textViewer": "Text Preview", "datasetSummary": "{rows} rows, {columns} columns, sheet {sheet}", "downloadArtifact": "Download", "chartGeneratedAt": "Generated at {time}", diff --git a/messages/zh.json b/messages/zh.json index 73df2bf..8b56ffa 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -109,7 +109,7 @@ "sandboxViewer": "沙盒查看器", "chartViewer": "图表查看器", "datasetViewer": "数据表查看器", - "typstViewer": "Typst 预览", + "textViewer": "文本预览", "datasetSummary": "{rows} 行,{columns} 列,工作表 {sheet}", "downloadArtifact": "下载", "chartGeneratedAt": "生成时间 {time}", diff --git a/package.json b/package.json index c773705..da9494d 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,6 @@ "@aws-sdk/client-s3": "^3.1024.0", "@e2b/code-interpreter": "^2.4.0", "@e2b/desktop": "^2.2.2", - "@myriaddreamin/typst-ts-renderer": "0.7.0-rc2", - "@myriaddreamin/typst-ts-web-compiler": "0.7.0-rc2", - "@myriaddreamin/typst.ts": "0.7.0-rc2", "@neondatabase/auth": "0.2.0-beta.1", "@neondatabase/neon-js": "0.2.0-beta.1", "@neondatabase/serverless": "^1.1.0", @@ -55,7 +52,9 @@ "iconv-lite": "^0.7.2", "input-otp": "^1.4.2", "jotai": "^2.18.0", + "katex": "^0.16.45", "lucide-react": "^0.575.0", + "mermaid": "^11.14.0", "next": "16.1.1", "next-intl": "^4.9.0", "next-themes": "^0.4.6", @@ -64,6 +63,10 @@ "react-dom": "19.2.3", "react-markdown": "^10.1.0", "react-resizable-panels": "^4", + "rehype-katex": "^7.0.1", + "rehype-raw": "^7.0.0", + "remark-gfm": "^4.0.1", + "remark-math": "^6.0.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "undici": "^8.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1b75525..e3471ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,15 +20,6 @@ importers: '@e2b/desktop': specifier: ^2.2.2 version: 2.2.2 - '@myriaddreamin/typst-ts-renderer': - specifier: 0.7.0-rc2 - version: 0.7.0-rc2 - '@myriaddreamin/typst-ts-web-compiler': - specifier: 0.7.0-rc2 - version: 0.7.0-rc2 - '@myriaddreamin/typst.ts': - specifier: 0.7.0-rc2 - version: 0.7.0-rc2(@myriaddreamin/typst-ts-renderer@0.7.0-rc2)(@myriaddreamin/typst-ts-web-compiler@0.7.0-rc2) '@neondatabase/auth': specifier: 0.2.0-beta.1 version: 0.2.0-beta.1(85ca8aaaf0dc70c8971f70acc0d3d7de) @@ -110,9 +101,15 @@ importers: jotai: specifier: ^2.18.0 version: 2.18.0(@babel/core@7.28.5)(@babel/template@7.28.6)(@types/react@19.2.0)(react@19.2.3) + katex: + specifier: ^0.16.45 + version: 0.16.45 lucide-react: specifier: ^0.575.0 version: 0.575.0(react@19.2.3) + mermaid: + specifier: ^11.14.0 + version: 11.14.0 next: specifier: 16.1.1 version: 16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -137,6 +134,18 @@ importers: react-resizable-panels: specifier: ^4 version: 4.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + rehype-katex: + specifier: ^7.0.1 + version: 7.0.1 + rehype-raw: + specifier: ^7.0.0 + version: 7.0.0 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 + remark-math: + specifier: ^6.0.0 + version: 6.0.0 sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -260,6 +269,9 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + '@antfu/ni@25.0.0': resolution: {integrity: sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA==} hasBin: true @@ -777,6 +789,9 @@ packages: cpu: [x64] os: [win32] + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + '@bufbuild/protobuf@2.11.0': resolution: {integrity: sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==} @@ -789,6 +804,21 @@ packages: '@captchafox/types@1.4.0': resolution: {integrity: sha512-4xnPMICLinsXghw6zWEF436lhMsBmLxui2QmU7xAEz/+572BRdvc518Sz5OoofbJ7GZG6QPz/wOtJoN8BfKyCg==} + '@chevrotain/cst-dts-gen@12.0.0': + resolution: {integrity: sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==} + + '@chevrotain/gast@12.0.0': + resolution: {integrity: sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==} + + '@chevrotain/regexp-to-ast@12.0.0': + resolution: {integrity: sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==} + + '@chevrotain/types@12.0.0': + resolution: {integrity: sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==} + + '@chevrotain/utils@12.0.0': + resolution: {integrity: sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==} + '@connectrpc/connect-web@2.0.0-rc.3': resolution: {integrity: sha512-w88P8Lsn5CCsA7MFRl2e6oLY4J/5toiNtJns/YJrlyQaWOy3RO8pDgkz+iIkG98RPMhj2thuBvsd3Cn4DKKCkw==} peerDependencies: @@ -1443,6 +1473,12 @@ packages: peerDependencies: react-hook-form: ^7.55.0 + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@3.1.1': + resolution: {integrity: sha512-MwzoDtw9rO1x+qfgLTV/IVXsHDBqeYZoMIQC8SfxfYSlaSUG+oWiAcoiB1yajAda6mqblm4/1/w2E8tRu7a7Tw==} + '@img/colour@1.0.0': resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} engines: {node: '>=18'} @@ -1787,6 +1823,9 @@ packages: react: ^17.0.2 || ^18.0.0 || ^19.0 react-dom: ^17.0.2 || ^18.0.0 || ^19.0 + '@mermaid-js/parser@1.1.0': + resolution: {integrity: sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==} + '@modelcontextprotocol/sdk@1.27.1': resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} engines: {node: '>=18'} @@ -1801,23 +1840,6 @@ packages: resolution: {integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==} engines: {node: '>=18'} - '@myriaddreamin/typst-ts-renderer@0.7.0-rc2': - resolution: {integrity: sha512-god1tcb2YJDkQfA8gLGcAmykVGBpNKorqqDkXVy3InC18KRbsverJhlrHoONurNIU9JuIHoWjJ2D1ntpjPgzbA==} - - '@myriaddreamin/typst-ts-web-compiler@0.7.0-rc2': - resolution: {integrity: sha512-WFO/ecKUfeclld5uDxyjgpnIafKpp2LrS6T1vY+CHaSxCm099AneAQIYFg+OtX+NbFpJsLGCBFSw/qppJJmBAw==} - - '@myriaddreamin/typst.ts@0.7.0-rc2': - resolution: {integrity: sha512-VM8JqsRcL3AEJ5cuPBn/YvnGTXK/BRPlxdGB2bR48Of/8OIGaPiunv2QfZBIMBBrtbTygUOtAY9BZvkS1AFqgA==} - peerDependencies: - '@myriaddreamin/typst-ts-renderer': ^0.7.0-rc2 - '@myriaddreamin/typst-ts-web-compiler': ^0.7.0-rc2 - peerDependenciesMeta: - '@myriaddreamin/typst-ts-renderer': - optional: true - '@myriaddreamin/typst-ts-web-compiler': - optional: true - '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -3817,6 +3839,99 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/debug@4.1.13': resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} @@ -3826,6 +3941,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -3848,6 +3966,9 @@ packages: '@types/jsdom@21.1.7': resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==} + '@types/katex@0.16.8': + resolution: {integrity: sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==} + '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -3889,6 +4010,9 @@ packages: '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -4013,6 +4137,9 @@ packages: cpu: [x64] os: [win32] + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + '@vercel/oidc@3.1.0': resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} engines: {node: '>= 20'} @@ -4338,6 +4465,15 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chevrotain-allstar@0.4.3: + resolution: {integrity: sha512-2X4mkroolSMKqW+H22pyPMUVDqYZzPhephTmg/NODKb1IGYPHfxfhcW0EjS7wcPJNbze2i4vBWT7zT5FKF2lrQ==} + peerDependencies: + chevrotain: ^12.0.0 + + chevrotain@12.0.0: + resolution: {integrity: sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==} + engines: {node: '>=22.0.0'} + chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -4436,12 +4572,23 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + compare-versions@6.1.1: resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + content-disposition@1.0.1: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} engines: {node: '>=18'} @@ -4476,6 +4623,12 @@ packages: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + cosmiconfig@9.0.0: resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} engines: {node: '>=14'} @@ -4515,6 +4668,162 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.33.3: + resolution: {integrity: sha512-Gej7U+OKR+LZ8kvX7rb2HhCYJ0IhvEFsnkud4SB1PR+BUY/TsSO0dmOW59WEVLu51b1Rm+gQRKoz4bLYxGSZ2g==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} @@ -4523,6 +4832,9 @@ packages: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -4565,6 +4877,9 @@ packages: defu@6.1.6: resolution: {integrity: sha512-f8mefEW4WIVg4LckePx3mALjQSPQgFlg9U8yaPdlsbdYcHQyj9n2zL2LJEA52smeYxOvmd/nB7TpMtHGMTHcug==} + delaunator@5.1.0: + resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -4627,6 +4942,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.4.2: + resolution: {integrity: sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -4848,6 +5166,10 @@ packages: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -5135,6 +5457,9 @@ packages: resolution: {integrity: sha512-uSisMYERbaB9bkA9M4/4dnqyktaEkf1kMHNKq/7DHyxVeWqHQ2mBmVqm5u6/FVHwF3iCNalKcg82Zfl+tffWoA==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -5151,12 +5476,42 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hast-util-from-dom@5.0.1: + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} + + hast-util-from-html-isomorphic@2.0.0: + resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + hast-util-to-jsx-runtime@2.3.6: resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + headers-polyfill@4.0.3: resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} @@ -5181,6 +5536,9 @@ packages: html-url-attributes@3.0.1: resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} @@ -5220,9 +5578,6 @@ packages: icu-minify@4.9.0: resolution: {integrity: sha512-9ev7MqkN29jcIelUAqJRfNCxzGOEkBJPnr+scYATMp2bfpU4Bm1eIwYU0/o5xRy8BBnSWMUjK58WTB3132P0bg==} - idb@7.1.1: - resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -5263,6 +5618,13 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + intl-messageformat@11.2.0: resolution: {integrity: sha512-IhghAA8n4KSlXuWKzYsWyWb82JoYTzShfyvdSF85oJPnNOjvv4kAo7S7Jtkm3/vJ53C7dQNRO+Gpnj3iWgTjBQ==} @@ -5638,6 +6000,13 @@ packages: resolution: {integrity: sha512-HIf1uwublnXZsy7p3yHTrhzMzrLO6xKnqXytT9pEil5QxaXi8eyer7Is4luF5hYSV4kD3v03Y32FWoAeVYTghQ==} hasBin: true + katex@0.16.45: + resolution: {integrity: sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==} + hasBin: true + + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -5650,6 +6019,16 @@ packages: resolution: {integrity: sha512-r2clcf7HLWvDXaVUEvQymXJY4i3bSOIV3xsL/Upy3ZfSv5HeKsk9tsqbBptLvth5qHEIhxeHTA2jNLyQABkLBA==} engines: {node: '>=20.0.0'} + langium@4.2.3: + resolution: {integrity: sha512-sOPIi4hISFnY7twwV97ca1TsxpBtXq0URu/LL1AvxwccPG/RIBBlKS7a/f/EL6w8lTNaS0EFs/F+IdSOaqYpng==} + engines: {node: '>=20.10.0', npm: '>=10.2.3'} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + leac@0.6.0: resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} @@ -5747,6 +6126,9 @@ packages: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} @@ -5799,18 +6181,50 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked@15.0.12: resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} engines: {node: '>= 18'} hasBin: true + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + mdast-util-from-markdown@2.0.3: resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-math@3.0.0: + resolution: {integrity: sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==} + mdast-util-mdx-expression@2.0.1: resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} @@ -5851,9 +6265,36 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + mermaid@11.14.0: + resolution: {integrity: sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==} + micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-math@3.1.0: + resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==} + micromark-factory-destination@2.0.1: resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} @@ -5968,6 +6409,9 @@ packages: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + mnemonist@0.39.6: resolution: {integrity: sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==} @@ -6221,6 +6665,9 @@ packages: path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -6258,6 +6705,9 @@ packages: path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + peberminta@0.9.0: resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} @@ -6334,6 +6784,9 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + platform@1.3.6: resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} @@ -6350,6 +6803,12 @@ packages: po-parser@2.1.1: resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==} + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + postcss-selector-parser@7.1.1: resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} @@ -6591,12 +7050,27 @@ packages: reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + rehype-katex@7.0.1: + resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-math@6.0.0: + resolution: {integrity: sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==} + remark-parse@11.0.0: resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} remark-rehype@11.1.2: resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -6651,9 +7125,15 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + rou3@0.7.12: resolution: {integrity: sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==} + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -6668,6 +7148,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + safe-regex2@3.1.0: resolution: {integrity: sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==} @@ -6916,6 +7399,9 @@ packages: babel-plugin-macros: optional: true + stylis@4.4.0: + resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==} + superjson@2.2.6: resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} engines: {node: '>=16'} @@ -7037,6 +7523,10 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + ts-morph@26.0.0: resolution: {integrity: sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==} @@ -7104,6 +7594,9 @@ packages: resolution: {integrity: sha512-OsqGhxyo/wGdLSXMSJxuMGN6H4gDnKz6Fb3IBm4bxZFMnyy0sdf6MN96Ie8tC6z/btdO+Bsy8guxlvLdwT076w==} hasBin: true + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -7118,12 +7611,18 @@ packages: unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} unist-util-position@5.0.0: resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} @@ -7214,18 +7713,35 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + vfile-message@4.0.3: resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + vscode-languageserver-textdocument@1.0.12: resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} vscode-languageserver-types@3.17.5: resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -7236,6 +7752,9 @@ packages: warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} @@ -7427,6 +7946,11 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.6.0 + tinyexec: 1.0.2 + '@antfu/ni@25.0.0': dependencies: ansis: 4.2.0 @@ -8285,6 +8809,8 @@ snapshots: '@biomejs/cli-win32-x64@1.9.4': optional: true + '@braintree/sanitize-url@7.1.2': {} + '@bufbuild/protobuf@2.11.0': {} '@captchafox/react@1.11.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': @@ -8295,6 +8821,21 @@ snapshots: '@captchafox/types@1.4.0': {} + '@chevrotain/cst-dts-gen@12.0.0': + dependencies: + '@chevrotain/gast': 12.0.0 + '@chevrotain/types': 12.0.0 + + '@chevrotain/gast@12.0.0': + dependencies: + '@chevrotain/types': 12.0.0 + + '@chevrotain/regexp-to-ast@12.0.0': {} + + '@chevrotain/types@12.0.0': {} + + '@chevrotain/utils@12.0.0': {} + '@connectrpc/connect-web@2.0.0-rc.3(@bufbuild/protobuf@2.11.0)(@connectrpc/connect@2.0.0-rc.3(@bufbuild/protobuf@2.11.0))': dependencies: '@bufbuild/protobuf': 2.11.0 @@ -8759,6 +9300,14 @@ snapshots: '@standard-schema/utils': 0.3.0 react-hook-form: 7.72.1(react@19.2.3) + '@iconify/types@2.0.0': {} + + '@iconify/utils@3.1.1': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + mlly: 1.8.2 + '@img/colour@1.0.0': optional: true @@ -9152,6 +9701,10 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) + '@mermaid-js/parser@1.1.0': + dependencies: + langium: 4.2.3 + '@modelcontextprotocol/sdk@1.27.1(zod@3.25.76)': dependencies: '@hono/node-server': 1.19.9(hono@4.12.3) @@ -9183,17 +9736,6 @@ snapshots: outvariant: 1.4.3 strict-event-emitter: 0.5.1 - '@myriaddreamin/typst-ts-renderer@0.7.0-rc2': {} - - '@myriaddreamin/typst-ts-web-compiler@0.7.0-rc2': {} - - '@myriaddreamin/typst.ts@0.7.0-rc2(@myriaddreamin/typst-ts-renderer@0.7.0-rc2)(@myriaddreamin/typst-ts-web-compiler@0.7.0-rc2)': - dependencies: - idb: 7.1.1 - optionalDependencies: - '@myriaddreamin/typst-ts-renderer': 0.7.0-rc2 - '@myriaddreamin/typst-ts-web-compiler': 0.7.0-rc2 - '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.7.1 @@ -11477,33 +12019,152 @@ snapshots: dependencies: '@types/node': 20.19.19 - '@types/debug@4.1.13': + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': dependencies: - '@types/ms': 2.1.0 + '@types/d3-selection': 3.0.11 - '@types/estree-jsx@1.0.5': + '@types/d3-brush@3.0.6': dependencies: - '@types/estree': 1.0.8 + '@types/d3-selection': 3.0.11 - '@types/estree@1.0.8': {} + '@types/d3-chord@3.0.6': {} - '@types/hast@3.0.4': + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': dependencies: - '@types/unist': 3.0.3 + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 - '@types/iconv-lite@0.0.1': + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': dependencies: - '@types/node': 20.19.19 + '@types/d3-selection': 3.0.11 - '@types/istanbul-lib-coverage@2.0.6': {} + '@types/d3-dsv@3.0.7': {} - '@types/istanbul-lib-report@3.0.3': + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': dependencies: - '@types/istanbul-lib-coverage': 2.0.6 + '@types/d3-dsv': 3.0.7 - '@types/istanbul-reports@3.0.4': + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': dependencies: - '@types/istanbul-lib-report': 3.0.3 + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + + '@types/estree@1.0.8': {} + + '@types/geojson@7946.0.16': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/iconv-lite@0.0.1': + dependencies: + '@types/node': 20.19.19 + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 '@types/jest@30.0.0': dependencies: @@ -11516,6 +12177,8 @@ snapshots: '@types/tough-cookie': 4.0.5 parse5: 7.3.0 + '@types/katex@0.16.8': {} + '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -11560,6 +12223,9 @@ snapshots: '@types/tough-cookie@4.0.5': {} + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -11637,6 +12303,11 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + '@vercel/oidc@3.1.0': {} '@wojtekmaj/react-recaptcha-v3@0.1.4(@types/react@19.2.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': @@ -11951,6 +12622,19 @@ snapshots: character-reference-invalid@2.0.1: {} + chevrotain-allstar@0.4.3(chevrotain@12.0.0): + dependencies: + chevrotain: 12.0.0 + lodash-es: 4.18.1 + + chevrotain@12.0.0: + dependencies: + '@chevrotain/cst-dts-gen': 12.0.0 + '@chevrotain/gast': 12.0.0 + '@chevrotain/regexp-to-ast': 12.0.0 + '@chevrotain/types': 12.0.0 + '@chevrotain/utils': 12.0.0 + chownr@3.0.0: {} ci-info@4.3.1: {} @@ -12030,10 +12714,16 @@ snapshots: commander@2.20.3: {} + commander@7.2.0: {} + + commander@8.3.0: {} + compare-versions@6.1.1: {} concat-map@0.0.1: {} + confbox@0.1.8: {} + content-disposition@1.0.1: {} content-type@1.0.5: {} @@ -12057,6 +12747,14 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + cosmiconfig@9.0.0(typescript@5.9.3): dependencies: env-paths: 2.2.1 @@ -12089,6 +12787,190 @@ snapshots: csstype@3.1.3: {} + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.3): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.33.3 + + cytoscape-fcose@2.2.0(cytoscape@3.33.3): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.33.3 + + cytoscape@3.33.3: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.1.0 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.2: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.14: + dependencies: + d3: 7.9.0 + lodash-es: 4.18.1 + data-uri-to-buffer@4.0.1: {} data-urls@5.0.0: @@ -12096,6 +12978,8 @@ snapshots: whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 + dayjs@1.11.20: {} + debug@4.4.3: dependencies: ms: 2.1.3 @@ -12121,6 +13005,10 @@ snapshots: defu@6.1.6: {} + delaunator@5.1.0: + dependencies: + robust-predicates: 3.0.3 + delayed-stream@1.0.0: {} depd@2.0.0: {} @@ -12168,6 +13056,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.4.2: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -12369,6 +13261,8 @@ snapshots: escape-string-regexp@2.0.0: {} + escape-string-regexp@5.0.0: {} + esprima@4.0.1: {} estree-util-is-identifier-name@3.0.0: {} @@ -12716,6 +13610,8 @@ snapshots: graphql@16.13.0: {} + hachure-fill@0.5.2: {} + has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -12728,6 +13624,63 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-from-dom@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hastscript: 9.0.1 + web-namespaces: 2.0.1 + + hast-util-from-html-isomorphic@2.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-dom: 5.0.1 + hast-util-from-html: 2.0.3 + unist-util-remove-position: 5.0.0 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.0 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + hast-util-to-jsx-runtime@2.3.6: dependencies: '@types/estree': 1.0.8 @@ -12748,10 +13701,35 @@ snapshots: transitivePeerDependencies: - supports-color + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + hast-util-whitespace@3.0.0: dependencies: '@types/hast': 3.0.4 + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + headers-polyfill@4.0.3: {} hoist-non-react-statics@3.3.2: @@ -12776,6 +13754,8 @@ snapshots: html-url-attributes@3.0.1: {} + html-void-elements@3.0.0: {} + htmlparser2@8.0.2: dependencies: domelementtype: 2.3.0 @@ -12823,8 +13803,6 @@ snapshots: dependencies: '@formatjs/icu-messageformat-parser': 3.5.3 - idb@7.1.1: {} - ignore@5.3.2: {} import-fresh@3.3.1: @@ -12862,6 +13840,10 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) + internmap@1.0.1: {} + + internmap@2.0.3: {} + intl-messageformat@11.2.0: dependencies: '@formatjs/ecma402-abstract': 3.2.0 @@ -13395,12 +14377,31 @@ snapshots: jsox@1.2.125: {} + katex@0.16.45: + dependencies: + commander: 8.3.0 + + khroma@2.1.0: {} + kleur@3.0.3: {} kleur@4.1.5: {} kysely@0.28.15: {} + langium@4.2.3: + dependencies: + '@chevrotain/regexp-to-ast': 12.0.0 + chevrotain: 12.0.0 + chevrotain-allstar: 0.4.3(chevrotain@12.0.0) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + leac@0.6.0: {} leven@3.1.0: {} @@ -13485,6 +14486,8 @@ snapshots: dependencies: p-locate: 4.1.0 + lodash-es@4.18.1: {} + log-symbols@6.0.0: dependencies: chalk: 5.6.2 @@ -13536,10 +14539,21 @@ snapshots: dependencies: tmpl: 1.0.5 + markdown-table@3.0.4: {} + marked@15.0.12: {} + marked@16.4.2: {} + math-intrinsics@1.1.0: {} + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + mdast-util-from-markdown@2.0.3: dependencies: '@types/mdast': 4.0.4 @@ -13557,6 +14571,75 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-math@3.0.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + longest-streak: 3.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + unist-util-remove-position: 5.0.0 + transitivePeerDependencies: + - supports-color + mdast-util-mdx-expression@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 @@ -13639,6 +14722,30 @@ snapshots: merge2@1.4.1: {} + mermaid@11.14.0: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.1 + '@mermaid-js/parser': 1.1.0 + '@types/d3': 7.4.3 + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.33.3 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.3) + cytoscape-fcose: 2.2.0(cytoscape@3.33.3) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.14 + dayjs: 1.11.20 + dompurify: 3.4.2 + katex: 0.16.45 + khroma: 2.1.0 + lodash-es: 4.18.1 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.4.0 + ts-dedent: 2.2.0 + uuid: 11.1.0 + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.3.0 @@ -13658,6 +14765,74 @@ snapshots: micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-math@3.1.0: + dependencies: + '@types/katex': 0.16.8 + devlop: 1.1.0 + katex: 0.16.45 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + micromark-factory-destination@2.0.1: dependencies: micromark-util-character: 2.1.1 @@ -13815,6 +14990,13 @@ snapshots: dependencies: minipass: 7.1.2 + mlly@1.8.2: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + mnemonist@0.39.6: dependencies: obliterator: 2.0.5 @@ -14073,6 +15255,8 @@ snapshots: path-browserify@1.0.1: {} + path-data-parser@0.1.0: {} + path-exists@4.0.0: {} path-expression-matcher@1.2.1: {} @@ -14099,6 +15283,8 @@ snapshots: path-to-regexp@8.3.0: {} + pathe@2.0.3: {} + peberminta@0.9.0: {} pg-cloudflare@1.3.0: @@ -14174,6 +15360,12 @@ snapshots: dependencies: find-up: 4.1.0 + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + platform@1.3.6: {} playwright-core@1.59.1: {} @@ -14186,6 +15378,13 @@ snapshots: po-parser@2.1.1: {} + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + postcss-selector-parser@7.1.1: dependencies: cssesc: 3.0.0 @@ -14474,6 +15673,42 @@ snapshots: reflect-metadata@0.2.2: {} + rehype-katex@7.0.1: + dependencies: + '@types/hast': 3.0.4 + '@types/katex': 0.16.8 + hast-util-from-html-isomorphic: 2.0.0 + hast-util-to-text: 4.0.2 + katex: 0.16.45 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-math@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-math: 3.0.0 + micromark-extension-math: 3.1.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 @@ -14491,6 +15726,12 @@ snapshots: unified: 11.0.5 vfile: 6.0.3 + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -14534,8 +15775,17 @@ snapshots: rfdc@1.4.1: {} + robust-predicates@3.0.3: {} + rou3@0.7.12: {} + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + router@2.2.0: dependencies: debug: 4.4.3 @@ -14554,6 +15804,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + safe-regex2@3.1.0: dependencies: ret: 0.4.3 @@ -14865,6 +16117,8 @@ snapshots: optionalDependencies: '@babel/core': 7.28.5 + stylis@4.4.0: {} + superjson@2.2.6: dependencies: copy-anything: 4.0.5 @@ -14975,6 +16229,8 @@ snapshots: trough@2.2.0: {} + ts-dedent@2.2.0: {} + ts-morph@26.0.0: dependencies: '@ts-morph/common': 0.27.0 @@ -15047,6 +16303,8 @@ snapshots: is-standalone-pwa: 0.1.1 ua-is-frozen: 0.1.2 + ufo@1.6.4: {} + undici-types@6.21.0: {} undici@8.1.0: {} @@ -15063,6 +16321,11 @@ snapshots: trough: 2.2.0 vfile: 6.0.3 + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -15071,6 +16334,11 @@ snapshots: dependencies: '@types/unist': 3.0.3 + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + unist-util-stringify-position@4.0.0: dependencies: '@types/unist': 3.0.3 @@ -15178,6 +16446,11 @@ snapshots: - '@types/react' - '@types/react-dom' + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + vfile-message@4.0.3: dependencies: '@types/unist': 3.0.3 @@ -15188,10 +16461,23 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + vscode-languageserver-textdocument@1.0.12: {} vscode-languageserver-types@3.17.5: {} + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.1.0: {} + w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -15204,6 +16490,8 @@ snapshots: dependencies: loose-envify: 1.4.0 + web-namespaces@2.0.1: {} + web-streams-polyfill@3.3.3: {} web-worker@1.5.0: {} diff --git a/public/typst_ts_renderer_bg.wasm b/public/typst_ts_renderer_bg.wasm deleted file mode 100644 index 1aafa22..0000000 Binary files a/public/typst_ts_renderer_bg.wasm and /dev/null differ diff --git a/public/typst_ts_web_compiler_bg.wasm b/public/typst_ts_web_compiler_bg.wasm deleted file mode 100644 index a6f8801..0000000 Binary files a/public/typst_ts_web_compiler_bg.wasm and /dev/null differ diff --git a/styles/markdown-preview.css b/styles/markdown-preview.css new file mode 100644 index 0000000..666ba63 --- /dev/null +++ b/styles/markdown-preview.css @@ -0,0 +1,161 @@ +.markdown-body h1 { + font-size: 1.75rem; + font-weight: 700; + text-align: center; + line-height: 1.4; + margin-top: 1.5rem; + margin-bottom: 1rem; +} + +.markdown-body h2 { + font-size: 1.375rem; + font-weight: 700; + line-height: 1.4; + margin-top: 1.5rem; + margin-bottom: 0.75rem; +} + +.markdown-body h3 { + font-size: 1.125rem; + font-weight: 600; + line-height: 1.4; + margin-top: 1.25rem; + margin-bottom: 0.5rem; +} + +.markdown-body h4 { + font-size: 1rem; + font-weight: 600; + line-height: 1.4; + margin-top: 1rem; + margin-bottom: 0.5rem; +} + +.markdown-body p { + font-size: 0.875rem; + line-height: 1.7; + margin-bottom: 0.75rem; +} + +.markdown-body ul, +.markdown-body ol { + font-size: 0.875rem; + line-height: 1.7; + padding-left: 1.5rem; + margin-bottom: 0.75rem; +} + +.markdown-body li { + margin-bottom: 0.25rem; +} + +.markdown-body blockquote { + border-left: 4px solid #d1d5db; + padding: 0.5rem 1rem; + margin: 0.75rem 0; + color: #4b5563; + background-color: #f9fafb; + border-radius: 0 6px 6px 0; +} + +.markdown-body hr { + border: none; + border-top: 1px solid #e5e7eb; + margin: 1.5rem 0; +} + +.markdown-body strong { + font-weight: 700; +} + +.markdown-body em { + font-style: italic; +} + +.markdown-body a { + color: #2563eb; + text-decoration: underline; + text-underline-offset: 2px; + transition: color 0.2s; +} + +.markdown-body a:hover { + color: #1d4ed8; +} + +.markdown-body img { + max-width: 100%; + border-radius: 8px; + margin: 0.75rem auto; + display: block; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); +} + +.markdown-body table { + width: 100%; + border-collapse: collapse; + border: 1px solid #d0d7de; + overflow: hidden; + font-size: 0.875rem; +} + +.markdown-body th { + background-color: #dbeafe; + color: #1e3a5f; + font-weight: 600; + text-align: center; + padding: 10px 14px; + border: 1px solid #93c5fd; +} + +.markdown-body td { + padding: 8px 14px; + border: 1px solid #d0d7de; + text-align: center; +} + +.markdown-body tbody tr:nth-child(odd) { + background-color: #f3f4f6; +} + +.markdown-body tbody tr:nth-child(even) { + background-color: #ffffff; +} + +.markdown-body code { + background-color: #f3f4f6; + padding: 0.125rem 0.375rem; + border-radius: 4px; + font-size: 0.8125rem; + font-family: "Geist Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, + Consolas, monospace; +} + +.markdown-body pre { + background-color: #1e293b; + color: #e2e8f0; + padding: 1rem; + border-radius: 8px; + overflow-x: auto; + font-size: 0.8125rem; + line-height: 1.6; +} + +.markdown-body pre code { + background: none; + padding: 0; + color: inherit; + font-size: inherit; +} + +.markdown-body .katex-display { + margin: 0.75rem 0; + overflow-x: auto; +} + +.note { + background: #e7f3ff; + border-left: 4px solid #2196f3; + padding: 12px; + border-radius: 6px; +} diff --git a/types/agent.ts b/types/agent.ts index 90e2c62..6bc2f0b 100644 --- a/types/agent.ts +++ b/types/agent.ts @@ -36,8 +36,7 @@ const ChartOutputSchema = z.object({ }); const ReportOutputSchema = z.object({ - typstContent: z.string(), - compiledSvg: z.string().optional(), + markdownContent: z.string(), }); type PipelineStep = z.infer; diff --git a/types/index.ts b/types/index.ts index eecf76d..18fe90b 100644 --- a/types/index.ts +++ b/types/index.ts @@ -4,5 +4,4 @@ export * from "./user"; export * from "./auth"; export * from "./file"; export * from "./workspace"; -export * from "./worker"; export * from "./settings"; diff --git a/types/worker.ts b/types/worker.ts deleted file mode 100644 index c89214e..0000000 --- a/types/worker.ts +++ /dev/null @@ -1,13 +0,0 @@ -type WorkerMessage = - | { type: "init" } - | { type: "compile"; content: string } - | { type: "terminate" }; - -type WorkerResponse = - | { type: "init-start"; message: string } - | { type: "init-complete" } - | { type: "compile-start" } - | { type: "compile-complete"; svg: string } - | { type: "error"; error: string }; - -export type { WorkerMessage, WorkerResponse }; diff --git a/types/workspace.ts b/types/workspace.ts index af7348d..f294467 100644 --- a/types/workspace.ts +++ b/types/workspace.ts @@ -1,4 +1,10 @@ -type WorkspaceView = "empty" | "vnc" | "chart" | "dataset" | "file" | "typst"; +type WorkspaceView = + | "empty" + | "vnc" + | "chart" + | "dataset" + | "file" + | "markdown"; type WorkspaceChartImage = { downloadUrl?: string;