From 5ddc952ecd31a04730a8ff28933e701a26dc0931 Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Thu, 24 Sep 2026 15:13:27 +0200 Subject: [PATCH 1/9] updates: Urteil und Paketliste sichtbar, ehrliche Lade- und Fehlerzustaende, Rueckfragen, Auftraege aller Gruppen - Update-Details zeigen jetzt das Urteil des Hirns ("Nichts zu tun" / "Du musst etwas tun" samt Text), die Zusammenfassung ist aufklappbar statt auf drei Zeilen gekappt, das Betriebssystem zeigt seine Paketliste (und was Ubuntu zurueckhaelt). - Scheitert eine Pruefung (z. B. git fetch bei Hermes), steht "Konnte nicht pruefen: ..." statt "- -> neu"; waehrend des Ladens ein Platzhalter statt "..." und kein voreiliges "neu". - Einzel-Update und Freigeben fragen vorher nach; der Ja-Knopf sperrt gegen Doppelklick. - Neue Job-Karte (Fortschritt, Abbrechen mit Rueckfrage, letzte Meldung, Protokoll) fuer alle laufenden Auftraege, egal welche Gruppe. Updates lassen sich bewusst nicht abbrechen. - Job-Typen an jobengine.py angeglichen ("canceled", group, started_at/finished_at): abgebrochene Auftraege erschienen bisher als "Laeuft". - Fehler aus "Jetzt sichern" (Feld error) und "Es laeuft schon ein Update" (status busy) werden gemeldet; ist ein Auftrag fertig, lesen Versionen, Modelle und Sicherungen neu. Co-Authored-By: Claude Opus 5.5 --- frontend/src/components/cockpit/Auftraege.tsx | 42 ++ .../src/components/cockpit/Bestaetigen.tsx | 23 +- .../src/components/cockpit/JobKarte.test.tsx | 82 ++++ frontend/src/components/cockpit/JobKarte.tsx | 116 +++++ frontend/src/lib/abfragen.ts | 93 ++-- frontend/src/lib/anzeige.ts | 112 ++++- frontend/src/lib/typen.ts | 61 ++- frontend/src/views/Updates.tsx | 419 +++++++++++++----- 8 files changed, 789 insertions(+), 159 deletions(-) create mode 100644 frontend/src/components/cockpit/Auftraege.tsx create mode 100644 frontend/src/components/cockpit/JobKarte.test.tsx create mode 100644 frontend/src/components/cockpit/JobKarte.tsx diff --git a/frontend/src/components/cockpit/Auftraege.tsx b/frontend/src/components/cockpit/Auftraege.tsx new file mode 100644 index 0000000..722a8b6 --- /dev/null +++ b/frontend/src/components/cockpit/Auftraege.tsx @@ -0,0 +1,42 @@ +import { useJobAbbrechen, useJobs } from "@/lib/abfragen" +import { jobTitel, sichtbareJobs } from "@/lib/anzeige" +import { JobKarte } from "./JobKarte" +import { Panel } from "./Panel" + +/** + * Laufende und zuletzt beendete Aufträge — egal, woher sie kommen (Update, Modell-Download, Suche + * nach Neuem). Solange nichts läuft und nichts frisch beendet ist, zeigt sie gar nichts. + */ +export function Auftraege({ alsPanel = false }: { alsPanel?: boolean }) { + const jobs = useJobs() + const abbrechen = useJobAbbrechen() + const liste = sichtbareJobs(jobs.data?.jobs ?? []) + + let inhalt + if (liste.length > 0) { + inhalt = ( +
+ {liste.map((j) => ( + abbrechen.mutate({ id: job.id, titel: jobTitel(job) })} + /> + ))} +
+ ) + } else if (jobs.isError && !jobs.data) { + inhalt =

Die Aufträge lassen sich gerade nicht lesen: {jobs.error.message}

+ } else { + return null + } + + if (alsPanel) return {inhalt} + return ( +
+

Aufträge

+ {inhalt} +
+ ) +} diff --git a/frontend/src/components/cockpit/Bestaetigen.tsx b/frontend/src/components/cockpit/Bestaetigen.tsx index f7d5116..230ec01 100644 --- a/frontend/src/components/cockpit/Bestaetigen.tsx +++ b/frontend/src/components/cockpit/Bestaetigen.tsx @@ -4,13 +4,19 @@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" -/** Rückfrage vor Schritten, die die Box umbauen (alles aktualisieren, zurückspielen, neu starten). */ -export function Bestaetigen({ offen, titel, text, knopf, gefahr, onJa, onNein, children }: { +/** + * Rückfrage vor Schritten, die die Box verändern (Updates, Freigeben, Zurückspielen, Neustarts, + * Installieren, Abbrechen). `gesperrt` hält den Ja-Knopf fest, solange die Aktion schon unterwegs + * ist — ein Doppelklick startet sie so nicht zweimal. + */ +export function Bestaetigen({ offen, titel, text, knopf, neinKnopf = "Abbrechen", gefahr, gesperrt, onJa, onNein, children }: { offen: boolean titel: string text: string knopf: string + neinKnopf?: string gefahr?: boolean + gesperrt?: boolean onJa: () => void onNein: () => void children?: ReactNode @@ -19,15 +25,22 @@ export function Bestaetigen({ offen, titel, text, knopf, gefahr, onJa, onNein, c !o && onNein()}> - {titel} + {titel} {text} {children} - diff --git a/frontend/src/components/cockpit/JobKarte.test.tsx b/frontend/src/components/cockpit/JobKarte.test.tsx new file mode 100644 index 0000000..b789a60 --- /dev/null +++ b/frontend/src/components/cockpit/JobKarte.test.tsx @@ -0,0 +1,82 @@ +import { fireEvent, render, screen } from "@testing-library/react" +import { sichtbareJobs } from "@/lib/anzeige" +import type { Job } from "@/lib/typen" +import { JobKarte } from "./JobKarte" + +const JETZT = 1_790_000_000 // Unix-Sekunden, fester Bezugspunkt + +function job(teil: Partial): Job { + return { + id: "j1", label: "Nach Updates suchen", state: "running", group: null, + log: ["$ bash -c 'sudo apt-get update'"], returncode: null, + started_at: JETZT - 120, finished_at: null, ...teil, + } +} + +describe("JobKarte", () => { + it("zeigt bei einem Download Fortschritt und fragt vor dem Abbrechen nach", () => { + const onAbbrechen = vi.fn() + render( + , + ) + expect(screen.getByText("Download unsloth/Qwen3.8-27B-GGUF")).toBeInTheDocument() + expect(screen.getByRole("progressbar")).toHaveAttribute("aria-valuenow", "42") + expect(screen.getByText("42 % · 12,0 GB von 29,0 GB · noch etwa 6 min")).toBeInTheDocument() + + fireEvent.click(screen.getByRole("button", { name: "Abbrechen" })) + expect(screen.getByRole("dialog", { name: "Auftrag abbrechen?" })).toBeInTheDocument() + expect(onAbbrechen).not.toHaveBeenCalled() + + fireEvent.click(screen.getByRole("button", { name: "Ja, abbrechen" })) + expect(onAbbrechen).toHaveBeenCalledTimes(1) + }) + + it("nennt einen abgebrochenen Auftrag „Abgebrochen“ und nicht „Läuft“", () => { + render( {}} />) + expect(screen.getByText("Abgebrochen")).toBeInTheDocument() + expect(screen.queryByText("Läuft")).not.toBeInTheDocument() + expect(screen.queryByRole("button", { name: "Abbrechen" })).not.toBeInTheDocument() + }) + + it("bietet bei Updates kein Abbrechen an und zeigt bei Fehlern die letzte Meldung", () => { + const { rerender } = render( + {}} />, + ) + expect(screen.queryByRole("button", { name: "Abbrechen" })).not.toBeInTheDocument() + + rerender( + , + ) + expect(screen.getByText("Fehler")).toBeInTheDocument() + expect(screen.getByText(/Letzte Meldung: ✗ HERMES-UPDATE FEHLGESCHLAGEN/)).toBeInTheDocument() + }) +}) + +describe("sichtbareJobs", () => { + it("zeigt alle laufenden Aufträge jeder Gruppe und die drei zuletzt beendeten", () => { + const liste = sichtbareJobs( + [ + job({ id: "alt", state: "done", finished_at: JETZT - 2 * 86_400 }), + job({ id: "f1", state: "done", finished_at: JETZT - 50 }), + job({ id: "f2", state: "failed", finished_at: JETZT - 40 }), + job({ id: "f3", state: "canceled", finished_at: JETZT - 30 }), + job({ id: "f4", state: "done", finished_at: JETZT - 20 }), + job({ id: "download", label: "download a/b", state: "running", group: null }), + job({ id: "update", group: "maintenance", state: "queued", started_at: JETZT - 10 }), + ], + JETZT, + ) + expect(liste.map((j) => j.id)).toEqual(["download", "update", "f4", "f3", "f2"]) + }) +}) diff --git a/frontend/src/components/cockpit/JobKarte.tsx b/frontend/src/components/cockpit/JobKarte.tsx new file mode 100644 index 0000000..53072e3 --- /dev/null +++ b/frontend/src/components/cockpit/JobKarte.tsx @@ -0,0 +1,116 @@ +import { useState } from "react" +import { Button } from "@/components/ui/button" +import { + abbrechbar, fortschrittText, jobDownload, jobTitel, laeuftNoch, laufText, letzteMeldung, +} from "@/lib/anzeige" +import type { Job, JobZustand } from "@/lib/typen" +import { flugplanZeit } from "@/lib/zeit" +import { Bestaetigen } from "./Bestaetigen" +import { Chip, type ChipArt } from "./Chip" + +const ZUSTAND: Record = { + queued: { text: "Wartet", art: "cyan" }, + running: { text: "Läuft", art: "cyan" }, + done: { text: "Fertig", art: "gruen" }, + failed: { text: "Fehler", art: "rot" }, + canceled: { text: "Abgebrochen", art: "grau" }, +} + +const zeitVon = (sekunden: number) => flugplanZeit(new Date(sekunden * 1000).toISOString()) + +/** + * Ein Hintergrund-Auftrag als Karte: Titel und Zustand, bei Downloads der Fortschritt, bei Fehlern + * die letzte Meldung, auf Wunsch das Protokoll. Abbrechen nur, wo es wirklich stoppt (`abbrechbar`). + */ +export function JobKarte({ job, onAbbrechen, abbrechenGesperrt }: { + job: Job + onAbbrechen?: (job: Job) => void + abbrechenGesperrt?: boolean +}) { + const [frage, setFrage] = useState(false) + const [protokoll, setProtokoll] = useState(false) + const zustand = ZUSTAND[job.state] ?? { text: job.state, art: "grau" as const } + const titel = jobTitel(job) + const fortschritt = fortschrittText(job) + const meldung = letzteMeldung(job) + const laeuft = laeuftNoch(job) + const darfAbbrechen = !!onAbbrechen && abbrechbar(job) + const protokollZeilen = (job.log ?? []).slice(-12) + + return ( +
+
+

{titel}

+ {zustand.text} +
+ + {job.progress != null && ( +
+
+
+ )} + +

+ {laeuft + ? fortschritt ?? laufText(job) + : `${zustand.text} · ${zeitVon(job.finished_at ?? job.started_at)}`} +

+ + {/* Bei Fehlern steht der Grund meist in der letzten Zeile; ohne Fortschrittsbalken zeigt sie, woran der Auftrag gerade ist. */} + {meldung && (job.state === "failed" || (laeuft && job.progress == null)) && ( +

+ {job.state === "failed" ? `Letzte Meldung: ${meldung}` : meldung} +

+ )} + + {(darfAbbrechen || protokollZeilen.length > 1) && ( +
+ {darfAbbrechen && ( + + )} + {protokollZeilen.length > 1 && ( + + )} +
+ )} + + {protokoll && ( +
+          {protokollZeilen.join("\n")}
+        
+ )} + + {darfAbbrechen && ( + setFrage(false)} + onJa={() => { + setFrage(false) + onAbbrechen?.(job) + }} + /> + )} +
+ ) +} diff --git a/frontend/src/lib/abfragen.ts b/frontend/src/lib/abfragen.ts index ac13732..87df48e 100644 --- a/frontend/src/lib/abfragen.ts +++ b/frontend/src/lib/abfragen.ts @@ -3,16 +3,28 @@ // Takte: Steht der Live-Strom, meldet er Änderungen selbst — die Abfragen sind dann nur // Sicherheitsnetz und laufen fünfmal seltener. -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" +import { type QueryClient, useMutation, useQuery, useQueryClient } from "@tanstack/react-query" import { api, post } from "./api" +import { fehlerText, laeuftNoch } from "./anzeige" import { melden } from "./meldungen" import { stromVerbunden } from "./strom" import type { - AktionsErgebnis, AufraeumKandidat, Job, Modell, Nutzung, Radar, Sicherung, Start, + AktionsErgebnis, AufraeumKandidat, Job, Modell, Nutzung, Radar, Sicherung, Start, UpdateDetails, } from "./typen" +import { gbText } from "./zeit" const takt = (ms: number) => () => (stromVerbunden() ? ms * 5 : ms) +/** Was ein beendeter Auftrag verändert haben kann: Versionen, Modelle, Sicherungen, Platte. */ +const NACH_AUFTRAG = ["start", "update-details", "updates-verlauf", "models", "sicherungen", "aufraeumen"] + +/** Ist seit der letzten Abfrage ein Auftrag fertig geworden, lesen die betroffenen Ansichten neu. */ +function auftragsEndeMelden(qc: QueryClient, neu: Job[]) { + const alt = qc.getQueryData<{ jobs: Job[] }>(["jobs"])?.jobs ?? [] + const ebenFertig = neu.some((j) => !laeuftNoch(j) && alt.some((a) => a.id === j.id && laeuftNoch(a))) + if (ebenFertig) for (const k of NACH_AUFTRAG) qc.invalidateQueries({ queryKey: [k] }) +} + export const useStart = () => useQuery({ queryKey: ["start"], @@ -34,14 +46,19 @@ export const useNutzung = () => export const useRadar = () => useQuery({ queryKey: ["radar"], queryFn: () => api("/api/radar"), retry: false, refetchInterval: 300_000 }) -export const useJobs = () => - useQuery({ +export const useJobs = () => { + const qc = useQueryClient() + return useQuery({ queryKey: ["jobs"], - queryFn: () => api<{ jobs: Job[] }>("/api/jobs"), + queryFn: async () => { + const daten = await api<{ jobs: Job[] }>("/api/jobs") + auftragsEndeMelden(qc, daten.jobs) + return daten + }, // Läuft etwas, wollen wir den Fortschritt sehen; sonst reicht der Strom. - refetchInterval: (q) => - q.state.data?.jobs.some((j) => j.state === "running" || j.state === "queued") ? 2000 : takt(30_000)(), + refetchInterval: (q) => (q.state.data?.jobs.some(laeuftNoch) ? 2000 : takt(30_000)()), }) +} export const useSicherungen = () => useQuery({ @@ -49,21 +66,6 @@ export const useSicherungen = () => queryFn: () => api<{ available: boolean; backups: Sicherung[] }>("/api/zeitmaschine"), }) -export interface UpdateDetails { - kind: string - installed_version?: string | null - behind?: number - installed_build?: number | null - latest_build?: number | null - latest_tag?: string | null - count?: number - packages?: { name: string; current: string; candidate: string }[] - summary?: string - action_needed?: boolean | null - action_text?: string - error?: string -} - export const useUpdateDetails = (art: string | null) => useQuery({ queryKey: ["update-details", art], @@ -108,7 +110,12 @@ export const useDienste = () => function useAktion>( fn: (v: V) => Promise, - opt: { erfolg: (v: V, e: E) => string; neuLaden: string[] }, + opt: { + erfolg: (v: V, e: E) => string + /** Eigener Text, wenn die Box mit ok: false antwortet (sonst der Grund aus der Antwort). */ + fehler?: (v: V, e: AktionsErgebnis) => string + neuLaden: string[] + }, ) { const qc = useQueryClient() return useMutation({ @@ -116,7 +123,7 @@ function useAktion>( onSuccess: (e, v) => { const ergebnis = e as AktionsErgebnis if (ergebnis && ergebnis.ok === false) { - melden("fehler", ergebnis.detail || ergebnis.err || "Das hat nicht geklappt.") + melden("fehler", opt.fehler?.(v, ergebnis) ?? fehlerText(ergebnis)) } else { melden("erfolg", opt.erfolg(v, e)) } @@ -130,7 +137,11 @@ export const useHinweisAktion = () => useAktion( ({ hinweis, aktion }: { hinweis: string; aktion: string; label: string }) => post(`/api/hinweise/${encodeURIComponent(hinweis)}/aktion/${aktion}`), - { erfolg: (v) => `${v.label}: erledigt. Der Wächter prüft in einer Minute nach.`, neuLaden: ["start"] }, + { + erfolg: (v, e) => + v.aktion === "freigeben" && e.text ? e.text : `${v.label}: erledigt. Der Wächter prüft in einer Minute nach.`, + neuLaden: ["start"], + }, ) const UPDATE_PFADE: Record = { @@ -144,10 +155,34 @@ const UPDATE_PFADE: Record = { export const useUpdateStarten = () => useAktion((art: string) => post(UPDATE_PFADE[art]), { - erfolg: (art) => (art === "pruefen" ? "Suche nach Neuem läuft." : "Update läuft. Den Fortschritt siehst du unten."), + erfolg: (art) => + art === "pruefen" + ? "Die Suche nach Neuem läuft. Den Fortschritt siehst du unten bei den Aufträgen." + : "Das Update läuft. Den Fortschritt siehst du unten bei den Aufträgen.", neuLaden: ["jobs", "start"], }) +/** Einen laufenden Auftrag abbrechen (nur Downloads und die Suche, siehe `abbrechbar`). */ +export const useJobAbbrechen = () => + useAktion(({ id }: { id: string; titel: string }) => post(`/api/jobs/${encodeURIComponent(id)}/cancel`), { + erfolg: (v) => `${v.titel}: wird abgebrochen.`, + fehler: (v) => `${v.titel} lief schon nicht mehr.`, + neuLaden: ["jobs"], + }) + +/** Ein Modell von Hugging Face holen (Hintergrund-Auftrag, mit optionaler Rolle nach dem Download). */ +export const useInstallieren = () => + useAktion( + ({ repo, quant, rolle }: { repo: string; quant: string; rolle: string | null }) => + post("/api/models/install", { repo, quant, role: rolle }), + { + erfolg: (v, e) => + `${v.repo} (${v.quant}) wird heruntergeladen${e.total_bytes ? `, ${gbText(e.total_bytes, 1)}` : ""}. ` + + "Den Fortschritt siehst du unter Aufträge.", + neuLaden: ["jobs", "models"], + }, + ) + export const useAufraeumen = () => useQuery({ queryKey: ["aufraeumen"], @@ -168,8 +203,10 @@ export const useFreigeben = () => ) export const useJetztSichern = () => - useAktion(() => post("/api/system/backup"), { - erfolg: () => "Sicherung erstellt.", + useAktion(() => post("/api/system/backup"), { + erfolg: (_, e) => + e.size_mb != null ? `Sicherung erstellt (${e.size_mb.toLocaleString("de-DE")} MB).` : "Sicherung erstellt.", + fehler: (_, e) => `Die Sicherung ging nicht: ${fehlerText(e)}`, neuLaden: ["sicherungen", "start"], }) diff --git a/frontend/src/lib/anzeige.ts b/frontend/src/lib/anzeige.ts index 01df897..c3d1876 100644 --- a/frontend/src/lib/anzeige.ts +++ b/frontend/src/lib/anzeige.ts @@ -1,8 +1,8 @@ // Reine Anzeige-Logik der Cockpit-Seiten — getrennt von den Komponenten, damit sie ohne // DOM testbar bleibt und Vites Hot-Reload die Komponenten-Dateien sauber tauschen kann. -import type { UpdateDetails } from "./abfragen" -import type { Modell, Start } from "./typen" +import type { AktionsErgebnis, Job, Modell, Start, UpdateDetails } from "./typen" +import { gbText } from "./zeit" // --- Rundinstrument ----------------------------------------------------------------- // 240°-Bogen wie ein Zeigerinstrument, Mittelpunkt (100|95) in einer 200×150-Zeichnung. @@ -57,10 +57,9 @@ export function hauptleuchte(z: Start["zustand"]) { // --- Updates ------------------------------------------------------------------------ -/** „Läuft“ und „Neu“ aus den Update-Details lesbar machen. */ -export function versionen(id: string, d: UpdateDetails | undefined): { laeuft: string; neu: string | null } { - if (!d) return { laeuft: "…", neu: null } - if (id === "os") return { laeuft: "Ubuntu", neu: d.count ? `${d.count} Pakete` : null } +/** „Läuft“ und „Neu“ aus den Update-Details lesbar machen (die Details sind schon geladen). */ +export function versionen(id: string, d: UpdateDetails): { laeuft: string; neu: string | null } { + if (id === "os") return { laeuft: "Ubuntu", neu: d.count ? `${d.count} ${d.count === 1 ? "Paket" : "Pakete"}` : null } // Hermes kommt aus git: „Neu“ ist die Zahl der Änderungen seit dem eingespielten Stand. if (id === "hermes") { return { @@ -74,6 +73,107 @@ export function versionen(id: string, d: UpdateDetails | undefined): { laeuft: s return { laeuft, neu: neuer ? `${pre}${d.latest_build}` : null } } +/** Sagen die Details, dass es Neues gibt? null = weiß man nicht (Prüfung gescheitert oder unvollständig). */ +export function detailsHabenNeues(id: string, d: UpdateDetails | undefined): boolean | null { + if (!d || d.error) return null + if (id === "os") return typeof d.count === "number" ? d.count > 0 : null + if (id === "hermes") return typeof d.behind === "number" ? d.behind > 0 : null + if (d.latest_build == null || d.installed_build == null) return null + return d.latest_build > d.installed_build +} + +/** Eine gescheiterte Update-Prüfung in Worten („Konnte nicht prüfen: …“), ohne Befehlszeilen-Kauderwelsch. */ +export function pruefFehlerText(fehler: string): string { + const f = fehler.trim() + if (/timed out|timeout|zeitüberschreitung/i.test(f)) { + return "Konnte nicht prüfen: Die Gegenstelle hat nicht rechtzeitig geantwortet. Später klappt es meist wieder." + } + if (/name resolution|name or service not known|network is unreachable|connection (refused|reset)|nicht erreichbar/i.test(f)) { + return "Konnte nicht prüfen: Die Box kommt gerade nicht ins Internet." + } + return `Konnte nicht prüfen: ${f.length > 160 ? `${f.slice(0, 157)}…` : f}` +} + +/** Warum eine Aktion nicht geklappt hat — die Endpunkte legen den Grund in verschiedene Felder. */ +export function fehlerText(e: AktionsErgebnis | null | undefined): string { + if (e?.status === "busy") { + return e.running + ? `Es läuft schon ein Update („${e.running}“). Warte, bis es fertig ist.` + : "Es läuft schon ein Update. Warte, bis es fertig ist." + } + return e?.detail || e?.err || e?.error || e?.text || "Das hat nicht geklappt." +} + +// --- Aufträge (services/jobengine.py) --------------------------------------------------- + +/** Wartet oder läuft der Auftrag noch? */ +export const laeuftNoch = (j: Pick) => j.state === "running" || j.state === "queued" + +/** + * Darf man den Auftrag abbrechen? Updates nicht: Der Abbruch beendet nur die äußere Shell, apt + * und die Update-Skripte liefen weiter, und die Karte zeigte fälschlich „Abgebrochen“. Scheitert + * ein Update, rollen Motor und llama-swap selbst zurück. + */ +export const abbrechbar = (j: Pick) => laeuftNoch(j) && j.group !== "maintenance" + +/** Die Beschriftung eines Auftrags auf Deutsch („download org/repo“ heißt im Backend noch englisch). */ +export function jobTitel(j: Pick): string { + const m = /^download\s+(.+)$/i.exec(j.label) + return m ? `Download ${m[1]}` : j.label +} + +/** Ist der Auftrag ein Modell-Download? (Bis das Backend eine Gruppe setzt, verrät es nur die Beschriftung.) */ +export const jobDownload = (j: Pick) => j.group === "download" || /^download\s/i.test(j.label) + +/** „noch etwa 6 min“ aus der geschätzten Restzeit in Sekunden. */ +export function restzeit(s: number): string { + if (s < 60) return "noch unter einer Minute" + const min = Math.round(s / 60) + if (min < 60) return `noch etwa ${min} min` + const h = Math.floor(min / 60) + const rest = min % 60 + return rest ? `noch etwa ${h} h ${rest} min` : `noch etwa ${h} h` +} + +/** „Läuft seit 12 min“ / „Wartet seit ein paar Sekunden“ für Aufträge ohne Fortschrittsanzeige. */ +export function laufText(j: Pick, jetzt = Date.now() / 1000): string { + const s = Math.max(0, jetzt - j.started_at) + const min = Math.floor(s / 60) + const dauer = s < 60 ? "ein paar Sekunden" : min < 60 ? `${min} min` : `${Math.floor(min / 60)} h ${min % 60} min` + return `${j.state === "queued" ? "Wartet" : "Läuft"} seit ${dauer}` +} + +/** „42 % · 12,3 GB von 29,1 GB · noch etwa 6 min“ — oder null, wenn der Auftrag keinen Fortschritt kennt. */ +export function fortschrittText(j: Job): string | null { + if (j.progress == null) return null + const teile = [`${Math.round(j.progress)} %`] + if (j.total_bytes) teile.push(`${gbText(j.done_bytes ?? 0, 1)} von ${gbText(j.total_bytes, 1)}`) + if (j.eta_s != null && laeuftNoch(j)) teile.push(restzeit(j.eta_s)) + return teile.join(" · ") +} + +/** Letzte aussagekräftige Zeile des Protokolls (nicht die Befehlszeile „$ …“, die der Auftrag zuerst schreibt). */ +export function letzteMeldung(j: Pick): string | null { + for (let i = (j.log?.length ?? 0) - 1; i >= 0; i--) { + const z = j.log[i].trim() + if (z && !z.startsWith("$ ")) return z + } + return null +} + +/** + * Welche Aufträge die Oberfläche zeigt: alle laufenden und wartenden (egal aus welcher Gruppe), + * dazu die drei zuletzt beendeten der letzten 24 Stunden — damit man sieht, wie es ausging. + */ +export function sichtbareJobs(jobs: Job[], jetzt = Date.now() / 1000): Job[] { + const laufend = jobs.filter(laeuftNoch).sort((a, b) => a.started_at - b.started_at) + const beendet = jobs + .filter((j) => !laeuftNoch(j) && jetzt - (j.finished_at ?? j.started_at) < 86_400) + .sort((a, b) => (b.finished_at ?? b.started_at) - (a.finished_at ?? a.started_at)) + .slice(0, 3) + return [...laufend, ...beendet] +} + // --- Modelle ------------------------------------------------------------------------ /** Rolle eines Modells aus seinen llama-swap-Aliasen. */ diff --git a/frontend/src/lib/typen.ts b/frontend/src/lib/typen.ts index 26bbd4a..0b5e66f 100644 --- a/frontend/src/lib/typen.ts +++ b/frontend/src/lib/typen.ts @@ -1,5 +1,6 @@ // Datenformen der Box-Wart-Schnittstellen — Gegenstück zu backend/routers/boxwart.py, -// services/waechter.py, modell_nutzung.py, zeitplan.py und routers/radar.py. +// services/waechter.py, modell_nutzung.py, zeitplan.py, routers/radar.py sowie +// services/jobengine.py (Aufträge) und services/maintenance.py (Update-Details). export type Stufe = "rot" | "gelb" export type LampenZustand = "ok" | "aus" | "warn" | "info" | "fehler" @@ -90,12 +91,48 @@ export interface AufraeumKandidat { hinweis: string } +/** Antwort einer Aktion. Je nach Endpunkt steht der Fehler in einem anderen Feld. */ export interface AktionsErgebnis { ok: boolean text?: string out?: string err?: string detail?: string + /** „Jetzt sichern“ (/api/system/backup) legt seinen Fehler hier ab. */ + error?: string + /** "busy" (es läuft schon ein Update), "nothing", "password_required" … */ + status?: string + /** Bei status "busy": welcher Auftrag gerade läuft. */ + running?: string + job_id?: string +} + +/** Was ein Update eines Bausteins bringen würde (GET /api/maintenance/update-details?kind=…). */ +export interface UpdateDetails { + kind: string + /** Die Prüfung selbst ist gescheitert, z. B. „git fetch“ lief in eine Zeitüberschreitung. */ + error?: string + // Betriebssystem + count?: number + packages?: { name: string; current: string; candidate: string }[] + /** Pakete, die Ubuntu noch zurückhält: "phasing" (schrittweise Verteilung) oder "kept_back". */ + held_back?: { name: string; reason: string }[] + // Motor und llama-swap + installed_build?: number | null + latest_build?: number | null + latest_tag?: string | null + name?: string | null + url?: string | null + // Hermes + branch?: string | null + installed_version?: string | null + behind?: number + commits?: { hash: string; subject: string; when: string }[] + // Zusammenfassung durchs Hirn (Motor, llama-swap, Hermes) — nur, wenn es Neues gibt + summary?: string + /** Musst du etwas tun? false = nein, true = ja (siehe action_text), null = unbekannt. */ + action_needed?: boolean | null + action_text?: string } export interface Nutzung { @@ -120,14 +157,28 @@ export interface Modell { capabilities?: { vision?: boolean; tools?: boolean; params_b?: number } & Record } +/** Zustände eines Auftrags, wie services/jobengine.py sie schreibt („canceled“ mit einem l). */ +export type JobZustand = "queued" | "running" | "done" | "failed" | "canceled" + +/** Ein Hintergrund-Auftrag (Update, Modell-Download, Suche) aus services/jobengine.py. */ export interface Job { id: string label: string - state: "running" | "done" | "failed" | "cancelled" | string + state: JobZustand + /** "maintenance" für Updates (davon läuft immer nur eins). Downloads und die Suche haben keine. */ + group: string | null + log: string[] + returncode: number | null + /** Unix-Sekunden */ + started_at: number + finished_at: number | null + canceled?: boolean + /** Nur bei Downloads: Fortschritt 0…100 und die Bytes dazu. */ progress?: number | null - log?: string[] - started?: number - finished?: number | null + total_bytes?: number + done_bytes?: number + rate_bps?: number + eta_s?: number } export interface Sicherung { diff --git a/frontend/src/views/Updates.tsx b/frontend/src/views/Updates.tsx index 04d6cc7..766a97b 100644 --- a/frontend/src/views/Updates.tsx +++ b/frontend/src/views/Updates.tsx @@ -1,5 +1,7 @@ import { useState } from "react" +import { ChevronRight } from "lucide-react" import { cn } from "cn" +import { Auftraege } from "@/components/cockpit/Auftraege" import { Bestaetigen } from "@/components/cockpit/Bestaetigen" import { Chip, type ChipArt, Zustandsfeld } from "@/components/cockpit/Chip" import { Panel } from "@/components/cockpit/Panel" @@ -8,8 +10,8 @@ import { type UpdateLauf, useFreigeben, useJetztSichern, useJobs, useSicherungen, useStart, useUpdateDetails, useUpdateStarten, useUpdateVerlauf, useZurueckspielen, } from "@/lib/abfragen" -import { versionen } from "@/lib/anzeige" -import type { Festgehalten, Job, Sicherung } from "@/lib/typen" +import { detailsHabenNeues, laeuftNoch, pruefFehlerText, versionen } from "@/lib/anzeige" +import type { Festgehalten, Sicherung, UpdateDetails } from "@/lib/typen" import { flugplanZeit } from "@/lib/zeit" const BAUSTEINE = [ @@ -19,46 +21,171 @@ const BAUSTEINE = [ { id: "hermes", name: "Hermes" }, ] as const -function BausteinZeile({ id, name, gelesen, hatUpdate, fest, onStart, onFreigeben, laeuftGerade }: { +/** Was ein einzelnes Update tut — steht in der Rückfrage, bevor es losgeht. */ +const EINZEL_TEXT: Record = { + os: "Die Ubuntu-Pakete werden eingespielt, danach prüft die Box, ob die Modelle noch antworten. Das kann einige Minuten dauern.", + engine: "Der Motor wird ersetzt, llama-swap startet dafür neu und die Modelle sind kurz nicht erreichbar. Klappt die Prüfung danach nicht, holt die Box den alten Stand von selbst zurück.", + swap: "llama-swap wird ersetzt und startet neu, die Modelle sind kurz nicht erreichbar. Klappt die Prüfung danach nicht, holt die Box den alten Stand von selbst zurück.", + hermes: "Vorher wird gesichert. Dann wird Hermes aktualisiert und startet neu — Lucy ist dabei ein paar Minuten nicht erreichbar.", +} + +/** Platzhalter, solange die Box noch nachsieht — statt „…“ oder eines voreiligen „neu“. */ +function Skelett({ breit = "w-16" }: { breit?: string }) { + return ( + + + wird geprüft + + ) +} + +/** Die Zusammenfassung des Hirns: drei Zeilen sichtbar, der Rest auf Knopfdruck. */ +function Zusammenfassung({ text }: { text: string }) { + const [offen, setOffen] = useState(false) + const lang = text.split("\n").length > 3 || text.length > 240 + return ( +
+

{text}

+ {lang && ( + + )} +
+ ) +} + +/** Die Paketliste des Betriebssystems, aufklappbar — dazu, was Ubuntu noch zurückhält. */ +function Paketliste({ d }: { d: UpdateDetails }) { + const pakete = d.packages ?? [] + const zurueck = d.held_back ?? [] + if (pakete.length === 0 && zurueck.length === 0) return null + return ( +
+ + + {pakete.length === 1 ? "Das Paket ansehen" : `Alle ${pakete.length} Pakete ansehen`} + +
    + {pakete.map((p) => ( +
  • + {p.name}{" "} + {p.current} → {p.candidate} +
  • + ))} +
+ {zurueck.length > 0 && ( +

+ Dazu {zurueck.length === 1 ? "kommt ein Paket" : `kommen ${zurueck.length} Pakete`}, die Ubuntu noch + zurückhält ({zurueck.map((p) => p.name).join(", ")}). Die kommen von selbst, wenn Ubuntu sie freigibt. +

+ )} +
+ ) +} + +/** Das Urteil des Hirns aus den Versionshinweisen: Muss der Besitzer etwas tun? */ +function Urteil({ d }: { d: UpdateDetails }) { + if (d.action_needed === false) return Nichts zu tun + if (d.action_needed !== true) return null + return ( + + Du musst etwas tun + {d.action_text && {d.action_text}} + + ) +} + +function zusammenfassung(summary: string | undefined): string | null { + const s = summary?.trim() + if (!s) return null + // Das Backend meldet ein nicht antwortendes Hirn als „(Zusammenfassung nicht verfügbar: )“. + if (s.startsWith("(Zusammenfassung nicht verfügbar")) return "Die Zusammenfassung ist gerade nicht verfügbar." + return s +} + +function BausteinZeile({ id, name, neuLautStart, fest, gesperrt, onStart, onFreigeben }: { id: string name: string - gelesen: boolean - hatUpdate: boolean + /** Was /api/start über diesen Baustein sagt („3 Pakete“, „neuer Build“), undefined = nichts Neues. */ + neuLautStart: string | undefined fest: Festgehalten | undefined + gesperrt: boolean onStart: () => void onFreigeben: () => void - laeuftGerade: boolean }) { - const { data, isPending } = useUpdateDetails(id) - const v = versionen(id, data) - const neu = hatUpdate ? v.neu ?? "neu" : null - const was = !gelesen - ? "Wird gerade geprüft …" - : !hatUpdate - ? "Aktuell." - : data?.summary?.trim() || (id === "os" && data?.count ? "Paketliste unten in den Details." : isPending ? "Wird gelesen …" : "") - const neuText = neu ? {neu} : – + const details = useUpdateDetails(id) + const d = details.data + const laedt = details.isPending + const fehler = details.isError ? details.error.message : d?.error + const v = d ? versionen(id, d) : null + // Frische Details schlagen den gecachten Stand der Startseite; wissen sie nichts, gilt der Start. + const hatUpdate = detailsHabenNeues(id, d) ?? neuLautStart != null + const neu = hatUpdate ? v?.neu ?? neuLautStart ?? null : null + const summary = zusammenfassung(d?.summary) + + const laeuftZelle = laedt ? : <>{v?.laeuft ?? "–"} + const neuZelle = laedt ? ( + + ) : neu ? ( + {neu} + ) : fehler ? ( + nicht geprüft + ) : ( + – + ) + + let was + if (laedt) { + was = Wird geprüft … + } else if (fehler && !hatUpdate) { + was = {pruefFehlerText(fehler)} + } else if (!hatUpdate) { + was = "Aktuell." + } else { + was = ( + + {fehler && {pruefFehlerText(fehler)}} + {d && } + {id === "os" ? ( + <> + {d?.count ? `${d.count} ${d.count === 1 ? "Paket" : "Pakete"} aus Ubuntu.` : "Neue Pakete aus Ubuntu."} + {d && } + + ) : summary ? ( + + ) : null} + + ) + } + // Am PC eine Tabellenzeile, am Handy ein Block: Name und Versionen oben, darunter was sich // ändert, darunter die Knöpfe — ohne seitliches Scrollen. return (
{name} - {v.laeuft} - {neu && <> → {neuText}} + {laeuftZelle} + {!laedt && (neu || fehler) && <> {neu ? "→" : "·"} {neuZelle}} - {v.laeuft} - {neuText} + {laeuftZelle} + {neuZelle} {fest && ( Festgehalten seit {fest.seit} auf {fest.version}: {fest.grund}. Der Sonntags-Lauf überspringt {name}. )} - {was} + {was} {(fest || hatUpdate) && ( @@ -68,7 +195,7 @@ function BausteinZeile({ id, name, gelesen, hatUpdate, fest, onStart, onFreigebe )} {hatUpdate && ( - )} @@ -89,17 +216,22 @@ const PUNKT: Record = { function LaufEintrag({ lauf }: { lauf: UpdateLauf }) { return (
  • -
    - {flugplanZeit(lauf.start)} - {lauf.anlass} - {lauf.titel} + {/* Handy: Zeit und Ergebnis oben, der Anlass darunter über die volle Breite. */} +
    + {flugplanZeit(lauf.start)} + + {lauf.anlass} + + + {lauf.titel} +
    {lauf.stufe !== "grau" && lauf.zeilen.length > 0 && ( + ) + } + return ( !o && onSchliessen()}> @@ -34,43 +110,7 @@ export function Dienste({ offen, onSchliessen }: { offen: boolean; onSchliessen: Dienste und Protokolle Welcher Dienst läuft, was er zuletzt geschrieben hat. -
      - {(dienste.data?.services ?? []).map((d) => ( -
    • - - - - {d.name} - - {d.unit} · {d.ok ? "läuft" : d.schlaeft ? "schläft (abgeschaltet)" : "antwortet nicht"} - - - - - - {bestaetigen === d.unit ? ( - - ) : ( - - )} - -
    • - ))} -
    - {gewaehlt && ( -
    -            {protokoll.isFetching ? "Wird gelesen …" : protokoll.data?.text || protokoll.data?.err || "Kein Protokoll."}
    -          
    - )} + {inhalt}
    ) diff --git a/frontend/src/views/Einstellungen.tsx b/frontend/src/views/Einstellungen.tsx index 8986ef9..6ceeb5d 100644 --- a/frontend/src/views/Einstellungen.tsx +++ b/frontend/src/views/Einstellungen.tsx @@ -20,8 +20,13 @@ export function Einstellungen({ offen, onSchliessen }: { offen: boolean; onSchli enabled: offen, }) const [token, setToken] = useState("") + const [speichert, setSpeichert] = useState(false) + const [loeschFrage, setLoeschFrage] = useState(false) async function speichern(wert: string | null) { + if (speichert) return + setSpeichert(true) + setLoeschFrage(false) try { await post("/api/maintenance/geheimnisse", { schluessel: "hf_token", wert }) melden("erfolg", wert ? "Hugging-Face-Zugang gespeichert." : "Hugging-Face-Zugang gelöscht.") @@ -29,10 +34,17 @@ export function Einstellungen({ offen, onSchliessen }: { offen: boolean; onSchli qc.invalidateQueries({ queryKey: ["geheimnisse"] }) } catch (f) { melden("fehler", (f as Error).message) + } finally { + setSpeichert(false) } } const s = stand.data + // Solange der Stand lädt, weiß die Oberfläche nicht, ob ein Zugang hinterlegt ist — also nicht „Fehlt.“ sagen. + let standText: string + if (stand.isPending) standText = "Wird gelesen …" + else if (!s) standText = `Lässt sich gerade nicht lesen${stand.error ? `: ${stand.error.message}` : "."}` + else standText = s.hf_token_gesetzt ? "Ist hinterlegt." : "Fehlt." return ( !o && onSchliessen()}> @@ -42,10 +54,14 @@ export function Einstellungen({ offen, onSchliessen }: { offen: boolean; onSchli

    Hugging-Face-Zugang

    -

    - {s?.hf_token_gesetzt ? "Ist hinterlegt." : "Fehlt."} Nötig für gesperrte Modelle und schnellere Downloads. +

    + {standText} Nötig für gesperrte Modelle und + schnellere Downloads. {s?.hf_token_aus_env ? " Er kommt aus der Dienst-Einstellung und lässt sich hier nicht löschen." : ""}

    + {s?.schreibbar === false && ( +

    Die Box kann den Zugang gerade nicht speichern: Ihre Ablage ist nicht beschreibbar.

    + )}
    { @@ -63,10 +79,21 @@ export function Einstellungen({ offen, onSchliessen }: { offen: boolean; onSchli placeholder="hf_…" className="h-11 min-w-0 flex-1 rounded-lg border border-linie-stark bg-erhaben px-3 text-[15px] outline-none focus:border-cyan" /> - +
    {s?.hf_token_gesetzt && !s.hf_token_aus_env && ( - + loeschFrage ? ( + + + + + ) : ( + + ) )}
    From 29ec6f2ccf0be98cd48ba048b5ceca9ed565d825 Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Thu, 24 Sep 2026 15:42:13 +0200 Subject: [PATCH 7/9] aufraeumen: shadcn nur noch zum Bauen, tote Exporte und Test-Attrappen raus, Lint-Regeln scharf - shadcn liefert zur Laufzeit nichts: gebraucht wird nur shadcn/tailwind.css beim Bauen (am PC und im CI, beide mit npm ci inkl. devDependencies). Also devDependency; 325 Pakete im Lockfile haengen ausschliesslich daran und sind jetzt "dev". - @testing-library/user-event war nirgends benutzt: entfernt. - Dialog/Sheet: ungenutzte Trigger/Close/Footer und "use client" raus. - test/setup.ts: ResizeObserver-Attrappe fuer Recharts und Kraftgraph entfernt - beide gibt es nicht mehr, und Radix' Dialog misst nichts. - eslint.config.js: Die vier React-Compiler-Regeln sollten laut Kommentar auf "error", sobald ihr Zaehler 0 ist. Er ist 0 - jetzt error. Veraltete Zahlen und "Recharts" im Kommentar korrigiert. - lib/utils.ts bleibt (Ziel von components.json fuer die shadcn-CLI), jetzt mit Kommentar. - Lockfile: npm 11.17 traegt sechs optionale wasm32-Unterpakete zusaetzlich ein, auch ohne diese Aenderung; die sind wieder raus, damit der Diff nur das Gewollte zeigt. Co-Authored-By: Claude Opus 5.5 --- frontend/eslint.config.js | 26 +- frontend/package-lock.json | 338 ++++++++++++++++++++++++-- frontend/package.json | 3 +- frontend/src/components/ui/dialog.tsx | 17 +- frontend/src/components/ui/sheet.tsx | 32 +-- frontend/src/lib/utils.ts | 2 + frontend/src/test/setup.ts | 44 +--- 7 files changed, 344 insertions(+), 118 deletions(-) diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index 3b9260b..f940abd 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -31,22 +31,18 @@ export default tseslint.config( ...reactHooks.configs.recommended.rules, "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], - // Die Regeln aus der React-Compiler-Generation (Plugin v7) finden im Bestand - // 18 echte Stellen: setState direkt im Effekt, Ref-Zugriff waehrend des Renderns, - // Komponenten im Render erzeugt. Das sind keine Fehlalarme — aber sie quer durch - // 10 000 Zeilen zu beheben ist die Arbeit von Etappe P5 (Feature-Slices), nicht - // von P1. Als Fehler waere das Gate ab Tag eins rot, und ein dauerhaft rotes Gate - // ist kein Gate mehr ("Rot ist ein Ergebnis, kein Aergernis"). - // Darum: sichtbare Warn-Liste statt stumm abgeschaltet. Beim Zerlegen eines - // Bereichs wird sein Anteil mit erledigt; ist der Zaehler bei 0, kommen sie - // hier auf "error" und der Rueckfall ist verbaut. - "react-hooks/set-state-in-effect": "warn", - "react-hooks/refs": "warn", - "react-hooks/immutability": "warn", - "react-hooks/static-components": "warn", + // Die Regeln aus der React-Compiler-Generation (Plugin v7): setState direkt im Effekt, + // Ref-Zugriff waehrend des Renderns, Komponenten im Render erzeugt. Im alten Bestand + // (10 000 Zeilen) fanden sie 18 Stellen und liefen darum als Warnung, mit der Abmachung: + // Ist der Zaehler bei 0, kommen sie auf "error" und der Rueckfall ist verbaut. + // Mit dem Box-Wart-Umbau (09/2026) stand der Zaehler bei 0 — also jetzt "error". + "react-hooks/set-state-in-effect": "error", + "react-hooks/refs": "error", + "react-hooks/immutability": "error", + "react-hooks/static-components": "error", - // `any` ist in diesem Projekt an einigen Stellen bewusst gesetzt (Recharts-Rueckrufe, - // Fehlerobjekte in catch). Warnen statt blockieren — sonst wird die Regel abgeschaltet. + // `any` kommt im Bestand nicht mehr vor (Stand 09/2026). Warnen statt blockieren, damit + // eine bewusst gesetzte Ausnahme (z. B. ein Fehlerobjekt in catch) das Gate nicht rot macht. "@typescript-eslint/no-explicit-any": "warn", // Ungenutzte Variablen sind fast immer ein Rest von etwas Halbfertigem. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 42a2ab3..af68ae8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -19,7 +19,6 @@ "radix-ui": "^1.6.7", "react": "^19.3.0", "react-dom": "^19.3.0", - "shadcn": "^4.21.0", "tw-animate-css": "^1.4.0" }, "devDependencies": { @@ -29,7 +28,6 @@ "@tailwindcss/vite": "^4.3.3", "@testing-library/jest-dom": "^7.0.1", "@testing-library/react": "^16.3.3", - "@testing-library/user-event": "^14.6.6", "@types/babel__core": "^7.20.5", "@types/node": "^22.10.1", "@types/react": "^19.2.18", @@ -42,6 +40,7 @@ "globals": "^17.11.0", "jsdom": "^30.0.1", "prettier": "^3.9.6", + "shadcn": "^4.21.0", "tailwindcss": "^4.3.3", "typescript": "^5.6.3", "typescript-eslint": "^8.68.0", @@ -113,6 +112,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", @@ -127,6 +127,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -136,6 +137,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", @@ -166,6 +168,7 @@ "version": "7.29.8", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.8", @@ -182,6 +185,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.7" @@ -194,6 +198,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.29.7", @@ -210,6 +215,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", @@ -231,6 +237,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -240,6 +247,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.29.7", @@ -253,6 +261,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.29.7", @@ -266,6 +275,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.29.7", @@ -283,6 +293,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.7" @@ -295,6 +306,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -304,6 +316,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.29.7", @@ -321,6 +334,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.29.7", @@ -334,6 +348,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -343,6 +358,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -352,6 +368,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -361,6 +378,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.29.7", @@ -374,6 +392,7 @@ "version": "7.29.9", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.8" @@ -389,6 +408,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" @@ -404,6 +424,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" @@ -419,6 +440,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.29.7", @@ -435,6 +457,7 @@ "version": "7.29.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.9.tgz", "integrity": "sha512-FFwIwzU+7SCOuxxV4YtJql6T9981ZVTm+FHO5GhVsRqCTdy0WwrEZh3l42ARpXruJUDGOptdduHW6Zr7pNPLNg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", @@ -454,6 +477,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", @@ -483,6 +507,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", @@ -497,6 +522,7 @@ "version": "7.29.8", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", @@ -515,6 +541,7 @@ "version": "7.29.8", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.29.7", @@ -705,6 +732,7 @@ "version": "1.75.1", "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.75.1.tgz", "integrity": "sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@dotenvx/primitives": "^0.8.0", @@ -735,6 +763,7 @@ "version": "11.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=16" @@ -744,6 +773,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -753,6 +783,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", @@ -776,6 +807,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -788,6 +820,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10.17.0" @@ -797,6 +830,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -812,6 +846,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -824,6 +859,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -836,6 +872,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": ">=18" @@ -845,6 +882,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -857,6 +895,7 @@ "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", @@ -874,12 +913,14 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, "license": "ISC" }, "node_modules/@dotenvx/dotenvx/node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -889,6 +930,7 @@ "version": "7.29.1", "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.1.tgz", "integrity": "sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=20.18.1" @@ -898,6 +940,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^3.1.1" @@ -913,6 +956,7 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/@dotenvx/primitives/-/primitives-0.8.0.tgz", "integrity": "sha512-VYJy0uhFm9zTJ1TxBaW/pA8bjbOM/OttaNMwZ1RHG4JKyRG7DhSdiqD1ipQoAyoD22olUtxbP78W9xY3Wd11bg==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/@eslint-community/eslint-utils": { @@ -1130,6 +1174,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.1.tgz", "integrity": "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -1208,6 +1253,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -1218,6 +1264,7 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -1228,6 +1275,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1237,12 +1285,14 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1277,6 +1327,7 @@ "version": "1.30.1", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.1.tgz", "integrity": "sha512-H2HxLvC3HDNybePJaLdSrU1hhUK5iQw+WvV1b01myFyI7sdVGe1u/IPTE5D9fGCiJDVtgMV/lmFkQXLmQyIFYA==", + "dev": true, "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.9 || ^2.0.5", @@ -1317,6 +1368,7 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -1333,12 +1385,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT" }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -1352,6 +1406,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -1361,6 +1416,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -3191,12 +3247,14 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, "license": "MIT" }, "node_modules/@sindresorhus/merge-streams": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3683,24 +3741,11 @@ } } }, - "node_modules/@testing-library/user-event": { - "version": "14.6.7", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.7.tgz", - "integrity": "sha512-MPCpX8bxe8zS+JmmTwLp8jd0dy1rAm60Te/SL8JrQM3qvQJcBOs1d7IefJMyZzqM3EWBrDn/LWDt1BCGu4ASfg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, "node_modules/@ts-morph/common": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz", "integrity": "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==", + "dev": true, "license": "MIT", "dependencies": { "fast-glob": "^3.3.3", @@ -3834,6 +3879,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz", "integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==", + "dev": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -4161,6 +4207,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, "license": "MIT", "dependencies": { "mime-types": "^3.0.0", @@ -4214,6 +4261,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -4231,6 +4279,7 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -4247,12 +4296,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT" }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4262,6 +4313,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4285,6 +4337,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, "license": "Python-2.0" }, "node_modules/aria-hidden": { @@ -4323,6 +4376,7 @@ "version": "0.16.3", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.3.tgz", "integrity": "sha512-FvWoWYfSCM6kRxCSH+MGLHIKKGRL6A6AW7Zek2O32REPQRdg131428uRTKMBYAeRd3XXAaHDS60Wpri7CdKDrA==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.0.1" @@ -4335,6 +4389,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.12.0" @@ -4354,6 +4409,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, "license": "MIT", "engines": { "node": "18 || 20 || >=22" @@ -4363,6 +4419,7 @@ "version": "2.11.25", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.25.tgz", "integrity": "sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==", + "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -4385,6 +4442,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -4409,6 +4467,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -4422,6 +4481,7 @@ "version": "5.0.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -4434,6 +4494,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -4446,6 +4507,7 @@ "version": "4.29.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz", "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -4479,6 +4541,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" @@ -4494,6 +4557,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -4517,6 +4581,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -4530,6 +4595,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -4546,6 +4612,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4555,6 +4622,7 @@ "version": "1.0.30001810", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "dev": true, "funding": [ { "type": "opencollective", @@ -4585,6 +4653,7 @@ "version": "5.6.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -4609,6 +4678,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, "license": "MIT", "dependencies": { "restore-cursor": "^5.0.0" @@ -4624,6 +4694,7 @@ "version": "2.9.2", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4657,12 +4728,14 @@ "version": "13.0.3", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "dev": true, "license": "MIT" }, "node_modules/commander": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -4672,6 +4745,7 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/conf/-/conf-10.2.0.tgz", "integrity": "sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.6.3", @@ -4696,6 +4770,7 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -4712,6 +4787,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -4729,18 +4805,21 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT" }, "node_modules/conf/node_modules/json-schema-typed": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz", "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/conf/node_modules/semver": { "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4753,6 +4832,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -4766,6 +4846,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -4775,12 +4856,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -4796,6 +4879,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.6.0" @@ -4805,6 +4889,7 @@ "version": "2.8.6", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, "license": "MIT", "dependencies": { "object-assign": "^4", @@ -4822,6 +4907,7 @@ "version": "9.0.2", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "dev": true, "license": "MIT", "dependencies": { "env-paths": "^2.2.1", @@ -4848,6 +4934,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -4883,6 +4970,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -4931,6 +5019,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==", + "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^3.0.0" @@ -4946,6 +5035,7 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4970,6 +5060,7 @@ "version": "1.7.2", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -4991,6 +5082,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5000,6 +5092,7 @@ "version": "5.5.1", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", @@ -5016,6 +5109,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5028,6 +5122,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -5040,6 +5135,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -5075,6 +5171,7 @@ "version": "8.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -5092,6 +5189,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, "license": "MIT", "dependencies": { "is-obj": "^2.0.0" @@ -5107,6 +5205,7 @@ "version": "17.4.2", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -5119,6 +5218,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -5133,24 +5233,28 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.438", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.438.tgz", "integrity": "sha512-AN9xMU1hJiT65LkCUPL1DZm5TCbOPb2Qsm5pYwFLEXp6/qj9SdT4yMiqs7Qqstwvkn1zF7l36SRGt+s6XcJ0FA==", + "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -5174,6 +5278,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1", @@ -5200,6 +5305,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5209,6 +5315,7 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -5218,6 +5325,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5227,6 +5335,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5243,6 +5352,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -5255,6 +5365,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5264,6 +5375,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, "license": "MIT" }, "node_modules/escape-string-regexp": { @@ -5422,6 +5534,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -5491,6 +5604,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -5500,6 +5614,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, "license": "MIT", "dependencies": { "eventsource-parser": "^3.0.1" @@ -5512,6 +5627,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.1.tgz", "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18.0.0" @@ -5521,6 +5637,7 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", @@ -5557,6 +5674,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, "license": "MIT", "dependencies": { "accepts": "^2.0.0", @@ -5600,6 +5718,7 @@ "version": "8.7.0", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.7.0.tgz", "integrity": "sha512-hOwV7WOxXfjRpAM1DSJWZDXx3GhplwD8IfwuwvogD8i1Qnkgosw/H45s4ZnFAUHDAhPjlY9hLBvJhKmGMyY26g==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.4.3", @@ -5619,12 +5738,14 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -5641,6 +5762,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -5667,6 +5789,7 @@ "version": "3.1.8", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "dev": true, "funding": [ { "type": "github", @@ -5683,6 +5806,7 @@ "version": "1.20.3", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", + "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -5692,6 +5816,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -5709,6 +5834,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, "license": "MIT", "dependencies": { "is-unicode-supported": "^2.0.0" @@ -5734,6 +5860,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -5746,6 +5873,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -5803,6 +5931,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -5812,6 +5941,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -5821,6 +5951,7 @@ "version": "11.4.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.1.tgz", "integrity": "sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -5850,6 +5981,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5859,12 +5991,14 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz", "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==", + "dev": true, "license": "MIT" }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -5874,6 +6008,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5886,6 +6021,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -5919,6 +6055,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz", "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.16" @@ -5931,6 +6068,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -5944,6 +6082,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, "license": "MIT", "dependencies": { "@sec-ant/readable-stream": "^0.4.1", @@ -5986,6 +6125,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5998,12 +6138,14 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, "license": "ISC" }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6029,6 +6171,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -6058,6 +6201,7 @@ "version": "4.13.8", "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.8.tgz", "integrity": "sha512-/Gng7NfoykZl2pjukW5Z6+8Yxm3BPRf86GTbQnt0SbySkvax4fyL4H3HhY1cCpBGmiW9XDRFzRV+CXK2W8QudQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=16.9.0" @@ -6087,6 +6231,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -6107,6 +6252,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -6116,6 +6262,7 @@ "version": "0.7.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -6132,6 +6279,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -6141,6 +6289,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -6177,12 +6326,14 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, "license": "ISC" }, "node_modules/ip-address": { "version": "10.7.2", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.2.tgz", "integrity": "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 12" @@ -6192,6 +6343,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.10" @@ -6201,12 +6353,14 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, "license": "MIT" }, "node_modules/is-docker": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -6222,6 +6376,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6231,6 +6386,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -6243,6 +6399,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -6255,6 +6412,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, "license": "MIT", "dependencies": { "is-docker": "^3.0.0" @@ -6273,6 +6431,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -6285,6 +6444,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -6294,6 +6454,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6303,6 +6464,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -6322,12 +6484,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, "license": "MIT" }, "node_modules/is-regexp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -6340,6 +6504,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -6352,6 +6517,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -6364,6 +6530,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" @@ -6388,6 +6555,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, "license": "ISC" }, "node_modules/jiti": { @@ -6404,6 +6572,7 @@ "version": "6.2.12", "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.12.tgz", "integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -6413,12 +6582,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "dev": true, "funding": [ { "type": "github", @@ -6491,6 +6662,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -6503,6 +6675,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { @@ -6516,6 +6689,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/json-stable-stringify-without-jsonify": { @@ -6529,6 +6703,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -6541,6 +6716,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -6563,6 +6739,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6859,6 +7036,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, "license": "MIT" }, "node_modules/locate-path": { @@ -6881,6 +7059,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^5.3.0", @@ -6897,6 +7076,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -6909,6 +7089,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -6948,6 +7129,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6964,6 +7146,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -6977,6 +7160,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -6989,12 +7173,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -7004,6 +7190,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -7017,6 +7204,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -7029,6 +7217,7 @@ "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -7038,6 +7227,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -7054,6 +7244,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7063,6 +7254,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -7085,6 +7277,7 @@ "version": "10.2.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.8" @@ -7100,6 +7293,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7109,12 +7303,14 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.19", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "dev": true, "funding": [ { "type": "github", @@ -7140,6 +7336,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", + "dev": true, "license": "MIT", "dependencies": { "content-type": "^2.1.0" @@ -7156,6 +7353,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -7169,6 +7367,7 @@ "version": "2.0.57", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.57.tgz", "integrity": "sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -7178,6 +7377,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^4.0.0", @@ -7194,6 +7394,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -7206,6 +7407,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7215,6 +7417,7 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -7227,6 +7430,7 @@ "version": "1.1.33", "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 10" @@ -7250,6 +7454,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -7262,6 +7467,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -7271,6 +7477,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -7286,6 +7493,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7295,6 +7503,7 @@ "version": "11.0.4", "resolved": "https://registry.npmjs.org/open/-/open-11.0.4.tgz", "integrity": "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==", + "dev": true, "license": "MIT", "dependencies": { "default-browser": "^5.5.1", @@ -7333,6 +7542,7 @@ "version": "8.2.0", "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^5.3.0", @@ -7356,6 +7566,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -7368,6 +7579,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.2.2" @@ -7415,6 +7627,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7424,6 +7637,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -7436,6 +7650,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", @@ -7454,6 +7669,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -7479,6 +7695,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -7488,6 +7705,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, "license": "MIT" }, "node_modules/path-exists": { @@ -7504,6 +7722,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7513,6 +7732,7 @@ "version": "8.4.2", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "dev": true, "license": "MIT", "funding": { "type": "opencollective", @@ -7523,12 +7743,14 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -7541,6 +7763,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=16.20.0" @@ -7550,6 +7773,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, "license": "MIT", "dependencies": { "find-up": "^3.0.0" @@ -7562,6 +7786,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^3.0.0" @@ -7574,6 +7799,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^3.0.0", @@ -7587,6 +7813,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -7602,6 +7829,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.0.0" @@ -7614,6 +7842,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -7623,6 +7852,7 @@ "version": "8.5.28", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "dev": true, "funding": [ { "type": "opencollective", @@ -7651,6 +7881,7 @@ "version": "7.1.6", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz", "integrity": "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -7664,6 +7895,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.1.tgz", "integrity": "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==", + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -7718,6 +7950,7 @@ "version": "9.3.1", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.1.tgz", "integrity": "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==", + "dev": true, "license": "MIT", "dependencies": { "parse-ms": "^4.0.0" @@ -7733,6 +7966,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, "license": "MIT", "dependencies": { "kleur": "^3.0.3", @@ -7746,6 +7980,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7755,6 +7990,7 @@ "version": "2.0.8", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.8.tgz", "integrity": "sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==", + "dev": true, "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -7802,6 +8038,7 @@ "version": "6.16.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "es-define-property": "^1.0.1", @@ -7818,6 +8055,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -7915,6 +8153,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -7928,6 +8167,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -8041,6 +8281,7 @@ "version": "0.23.21", "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.21.tgz", "integrity": "sha512-mFAyJq9vUbSTARLZUvAEf1z3YxlvAwswbmxMx2mPA/MSm4KmpwvwvhsH/NIrZhyOuwD60Lzyw2qh83uCbgTPYw==", + "dev": true, "license": "MIT", "dependencies": { "ast-types": "^0.16.1", @@ -8071,6 +8312,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8080,6 +8322,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -8089,6 +8332,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, "license": "MIT", "dependencies": { "onetime": "^7.0.0", @@ -8105,6 +8349,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, "license": "MIT", "dependencies": { "mimic-function": "^5.0.0" @@ -8120,6 +8365,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -8164,6 +8410,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -8180,6 +8427,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -8192,6 +8440,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -8215,6 +8464,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, "license": "MIT" }, "node_modules/saxes": { @@ -8240,6 +8490,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -8249,6 +8500,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.4.3", @@ -8296,6 +8548,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -8315,12 +8568,14 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, "license": "ISC" }, "node_modules/shadcn": { "version": "4.21.0", "resolved": "https://registry.npmjs.org/shadcn/-/shadcn-4.21.0.tgz", "integrity": "sha512-UU2mFNusW8C5rvadKdH69vERYZqUlOOlXBcf0MYhYLdTGP6DPti7X4qovCu+RTfCqsAgq/T+YfE0Vnttxh9aiw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.28.0", @@ -8368,6 +8623,7 @@ "version": "0.2.6", "resolved": "https://registry.npmjs.org/cn/-/cn-0.2.6.tgz", "integrity": "sha512-+i4L0zUGgRcEnhsxueVrP7iBGxBx5iD0WOTYg1MwFEu2ZyCmH5Ov2V1cul2Ht5UchRQQgftCf4be/RxspuW6QQ==", + "dev": true, "license": "MIT", "bin": { "cn": "bin/cn.mjs" @@ -8380,6 +8636,7 @@ "version": "7.29.1", "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.1.tgz", "integrity": "sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=20.18.1" @@ -8389,6 +8646,7 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -8398,6 +8656,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -8410,6 +8669,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8419,6 +8679,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -8438,6 +8699,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -8454,6 +8716,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8472,6 +8735,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8498,6 +8762,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -8510,12 +8775,14 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, "license": "MIT" }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6.0.0", @@ -8526,6 +8793,7 @@ "version": "2.8.10", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.10.tgz", "integrity": "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==", + "dev": true, "license": "MIT", "dependencies": { "ip-address": "^10.1.1", @@ -8540,6 +8808,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -8549,6 +8818,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -8565,6 +8835,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -8581,6 +8852,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -8593,6 +8865,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", @@ -8610,6 +8883,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8622,6 +8896,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.2.2" @@ -8637,6 +8912,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz", "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "get-own-enumerable-keys": "^1.0.0", @@ -8654,6 +8930,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz", "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8666,6 +8943,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -8678,6 +8956,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -8687,6 +8966,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -8712,6 +8992,7 @@ "version": "5.33.13", "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.13.tgz", "integrity": "sha512-GtyakkchTQKymM1WeAB652zi3rM1q00RKdc+jZe9KGstuc/mWUwAnQGN/RE5gVYvHIR8xYOUIUD9irVKDtA0wA==", + "dev": true, "license": "MIT", "os": [ "darwin", @@ -8759,6 +9040,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, "license": "MIT" }, "node_modules/tinybench": { @@ -8822,6 +9104,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -8834,6 +9117,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.6" @@ -8882,6 +9166,7 @@ "version": "26.0.0", "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-26.0.0.tgz", "integrity": "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==", + "dev": true, "license": "MIT", "dependencies": { "@ts-morph/common": "~0.27.0", @@ -8892,6 +9177,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, "license": "MIT", "dependencies": { "json5": "^2.2.2", @@ -8934,6 +9220,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, "license": "MIT", "dependencies": { "content-type": "^2.0.0", @@ -8952,6 +9239,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -8965,7 +9253,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -9020,6 +9308,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -9032,6 +9321,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -9041,6 +9331,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -9050,6 +9341,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -9142,12 +9434,14 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, "license": "MIT" }, "node_modules/validate-npm-package-name": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", + "dev": true, "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -9157,6 +9451,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -9658,6 +9953,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -9700,12 +9996,14 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, "license": "ISC" }, "node_modules/wsl-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.0.tgz", "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", + "dev": true, "license": "MIT", "dependencies": { "is-wsl": "^3.1.0", @@ -9722,6 +10020,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -9751,6 +10050,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yocto-queue": { @@ -9770,6 +10070,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-1.2.2.tgz", "integrity": "sha512-DODGl1wJjA/s5pnJFKau9lIYHT81lnhob1i3e1TjxZRxEhWRKl74nTbWE6H5KlkViQQTo/Z29YFdxzTZAMY3ng==", + "dev": true, "license": "MIT", "dependencies": { "yoctocolors": "^2.1.1" @@ -9785,6 +10086,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -9797,6 +10099,7 @@ "version": "4.6.5", "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -9806,6 +10109,7 @@ "version": "3.25.2", "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, "license": "ISC", "peerDependencies": { "zod": "^3.25.28 || ^4" diff --git a/frontend/package.json b/frontend/package.json index 93047ee..639d467 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,7 +24,6 @@ "radix-ui": "^1.6.7", "react": "^19.3.0", "react-dom": "^19.3.0", - "shadcn": "^4.21.0", "tw-animate-css": "^1.4.0" }, "devDependencies": { @@ -34,7 +33,6 @@ "@tailwindcss/vite": "^4.3.3", "@testing-library/jest-dom": "^7.0.1", "@testing-library/react": "^16.3.3", - "@testing-library/user-event": "^14.6.6", "@types/babel__core": "^7.20.5", "@types/node": "^22.10.1", "@types/react": "^19.2.18", @@ -47,6 +45,7 @@ "globals": "^17.11.0", "jsdom": "^30.0.1", "prettier": "^3.9.6", + "shadcn": "^4.21.0", "tailwindcss": "^4.3.3", "typescript": "^5.6.3", "typescript-eslint": "^8.68.0", diff --git a/frontend/src/components/ui/dialog.tsx b/frontend/src/components/ui/dialog.tsx index 35e7fa9..d1d36b1 100644 --- a/frontend/src/components/ui/dialog.tsx +++ b/frontend/src/components/ui/dialog.tsx @@ -11,24 +11,12 @@ function Dialog({ return } -function DialogTrigger({ - ...props -}: React.ComponentProps) { - return -} - function DialogPortal({ ...props }: React.ComponentProps) { return } -function DialogClose({ - ...props -}: React.ComponentProps) { - return -} - function DialogOverlay({ className, ...props @@ -152,15 +140,12 @@ function DialogDescription({ ) } +// Nur was die Oberfläche nutzt (Rückfrage „Bestaetigen“); Trigger/Close von shadcn sind raus. export { Dialog, - DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, - DialogOverlay, - DialogPortal, DialogTitle, - DialogTrigger, } diff --git a/frontend/src/components/ui/sheet.tsx b/frontend/src/components/ui/sheet.tsx index f795755..7d041cb 100644 --- a/frontend/src/components/ui/sheet.tsx +++ b/frontend/src/components/ui/sheet.tsx @@ -1,5 +1,3 @@ -"use client" - import * as React from "react" import { cn } from "cn" import { Dialog as SheetPrimitive } from "radix-ui" @@ -7,22 +5,14 @@ import { Dialog as SheetPrimitive } from "radix-ui" import { Button } from "@/components/ui/button" import { XIcon } from "lucide-react" +// Seitenschublade (shadcn). Breite am Handy/PC setzen die Ansichten selbst — und zwar mit derselben +// Varianten-Kette (`data-[side=right]:w-full`, `data-[side=right]:sm:max-w-xl`), sonst schlagen die +// Grundklassen unten die eigenen: `w-full` allein verlor gegen `data-[side=right]:w-3/4`. + function Sheet({ ...props }: React.ComponentProps) { return } -function SheetTrigger({ - ...props -}: React.ComponentProps) { - return -} - -function SheetClose({ - ...props -}: React.ComponentProps) { - return -} - function SheetPortal({ ...props }: React.ComponentProps) { @@ -96,16 +86,6 @@ function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { ) } -function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { - return ( -
    - ) -} - function SheetTitle({ className, ...props @@ -135,13 +115,11 @@ function SheetDescription({ ) } +// Nur was die Oberfläche nutzt; Trigger/Close/Footer von shadcn sind raus. export { Sheet, - SheetTrigger, - SheetClose, SheetContent, SheetHeader, - SheetFooter, SheetTitle, SheetDescription, } diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index f815ded..a3d4628 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -1 +1,3 @@ +// Nur für die shadcn-CLI: components.json nennt „@/lib/utils“ als Ort von cn(), und neu +// hinzugefügte Bausteine importieren es von hier. Die Oberfläche selbst importiert direkt aus „cn“. export { cn } from "cn" diff --git a/frontend/src/test/setup.ts b/frontend/src/test/setup.ts index aa8a9cd..b75d8ed 100644 --- a/frontend/src/test/setup.ts +++ b/frontend/src/test/setup.ts @@ -9,44 +9,6 @@ afterEach(() => { localStorage.clear() }) -// jsdom rechnet kein Layout: JEDES Element ist 0x0, und es gibt keinen ResizeObserver. -// Messende Komponenten (Recharts' ResponsiveContainer, der Kraftgraph) zeichnen daraufhin -// gar nichts und warnen "width(0) and height(0)". -// -// Diese Attrappe meldet den Beobachtern EINMAL eine plausible Groesse, damit solche -// Komponenten ueberhaupt rendern. Sie ist bewusst konstant: Tests hier pruefen Logik und -// Struktur, nie gemessene Pixel — auf echte Layout-Werte darf sich kein Test stuetzen. -const TEST_BREITE = 800 -const TEST_HOEHE = 400 - -class TestResizeObserver implements ResizeObserver { - constructor(private rueckruf: ResizeObserverCallback) {} - - observe(ziel: Element) { - const rect = { - width: TEST_BREITE, height: TEST_HOEHE, top: 0, left: 0, - right: TEST_BREITE, bottom: TEST_HOEHE, x: 0, y: 0, - toJSON: () => ({}), - } as DOMRectReadOnly - const eintrag = { - target: ziel, - contentRect: rect, - borderBoxSize: [{ inlineSize: TEST_BREITE, blockSize: TEST_HOEHE }], - contentBoxSize: [{ inlineSize: TEST_BREITE, blockSize: TEST_HOEHE }], - devicePixelContentBoxSize: [{ inlineSize: TEST_BREITE, blockSize: TEST_HOEHE }], - } as unknown as ResizeObserverEntry - // Asynchron wie das Original — ein synchroner Rueckruf im Konstruktor-Pfad wuerde - // React mitten im Rendern aktualisieren. - queueMicrotask(() => this.rueckruf([eintrag], this)) - } - - unobserve() {} - disconnect() {} -} - -globalThis.ResizeObserver = TestResizeObserver as unknown as typeof ResizeObserver - -// Denselben Dienst fuer Komponenten, die direkt messen statt zu beobachten. -for (const [name, wert] of [["offsetWidth", TEST_BREITE], ["offsetHeight", TEST_HOEHE]] as const) { - Object.defineProperty(HTMLElement.prototype, name, { configurable: true, value: wert }) -} +// Bis 09/2026 stand hier eine ResizeObserver-Attrappe fuer Recharts und den Kraftgraph. Beide +// sind mit dem Box-Wart-Umbau entfallen, und Radix' Dialog misst nichts. Braucht ein kuenftiger +// Baustein wieder Layout-Masse, meldet jsdom das deutlich ("ResizeObserver is not defined"). From 83941847ab2a1bceefaec783e1b6c938c2227cc8 Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Thu, 24 Sep 2026 15:43:23 +0200 Subject: [PATCH 8/9] auftraege: Karten am PC zweispaltig Vier Auftraege (zwei laufende, zwei frisch beendete) nahmen auf der Modelle-Seite fast eine Bildschirmhoehe ein. Ab 1024 px stehen die Karten nebeneinander. Co-Authored-By: Claude Opus 5.5 --- frontend/src/components/cockpit/Auftraege.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/cockpit/Auftraege.tsx b/frontend/src/components/cockpit/Auftraege.tsx index d53f01c..2eaa696 100644 --- a/frontend/src/components/cockpit/Auftraege.tsx +++ b/frontend/src/components/cockpit/Auftraege.tsx @@ -15,7 +15,7 @@ export function Auftraege({ alsPanel = false }: { alsPanel?: boolean }) { let inhalt if (liste.length > 0) { inhalt = ( -
    +
    {liste.map((j) => ( Date: Thu, 24 Sep 2026 17:44:40 +0200 Subject: [PATCH 9/9] durchsicht: Rueckfragen passen aufs kleine Handy, ehrlichere Texte, Abbrechen nur wo es stoppt Befunde der Schlussdurchsicht (Attrappe des Backends, 320 x 568 bis 1440 px): - Rueckfragen: Bei 320 x 568 lagen "Installieren"/"Abbrechen" unter dem Bildschirmrand und liessen sich nicht erreichen (Dialog 791 px hoch, kein Scrollen). Jetzt hoechstens Bildschirmhoehe, der Text scrollt, die Knoepfe bleiben unten stehen. Gilt fuer alle. - Installieren: Die Rueckfrage sagt jetzt, dass llama-swap beim Eintragen sofort neu laedt (--watch-config): laufende Antworten von Lucy/OpenChamber brechen ab, mit Rolle nach dem Download noch einmal. Der Ersatz-Hinweis nennt, dass das bisherige Modell "heavy" behaelt. - Abbrechen nur noch bei Downloads (eigener Prozess). Updates und die Suche laufen als Shell-Kette, ein Abbruch stoppt dort nicht sicher alles. - Auftragstitel in den Worten der Oberflaeche ("Update Motor (llama.cpp)" statt "Engine-Update (llama.cpp Vulkan)"); "Laeuft seit ... min" zaehlt weiter, auch wenn der Auftrag nichts schreibt; Ueberschriftenebene passend zum Panel. - Updates: "Alles jetzt aktualisieren" richtet sich wie die Zeilen nach den frischen Details (vorher nur nach dem bis zu 10 min alten Start-Stand); "Nach Neuem suchen" sperrt, solange eine Suche laeuft (zwei apt-get update stolpern ueber die Sperre); Rueckfragetext sagt genau, was gesichert wird. - Nach Auftragsende nur nachladen, was betroffen ist (Download: Modelle/Platte; sonst Versionen/Verlauf/Sicherungen) - die Update-Pruefung fragt GitHub, apt und git. - Radar "Uebernehmen"/"Verwerfen" und "Endgueltig loeschen": Ja-Knopf gesperrt, solange die Aktion laeuft, und ein zweiter Klick waehrend des Schliessens loest nichts mehr aus. Co-Authored-By: Claude Opus 5.5 --- frontend/src/components/cockpit/Auftraege.tsx | 1 + .../src/components/cockpit/Bestaetigen.tsx | 7 +- .../src/components/cockpit/JobKarte.test.tsx | 21 ++++- frontend/src/components/cockpit/JobKarte.tsx | 26 +++++- .../components/cockpit/Rueckfrage.test.tsx | 15 +++- frontend/src/lib/abfragen.ts | 42 ++++++--- frontend/src/lib/wartung.ts | 86 ++++++++++++++----- frontend/src/views/ModellSuche.tsx | 12 ++- frontend/src/views/Modelle.tsx | 11 ++- frontend/src/views/Updates.tsx | 29 ++++--- 10 files changed, 188 insertions(+), 62 deletions(-) diff --git a/frontend/src/components/cockpit/Auftraege.tsx b/frontend/src/components/cockpit/Auftraege.tsx index 2eaa696..7fb74e3 100644 --- a/frontend/src/components/cockpit/Auftraege.tsx +++ b/frontend/src/components/cockpit/Auftraege.tsx @@ -20,6 +20,7 @@ export function Auftraege({ alsPanel = false }: { alsPanel?: boolean }) { abbrechen.mutate({ id: job.id, titel: jobTitel(job) })} /> diff --git a/frontend/src/components/cockpit/Bestaetigen.tsx b/frontend/src/components/cockpit/Bestaetigen.tsx index 230ec01..2b7014a 100644 --- a/frontend/src/components/cockpit/Bestaetigen.tsx +++ b/frontend/src/components/cockpit/Bestaetigen.tsx @@ -23,13 +23,16 @@ export function Bestaetigen({ offen, titel, text, knopf, neinKnopf = "Abbrechen" }) { return ( !o && onNein()}> - + {/* Nie höher als der Bildschirm: Auf kleinen Handys (320 × 568) lagen die Knöpfe sonst außerhalb + und ließen sich nicht erreichen. Der Text scrollt, die Knöpfe bleiben unten stehen — bündig, + darum ohne Bodenpolster (sticky rechnet das Polster ein, darunter schien sonst Text durch). */} + {titel} {text} {children} - + diff --git a/frontend/src/components/cockpit/JobKarte.test.tsx b/frontend/src/components/cockpit/JobKarte.test.tsx index 85d1dfc..9fea111 100644 --- a/frontend/src/components/cockpit/JobKarte.test.tsx +++ b/frontend/src/components/cockpit/JobKarte.test.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from "@testing-library/react" -import { sichtbareJobs } from "@/lib/wartung" +import { jobTitel, sichtbareJobs } from "@/lib/wartung" import type { Job } from "@/lib/typen" import { JobKarte } from "./JobKarte" @@ -44,10 +44,15 @@ describe("JobKarte", () => { expect(screen.queryByRole("button", { name: "Abbrechen" })).not.toBeInTheDocument() }) - it("bietet bei Updates kein Abbrechen an und zeigt bei Fehlern die letzte Meldung", () => { + it("bietet bei Updates und der Suche kein Abbrechen an und zeigt bei Fehlern die letzte Meldung", () => { const { rerender } = render( {}} />, ) + expect(screen.getByText("Update Hermes")).toBeInTheDocument() + expect(screen.queryByRole("button", { name: "Abbrechen" })).not.toBeInTheDocument() + + // Die Suche läuft als Shell-Kette wie die Updates: kein Abbrechen, das womöglich nichts stoppt. + rerender( {}} />) expect(screen.queryByRole("button", { name: "Abbrechen" })).not.toBeInTheDocument() rerender( @@ -63,6 +68,18 @@ describe("JobKarte", () => { }) }) +describe("jobTitel", () => { + it("nennt die Bausteine wie die Oberfläche und lässt Unbekanntes stehen", () => { + expect(jobTitel({ label: "Engine-Update (llama.cpp Vulkan)" })).toBe("Update Motor (llama.cpp)") + expect(jobTitel({ label: "Router-Update (llama-swap)" })).toBe("Update llama-swap") + expect(jobTitel({ label: "OS-Update (apt)" })).toBe("Update Betriebssystem") + expect(jobTitel({ label: "Alle aktualisieren (Engine (llama.cpp) → Router (llama-swap) → Hermes-Agent → OS (apt))" })) + .toBe("Alle aktualisieren (Motor → llama-swap → Hermes → Betriebssystem)") + expect(jobTitel({ label: "download unsloth/Qwen3.8-27B-GGUF" })).toBe("Download unsloth/Qwen3.8-27B-GGUF") + expect(jobTitel({ label: "Nach Updates suchen" })).toBe("Nach Updates suchen") + }) +}) + describe("sichtbareJobs", () => { it("zeigt alle laufenden Aufträge jeder Gruppe und die drei zuletzt beendeten", () => { const liste = sichtbareJobs( diff --git a/frontend/src/components/cockpit/JobKarte.tsx b/frontend/src/components/cockpit/JobKarte.tsx index c404221..94796c2 100644 --- a/frontend/src/components/cockpit/JobKarte.tsx +++ b/frontend/src/components/cockpit/JobKarte.tsx @@ -1,4 +1,4 @@ -import { useState } from "react" +import { useEffect, useState } from "react" import { cn } from "cn" import { Button } from "@/components/ui/button" import { laeuftNoch } from "@/lib/anzeige" @@ -22,14 +22,30 @@ const BALKEN: Record = { const zeitVon = (sekunden: number) => flugplanZeit(new Date(sekunden * 1000).toISOString()) +/** + * Die Uhrzeit in Sekunden, alle 30 s neu, solange `aktiv`. Ohne sie bliebe „Läuft seit 5 min“ stehen, + * wenn ein Auftrag eine Weile nichts schreibt: Die Karte zeichnet sonst nur neu, wenn sich der Auftrag ändert. + */ +function useJetzt(aktiv: boolean) { + const [jetzt, setJetzt] = useState(() => Date.now() / 1000) + useEffect(() => { + if (!aktiv) return + const t = window.setInterval(() => setJetzt(Date.now() / 1000), 30_000) + return () => window.clearInterval(t) + }, [aktiv]) + return jetzt +} + /** * Ein Hintergrund-Auftrag als Karte: Titel und Zustand, bei Downloads der Fortschritt, bei Fehlern * die letzte Meldung, auf Wunsch das Protokoll. Abbrechen nur, wo es wirklich stoppt (`abbrechbar`). + * `ebene` ist die Überschriftenebene (unter einem Panel-Titel h3, unter einer Zwischenüberschrift h4). */ -export function JobKarte({ job, onAbbrechen, abbrechenGesperrt }: { +export function JobKarte({ job, onAbbrechen, abbrechenGesperrt, ebene = 4 }: { job: Job onAbbrechen?: (job: Job) => void abbrechenGesperrt?: boolean + ebene?: 3 | 4 }) { const [frage, setFrage] = useState(false) const [protokoll, setProtokoll] = useState(false) @@ -38,13 +54,15 @@ export function JobKarte({ job, onAbbrechen, abbrechenGesperrt }: { const fortschritt = fortschrittText(job) const meldung = letzteMeldung(job) const laeuft = laeuftNoch(job) + const jetzt = useJetzt(laeuft) const darfAbbrechen = !!onAbbrechen && abbrechbar(job) const protokollZeilen = (job.log ?? []).slice(-12) + const Titel = ebene === 3 ? "h3" : "h4" return (
    -

    {titel}

    + {titel} {zustand.text}
    @@ -66,7 +84,7 @@ export function JobKarte({ job, onAbbrechen, abbrechenGesperrt }: {

    {laeuft - ? fortschritt ?? laufText(job) + ? fortschritt ?? laufText(job, jetzt) : `${zustand.text} · ${zeitVon(job.finished_at ?? job.started_at)}`}

    diff --git a/frontend/src/components/cockpit/Rueckfrage.test.tsx b/frontend/src/components/cockpit/Rueckfrage.test.tsx index 713c7bb..b9271f6 100644 --- a/frontend/src/components/cockpit/Rueckfrage.test.tsx +++ b/frontend/src/components/cockpit/Rueckfrage.test.tsx @@ -3,7 +3,7 @@ import { fireEvent, render, screen, waitFor, within } from "@testing-library/rea import { hinweisRueckfrage } from "@/lib/anzeige" import { post } from "@/lib/api" import type { Hinweis } from "@/lib/typen" -import { rollenErsatzText } from "@/lib/wartung" +import { installierenUnterbrechung, rollenErsatzText } from "@/lib/wartung" import { Bestaetigen } from "./Bestaetigen" import { Checkliste } from "./Checkliste" @@ -63,11 +63,18 @@ describe("Bestaetigen", () => { }) describe("rollenErsatzText", () => { - it("sagt deutlich, welches Modell die Rolle verliert", () => { - expect(rollenErsatzText("org/Neu-GGUF", "Coder", { name: "Qwen3.8-27B-Heretic", zwilling: true })).toBe( + it("sagt deutlich, welches Modell die Rolle verliert und was es behält", () => { + expect(rollenErsatzText("org/Neu-GGUF", "Coder", { name: "Qwen3.8-27B-Heretic", zwilling: true, weitere: ["heavy"] })).toBe( "Achtung: Nach dem Download übernimmt org/Neu-GGUF die Rolle „Coder“ und ersetzt damit Qwen3.8-27B-Heretic. " + - "Das bisherige Modell bleibt auf der Platte. Bilder liest vorerst weiter sein Bild-Zwilling, also noch das bisherige Modell.", + "Das bisherige Modell bleibt auf der Platte. Die Rolle „heavy“ behält es. " + + "Bilder liest vorerst weiter sein Bild-Zwilling, also noch das bisherige Modell.", ) expect(rollenErsatzText("org/Neu-GGUF", "Coder", undefined)).toBe("Nach dem Download übernimmt org/Neu-GGUF die Rolle „Coder“.") }) + + it("warnt vor der Unterbrechung durch das Neuladen von llama-swap", () => { + expect(installierenUnterbrechung(false)).toContain("bricht ab") + expect(installierenUnterbrechung(false)).not.toContain("noch einmal") + expect(installierenUnterbrechung(true)).toContain("Mit Rolle passiert das nach dem Download noch einmal.") + }) }) diff --git a/frontend/src/lib/abfragen.ts b/frontend/src/lib/abfragen.ts index 87df48e..8ff964d 100644 --- a/frontend/src/lib/abfragen.ts +++ b/frontend/src/lib/abfragen.ts @@ -3,7 +3,7 @@ // Takte: Steht der Live-Strom, meldet er Änderungen selbst — die Abfragen sind dann nur // Sicherheitsnetz und laufen fünfmal seltener. -import { type QueryClient, useMutation, useQuery, useQueryClient } from "@tanstack/react-query" +import { type QueryClient, useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/react-query" import { api, post } from "./api" import { fehlerText, laeuftNoch } from "./anzeige" import { melden } from "./meldungen" @@ -15,14 +15,24 @@ import { gbText } from "./zeit" const takt = (ms: number) => () => (stromVerbunden() ? ms * 5 : ms) -/** Was ein beendeter Auftrag verändert haben kann: Versionen, Modelle, Sicherungen, Platte. */ -const NACH_AUFTRAG = ["start", "update-details", "updates-verlauf", "models", "sicherungen", "aufraeumen"] - -/** Ist seit der letzten Abfrage ein Auftrag fertig geworden, lesen die betroffenen Ansichten neu. */ +/** + * Ist seit der letzten Abfrage ein Auftrag fertig geworden, lesen die betroffenen Ansichten neu: + * nach einem Download die Modelle und die Platte, nach Updates und der Suche die Versionen, der + * Verlauf und die Sicherungen. Gezielt, weil die Update-Prüfung teuer ist (GitHub, apt, git fetch). + */ function auftragsEndeMelden(qc: QueryClient, neu: Job[]) { const alt = qc.getQueryData<{ jobs: Job[] }>(["jobs"])?.jobs ?? [] - const ebenFertig = neu.some((j) => !laeuftNoch(j) && alt.some((a) => a.id === j.id && laeuftNoch(a))) - if (ebenFertig) for (const k of NACH_AUFTRAG) qc.invalidateQueries({ queryKey: [k] }) + const ebenFertig = neu.filter((j) => !laeuftNoch(j) && alt.some((a) => a.id === j.id && laeuftNoch(a))) + if (ebenFertig.length === 0) return + const schluessel = new Set(["start"]) + for (const j of ebenFertig) { + // Wie wartung.jobDownload — hier ausgeschrieben, damit wartung.ts nicht ins Start-Bündel wandert. + const download = j.group === "download" || /^download\s/i.test(j.label) + for (const k of download ? ["models", "aufraeumen"] : ["update-details", "updates-verlauf", "sicherungen"]) { + schluessel.add(k) + } + } + for (const k of schluessel) qc.invalidateQueries({ queryKey: [k] }) } export const useStart = () => @@ -66,12 +76,18 @@ export const useSicherungen = () => queryFn: () => api<{ available: boolean; backups: Sicherung[] }>("/api/zeitmaschine"), }) -export const useUpdateDetails = (art: string | null) => - useQuery({ - queryKey: ["update-details", art], - queryFn: () => api(`/api/maintenance/update-details?kind=${art}`), - enabled: !!art, - staleTime: 600_000, +/** + * Was die Updates der Bausteine bringen würden — je Baustein eine eigene Abfrage, damit ein langsamer + * (Hermes: git fetch bis 25 s) die anderen nicht aufhält. Die Prüfung fragt GitHub, apt und git, + * darum gilt ein Ergebnis zehn Minuten. + */ +export const useUpdateDetails = (arten: readonly string[]) => + useQueries({ + queries: arten.map((art) => ({ + queryKey: ["update-details", art], + queryFn: () => api(`/api/maintenance/update-details?kind=${encodeURIComponent(art)}`), + staleTime: 600_000, + })), }) export interface UpdateLauf { diff --git a/frontend/src/lib/wartung.ts b/frontend/src/lib/wartung.ts index 2cec672..19cd586 100644 --- a/frontend/src/lib/wartung.ts +++ b/frontend/src/lib/wartung.ts @@ -46,22 +46,45 @@ export function pruefFehlerText(fehler: string): string { // --- Aufträge (services/jobengine.py) --------------------------------------------------- -/** - * Darf man den Auftrag abbrechen? Updates nicht: Der Abbruch beendet nur die äußere Shell, apt - * und die Update-Skripte liefen weiter, und die Karte zeigte fälschlich „Abgebrochen“. Scheitert - * ein Update, rollen Motor und llama-swap selbst zurück. - */ -export const abbrechbar = (j: Pick) => laeuftNoch(j) && j.group !== "maintenance" - -/** Die Beschriftung eines Auftrags auf Deutsch („download org/repo“ heißt im Backend noch englisch). */ -export function jobTitel(j: Pick): string { - const m = /^download\s+(.+)$/i.exec(j.label) - return m ? `Download ${m[1]}` : j.label -} - /** Ist der Auftrag ein Modell-Download? (Bis das Backend eine Gruppe setzt, verrät es nur die Beschriftung.) */ export const jobDownload = (j: Pick) => j.group === "download" || /^download\s/i.test(j.label) +/** Ist der Auftrag die Suche nach Updates (apt-get update)? Auch sie hat im Backend noch keine Gruppe. */ +export const jobSuche = (j: Pick) => j.group === "pruefen" || j.label === "Nach Updates suchen" + +/** + * Darf man den Auftrag abbrechen? Nur Downloads: Sie laufen als eigener Prozess (`hf download`), den + * der Abbruch wirklich beendet. Updates und die Suche laufen als Shell-Kette (`bash -c …`), und ob + * ein Abbruch dort alles stoppt, ist nicht sicher — bei Updates liefen apt und die Update-Skripte + * weiter, während die Karte „Abgebrochen“ zeigte. Scheitert ein Update, rollen Motor und llama-swap + * selbst zurück. + */ +export const abbrechbar = (j: Pick) => laeuftNoch(j) && jobDownload(j) + +// Die Beschriftungen setzt das Backend (services/maintenance.py, routers/models.py) mit technischen +// Namen; die Oberfläche sagt Motor, llama-swap, Hermes und Betriebssystem. +const TITEL: [RegExp, string][] = [ + [/^download\s+(.+)$/i, "Download $1"], + [/^OS-Update \(apt\)$/, "Update Betriebssystem"], + [/^Engine-Update \(llama\.cpp Vulkan\)$/, "Update Motor (llama.cpp)"], + [/^Router-Update \(llama-swap\)$/, "Update llama-swap"], + [/^Hermes-Agent-Update$/, "Update Hermes"], +] +const TEILE: [string, string][] = [ + ["Engine (llama.cpp)", "Motor"], + ["Router (llama-swap)", "llama-swap"], + ["Hermes-Agent", "Hermes"], + ["OS (apt)", "Betriebssystem"], +] + +/** Die Beschriftung eines Auftrags in den Worten der Oberfläche. Unbekanntes bleibt, wie es ist. */ +export function jobTitel(j: Pick): string { + for (const [muster, ersatz] of TITEL) if (muster.test(j.label)) return j.label.replace(muster, ersatz) + // „Alle aktualisieren (Engine (llama.cpp) → Router (llama-swap) → Hermes-Agent → OS (apt))“ + if (j.label.startsWith("Alle aktualisieren")) return TEILE.reduce((t, [alt, neu]) => t.split(alt).join(neu), j.label) + return j.label +} + /** „noch etwa 6 min“ aus der geschätzten Restzeit in Sekunden. */ export function restzeit(s: number): string { if (s < 60) return "noch unter einer Minute" @@ -113,20 +136,41 @@ export function sichtbareJobs(jobs: Job[], jetzt = Date.now() / 1000): Job[] { // --- Installieren ------------------------------------------------------------------- +/** Wer eine Rolle heute innehat — für den Hinweis vor dem Installieren. */ +export interface RollenInhaber { + name: string + /** Hängt ein Bild-Zwilling an seinen Gewichten (vision, coder-bild)? */ + zwilling: boolean + /** Rollen, die das Modell außerdem trägt (der Coder auch „heavy“) — die behält es. */ + weitere: string[] +} + /** * Hinweis vor dem Installieren mit Rolle: Wen ersetzt das neue Modell? Nach dem Download wandert - * nur der Rollen-Alias um (services/llamaswap.set_role) — das bisherige Modell bleibt auf der Platte - * und sein Bild-Zwilling zeigt weiter auf dessen Gewichte. + * nur dieser eine Rollen-Alias um (services/llamaswap.set_role_alias): Das bisherige Modell bleibt + * auf der Platte, behält seine übrigen Rollen, und sein Bild-Zwilling zeigt weiter auf dessen Gewichte. */ -export function rollenErsatzText( - neu: string, - rolle: string, - bisher: { name: string; zwilling: boolean } | undefined, -): string { +export function rollenErsatzText(neu: string, rolle: string, bisher: RollenInhaber | undefined): string { if (!bisher) return `Nach dem Download übernimmt ${neu} die Rolle „${rolle}“.` + const behaelt = bisher.weitere.length + ? ` Die Rolle${bisher.weitere.length === 1 ? "" : "n"} „${bisher.weitere.join("“, „")}“ behält es.` + : "" return ( `Achtung: Nach dem Download übernimmt ${neu} die Rolle „${rolle}“ und ersetzt damit ${bisher.name}. ` + - "Das bisherige Modell bleibt auf der Platte." + + `Das bisherige Modell bleibt auf der Platte.${behaelt}` + (bisher.zwilling ? " Bilder liest vorerst weiter sein Bild-Zwilling, also noch das bisherige Modell." : "") ) } + +/** + * Was das Eintragen in llama-swap unterwegs anrichtet: llama-swap läuft mit `--watch-config` und lädt + * bei jeder Änderung sofort neu (services/warmer.py, deploy/coder-vollkontext.sh) — laufende Antworten + * brechen ab, geladene Modelle fliegen raus. Mit Rolle schreibt das Backend nach dem Download noch einmal. + */ +export function installierenUnterbrechung(mitRolle: boolean): string { + return ( + "Kurze Unterbrechung: Beim Eintragen lädt llama-swap sofort neu. Was Lucy oder OpenChamber gerade " + + "schreiben, bricht ab, und die Modelle werden neu geladen." + + (mitRolle ? " Mit Rolle passiert das nach dem Download noch einmal." : "") + ) +} diff --git a/frontend/src/views/ModellSuche.tsx b/frontend/src/views/ModellSuche.tsx index b6e152a..b8780fb 100644 --- a/frontend/src/views/ModellSuche.tsx +++ b/frontend/src/views/ModellSuche.tsx @@ -5,18 +5,21 @@ import { Button } from "@/components/ui/button" import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ui/sheet" import { useInstallieren } from "@/lib/abfragen" import { api } from "@/lib/api" -import { rollenErsatzText } from "@/lib/wartung" +import { installierenUnterbrechung, type RollenInhaber, rollenErsatzText } from "@/lib/wartung" import { gbText, zahl } from "@/lib/zeit" interface Treffer { repo: string; downloads: number; likes: number } /** /api/hf/quants liefert heute nur die Namen. Kommen Größen dazu, zeigen Liste und Rückfrage sie an. */ interface Quant { quant?: string; name?: string; size_bytes?: number; total_bytes?: number } -/** Rollen, die sich beim Installieren gleich vergeben lassen (Rollen-Alias → Name in der Oberfläche). */ +/** + * Rollen, die sich beim Installieren gleich vergeben lassen (Rollen-Alias → Name in der Oberfläche). + * Das Hirn steht hier (wie bisher) nicht zur Wahl; Hirn-Kandidaten testet das Radar nachts, bevor man sie übernimmt. + */ const ROLLEN: Record = { coder: "Coder" } -/** Wer eine Rolle heute innehat: Modellname und ob ein Bild-Zwilling daran hängt. */ -export type RollenStand = Record +/** Wer die Rollen heute innehat (Schlüssel = Rollen-Alias). */ +export type RollenStand = Record /** Modelle selbst auf Hugging Face suchen und installieren — zusätzlich zum Radar. */ export function ModellSuche({ offen, onSchliessen, rollenJetzt }: { @@ -188,6 +191,7 @@ export function ModellSuche({ offen, onSchliessen, rollenJetzt }: { {ersatz}

    )} +

    {installierenUnterbrechung(!!rolle)}

    diff --git a/frontend/src/views/Modelle.tsx b/frontend/src/views/Modelle.tsx index 40aec5f..a706399 100644 --- a/frontend/src/views/Modelle.tsx +++ b/frontend/src/views/Modelle.tsx @@ -214,8 +214,10 @@ function Kandidat({ k, test, heute }: { k: RadarKandidat; test: RadarTest | unde ? `${k.name} wird Lucys Hirn${heute ? ` und löst ${heute} ab` : ""}. NerdQuiz und OpenChamber nutzen ab dann ebenfalls das neue Modell. Hermes startet dafür kurz neu, Lucy ist etwa eine Minute nicht erreichbar. Das alte Modell bleibt auf der Platte.` : `${k.name} wird der Coder${heute ? ` und löst ${heute} ab` : ""}. OpenChamber plant und baut ab dann damit. Das alte Modell bleibt auf der Platte.`} knopf="Übernehmen" + gesperrt={aktion.isPending} onNein={() => setFrage(null)} onJa={() => { + if (frage !== "uebernehmen") return // zweiter Klick eines Doppelklicks, der Dialog schließt schon aktion.mutate({ id: k.id, aktion: "uebernehmen", name: k.name }) setFrage(null) }} @@ -226,8 +228,10 @@ function Kandidat({ k, test, heute }: { k: RadarKandidat; test: RadarTest | unde titel={`${k.name} verwerfen?`} text="Die heruntergeladenen Dateien werden gelöscht, und das Radar testet dieses Modell nicht noch einmal." knopf="Verwerfen" + gesperrt={aktion.isPending} onNein={() => setFrage(null)} onJa={() => { + if (frage !== "verwerfen") return aktion.mutate({ id: k.id, aktion: "verwerfen", name: k.name }) setFrage(null) }} @@ -353,6 +357,7 @@ function AufraeumenPanel() { titel={`${frage?.name ?? ""} löschen?`} text={`${frage?.hinweis ?? ""} Es werden ${frage?.groesse_gb.toLocaleString("de-DE") ?? ""} GB frei. Das lässt sich nicht rückgängig machen — zurück ginge es nur mit einem neuen Download.`} knopf="Endgültig löschen" + gesperrt={loeschen.isPending} onNein={() => setFrage(null)} onJa={() => { if (frage) loeschen.mutate(frage) @@ -432,7 +437,11 @@ export function ModelleSeite() { setSuche(false)} - rollenJetzt={{ coder: coder ? { name: coder.name, zwilling: !!coderZwilling } : undefined }} + rollenJetzt={{ + coder: coder + ? { name: coder.name, zwilling: !!coderZwilling, weitere: coder.aliases.filter((a) => a.toLowerCase() !== "coder") } + : undefined, + }} /> ) diff --git a/frontend/src/views/Updates.tsx b/frontend/src/views/Updates.tsx index 8487c1d..8afc0ba 100644 --- a/frontend/src/views/Updates.tsx +++ b/frontend/src/views/Updates.tsx @@ -1,4 +1,5 @@ import { useState } from "react" +import type { UseQueryResult } from "@tanstack/react-query" import { ChevronRight } from "lucide-react" import { cn } from "cn" import { Auftraege } from "@/components/cockpit/Auftraege" @@ -11,7 +12,7 @@ import { useUpdateStarten, useUpdateVerlauf, useZurueckspielen, } from "@/lib/abfragen" import { laeuftNoch } from "@/lib/anzeige" -import { detailsHabenNeues, pruefFehlerText, versionen } from "@/lib/wartung" +import { detailsHabenNeues, jobSuche, pruefFehlerText, versionen } from "@/lib/wartung" import type { Festgehalten, Sicherung, UpdateDetails } from "@/lib/typen" import { flugplanZeit } from "@/lib/zeit" @@ -110,9 +111,12 @@ function zusammenfassung(summary: string | undefined): string | null { return s } -function BausteinZeile({ id, name, neuLautStart, fest, gesperrt, onStart, onFreigeben }: { +function BausteinZeile({ id, name, details, hatUpdate, neuLautStart, fest, gesperrt, onStart, onFreigeben }: { id: string name: string + details: UseQueryResult + /** Gibt es Neues? Frische Details schlagen den gecachten Stand der Startseite (siehe UpdatesSeite). */ + hatUpdate: boolean /** Was /api/start über diesen Baustein sagt („3 Pakete“, „neuer Build“), undefined = nichts Neues. */ neuLautStart: string | undefined fest: Festgehalten | undefined @@ -120,13 +124,10 @@ function BausteinZeile({ id, name, neuLautStart, fest, gesperrt, onStart, onFrei onStart: () => void onFreigeben: () => void }) { - const details = useUpdateDetails(id) const d = details.data const laedt = details.isPending const fehler = details.isError ? details.error.message : d?.error const v = d ? versionen(id, d) : null - // Frische Details schlagen den gecachten Stand der Startseite; wissen sie nichts, gilt der Start. - const hatUpdate = detailsHabenNeues(id, d) ?? neuLautStart != null const neu = hatUpdate ? v?.neu ?? neuLautStart ?? null : null const summary = zusammenfassung(d?.summary) @@ -269,12 +270,16 @@ export function UpdatesSeite() { const neuLautStart = new Map((start.data?.updates.bausteine ?? []).map((b) => [b.id, b.neu])) const festgehalten = new Map((start.data?.updates.festgehalten ?? []).map((f) => [f.baustein, f])) + // /api/start kennt nur einen bis zu zehn Minuten alten Stand. Die Details prüfen frisch — sagen + // sie etwas, gilt das (für die Zeilen UND für „Alles jetzt aktualisieren“), sonst der Start. + const details = useUpdateDetails(BAUSTEINE.map((b) => b.id)) + const hatNeues = BAUSTEINE.map((b, i) => detailsHabenNeues(b.id, details[i].data) ?? neuLautStart.has(b.id)) const alleJobs = jobs.data?.jobs ?? [] // Nur ein Update gleichzeitig (Riegel im Backend) — auch der Sonntags-Lauf zählt. const updateLaeuft = alleJobs.some((j) => j.group === "maintenance" && laeuftNoch(j)) || (start.data?.zustand.update_laeuft ?? false) - // Die Suche hat im Backend (noch) keine Gruppe; sobald sie "pruefen" heißt, sperrt der Knopf auch hier. - const suchtGerade = alleJobs.some((j) => j.group === "pruefen" && laeuftNoch(j)) + // Zwei Suchen gleichzeitig stolpern über die apt-Sperre — solange eine läuft, bleibt der Knopf zu. + const suchtGerade = alleJobs.some((j) => jobSuche(j) && laeuftNoch(j)) const gesperrt = updateLaeuft || updateStarten.isPending const zurueckMoeglich = sicherungen.data?.available ?? false @@ -296,11 +301,13 @@ export function UpdatesSeite() { Was sich ändert Aktion
    - {BAUSTEINE.map((b) => ( + {BAUSTEINE.map((b, i) => ( updateStarten.mutate("pruefen")} disabled={updateStarten.isPending || suchtGerade} > - Nach Neuem suchen + {suchtGerade ? "Sucht …" : "Nach Neuem suchen"} -
    @@ -413,7 +420,7 @@ export function UpdatesSeite() { setFrage(null)}