mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-07 19:44:52 +10:00
fix: polish ai agent and command palette
This commit is contained in:
+1
-4
@@ -23,10 +23,7 @@
|
||||
<div id="app"></div>
|
||||
<!-- Branded first paint; hidden once React populates #app (higher-specificity rule below). -->
|
||||
<div id="initial-loader">
|
||||
<svg width="48" height="48" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="Reactive Resume">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M173.611 166.311L132.877 219.804H173.524L193.973 191.813L213.183 219.804H256L215.673 165.707L215.15 165.046L207.461 155.332L195.329 140.004L195.258 139.915L193.813 138.089L193.923 138.001L176.286 112.861H134.061L173.611 166.311ZM199.89 133.554L214.959 112.861H254.619L219.874 158.8L199.89 133.554Z" fill="#FAFAFA"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 36.1959V174.314H39.0678V137.614H60.3938L60.4323 137.671C60.8436 137.653 61.2517 137.634 61.6567 137.614C75.0665 136.968 85.1471 135.549 96.385 131.385C96.7596 131.246 97.1355 131.104 97.5128 130.959L97.4591 130.881C105.816 126.86 112.331 121.344 117.006 114.331C122.005 106.702 124.504 97.6915 124.504 87.2997C124.504 76.7764 122.005 67.7 117.006 60.0706C112.007 52.3097 104.904 46.3903 95.6964 42.3125C86.62 38.2347 75.7679 36.1959 63.1399 36.1959H0ZM102.156 137.725L64.8705 144.175L85.4361 174.314H127.266L102.156 137.725ZM39.0678 107.426H60.7721C68.9277 107.426 74.9786 105.65 78.9248 102.098C83.0026 98.5465 85.0415 93.6137 85.0415 87.2997C85.0415 80.8542 83.0026 75.8556 78.9248 72.304C74.9786 68.7523 68.9277 66.9765 60.7721 66.9765H39.0678V107.426Z" fill="#FAFAFA"/>
|
||||
</svg>
|
||||
<img src="/icon/dark.svg" width="48" height="48" alt="Reactive Resume" />
|
||||
<div class="initial-loader__spinner"></div>
|
||||
<span class="initial-loader__sr-only">Loading</span>
|
||||
</div>
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
"react-resizable-panels": "^4.12.1",
|
||||
"react-window": "^2.2.7",
|
||||
"react-zoom-pan-pinch": "^4.0.3",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"sonner": "^2.0.7",
|
||||
"ts-pattern": "^5.9.0",
|
||||
"usehooks-ts": "^3.1.1",
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { readFileSync } from "node:fs";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { LoadingScreen } from "./loading-screen";
|
||||
|
||||
describe("LoadingScreen", () => {
|
||||
it("renders the Reactive Resume logo and spinner", () => {
|
||||
it("renders the Reactive Resume icon and spinner", () => {
|
||||
render(<LoadingScreen />);
|
||||
|
||||
expect(screen.getAllByAltText("Reactive Resume")).toHaveLength(2);
|
||||
const icons = screen.getAllByAltText("Reactive Resume");
|
||||
expect(icons).toHaveLength(2);
|
||||
expect(icons.map((icon) => icon.getAttribute("src"))).toEqual(["/icon/dark.svg", "/icon/light.svg"]);
|
||||
expect(screen.getByLabelText("Loading")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("uses the same icon asset as the initial HTML loader", () => {
|
||||
const html = readFileSync("index.html", "utf8");
|
||||
|
||||
expect(html).toContain('src="/icon/dark.svg"');
|
||||
expect(html).not.toContain('src="/logo/dark.svg"');
|
||||
});
|
||||
|
||||
it("fills the viewport (fixed inset-0)", () => {
|
||||
const { container } = render(<LoadingScreen />);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Spinner } from "@reactive-resume/ui/components/spinner";
|
||||
export function LoadingScreen() {
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex h-svh w-svw flex-col items-center justify-center gap-y-6 bg-background">
|
||||
<BrandIcon variant="logo" className="size-12" />
|
||||
<BrandIcon variant="icon" className="size-12" />
|
||||
<Spinner className="size-6" />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { i18n } from "@lingui/core";
|
||||
import { I18nProvider } from "@lingui/react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Command, CommandList } from "@reactive-resume/ui/components/command";
|
||||
import { useCommandPaletteStore } from "../store";
|
||||
|
||||
const queryOptionsMock = vi.fn((options?: unknown) => options ?? {});
|
||||
|
||||
vi.mock("@tanstack/react-query", () => ({
|
||||
useQuery: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@tanstack/react-router", () => ({
|
||||
useNavigate: () => vi.fn(),
|
||||
useRouteContext: () => ({ session: { user: { id: "user-1" } } }),
|
||||
}));
|
||||
|
||||
vi.mock("@/dialogs/store", () => ({
|
||||
useDialogStore: () => ({ openDialog: vi.fn() }),
|
||||
}));
|
||||
|
||||
vi.mock("@/libs/orpc/client", () => ({
|
||||
orpc: {
|
||||
resume: {
|
||||
list: {
|
||||
queryOptions: queryOptionsMock,
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const { ResumesCommandGroup } = await import("./resumes");
|
||||
|
||||
beforeAll(() => {
|
||||
i18n.loadAndActivate({ locale: "en", messages: {} });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
useCommandPaletteStore.setState({ open: false, search: "", pages: [] });
|
||||
});
|
||||
|
||||
const renderGroup = () =>
|
||||
render(
|
||||
<I18nProvider i18n={i18n}>
|
||||
<Command>
|
||||
<CommandList>
|
||||
<ResumesCommandGroup />
|
||||
</CommandList>
|
||||
</Command>
|
||||
</I18nProvider>,
|
||||
);
|
||||
|
||||
describe("ResumesCommandGroup", () => {
|
||||
it("loads resumes with the default list input on the resumes page", () => {
|
||||
useCommandPaletteStore.setState({ pages: ["resumes"] });
|
||||
vi.mocked(useQuery).mockReturnValue({
|
||||
data: [{ id: "resume-1", name: "Evil Apricot Pike" }],
|
||||
isLoading: false,
|
||||
} as ReturnType<typeof useQuery>);
|
||||
|
||||
renderGroup();
|
||||
|
||||
expect(queryOptionsMock).toHaveBeenCalledWith({
|
||||
enabled: true,
|
||||
input: { sort: "lastUpdatedAt", tags: [] },
|
||||
});
|
||||
expect(screen.getByText("Evil Apricot Pike")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -24,6 +24,7 @@ export function ResumesCommandGroup() {
|
||||
const { data: resumes, isLoading } = useQuery(
|
||||
orpc.resume.list.queryOptions({
|
||||
enabled: !!session && isResumesPage,
|
||||
input: { sort: "lastUpdatedAt", tags: [] },
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { render, screen, within } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { AssistantMarkdown } from "./agent-chat";
|
||||
|
||||
describe("AssistantMarkdown", () => {
|
||||
it("renders GitHub-style pipe tables as tables", () => {
|
||||
render(
|
||||
<AssistantMarkdown
|
||||
text={
|
||||
"Before\n\n| Weak/Generic | Improved Version |\n| --- | --- |\n| Placeholder text | Mentored 3+ juniors |\n| Worked closely | Collaborated with 6+ artists |\n\nAfter"
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
const table = screen.getByRole("table");
|
||||
|
||||
expect(within(table).getByRole("columnheader", { name: "Weak/Generic" })).toBeInTheDocument();
|
||||
expect(within(table).getByRole("columnheader", { name: "Improved Version" })).toBeInTheDocument();
|
||||
expect(within(table).getByRole("cell", { name: "Mentored 3+ juniors" })).toBeInTheDocument();
|
||||
expect(screen.getByText("Before")).toBeInTheDocument();
|
||||
expect(screen.getByText("After")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -27,6 +27,7 @@ import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
|
||||
import { m } from "motion/react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Attachment,
|
||||
@@ -380,10 +381,11 @@ function getMessagePartKey(messageId: string, part: UIMessage["parts"][number])
|
||||
return `${messageId}-${part.type}-${JSON.stringify(part)}`;
|
||||
}
|
||||
|
||||
function AssistantMarkdown({ text }: AssistantMarkdownProps) {
|
||||
export function AssistantMarkdown({ text }: AssistantMarkdownProps) {
|
||||
return (
|
||||
<ReactMarkdown
|
||||
skipHtml
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
p: ({ children }) => <p className="my-2 leading-relaxed first:mt-0 last:mb-0">{children}</p>,
|
||||
ul: ({ children }) => <ul className="my-2 ms-5 list-disc space-y-1">{children}</ul>,
|
||||
@@ -407,6 +409,13 @@ function AssistantMarkdown({ text }: AssistantMarkdownProps) {
|
||||
blockquote: ({ children }) => (
|
||||
<blockquote className="my-3 border-l-2 ps-3 text-muted-foreground">{children}</blockquote>
|
||||
),
|
||||
table: ({ children }) => (
|
||||
<div className="my-3 max-w-full overflow-x-auto">
|
||||
<table className="w-full min-w-max border-collapse text-left text-sm">{children}</table>
|
||||
</div>
|
||||
),
|
||||
th: ({ children }) => <th className="border px-3 py-2 font-semibold">{children}</th>,
|
||||
td: ({ children }) => <td className="border px-3 py-2 align-top">{children}</td>,
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildAgentDraftResumeName, buildUniqueAgentDraftSlug } from "./resume";
|
||||
import { buildAgentDraftResumeName, buildUniqueAgentDraftSlug, normalizeAgentResumePatchOperations } from "./resume";
|
||||
|
||||
describe("agent resume setup helpers", () => {
|
||||
it("names duplicated resumes as AI drafts", () => {
|
||||
@@ -14,3 +14,25 @@ describe("agent resume setup helpers", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("normalizeAgentResumePatchOperations", () => {
|
||||
it("prefixes shorthand standard section paths without touching custom section paths", () => {
|
||||
const result = normalizeAgentResumePatchOperations(
|
||||
{
|
||||
sections: {
|
||||
experience: {},
|
||||
education: {},
|
||||
},
|
||||
},
|
||||
[
|
||||
{ op: "replace", path: "/experience/items/0/description", value: "Updated" },
|
||||
{ op: "copy", from: "/education/items/0", path: "/customSections/0/items/-" },
|
||||
],
|
||||
);
|
||||
|
||||
expect(result).toEqual([
|
||||
{ op: "replace", path: "/sections/experience/items/0/description", value: "Updated" },
|
||||
{ op: "copy", from: "/sections/education/items/0", path: "/customSections/0/items/-" },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { JsonPatchOperation } from "@reactive-resume/resume/patch";
|
||||
import { slugify } from "@reactive-resume/utils/string";
|
||||
|
||||
const AI_DRAFT_SUFFIX = " - AI Draft";
|
||||
@@ -23,3 +24,31 @@ export function buildUniqueAgentDraftSlug(sourceName: string, existingSlugs: Set
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
function decodeJsonPointerSegment(segment: string) {
|
||||
return segment.replace(/~1/g, "/").replace(/~0/g, "~");
|
||||
}
|
||||
|
||||
function normalizeSectionShortcutPath(data: { sections: Record<string, unknown> }, path: string) {
|
||||
if (!path.startsWith("/") || path.startsWith("/sections/")) return path;
|
||||
|
||||
const sectionId = decodeJsonPointerSegment(path.slice(1).split("/")[0] ?? "");
|
||||
if (!Object.hasOwn(data.sections, sectionId)) return path;
|
||||
|
||||
return `/sections${path}`;
|
||||
}
|
||||
|
||||
export function normalizeAgentResumePatchOperations(
|
||||
data: { sections: Record<string, unknown> },
|
||||
operations: JsonPatchOperation[],
|
||||
): JsonPatchOperation[] {
|
||||
return operations.map((operation) => {
|
||||
const path = normalizeSectionShortcutPath(data, operation.path);
|
||||
const normalized = path === operation.path ? operation : { ...operation, path };
|
||||
|
||||
if (!("from" in normalized)) return normalized;
|
||||
|
||||
const from = normalizeSectionShortcutPath(data, normalized.from);
|
||||
return from === normalized.from ? normalized : { ...normalized, from };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { getAgentModel } from "../ai/service";
|
||||
import { aiProvidersService } from "../ai-providers/service";
|
||||
import { resumeService } from "../resume/service";
|
||||
import { getStorageService, inferContentType } from "../storage/service";
|
||||
import { buildAgentDraftResumeName, buildUniqueAgentDraftSlug } from "./resume";
|
||||
import { buildAgentDraftResumeName, buildUniqueAgentDraftSlug, normalizeAgentResumePatchOperations } from "./resume";
|
||||
import { claimActiveAgentRun, clearActiveAgentRunIfCurrent } from "./runs";
|
||||
import { agentStreamLifecycle } from "./streams";
|
||||
import { buildAgentInstructions, buildAgentTools } from "./tools";
|
||||
@@ -717,12 +717,13 @@ async function applyResumePatch(input: {
|
||||
}) {
|
||||
const before = await resumeService.getById({ id: input.resumeId, userId: input.userId });
|
||||
const snapshotData = cloneResumeData(before.data);
|
||||
const operations = normalizeAgentResumePatchOperations(before.data, input.operations);
|
||||
|
||||
const { action, patched } = await db.transaction(async (tx) => {
|
||||
const patched = await resumeService.patchInTransaction(tx, {
|
||||
id: input.resumeId,
|
||||
userId: input.userId,
|
||||
operations: input.operations,
|
||||
operations,
|
||||
});
|
||||
|
||||
const [action] = await tx
|
||||
@@ -735,7 +736,7 @@ async function applyResumePatch(input: {
|
||||
status: "applied",
|
||||
title: input.title,
|
||||
...(input.summary !== undefined ? { summary: input.summary } : {}),
|
||||
operations: input.operations,
|
||||
operations,
|
||||
snapshotData,
|
||||
baseUpdatedAt: before.updatedAt,
|
||||
appliedUpdatedAt: patched.updatedAt,
|
||||
@@ -787,10 +788,14 @@ function createAgent(input: {
|
||||
patchRoot: "data",
|
||||
patchPathExamples: {
|
||||
visibleName: "/basics/name",
|
||||
standardExperienceDescription: "/sections/experience/items/0/description",
|
||||
customSectionDescription: "/customSections/0/items/0/description",
|
||||
},
|
||||
patchNotes: [
|
||||
"apply_resume_patch paths are rooted at the `data` object below.",
|
||||
"Do not prefix paths with `/data`.",
|
||||
"Built-in sections live under `/sections/<sectionId>`, for example `/sections/experience/items/0/description`.",
|
||||
"Custom sections live under `/customSections/<index>`, even when their `type` is `experience`, `education`, or another built-in section type.",
|
||||
"The resume file/title `name` metadata is read-only for apply_resume_patch.",
|
||||
],
|
||||
data: resume.data,
|
||||
|
||||
@@ -90,6 +90,12 @@ describe("agent tools", () => {
|
||||
);
|
||||
expect(buildAgentInstructions({ hasProviderNativeSearch: false })).toContain("Batch related JSON Patch operations");
|
||||
expect(buildAgentInstructions({ hasProviderNativeSearch: false })).toContain("/basics/name");
|
||||
expect(buildAgentInstructions({ hasProviderNativeSearch: false })).toContain(
|
||||
"/sections/experience/items/0/description",
|
||||
);
|
||||
expect(buildAgentInstructions({ hasProviderNativeSearch: false })).toContain(
|
||||
"/customSections/0/items/0/description",
|
||||
);
|
||||
expect(buildAgentInstructions({ hasProviderNativeSearch: false })).toContain("never /data/basics/name or /name");
|
||||
expect(buildAgentInstructions({ hasProviderNativeSearch: false })).toContain("clean Markdown");
|
||||
});
|
||||
|
||||
@@ -52,7 +52,7 @@ function buildProviderNativeAgentTools(provider: AgentProviderConfig): ToolSet {
|
||||
|
||||
export function buildAgentInstructions({ hasProviderNativeSearch }: { hasProviderNativeSearch: boolean }) {
|
||||
const baseInstructions =
|
||||
"You are an expert resume-writing agent inside Reactive Resume. Help the user improve the working resume for a target role. Read the resume before editing. Respond to the user in clean Markdown with concise paragraphs, bullets, and bold text when it improves scanability. Apply concise, valid JSON Patch operations when changes are useful. Patch paths are evaluated against the resume data object returned by read_resume, so use paths like /basics/name for the visible name and never /data/basics/name or /name. apply_resume_patch cannot rename the resume file/title metadata. Batch related JSON Patch operations into one apply_resume_patch call for each coherent edit instead of making repeated patch calls for the same request. Ask the user a question when a missing preference blocks a high-confidence edit.";
|
||||
"You are an expert resume-writing agent inside Reactive Resume. Help the user improve the working resume for a target role. Read the resume before editing. Respond to the user in clean Markdown with concise paragraphs, bullets, and bold text when it improves scanability. Apply concise, valid JSON Patch operations when changes are useful. Patch paths are evaluated against the resume data object returned by read_resume, so use paths like /basics/name for the visible name and never /data/basics/name or /name. Built-in sections must use /sections/<sectionId>, for example /sections/experience/items/0/description. Custom sections must use /customSections/<index>, for example /customSections/0/items/0/description, even when their type is experience, education, or another built-in section type. apply_resume_patch cannot rename the resume file/title metadata. Batch related JSON Patch operations into one apply_resume_patch call for each coherent edit instead of making repeated patch calls for the same request. Ask the user a question when a missing preference blocks a high-confidence edit.";
|
||||
|
||||
if (!hasProviderNativeSearch) {
|
||||
return `${baseInstructions} Live web research is unavailable with the selected provider or model. If the user asks you to browse, search the web, fetch a URL, or use current online context, briefly tell them live web research is unavailable with the selected provider/model and ask them to paste or attach the relevant content. Continue normal resume editing using the resume, chat context, and attachments.`;
|
||||
|
||||
Generated
+195
@@ -454,6 +454,9 @@ importers:
|
||||
react-zoom-pan-pinch:
|
||||
specifier: ^4.0.3
|
||||
version: 4.0.3(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
remark-gfm:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
sonner:
|
||||
specifier: ^2.0.7
|
||||
version: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
@@ -5907,6 +5910,9 @@ packages:
|
||||
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
markdown-table@3.0.4:
|
||||
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
|
||||
|
||||
marked@15.0.12:
|
||||
resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==}
|
||||
engines: {node: '>= 18'}
|
||||
@@ -5916,9 +5922,30 @@ packages:
|
||||
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-mdx-expression@2.0.1:
|
||||
resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==}
|
||||
|
||||
@@ -5975,6 +6002,27 @@ packages:
|
||||
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-factory-destination@2.0.1:
|
||||
resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
|
||||
|
||||
@@ -6747,12 +6795,18 @@ packages:
|
||||
resolution: {integrity: sha512-GP6h9OgJmhAZpb3dbNbXTfRWVnGcoMhWRZv/HxgM4/qCVqs1P9ukQdYxaUhjWBSAs9oJ/uPXUUvGT1VMe0Bs0Q==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
remark-gfm@4.0.1:
|
||||
resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==}
|
||||
|
||||
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'}
|
||||
@@ -12232,10 +12286,19 @@ snapshots:
|
||||
dependencies:
|
||||
semver: 7.8.5
|
||||
|
||||
markdown-table@3.0.4: {}
|
||||
|
||||
marked@15.0.12: {}
|
||||
|
||||
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
|
||||
@@ -12253,6 +12316,63 @@ 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-mdx-expression@2.0.1:
|
||||
dependencies:
|
||||
'@types/estree-jsx': 1.0.5
|
||||
@@ -12362,6 +12482,64 @@ 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-factory-destination@2.0.1:
|
||||
dependencies:
|
||||
micromark-util-character: 2.1.1
|
||||
@@ -13252,6 +13430,17 @@ snapshots:
|
||||
|
||||
regexp-util@2.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-parse@11.0.0:
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
@@ -13269,6 +13458,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:
|
||||
optional: true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user