diff --git a/PATCH.homepage.md b/PATCH.homepage.md new file mode 100644 index 0000000..8c94aef --- /dev/null +++ b/PATCH.homepage.md @@ -0,0 +1,178 @@ +--- +title: PATCH.md +description: A file format for defining source patches that AI agents can apply and maintain. +version: 0.1.0 +lastUpdated: 2026-06-25 +--- + +# PATCH.md + +> [!IMPORTANT] +> **Status: early draft (v0.1.0).** This format is new and intentionally small. +> Refinements, proposals, and discussions are welcome. + +`PATCH.md` is a file format for defining a source patch that agents can apply +and self-update over time. A patch file holds two things: its **intent**, +written in plain prose, and its **edits**, anchored to the content they change +rather than to line numbers. + +Anchoring to content is what lets a patch survive changes to the file it targets. +When an edit stops matching, an agent can read the intent and the old edit, find +the equivalent place in the updated file, and rewrite the edit to fit. The format +describes the patch. The tools built around it do the applying and the repairing. + +## File + +One patch is one `PATCH.md` file, kept by convention at `/PATCH.md`. + can be a custom or generated name, id, etc. + +## Structure + +````md +--- +id: +summary: +version: +lastUpdated: +--- + +# + +## Intent + + + +```diff file= +@@ optional hint @@ + context ++added line +``` +```` + +The `## Intent` section is the conventional place for the patch's purpose and +re-anchoring guidance. It is the only heading convention defined by this spec. + +A patch can list several targets by including several edit fences. The target file +is declared on each edit fence with `file=`. Any headings used to +organize edits are optional prose, not part of the patch format. + +## Edit forms + +An edit is a fenced code block that defines the patch's current code. +To start, we have added two recommended formats, use whichever you prefer: + +**Search/replace block form** shows the full before and after, anchored on the whole replaced region: + +```patch file=dist/package-manager-cli.js +<<<<<<< SEARCH + console.log(chalk.green(`Updated ${APP_NAME}`)); +======= + console.log(chalk.green(`Updated ${APP_NAME}`)); + try { (await import("node:child_process")).spawnSync("pi-patcher", ["reconcile"], { stdio: "inherit" }); } catch {} +>>>>>>> REPLACE +``` + +**Hunk form** is diff style and marks only the changed lines: + +```diff file=dist/package-manager-cli.js +@@ pi self_update success branch @@ + console.log(chalk.green(`Updated ${APP_NAME}`)); ++ try { (await import("node:child_process")).spawnSync("pi-patcher", ["reconcile"], { stdio: "inherit" }); } catch {} +``` + +- `-` marks a removed line and `+` marks an added line. +- The fence info string must include `file=` so tools can apply the edit without interpreting prose. The value may be bare (`file=dist/foo.js`) or quoted (`file="path with spaces/foo.js"`). Fences without `file=` are examples/prose, not mechanical edits. +- Optional: For additional context, or agent hints: + - `@@ ... @@` header as a hint or more context. + - `> note:` line directly before an edit for more context or a hint. + +## Applying edits + +Every edit has a before and an after. The before must appear exactly once in the +target file, so there is never any doubt about where the edit goes. Applying +replaces the before with the after. In hunk form the before is the context plus +the removed lines, and the after is the context plus the added lines. + +Because the match is unique, applying the same patch twice is safe, and a tool +can read each edit's state directly: + +- **applied**: the after is present +- **pending**: the before is present +- **drift**: neither is present + +All edits in a patch apply together or not at all. If any edit fails, a tool +restores the file to how it started. + +## Splitting a patch + +A patch can touch several files, but when one grows large or bundles unrelated +changes, split it into smaller sub-patches. Smaller patches are easier to +maintain, and easier for an agent to heal. + +Sub-patches should be nested inside their parents' directory, and the parent/child +relationships are defined in frontmatter. A parent patch lists its parts, and each +sub-patch names its parent: + +``` +bootstrap-hook/ +├── PATCH.md +├── hook-insert/ +│ └── PATCH.md +└── hook-config/ + └── PATCH.md +``` + +``` +# parent patch frontmatter +parts: [hook-insert, hook-config] + +# sub-patch frontmatter +parent: bootstrap-hook +``` + +## Agent Driven Healing + +When an edit no longer matches its target, the patch has drifted. Based on the `PATCH.md`, +an agent can automatically fix and update the patch when the target changes. + +Snapshot the target before editing and restore it if anything fails. A tool can also +let the agent decline, for example when the feature a patch depended on has been removed, +instead of forcing a change that no longer fits. + +Tool developers and/or patch authors can decide how complex of a change their agent +is allowed to heal automatically. + +## Example + +The `bootstrap-hook` patch from [pi-patcher](https://github.com/AVGVSTVS96/pi-patcher), written as a single PATCH.md: + +````md +--- +id: bootstrap-hook +summary: Re-run `pi-patcher reconcile` after pi finishes updating itself. +version: 0.1.0 +lastUpdated: 2026-06-25 +--- + +# Bootstrap hook + +## Intent + +Patches Pi to run `pi-patcher reconcile` after pi finishes updating itself. + +After pi's `pi update` finishes updating pi, run `pi-patcher reconcile` so every +installed patch is re-applied to the freshly updated install. + +The hook goes right after the existing `Updated ${APP_NAME}` success log in pi's +self-update path. It must stay valid in pi's compiled ESM output, and it must not +change update behavior if `pi-patcher` is missing or fails to start. + +> note: end of the self-update branch, right after `Updated ${APP_NAME}` + +```diff file=dist/package-manager-cli.js +@@ pi self update success branch @@ + console.log(chalk.green(`Updated ${APP_NAME}`)); ++ try { (await import("node:child_process")).spawnSync("pi-patcher", ["reconcile"], { stdio: "inherit" }); } catch {} +``` +```` diff --git a/apps/website/index.html b/apps/website/index.html index 8c55c96..aaf0838 100644 --- a/apps/website/index.html +++ b/apps/website/index.html @@ -4,7 +4,11 @@ - website + + PATCH.md: a patch format agents can apply and maintain
diff --git a/apps/website/package.json b/apps/website/package.json index ebf4351..04c3919 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -9,6 +9,8 @@ "preview": "vp preview" }, "devDependencies": { + "@tailwindcss/vite": "catalog:", + "tailwindcss": "catalog:", "typescript": "~6.0.2", "vite": "catalog:", "vite-plus": "catalog:" diff --git a/apps/website/src/counter.ts b/apps/website/src/counter.ts deleted file mode 100644 index 969e0f2..0000000 --- a/apps/website/src/counter.ts +++ /dev/null @@ -1,9 +0,0 @@ -export function setupCounter(element: HTMLButtonElement) { - let counter = 0; - const setCounter = (count: number) => { - counter = count; - element.innerHTML = `Count is ${counter}`; - }; - element.addEventListener("click", () => setCounter(counter + 1)); - setCounter(0); -} diff --git a/apps/website/src/main.ts b/apps/website/src/main.ts index ca6cbba..0e57853 100644 --- a/apps/website/src/main.ts +++ b/apps/website/src/main.ts @@ -1,60 +1,308 @@ import "./style.css"; -import typescriptLogo from "./assets/typescript.svg"; -import viteLogo from "./assets/vite.svg"; -import heroImg from "./assets/hero.png"; -import { setupCounter } from "./counter.ts"; - -document.querySelector("#app")!.innerHTML = ` -
-
- - TypeScript logo - Vite logo + +const REPO = "https://github.com/AVGVSTVS96/pi-patcher"; + +/* --------------------------------------------------------------------------- + * Code samples + * + * Kept as plain strings (arrays joined with newlines where the content holds + * backticks or `${...}`) so nothing is interpreted as a template expression. + * ------------------------------------------------------------------------- */ +const structureSample = [ + "---", + "id: ", + "summary: ", + "version: ", + "lastUpdated: ", + "---", + "", + "# ", + "", + "## Intent", + "", + "", + "", + "```diff file=", + "@@ optional hint @@", + " context", + "+added line", + "```", +].join("\n"); + +const searchReplaceSample = [ + "```patch file=dist/package-manager-cli.js", + "<<<<<<< SEARCH", + " console.log(chalk.green(`Updated ${APP_NAME}`));", + "=======", + " console.log(chalk.green(`Updated ${APP_NAME}`));", + ' try { (await import("node:child_process")).spawnSync("pi-patcher", ["reconcile"], { stdio: "inherit" }); } catch {}', + ">>>>>>> REPLACE", + "```", +].join("\n"); + +const hunkSample = [ + "```diff file=dist/package-manager-cli.js", + "@@ pi self_update success branch @@", + " console.log(chalk.green(`Updated ${APP_NAME}`));", + '+ try { (await import("node:child_process")).spawnSync("pi-patcher", ["reconcile"], { stdio: "inherit" }); } catch {}', + "```", +].join("\n"); + +const treeSample = `bootstrap-hook/ +├── PATCH.md +├── hook-insert/ +│ └── PATCH.md +└── hook-config/ + └── PATCH.md`; + +const frontmatterSample = `# parent patch frontmatter +parts: [hook-insert, hook-config] + +# sub-patch frontmatter +parent: bootstrap-hook`; + +const exampleSample = [ + "---", + "id: bootstrap-hook", + "summary: Re-run `pi-patcher reconcile` after pi finishes updating itself.", + "---", + "", + "# Bootstrap hook", + "", + "## Intent", + "", + "Patches Pi to run `pi-patcher reconcile` after pi finishes updating itself.", + "", + "After pi's `pi update` finishes updating pi, run `pi-patcher reconcile` so every", + "installed patch is re-applied to the freshly updated install.", + "", + "The hook goes right after the existing `Updated ${APP_NAME}` success log in pi's", + "self-update path. It must stay valid in pi's compiled ESM output, and it must not", + "change update behavior if `pi-patcher` is missing or fails to start.", + "", + "> note: end of the self-update branch, right after `Updated ${APP_NAME}`", + "", + "```diff file=dist/package-manager-cli.js", + "@@ pi self update success branch @@", + " console.log(chalk.green(`Updated ${APP_NAME}`));", + '+ try { (await import("node:child_process")).spawnSync("pi-patcher", ["reconcile"], { stdio: "inherit" }); } catch {}', + "```", +].join("\n"); + +/* ------------------------------------------------------------------------- */ + +const esc = (s: string): string => + s.replace(/&/g, "&").replace(//g, ">"); + +function highlight(src: string): string { + return src + .split("\n") + .map((line) => { + const safe = esc(line); + if (line.startsWith("@@")) return `${safe}`; + if (line.startsWith("<<<<<<<") || line.startsWith(">>>>>>>") || line.startsWith("=======")) + return `${safe}`; + if (line.startsWith("+") && !line.startsWith("++")) + return `${safe}`; + if (line.startsWith("-") && !line.startsWith("--")) + return `${safe}`; + if (line.startsWith(">")) return `${safe}`; + return safe; + }) + .join("\n"); +} + +const codeBlock = (src: string): string => `
${highlight(src)}
`; +const block = (src: string): string => `
${codeBlock(src)}
`; + +const githubIcon = ``; + +const iconIntent = ``; +const iconAnchor = ``; +const iconHeal = ``; +const arrowDown = ``; + +const card = (icon: string, title: string, body: string): string => ` +
+ ${icon} +

${title}

+

${body}

+
`; + +const specHeading = (id: string, title: string): string => `

${title}

`; + +const app = document.querySelector("#app")!; +app.className = "mx-auto flex min-h-svh w-full max-w-[1126px] flex-col border-x border-border"; + +app.innerHTML = ` +
+ + + PATCH.md + + +
+ +
+ PATCH.md logo + early draft · v0.1.0 +

PATCH.md

+

+ A file format for defining source patches that AI agents can apply and + maintain. Plain-prose intent plus + content-anchored edits, never line numbers. +

+ -
-

Get started

-

Edit src/main.ts and save to test HMR

+
+ +
+
+
+

+ PATCH.md is a file format for defining a source + patch that agents can apply and self-update over time. A patch file holds two + things: its intent, written in plain prose, + and its edits, anchored to the content they + change rather than to line numbers. +

+

+ Anchoring to content is what lets a patch survive changes to the file it targets. + When an edit stops matching, an agent can read the intent and the old edit, find + the equivalent place in the updated file, and rewrite the edit to fit. The format + describes the patch; the tools built around it do the applying and the repairing. +

-
+
+ ${card(iconIntent, "Intent in prose", "Every patch explains what it does and why in plain language, the description an agent reads to re-anchor an edit when the target file moves.")} + ${card(iconAnchor, "Content-anchored edits", "Edits match on the code around them, as search/replace blocks or diff hunks, never on line numbers, so they survive upstream changes.")} + ${card(iconHeal, "Agent-driven healing", "When an edit drifts, an agent reads the intent and the old edit, finds the new location, and rewrites the patch to fit the updated file.")} +
-
-
- -

Documentation

-

Your questions, answered

- -
-
- -

Connect with us

-

Join the Vite community

- +
+
+
+

Specification · v0.1.0

+

The format

+ +
+ ${specHeading("file", "File")} +

+ One patch is one PATCH.md file, kept by convention at + <patch-id>/PATCH.md. The <patch-id> can be + a custom or generated name, id, etc. +

+
+ +
+ ${specHeading("structure", "Structure")} +

+ The only conventional heading is ## Intent. After that, edits can + appear directly as fenced code blocks. Each mechanical edit declares its target + file on the fence with file=<target/path>. +

+ ${block(structureSample)} +
+ +
+ ${specHeading("edit-forms", "Edit forms")} +

+ An edit is a fenced code block that defines the patch's current code. Two + formats are recommended to start. Use whichever you prefer. +

+

Search/replace block

+

Shows the full before and after, anchored on the whole replaced region.

+ ${block(searchReplaceSample)} +

Hunk

+

Diff style, marks only the changed lines.

+ ${block(hunkSample)} +
    +
  • - marks a removed line and + marks an added line.
  • +
  • + The fence info string must include file=<target/path>, bare or + quoted, so tools can apply the edit without interpreting prose. +
  • +
  • + Optional, for extra context or agent hints: an @@ … @@ header, + or a > note: line directly before an edit. +
  • +
+
+ +
+ ${specHeading("applying", "Applying edits")} +

+ Every edit has a before and an after. The before must appear exactly once in + the target file, so there is never any doubt about where the edit goes. Applying + replaces the before with the after. Because the match is unique, applying the + same patch twice is safe, and a tool can read each edit's state directly: +

+
    +
  • appliedthe after is present
  • +
  • pendingthe before is present
  • +
  • driftneither is present
  • +
+

+ All edits in a patch apply together or not at all. If any edit fails, a tool + restores the file to how it started. +

+
+ +
+ ${specHeading("splitting", "Splitting a patch")} +

+ A patch can touch several files, but when one grows large or bundles unrelated + changes, split it into smaller sub-patches. Smaller patches are easier to + maintain, and easier for an agent to heal. Sub-patches nest inside their + parent's directory, and the + relationships are declared in frontmatter. +

+ ${block(treeSample)} + ${block(frontmatterSample)} +
+ +
+ ${specHeading("healing", "Agent-driven healing")} +

+ When an edit no longer matches its target, the patch has drifted. From the + PATCH.md, an agent can automatically fix and update the patch when + the target changes. Snapshot the target before editing and restore it if + anything fails. A tool can also let the agent decline, for example when the + feature a patch depended on has been removed, instead of forcing a change that + no longer fits. +

+

+ Tool developers and patch authors decide how complex a change their agent is + allowed to heal automatically. +

+
+ +
+ ${specHeading("example", "Example")} +

+ The bootstrap-hook patch from + pi-patcher, + written as a single PATCH.md: +

+ ${block(exampleSample)} +
-
-`; +
+

PATCH.md · v0.1.0 · early draft. Refinements and proposals welcome.

+ ${githubIcon}GitHub +
-setupCounter(document.querySelector("#counter")!); +
+`; diff --git a/apps/website/src/style.css b/apps/website/src/style.css index 710c12b..6953d66 100644 --- a/apps/website/src/style.css +++ b/apps/website/src/style.css @@ -1,3 +1,14 @@ +@import "tailwindcss"; + +/* ---------------------------------------------------------------------------- + * Design tokens + * + * Light theme + automatic dark theme via `prefers-color-scheme`, matching the + * Vite+ template. These are mapped into the Tailwind theme with `@theme inline` + * below (shadcn-style) so utilities like `bg-bg`, `text-text-h`, + * `border-border`, and `font-mono` resolve to these vars and follow the active + * color scheme automatically. + * ------------------------------------------------------------------------- */ :root { --text: #6b6375; --text-h: #08060d; @@ -16,6 +27,8 @@ font: 18px/145% var(--sans); letter-spacing: 0.18px; + scroll-behavior: smooth; + scroll-padding-top: 4rem; color-scheme: light dark; color: var(--text); background: var(--bg); @@ -42,61 +55,128 @@ --social-bg: rgba(47, 48, 58, 0.5); --shadow: rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px; } - - #social .button-icon { - filter: invert(1) brightness(2); - } } -body { - margin: 0; -} +/* Expose the tokens to Tailwind. `inline` keeps the utilities referencing the + * raw `var(--*)`, so light/dark swapping from the media query above just works. */ +@theme inline { + --color-text: var(--text); + --color-text-h: var(--text-h); + --color-bg: var(--bg); + --color-border: var(--border); + --color-code-bg: var(--code-bg); + --color-accent: var(--accent); + --color-accent-bg: var(--accent-bg); + --color-accent-border: var(--accent-border); + --color-social-bg: var(--social-bg); -h1, -h2 { - font-family: var(--heading); - font-weight: 500; - color: var(--text-h); + --font-sans: var(--sans); + --font-heading: var(--heading); + --font-mono: var(--mono); + + --shadow-card: var(--shadow); } -h1 { - font-size: 56px; - letter-spacing: -1.68px; - margin: 32px 0; - @media (max-width: 1024px) { - font-size: 36px; - margin: 20px 0; +/* ---------------------------------------------------------------------------- + * Base layer — global document defaults from the template. + * ------------------------------------------------------------------------- */ +@layer base { + body { + margin: 0; } -} -h2 { - font-size: 24px; - line-height: 118%; - letter-spacing: -0.24px; - margin: 0 0 8px; - @media (max-width: 1024px) { - font-size: 20px; + + h1, + h2 { + font-family: var(--heading); + font-weight: 500; + color: var(--text-h); + } + + h1 { + font-size: 56px; + letter-spacing: -1.68px; + margin: 32px 0; + + @media (max-width: 1024px) { + font-size: 36px; + margin: 20px 0; + } + } + + h2 { + font-size: 24px; + line-height: 118%; + letter-spacing: -0.24px; + margin: 0 0 8px; + + @media (max-width: 1024px) { + font-size: 20px; + } + } + + p { + margin: 0; + } + + code { + font-family: var(--mono); + display: inline-flex; + border-radius: 4px; + color: var(--text-h); + font-size: 15px; + line-height: 135%; + padding: 4px 8px; + background: var(--code-bg); } -} -p { - margin: 0; -} -code, -.counter { + pre { + font-family: var(--mono); + font-size: 13.5px; + line-height: 160%; + color: var(--text-h); + background: var(--code-bg); + border: 1px solid var(--border); + border-radius: 10px; + padding: 16px 18px; + overflow-x: auto; + } + + /* Reset the inline pill styling for code inside a block. */ + pre code { + display: block; + padding: 0; + border-radius: 0; + background: none; + color: inherit; + font-size: inherit; + line-height: inherit; + } +} + +/* ---------------------------------------------------------------------------- + * Reusable design primitives (`@utility`) + * + * The signature, multi-property pieces of the template's design system, exposed + * as composable utility classes for the spec site. Simple one-off layout and + * spacing styles are intended to live inline in the markup instead. + * ------------------------------------------------------------------------- */ + +/* Inline-code / keyboard-style pill (the standalone, non-`` variant). */ +@utility chip { font-family: var(--mono); display: inline-flex; border-radius: 4px; color: var(--text-h); -} - -code { font-size: 15px; line-height: 135%; padding: 4px 8px; background: var(--code-bg); } -.counter { +/* Accent "pill" button (the template's counter button). */ +@utility counter { + font-family: var(--mono); + display: inline-flex; font-size: 16px; padding: 5px 10px; border-radius: 5px; @@ -104,7 +184,6 @@ code { background: var(--accent-bg); border: 2px solid transparent; transition: border-color 0.3s; - margin-bottom: 24px; &:hover { border-color: var(--accent-border); @@ -115,161 +194,8 @@ code { } } -.hero { - position: relative; - - .base, - .framework, - .vite { - inset-inline: 0; - margin: 0 auto; - } - - .base { - width: 170px; - position: relative; - z-index: 0; - } - - .framework, - .vite { - position: absolute; - } - - .framework { - z-index: 1; - top: 34px; - height: 28px; - transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) scale(1.4); - } - - .vite { - z-index: 0; - top: 107px; - height: 26px; - width: auto; - transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) scale(0.8); - } -} - -#app { - width: 1126px; - max-width: 100%; - margin: 0 auto; - text-align: center; - border-inline: 1px solid var(--border); - min-height: 100svh; - display: flex; - flex-direction: column; - box-sizing: border-box; -} - -#center { - display: flex; - flex-direction: column; - gap: 25px; - place-content: center; - place-items: center; - flex-grow: 1; - - @media (max-width: 1024px) { - padding: 32px 20px 24px; - gap: 18px; - } -} - -#next-steps { - display: flex; - border-top: 1px solid var(--border); - text-align: left; - - & > div { - flex: 1 1 0; - padding: 32px; - @media (max-width: 1024px) { - padding: 24px 20px; - } - } - - .icon { - margin-bottom: 16px; - width: 22px; - height: 22px; - } - - @media (max-width: 1024px) { - flex-direction: column; - text-align: center; - } -} - -#docs { - border-right: 1px solid var(--border); - - @media (max-width: 1024px) { - border-right: none; - border-bottom: 1px solid var(--border); - } -} - -#next-steps ul { - list-style: none; - padding: 0; - display: flex; - gap: 8px; - margin: 32px 0 0; - - .logo { - height: 18px; - } - - a { - color: var(--text-h); - font-size: 16px; - border-radius: 6px; - background: var(--social-bg); - display: flex; - padding: 6px 12px; - align-items: center; - gap: 8px; - text-decoration: none; - transition: box-shadow 0.3s; - - &:hover { - box-shadow: var(--shadow); - } - .button-icon { - height: 18px; - width: 18px; - } - } - - @media (max-width: 1024px) { - margin-top: 20px; - flex-wrap: wrap; - justify-content: center; - - li { - flex: 1 1 calc(50% - 8px); - } - - a { - width: 100%; - justify-content: center; - box-sizing: border-box; - } - } -} - -#spacer { - height: 88px; - border-top: 1px solid var(--border); - @media (max-width: 1024px) { - height: 48px; - } -} - -.ticks { +/* The little corner ticks that mark the grid-line intersections. */ +@utility ticks { position: relative; width: 100%; @@ -290,3 +216,21 @@ code { border-right-color: var(--border); } } + +/* Soft-filled link/button used in the footer card rows. */ +@utility card-link { + color: var(--text-h); + font-size: 16px; + border-radius: 6px; + background: var(--social-bg); + display: flex; + padding: 6px 12px; + align-items: center; + gap: 8px; + text-decoration: none; + transition: box-shadow 0.3s; + + &:hover { + box-shadow: var(--shadow); + } +} diff --git a/apps/website/vite.config.ts b/apps/website/vite.config.ts new file mode 100644 index 0000000..6bf9b03 --- /dev/null +++ b/apps/website/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite-plus"; +import tailwindcss from "@tailwindcss/vite"; + +export default defineConfig({ + plugins: [tailwindcss()], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 539d44d..96b1af1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -205,6 +205,12 @@ settings: catalogs: default: + '@tailwindcss/vite': + specifier: ^4.3.1 + version: 4.3.1 + tailwindcss: + specifier: ^4.3.1 + version: 4.3.1 vite-plus: specifier: latest version: 0.2.1 @@ -223,6 +229,12 @@ importers: apps/website: devDependencies: + '@tailwindcss/vite': + specifier: 'catalog:' + version: 4.3.1(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)) + tailwindcss: + specifier: 'catalog:' + version: 4.3.1 typescript: specifier: ~6.0.2 version: 6.0.3 @@ -277,9 +289,22 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@napi-rs/wasm-runtime@1.1.5': resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} peerDependencies: @@ -681,6 +706,100 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@tailwindcss/node@4.3.1': + resolution: {integrity: sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==} + + '@tailwindcss/oxide-android-arm64@4.3.1': + resolution: {integrity: sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.1': + resolution: {integrity: sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.1': + resolution: {integrity: sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.1': + resolution: {integrity: sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1': + resolution: {integrity: sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.1': + resolution: {integrity: sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.1': + resolution: {integrity: sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.1': + resolution: {integrity: sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.1': + resolution: {integrity: sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.1': + resolution: {integrity: sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.1': + resolution: {integrity: sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.1': + resolution: {integrity: sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.1': + resolution: {integrity: sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.3.1': + resolution: {integrity: sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 || ^8 + '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} @@ -958,6 +1077,10 @@ packages: dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} + engines: {node: '>=10.13.0'} + es-module-lexer@2.1.0: resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} @@ -982,6 +1105,9 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + jiti@2.7.0: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true @@ -1174,6 +1300,13 @@ packages: std-env@4.1.0: resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + tailwindcss@4.3.1: + resolution: {integrity: sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -1363,8 +1496,25 @@ snapshots: tslib: 2.8.1 optional: true + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -1571,6 +1721,74 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@tailwindcss/node@4.3.1': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.6 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.1 + + '@tailwindcss/oxide-android-arm64@4.3.1': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.1': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.1': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.1': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.1': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.1': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.1': + optional: true + + '@tailwindcss/oxide@4.3.1': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.1 + '@tailwindcss/oxide-darwin-arm64': 4.3.1 + '@tailwindcss/oxide-darwin-x64': 4.3.1 + '@tailwindcss/oxide-freebsd-x64': 4.3.1 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.1 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.1 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.1 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.1 + '@tailwindcss/oxide-linux-x64-musl': 4.3.1 + '@tailwindcss/oxide-wasm32-wasi': 4.3.1 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.1 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.1 + + '@tailwindcss/vite@4.3.1(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))': + dependencies: + '@tailwindcss/node': 4.3.1 + '@tailwindcss/oxide': 4.3.1 + tailwindcss: 4.3.1 + vite: '@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)' + '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.29.7 @@ -1637,12 +1855,12 @@ snapshots: '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260509.2 '@typescript/native-preview-win32-x64': 7.0.0-dev.20260509.2 - '@vitest/browser-preview@4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(vite@8.0.16(@types/node@25.9.4)(jiti@2.7.0)(yaml@2.9.0)))': + '@vitest/browser-preview@4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9)': dependencies: '@testing-library/dom': 10.4.1 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) - '@vitest/browser': 4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(vite@8.0.16(@types/node@25.9.4)(jiti@2.7.0)(yaml@2.9.0))) - vitest: 4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(vite@8.0.16(@types/node@25.9.4)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/browser': 4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9) + vitest: 4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)) transitivePeerDependencies: - bufferutil - msw @@ -1661,7 +1879,7 @@ snapshots: - utf-8-validate - vite - '@vitest/browser@4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(vite@8.0.16(@types/node@25.9.4)(jiti@2.7.0)(yaml@2.9.0)))': + '@vitest/browser@4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9)': dependencies: '@blazediff/core': 1.9.1 '@vitest/mocker': 4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)) @@ -1670,7 +1888,7 @@ snapshots: pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(vite@8.0.16(@types/node@25.9.4)(jiti@2.7.0)(yaml@2.9.0)) + vitest: 4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)) ws: 8.21.0 transitivePeerDependencies: - bufferutil @@ -1819,6 +2037,11 @@ snapshots: dom-accessibility-api@0.5.16: {} + enhanced-resolve@5.21.6: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + es-module-lexer@2.1.0: {} estree-walker@3.0.3: @@ -1834,6 +2057,8 @@ snapshots: fsevents@2.3.3: optional: true + graceful-fs@4.2.11: {} + jiti@2.7.0: {} js-tokens@4.0.0: {} @@ -2071,6 +2296,10 @@ snapshots: std-env@4.1.0: {} + tailwindcss@4.3.1: {} + + tapable@2.3.3: {} + tinybench@2.9.0: {} tinyexec@1.2.4: {} @@ -2110,8 +2339,8 @@ snapshots: dependencies: '@oxc-project/types': 0.136.0 '@oxlint/plugins': 1.68.0 - '@vitest/browser': 4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(vite@8.0.16(@types/node@25.9.4)(jiti@2.7.0)(yaml@2.9.0))) - '@vitest/browser-preview': 4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(vite@8.0.16(@types/node@25.9.4)(jiti@2.7.0)(yaml@2.9.0))) + '@vitest/browser': 4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9) + '@vitest/browser-preview': 4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9) '@vitest/expect': 4.1.9 '@vitest/mocker': 4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.9 @@ -2123,7 +2352,7 @@ snapshots: oxfmt: 0.55.0(vite-plus@0.2.1(@types/node@25.9.4)(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)) oxlint: 1.70.0(oxlint-tsgolint@0.23.0)(vite-plus@0.2.1(@types/node@25.9.4)(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)) oxlint-tsgolint: 0.23.0 - vitest: 4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9(vite@8.0.16(@types/node@25.9.4)(jiti@2.7.0)(yaml@2.9.0))(vitest@4.1.9))(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)) + vitest: 4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)) optionalDependencies: '@voidzero-dev/vite-plus-darwin-arm64': 0.2.1 '@voidzero-dev/vite-plus-darwin-x64': 0.2.1 @@ -2239,7 +2468,7 @@ snapshots: jiti: 2.7.0 yaml: 2.9.0 - vitest@4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9(vite@8.0.16(@types/node@25.9.4)(jiti@2.7.0)(yaml@2.9.0))(vitest@4.1.9))(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)): + vitest@4.1.9(@types/node@25.9.4)(@vitest/browser-preview@4.1.9)(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.9 '@vitest/mocker': 4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0)) @@ -2263,7 +2492,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.9.4 - '@vitest/browser-preview': 4.1.9(vite@8.0.16(@types/node@25.9.4)(jiti@2.7.0)(yaml@2.9.0))(vitest@4.1.9) + '@vitest/browser-preview': 4.1.9(@voidzero-dev/vite-plus-core@0.2.1(@types/node@25.9.4)(jiti@2.7.0)(typescript@6.0.3)(yaml@2.9.0))(vitest@4.1.9) transitivePeerDependencies: - msw diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 83ed55f..f66525e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,6 +11,8 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@latest vitest: 4.1.9 vite-plus: latest + tailwindcss: ^4.3.1 + "@tailwindcss/vite": ^4.3.1 overrides: vite: "catalog:" vitest: "catalog:" diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..5db72dd --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ] +}