From 5ecea0369c81ff13d1cd5f24ecc50c0898836e0a Mon Sep 17 00:00:00 2001 From: Cash-Codes Date: Tue, 28 Apr 2026 22:05:08 +0100 Subject: [PATCH 1/4] feat: add thinking indicatior with phase feedbacks --- .../app/src/components/ThinkingIndicator.tsx | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 apps/widget/app/src/components/ThinkingIndicator.tsx diff --git a/apps/widget/app/src/components/ThinkingIndicator.tsx b/apps/widget/app/src/components/ThinkingIndicator.tsx new file mode 100644 index 0000000..66093da --- /dev/null +++ b/apps/widget/app/src/components/ThinkingIndicator.tsx @@ -0,0 +1,69 @@ +import type { PhaseEvent, PhaseName } from "@ai-support/shared"; + +interface Props { + events: PhaseEvent[]; +} + +const PHASE_LABEL: Record = { + intake: "Reading your message", + docsRetrieval: "Searching the docs", + router: "Deciding next step", + codeInvestigation: "Looking through code", + resolution: "Composing the answer", + ticketing: "Filing a ticket", + openFixPR: "Drafting a fix", +}; + +export function ThinkingIndicator({ events }: Props) { + // Show the latest phase that's "started" but not yet "completed". + // Falls back to the most recent event when nothing is active. + let activeLabel = "Thinking"; + for (let i = events.length - 1; i >= 0; i--) { + const e = events[i]; + if (e.status === "started") { + activeLabel = PHASE_LABEL[e.phase] ?? e.phase; + break; + } + if ( + e.status === "completed" || + e.status === "skipped" || + e.status === "failed" + ) { + activeLabel = PHASE_LABEL[e.phase] ?? e.phase; + break; + } + } + + return ( +
+ +
+
+ + + + + + {activeLabel}… +
+
+
+ ); +} + +function Dot({ delay }: { delay: string }) { + return ( + + ); +} From 6a2e7c79022f814ef3c8eaed6941ad2e6a5a5144 Mon Sep 17 00:00:00 2001 From: Cash-Codes Date: Tue, 28 Apr 2026 22:06:04 +0100 Subject: [PATCH 2/4] feat: add SQLite backed session store --- apps/api/src/sessions/sqliteStore.test.ts | 139 ++++++++ apps/api/src/sessions/sqliteStore.ts | 402 ++++++++++++++++++++++ apps/api/src/sessions/store.test.ts | 12 +- apps/api/src/sessions/store.ts | 22 +- 4 files changed, 567 insertions(+), 8 deletions(-) create mode 100644 apps/api/src/sessions/sqliteStore.test.ts create mode 100644 apps/api/src/sessions/sqliteStore.ts diff --git a/apps/api/src/sessions/sqliteStore.test.ts b/apps/api/src/sessions/sqliteStore.test.ts new file mode 100644 index 0000000..2b7b75c --- /dev/null +++ b/apps/api/src/sessions/sqliteStore.test.ts @@ -0,0 +1,139 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import type { + ChatMessage, + PRSummary, + PipelineTrace, + TicketSummary, +} from "@ai-support/shared"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { SqliteSessionStore } from "./sqliteStore.js"; + +const message = (id: string, content: string): ChatMessage => ({ + id, + role: "user", + content, + createdAt: new Date().toISOString(), +}); + +const trace = (confidence: "low" | "medium" | "high"): PipelineTrace => ({ + events: [], + retrievedDocs: [], + confidence, +}); + +const ticket = (id: string): TicketSummary => ({ + ticketId: id, + ticketUrl: `https://example.test/t/${id}`, + provider: "mock", +}); + +const pr = (branch: string): PRSummary => ({ + branch, + prUrl: `https://example.test/pr/${branch}`, + provider: "mock", +}); + +let store: SqliteSessionStore; + +beforeEach(() => { + store = new SqliteSessionStore({ dbPath: ":memory:" }); +}); + +afterEach(() => { + store.close(); +}); + +describe("SqliteSessionStore", () => { + it("creates a session, persists, and reflects it in the summary", () => { + const s = store.create("acme-app"); + expect(s.product).toBe("acme-app"); + expect(s.messageCount).toBe(0); + expect(s.hasTicket).toBe(false); + expect(s.hasPR).toBe(false); + expect(store.has(s.sessionId)).toBe(true); + }); + + it("records messages, traces, tickets, prs and surfaces them in detail", () => { + const s = store.create("acme"); + store.appendMessage(s.sessionId, message("m1", "hi")); + store.appendMessage(s.sessionId, message("m2", "second")); + store.appendTrace(s.sessionId, trace("medium")); + store.appendTrace(s.sessionId, trace("high")); + store.appendTicket(s.sessionId, ticket("T-1")); + store.appendPR(s.sessionId, pr("fix/x")); + + const detail = store.getDetail(s.sessionId); + expect(detail).toBeDefined(); + expect(detail?.messages.map((m) => m.id)).toEqual(["m1", "m2"]); + expect(detail?.traces).toHaveLength(2); + expect(detail?.tickets[0].ticketId).toBe("T-1"); + expect(detail?.prs[0].branch).toBe("fix/x"); + // summary reflects latest trace's confidence + boolean flags + expect(detail?.summary.messageCount).toBe(2); + expect(detail?.summary.latestConfidence).toBe("high"); + expect(detail?.summary.hasTicket).toBe(true); + expect(detail?.summary.hasPR).toBe(true); + }); + + it("list() returns newest-first up to limit", async () => { + const a = store.create("a"); + await new Promise((r) => setTimeout(r, 5)); + const b = store.create("b"); + const list = store.list(); + expect(list[0].sessionId).toBe(b.sessionId); + expect(list[1].sessionId).toBe(a.sessionId); + }); + + it("evicts oldest sessions when the cap is exceeded", () => { + const small = new SqliteSessionStore({ + dbPath: ":memory:", + maxSessions: 2, + }); + try { + const a = small.create("a"); + small.create("b"); + small.create("c"); + expect(small.size()).toBe(2); + expect(small.has(a.sessionId)).toBe(false); + } finally { + small.close(); + } + }); + + it("throws on append to a missing session", () => { + expect(() => + store.appendMessage("does-not-exist", message("m", "x")), + ).toThrow(/session not found/); + }); + + it("getDetail returns undefined for unknown id", () => { + expect(store.getDetail("nope")).toBeUndefined(); + }); + + it("persists across reopen of the same db file", () => { + const tmp = path.join(os.tmpdir(), `sqlite-store-test-${Date.now()}.db`); + const s1 = new SqliteSessionStore({ dbPath: tmp }); + const created = s1.create("persistent"); + s1.appendMessage(created.sessionId, message("m1", "before restart")); + s1.close(); + + const s2 = new SqliteSessionStore({ dbPath: tmp }); + try { + expect(s2.has(created.sessionId)).toBe(true); + const detail = s2.getDetail(created.sessionId); + expect(detail?.messages[0].content).toBe("before restart"); + } finally { + s2.close(); + // SQLite WAL mode leaves -wal/-shm sidecar files; clean them up. + for (const suffix of ["", "-wal", "-shm"]) { + try { + fs.unlinkSync(`${tmp}${suffix}`); + } catch { + // ignore — file may not exist + } + } + } + }); +}); diff --git a/apps/api/src/sessions/sqliteStore.ts b/apps/api/src/sessions/sqliteStore.ts new file mode 100644 index 0000000..4eec5de --- /dev/null +++ b/apps/api/src/sessions/sqliteStore.ts @@ -0,0 +1,402 @@ +import { randomUUID } from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import type { + ChatMessage, + ChatRole, + Confidence, + PRSummary, + PipelineTrace, + SessionDetail, + SessionSummary, + TicketSummary, +} from "@ai-support/shared"; +import Database, { type Database as DB, type Statement } from "better-sqlite3"; +import { DEFAULT_MAX_SESSIONS, type SessionStore } from "./store.js"; + +interface RawSession { + session_id: string; + product: string; + created_at: string; + last_activity_at: string; +} + +interface RawMessage { + id: string; + session_id: string; + role: ChatRole; + content: string; + created_at: string; +} + +interface RawTrace { + payload: string; +} + +interface RawTicket { + ticket_id: string; + ticket_url: string; + provider: string; +} + +interface RawPR { + pr_url: string; + branch: string; + provider: string; +} + +/** + * SQLite-backed session store. Schema is created on first connection; + * concurrent writes from the api process are safe (better-sqlite3 is + * synchronous and the api is single-process). Multi-instance Cloud Run + * is NOT supported by this store — that's a v2 problem. + */ +export class SqliteSessionStore implements SessionStore { + private readonly db: DB; + private readonly maxSessions: number; + private readonly stmts: ReturnType; + + constructor(opts: { dbPath: string; maxSessions?: number }) { + if (opts.dbPath !== ":memory:") { + fs.mkdirSync(path.dirname(opts.dbPath), { recursive: true }); + } + this.db = new Database(opts.dbPath); + this.db.pragma("journal_mode = WAL"); + this.db.pragma("synchronous = NORMAL"); + this.db.pragma("foreign_keys = ON"); + this.maxSessions = opts.maxSessions ?? DEFAULT_MAX_SESSIONS; + initSchema(this.db); + this.stmts = prepareStatements(this.db); + } + + close(): void { + this.db.close(); + } + + create(product: string): SessionSummary { + const now = new Date().toISOString(); + const sessionId = randomUUID(); + this.stmts.insertSession.run(sessionId, product, now, now); + this.evictIfNeeded(); + return { + sessionId, + product, + createdAt: now, + lastActivityAt: now, + messageCount: 0, + latestConfidence: undefined, + hasTicket: false, + hasPR: false, + }; + } + + has(sessionId: string): boolean { + return this.stmts.hasSession.get(sessionId) !== undefined; + } + + appendMessage(sessionId: string, message: ChatMessage): void { + this.assertExists(sessionId); + const now = new Date().toISOString(); + const tx = this.db.transaction(() => { + this.stmts.insertMessage.run( + message.id, + sessionId, + message.role, + message.content, + message.createdAt, + ); + this.stmts.touchSession.run(now, sessionId); + }); + tx(); + } + + appendTrace(sessionId: string, trace: PipelineTrace): void { + this.assertExists(sessionId); + const now = new Date().toISOString(); + const tx = this.db.transaction(() => { + this.stmts.insertTrace.run(sessionId, JSON.stringify(trace), now); + this.stmts.touchSession.run(now, sessionId); + }); + tx(); + } + + appendTicket(sessionId: string, ticket: TicketSummary): void { + this.assertExists(sessionId); + const now = new Date().toISOString(); + const tx = this.db.transaction(() => { + this.stmts.insertTicket.run( + sessionId, + ticket.ticketId, + ticket.ticketUrl, + ticket.provider, + now, + ); + this.stmts.touchSession.run(now, sessionId); + }); + tx(); + } + + appendPR(sessionId: string, pr: PRSummary): void { + this.assertExists(sessionId); + const now = new Date().toISOString(); + const tx = this.db.transaction(() => { + this.stmts.insertPR.run(sessionId, pr.branch, pr.prUrl, pr.provider, now); + this.stmts.touchSession.run(now, sessionId); + }); + tx(); + } + + list(limit = 50): SessionSummary[] { + const rows = this.stmts.listSessions.all(limit) as RawSession[]; + return rows.map((r) => this.buildSummary(r)); + } + + getDetail(sessionId: string): SessionDetail | undefined { + const session = this.stmts.getSession.get(sessionId) as + | RawSession + | undefined; + if (!session) return undefined; + + const messages = ( + this.stmts.getMessages.all(sessionId) as RawMessage[] + ).map( + (m): ChatMessage => ({ + id: m.id, + role: m.role, + content: m.content, + createdAt: m.created_at, + }), + ); + + const traces = (this.stmts.getTraces.all(sessionId) as RawTrace[]).map( + (t) => JSON.parse(t.payload) as PipelineTrace, + ); + + const tickets = (this.stmts.getTickets.all(sessionId) as RawTicket[]).map( + (t): TicketSummary => ({ + ticketId: t.ticket_id, + ticketUrl: t.ticket_url, + provider: t.provider as TicketSummary["provider"], + }), + ); + + const prs = (this.stmts.getPRs.all(sessionId) as RawPR[]).map( + (p): PRSummary => ({ + branch: p.branch, + prUrl: p.pr_url, + provider: p.provider as PRSummary["provider"], + }), + ); + + return { + summary: this.buildSummary(session, { messages, traces, tickets, prs }), + messages, + traces, + tickets, + prs, + }; + } + + size(): number { + const row = this.stmts.countSessions.get() as { n: number }; + return row.n; + } + + private assertExists(sessionId: string): void { + if (!this.has(sessionId)) { + throw new Error(`session not found: ${sessionId}`); + } + } + + private buildSummary( + s: RawSession, + preloaded?: { + messages: ChatMessage[]; + traces: PipelineTrace[]; + tickets: TicketSummary[]; + prs: PRSummary[]; + }, + ): SessionSummary { + const counts = preloaded + ? { + messageCount: preloaded.messages.length, + latestConfidence: + preloaded.traces[preloaded.traces.length - 1]?.confidence, + hasTicket: preloaded.tickets.length > 0, + hasPR: preloaded.prs.length > 0, + } + : this.deriveSummaryCounts(s.session_id); + + return { + sessionId: s.session_id, + product: s.product, + createdAt: s.created_at, + lastActivityAt: s.last_activity_at, + ...counts, + }; + } + + private deriveSummaryCounts(sessionId: string): { + messageCount: number; + latestConfidence: Confidence | undefined; + hasTicket: boolean; + hasPR: boolean; + } { + const m = this.stmts.countMessages.get(sessionId) as { n: number }; + const t = this.stmts.countTickets.get(sessionId) as { n: number }; + const p = this.stmts.countPRs.get(sessionId) as { n: number }; + const lastTraceRow = this.stmts.getLatestTrace.get(sessionId) as + | RawTrace + | undefined; + const latestConfidence = lastTraceRow + ? (JSON.parse(lastTraceRow.payload) as PipelineTrace).confidence + : undefined; + return { + messageCount: m.n, + latestConfidence, + hasTicket: t.n > 0, + hasPR: p.n > 0, + }; + } + + private evictIfNeeded(): void { + const total = this.size(); + if (total <= this.maxSessions) return; + const overflow = total - this.maxSessions; + this.stmts.evictOldest.run(overflow); + } +} + +function initSchema(db: DB): void { + db.exec(` + CREATE TABLE IF NOT EXISTS sessions ( + session_id TEXT PRIMARY KEY, + product TEXT NOT NULL, + created_at TEXT NOT NULL, + last_activity_at TEXT NOT NULL + ); + CREATE INDEX IF NOT EXISTS idx_sessions_activity + ON sessions(last_activity_at DESC); + + CREATE TABLE IF NOT EXISTS messages ( + id TEXT PRIMARY KEY, + session_id TEXT NOT NULL REFERENCES sessions(session_id) ON DELETE CASCADE, + role TEXT NOT NULL, + content TEXT NOT NULL, + created_at TEXT NOT NULL + ); + CREATE INDEX IF NOT EXISTS idx_messages_session + ON messages(session_id, created_at); + + CREATE TABLE IF NOT EXISTS traces ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + session_id TEXT NOT NULL REFERENCES sessions(session_id) ON DELETE CASCADE, + payload TEXT NOT NULL, + created_at TEXT NOT NULL + ); + CREATE INDEX IF NOT EXISTS idx_traces_session + ON traces(session_id, id); + + CREATE TABLE IF NOT EXISTS tickets ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + session_id TEXT NOT NULL REFERENCES sessions(session_id) ON DELETE CASCADE, + ticket_id TEXT NOT NULL, + ticket_url TEXT NOT NULL, + provider TEXT NOT NULL, + created_at TEXT NOT NULL + ); + CREATE INDEX IF NOT EXISTS idx_tickets_session + ON tickets(session_id, id); + + CREATE TABLE IF NOT EXISTS prs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + session_id TEXT NOT NULL REFERENCES sessions(session_id) ON DELETE CASCADE, + branch TEXT NOT NULL, + pr_url TEXT NOT NULL, + provider TEXT NOT NULL, + created_at TEXT NOT NULL + ); + CREATE INDEX IF NOT EXISTS idx_prs_session + ON prs(session_id, id); + `); +} + +interface PreparedStatements { + insertSession: Statement; + hasSession: Statement; + getSession: Statement; + listSessions: Statement; + countSessions: Statement; + touchSession: Statement; + evictOldest: Statement; + insertMessage: Statement; + getMessages: Statement; + countMessages: Statement; + insertTrace: Statement; + getTraces: Statement; + getLatestTrace: Statement; + insertTicket: Statement; + getTickets: Statement; + countTickets: Statement; + insertPR: Statement; + getPRs: Statement; + countPRs: Statement; +} + +function prepareStatements(db: DB): PreparedStatements { + return { + insertSession: db.prepare( + "INSERT INTO sessions (session_id, product, created_at, last_activity_at) VALUES (?, ?, ?, ?)", + ), + hasSession: db.prepare("SELECT 1 FROM sessions WHERE session_id = ?"), + getSession: db.prepare("SELECT * FROM sessions WHERE session_id = ?"), + listSessions: db.prepare( + "SELECT * FROM sessions ORDER BY last_activity_at DESC, rowid DESC LIMIT ?", + ), + countSessions: db.prepare("SELECT COUNT(*) AS n FROM sessions"), + touchSession: db.prepare( + "UPDATE sessions SET last_activity_at = ? WHERE session_id = ?", + ), + evictOldest: db.prepare(` + DELETE FROM sessions WHERE session_id IN ( + SELECT session_id FROM sessions + ORDER BY last_activity_at ASC, rowid ASC + LIMIT ? + ) + `), + insertMessage: db.prepare( + "INSERT INTO messages (id, session_id, role, content, created_at) VALUES (?, ?, ?, ?, ?)", + ), + getMessages: db.prepare( + "SELECT * FROM messages WHERE session_id = ? ORDER BY created_at ASC, id ASC", + ), + countMessages: db.prepare( + "SELECT COUNT(*) AS n FROM messages WHERE session_id = ?", + ), + insertTrace: db.prepare( + "INSERT INTO traces (session_id, payload, created_at) VALUES (?, ?, ?)", + ), + getTraces: db.prepare( + "SELECT payload FROM traces WHERE session_id = ? ORDER BY id ASC", + ), + getLatestTrace: db.prepare( + "SELECT payload FROM traces WHERE session_id = ? ORDER BY id DESC LIMIT 1", + ), + insertTicket: db.prepare( + "INSERT INTO tickets (session_id, ticket_id, ticket_url, provider, created_at) VALUES (?, ?, ?, ?, ?)", + ), + getTickets: db.prepare( + "SELECT ticket_id, ticket_url, provider FROM tickets WHERE session_id = ? ORDER BY id ASC", + ), + countTickets: db.prepare( + "SELECT COUNT(*) AS n FROM tickets WHERE session_id = ?", + ), + insertPR: db.prepare( + "INSERT INTO prs (session_id, branch, pr_url, provider, created_at) VALUES (?, ?, ?, ?, ?)", + ), + getPRs: db.prepare( + "SELECT branch, pr_url, provider FROM prs WHERE session_id = ? ORDER BY id ASC", + ), + countPRs: db.prepare("SELECT COUNT(*) AS n FROM prs WHERE session_id = ?"), + }; +} diff --git a/apps/api/src/sessions/store.test.ts b/apps/api/src/sessions/store.test.ts index 2f8c761..efd5f7f 100644 --- a/apps/api/src/sessions/store.test.ts +++ b/apps/api/src/sessions/store.test.ts @@ -4,7 +4,7 @@ import type { TicketSummary, } from "@ai-support/shared"; import { describe, expect, it } from "vitest"; -import { SessionStore } from "./store.js"; +import { InMemorySessionStore } from "./store.js"; const message = (id: string, content: string): ChatMessage => ({ id, @@ -25,9 +25,9 @@ const ticket = (id: string): TicketSummary => ({ provider: "mock", }); -describe("SessionStore", () => { +describe("InMemorySessionStore", () => { it("creates a session with the given product and no messages", () => { - const store = new SessionStore(); + const store = new InMemorySessionStore(); const s = store.create("acme-app"); expect(s.product).toBe("acme-app"); expect(s.messageCount).toBe(0); @@ -36,7 +36,7 @@ describe("SessionStore", () => { }); it("records messages, traces, tickets, and reflects them in detail + summary", () => { - const store = new SessionStore(); + const store = new InMemorySessionStore(); const s = store.create("acme-app"); store.appendMessage(s.sessionId, message("m1", "hi")); store.appendTrace(s.sessionId, trace("high")); @@ -52,7 +52,7 @@ describe("SessionStore", () => { }); it("list() returns newest first", async () => { - const store = new SessionStore(); + const store = new InMemorySessionStore(); const a = store.create("a"); await new Promise((r) => setTimeout(r, 5)); const b = store.create("b"); @@ -62,7 +62,7 @@ describe("SessionStore", () => { }); it("evicts oldest entries when the cap is exceeded", () => { - const store = new SessionStore(2); + const store = new InMemorySessionStore(2); const a = store.create("a"); store.create("b"); store.create("c"); diff --git a/apps/api/src/sessions/store.ts b/apps/api/src/sessions/store.ts index 6fa9de2..9d9a026 100644 --- a/apps/api/src/sessions/store.ts +++ b/apps/api/src/sessions/store.ts @@ -8,6 +8,23 @@ import type { TicketSummary, } from "@ai-support/shared"; +/** + * SessionStore is the persistence boundary for chat sessions. The api + * orchestrator calls these methods; the choice of in-memory vs SQLite + * (or anything else later) is made at server boot. + */ +export interface SessionStore { + create(product: string): SessionSummary; + has(sessionId: string): boolean; + appendMessage(sessionId: string, message: ChatMessage): void; + appendTrace(sessionId: string, trace: PipelineTrace): void; + appendTicket(sessionId: string, ticket: TicketSummary): void; + appendPR(sessionId: string, pr: PRSummary): void; + list(limit?: number): SessionSummary[]; + getDetail(sessionId: string): SessionDetail | undefined; + size(): number; +} + interface SessionRecord { sessionId: string; product: string; @@ -19,9 +36,10 @@ interface SessionRecord { prs: PRSummary[]; } -const DEFAULT_MAX_SESSIONS = 500; +export const DEFAULT_MAX_SESSIONS = 500; -export class SessionStore { +/** In-memory `SessionStore` — fast, ephemeral, used for tests + dev w/o persistence. */ +export class InMemorySessionStore implements SessionStore { private readonly records = new Map(); private readonly maxSessions: number; From 0394da59dcbcde0274cc7c9f391c686896fc80e3 Mon Sep 17 00:00:00 2001 From: Cash-Codes Date: Tue, 28 Apr 2026 22:08:00 +0100 Subject: [PATCH 3/4] feat: widget ui tidy up --- apps/widget/app/src/App.test.tsx | 3 +- .../app/src/components/ChatWindow.test.tsx | 9 +- apps/widget/app/src/components/ChatWindow.tsx | 215 +++++++++++++++--- apps/widget/app/src/index.css | 36 ++- apps/widget/app/src/lib/api.ts | 31 +++ apps/widget/loader/src/loader.test.ts | 42 +++- apps/widget/loader/src/loader.ts | 49 +++- apps/widget/loader/tsconfig.tsbuildinfo | 2 +- demo/host.html | 150 ++++++++++-- .../mock-responses/basket-push-empty.json | 48 ---- fixtures/mock-responses/heic-rotation.json | 24 -- fixtures/mock-responses/quantity-ocr.json | 42 ---- package.json | 1 + pnpm-lock.yaml | 33 +++ 14 files changed, 495 insertions(+), 190 deletions(-) delete mode 100644 fixtures/mock-responses/basket-push-empty.json delete mode 100644 fixtures/mock-responses/heic-rotation.json delete mode 100644 fixtures/mock-responses/quantity-ocr.json diff --git a/apps/widget/app/src/App.test.tsx b/apps/widget/app/src/App.test.tsx index b3e6cdb..91a300b 100644 --- a/apps/widget/app/src/App.test.tsx +++ b/apps/widget/app/src/App.test.tsx @@ -25,8 +25,9 @@ describe("App (widget)", () => { expect( screen.getByRole("button", { name: /close chat/i }), ).toBeInTheDocument(); + // After session init completes, empty-state suggestions appear. await waitFor(() => - expect(screen.getByText(/Describe your issue/i)).toBeInTheDocument(), + expect(screen.getByText(/describe a bug/i)).toBeInTheDocument(), ); }); }); diff --git a/apps/widget/app/src/components/ChatWindow.test.tsx b/apps/widget/app/src/components/ChatWindow.test.tsx index 91f61ff..3dde41d 100644 --- a/apps/widget/app/src/components/ChatWindow.test.tsx +++ b/apps/widget/app/src/components/ChatWindow.test.tsx @@ -57,8 +57,15 @@ describe("ChatWindow", () => { expect(await screen.findByText("refund missing")).toBeInTheDocument(); expect(await screen.findByText("Here is the answer.")).toBeInTheDocument(); + expect(await screen.findByText(/Ticket MOCK-1/)).toBeInTheDocument(); + + // Confidence pill is visible immediately + expect(await screen.findByText(/high confidence/i)).toBeInTheDocument(); + + // Phase trace is collapsed behind a toggle; expand it + const toggle = await screen.findByRole("button", { name: /view trace/i }); + await user.click(toggle); expect(await screen.findByText("intake")).toBeInTheDocument(); expect(await screen.findByText("docsRetrieval")).toBeInTheDocument(); - expect(await screen.findByText(/Ticket MOCK-1/)).toBeInTheDocument(); }); }); diff --git a/apps/widget/app/src/components/ChatWindow.tsx b/apps/widget/app/src/components/ChatWindow.tsx index f3ef190..f504b1e 100644 --- a/apps/widget/app/src/components/ChatWindow.tsx +++ b/apps/widget/app/src/components/ChatWindow.tsx @@ -1,65 +1,136 @@ -import { useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import { useChatStream } from "../hooks/useChatStream.js"; +import { type Suggestion, readSuggestionsFromUrl } from "../lib/api.js"; import { postToHost } from "../lib/hostBridge.js"; import { MessageBubble } from "./MessageBubble.js"; import { PhaseTimeline } from "./PhaseTimeline.js"; +import { ThinkingIndicator } from "./ThinkingIndicator.js"; import { TicketCard } from "./TicketCard.js"; export function ChatWindow() { const { messages, phaseEvents, lastResponse, state, error, send } = useChatStream(); const [draft, setDraft] = useState(""); + const [traceOpen, setTraceOpen] = useState(false); + const scrollRef = useRef(null); + // Host page passes optional suggestion chips via the loader's + // `data-suggestions` attribute → forwarded as a query param. Empty when + // the host doesn't configure any. + const suggestions = useMemo(() => readSuggestionsFromUrl(), []); + + // Auto-scroll the transcript to bottom on every new message + while + // streaming (so the thinking indicator stays in view). + useEffect(() => { + const el = scrollRef.current; + if (!el) return; + if (typeof el.scrollTo === "function") { + el.scrollTo({ top: el.scrollHeight, behavior: "smooth" }); + } else { + el.scrollTop = el.scrollHeight; + } + }, [state, lastResponse]); + + const isBusy = state === "streaming" || state === "initializing"; async function onSubmit(e: React.FormEvent) { e.preventDefault(); const trimmed = draft.trim(); - if (!trimmed || state === "streaming" || state === "initializing") return; + if (!trimmed || isBusy) return; setDraft(""); + setTraceOpen(false); await send(trimmed); } + async function pickSuggestion(query: string) { + if (isBusy) return; + setDraft(""); + setTraceOpen(false); + await send(query); + } + return (
-
-
-

- AI Support Engineer -

-

- {state === "initializing" ? "connecting..." : "Describe your issue"} -

+
+
+ +
+
+

+ AI Support +

+
+

+ {state === "initializing" + ? "connecting…" + : state === "streaming" + ? "looking into it…" + : "Typically replies in seconds"} +

+
-
- {messages.length === 0 ? ( -

- How can I help! start by describing your issue. -

+
+ {messages.length === 0 && state !== "streaming" ? ( + ) : null} + {messages.map((m) => ( ))} - {phaseEvents.length > 0 ? ( -
-

- Phases -

- + {state === "streaming" ? ( +
+
) : null} - {lastResponse?.ticket || lastResponse?.pr ? ( - + {lastResponse && state === "idle" ? ( +
+ setTraceOpen((o) => !o)} + /> + {traceOpen ? ( +
+ +
+ ) : null} + {lastResponse.ticket || lastResponse.pr ? ( + + ) : null} +
) : null}
@@ -71,27 +142,101 @@ export function ChatWindow() {
setDraft(e.target.value)} - disabled={state === "streaming" || state === "initializing"} + disabled={isBusy} />
); } + +function EmptyState({ + onPick, + disabled, + suggestions, +}: { + onPick: (q: string) => void; + disabled: boolean; + suggestions: Suggestion[]; +}) { + const intro = + suggestions.length > 0 + ? "Describe a bug or unexpected behaviour and I'll check the docs and inspect the code if needed. Try one of these to start:" + : "Describe a bug or unexpected behaviour and I'll check the docs and inspect the code if needed."; + return ( +
+
+

Hi there 👋

+

{intro}

+
+ {suggestions.length > 0 ? ( +
    + {suggestions.map((s) => ( +
  • + +
  • + ))} +
+ ) : null} +
+ ); +} + +const CONFIDENCE_STYLE: Record = { + high: "bg-emerald-50 text-emerald-700 ring-emerald-200", + medium: "bg-amber-50 text-amber-700 ring-amber-200", + low: "bg-slate-100 text-slate-600 ring-slate-200", +}; + +function ResponseMeta({ + confidence, + traceOpen, + onToggleTrace, +}: { + confidence: "low" | "medium" | "high"; + traceOpen: boolean; + onToggleTrace: () => void; +}) { + return ( +
+ + + +
+ ); +} diff --git a/apps/widget/app/src/index.css b/apps/widget/app/src/index.css index 6d09aab..195b861 100644 --- a/apps/widget/app/src/index.css +++ b/apps/widget/app/src/index.css @@ -9,7 +9,41 @@ body, } body { - @apply bg-white text-slate-900 antialiased; + @apply bg-slate-50 text-slate-900 antialiased; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif; } + +@keyframes ai-support-dot-bounce { + 0%, + 60%, + 100% { + transform: translateY(0); + opacity: 0.4; + } + 30% { + transform: translateY(-3px); + opacity: 1; + } +} + +@keyframes ai-support-fade-in { + from { + opacity: 0; + transform: translateY(4px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.fade-in { + animation: ai-support-fade-in 0.22s ease-out both; +} + +@media (prefers-reduced-motion: reduce) { + .fade-in { + animation: none !important; + } +} diff --git a/apps/widget/app/src/lib/api.ts b/apps/widget/app/src/lib/api.ts index 0ab18e7..73953d0 100644 --- a/apps/widget/app/src/lib/api.ts +++ b/apps/widget/app/src/lib/api.ts @@ -33,3 +33,34 @@ export function readProductFromUrl(search: string = location.search): string { const params = new URLSearchParams(search); return params.get("product") ?? "unknown"; } + +export interface Suggestion { + label: string; + query: string; +} + +/** + * Reads the host-provided suggestion chips from the iframe URL. + * Loader script's `data-suggestions` attribute is JSON-encoded and + * forwarded as a query param. Returns an empty array when nothing is + * configured — the widget falls back to its own no-chip empty state. + */ +export function readSuggestionsFromUrl( + search: string = location.search, +): Suggestion[] { + const raw = new URLSearchParams(search).get("suggestions"); + if (!raw) return []; + try { + const parsed = JSON.parse(raw) as unknown; + if (!Array.isArray(parsed)) return []; + return parsed.filter( + (s): s is Suggestion => + typeof s === "object" && + s !== null && + typeof (s as Suggestion).label === "string" && + typeof (s as Suggestion).query === "string", + ); + } catch { + return []; + } +} diff --git a/apps/widget/loader/src/loader.test.ts b/apps/widget/loader/src/loader.test.ts index ef98fad..ebe6927 100644 --- a/apps/widget/loader/src/loader.test.ts +++ b/apps/widget/loader/src/loader.test.ts @@ -13,10 +13,9 @@ describe("readConfigFromScript", () => { script.dataset.apiBase = "https://api.example.com"; script.dataset.product = "acme-app"; const config = readConfigFromScript(script); - expect(config).toEqual({ - apiBase: "https://api.example.com", - product: "acme-app", - }); + expect(config.apiBase).toBe("https://api.example.com"); + expect(config.product).toBe("acme-app"); + expect(config.suggestions).toBeUndefined(); }); it("falls back to script src origin when data-api-base is missing", () => { @@ -26,6 +25,28 @@ describe("readConfigFromScript", () => { expect(config.apiBase).toBe("https://api.example.com"); expect(config.product).toBe("unknown"); }); + + it("parses data-suggestions JSON when present and well-formed", () => { + const script = document.createElement("script"); + script.src = "https://api.example.com/widget/loader.js"; + script.dataset.suggestions = JSON.stringify([ + { label: "A", query: "do A" }, + { label: "B", query: "do B" }, + ]); + const config = readConfigFromScript(script); + expect(config.suggestions).toEqual([ + { label: "A", query: "do A" }, + { label: "B", query: "do B" }, + ]); + }); + + it("ignores malformed suggestions silently", () => { + const script = document.createElement("script"); + script.src = "https://api.example.com/widget/loader.js"; + script.dataset.suggestions = "{not-json"; + const config = readConfigFromScript(script); + expect(config.suggestions).toBeUndefined(); + }); }); describe("mount", () => { @@ -49,6 +70,19 @@ describe("mount", () => { expect(style).not.toBeNull(); }); + it("forwards suggestions through the iframe URL when configured", () => { + const result = mount({ + apiBase: "https://api.example.com", + product: "acme-app", + suggestions: [{ label: "A", query: "do A" }], + }); + const iframeSrc = new URL(result.iframe.src); + expect(iframeSrc.searchParams.get("product")).toBe("acme-app"); + const raw = iframeSrc.searchParams.get("suggestions"); + expect(raw).not.toBeNull(); + expect(JSON.parse(raw ?? "[]")).toEqual([{ label: "A", query: "do A" }]); + }); + it("toggles iframe data-open on button click", () => { const { button, iframe } = mount({ apiBase: "https://api.example.com", diff --git a/apps/widget/loader/src/loader.ts b/apps/widget/loader/src/loader.ts index fabe6d8..95efaa8 100644 --- a/apps/widget/loader/src/loader.ts +++ b/apps/widget/loader/src/loader.ts @@ -1,6 +1,12 @@ +export interface LoaderSuggestion { + label: string; + query: string; +} + export interface LoaderConfig { apiBase: string; product: string; + suggestions?: LoaderSuggestion[]; } export function readConfigFromScript( @@ -10,7 +16,28 @@ export function readConfigFromScript( script?.dataset.apiBase ?? new URL(".", script?.src ?? location.href).origin; const product = script?.dataset.product ?? "unknown"; - return { apiBase, product }; + const suggestions = parseSuggestions(script?.dataset.suggestions); + return { apiBase, product, suggestions }; +} + +function parseSuggestions( + raw: string | undefined, +): LoaderSuggestion[] | undefined { + if (!raw) return undefined; + try { + const parsed = JSON.parse(raw) as unknown; + if (!Array.isArray(parsed)) return undefined; + const cleaned = parsed.filter( + (s): s is LoaderSuggestion => + typeof s === "object" && + s !== null && + typeof (s as LoaderSuggestion).label === "string" && + typeof (s as LoaderSuggestion).query === "string", + ); + return cleaned.length > 0 ? cleaned : undefined; + } catch { + return undefined; + } } export function injectStyles(doc: Document): void { @@ -143,6 +170,12 @@ export function mount( iframe.title = "AI Support Chat"; const iframeUrl = new URL("/widget/", config.apiBase); iframeUrl.searchParams.set("product", config.product); + if (config.suggestions && config.suggestions.length > 0) { + iframeUrl.searchParams.set( + "suggestions", + JSON.stringify(config.suggestions), + ); + } iframe.src = iframeUrl.toString(); iframe.dataset.open = "false"; @@ -174,15 +207,15 @@ export function mount( return { button, iframe }; } -function autoMount() { - const script = document.currentScript as HTMLScriptElement | null; - mount(readConfigFromScript(script)); -} - if (typeof document !== "undefined" && !("VITEST" in globalThis)) { + // `document.currentScript` is only valid synchronously while the + // script is executing — inside a DOMContentLoaded callback it returns + // null. Capture it here, in the IIFE, and close over it. + const script = document.currentScript as HTMLScriptElement | null; + const run = () => mount(readConfigFromScript(script)); if (document.readyState === "loading") { - document.addEventListener("DOMContentLoaded", autoMount); + document.addEventListener("DOMContentLoaded", run); } else { - autoMount(); + run(); } } diff --git a/apps/widget/loader/tsconfig.tsbuildinfo b/apps/widget/loader/tsconfig.tsbuildinfo index ea04bd9..aa2e113 100644 --- a/apps/widget/loader/tsconfig.tsbuildinfo +++ b/apps/widget/loader/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"fileNames":["../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../node_modules/.pnpm/@vitest+pretty-format@2.1.9/node_modules/@vitest/pretty-format/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/types.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/helpers.d.ts","../../../node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/index-c1cfc5e9.d.ts","../../../node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/node.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/tasks-3znpj1lr.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/types-bxe-2udy.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/diff.d.ts","../../../node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/types.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/error.d.ts","../../../node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/environment.looobwuu.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/compatibility/disposable.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/compatibility/indexable.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/compatibility/iterators.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/compatibility/index.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/globals.typedarray.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/buffer.buffer.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/globals.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/abortcontroller.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/domexception.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/events.d.ts","../../../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/header.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/readable.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/file.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/fetch.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/formdata.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/connector.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/client.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/errors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/dispatcher.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/global-dispatcher.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/global-origin.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/pool-stats.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/handlers.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/balanced-pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-interceptor.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-client.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-errors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/env-http-proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/retry-handler.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/retry-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/api.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/interceptors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/util.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/cookies.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/patch.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/websocket.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/eventsource.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/filereader.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/diagnostics-channel.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/content-type.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/cache.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/index.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/fetch.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/navigator.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/storage.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/assert.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/assert/strict.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/async_hooks.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/buffer.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/child_process.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/cluster.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/console.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/constants.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/crypto.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/dgram.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/dns.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/dns/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/domain.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/events.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/fs.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/fs/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/http.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/http2.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/https.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/inspector.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/inspector.generated.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/module.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/net.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/os.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/path.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/process.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/punycode.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/querystring.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/readline.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/readline/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/repl.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/sea.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/sqlite.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/stream.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/stream/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/stream/web.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/string_decoder.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/test.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/timers.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/timers/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/tls.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/trace_events.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/tty.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/url.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/util.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/v8.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/vm.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/wasi.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/worker_threads.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/zlib.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/index.d.ts","../../../node_modules/.pnpm/@types+estree@1.0.8/node_modules/@types/estree/index.d.ts","../../../node_modules/.pnpm/rollup@4.60.2/node_modules/rollup/dist/rollup.d.ts","../../../node_modules/.pnpm/rollup@4.60.2/node_modules/rollup/dist/parseast.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/types/hmrpayload.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/types/customevent.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/types/hot.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/dist/node/types.d-agj9qkwt.d.ts","../../../node_modules/.pnpm/esbuild@0.21.5/node_modules/esbuild/lib/main.d.ts","../../../node_modules/.pnpm/source-map-js@1.2.1/node_modules/source-map-js/source-map.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/previous-map.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/input.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/css-syntax-error.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/declaration.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/root.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/warning.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/lazy-result.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/no-work-result.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/processor.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/result.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/document.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/rule.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/node.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/comment.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/container.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/at-rule.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/list.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/postcss.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/postcss.d.mts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/dist/node/runtime.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/types/importglob.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/types/metadata.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/dist/node/index.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@2.1.9/node_modules/@vitest/snapshot/dist/environment-ddx0edty.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@2.1.9/node_modules/@vitest/snapshot/dist/rawsnapshot-cpnkto81.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@2.1.9/node_modules/@vitest/snapshot/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@2.1.9/node_modules/@vitest/snapshot/dist/environment.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/config.cy0c388z.d.ts","../../../node_modules/.pnpm/vite-node@2.1.9_@types+node@22.19.17/node_modules/vite-node/dist/trace-mapping.d-dlvdeqop.d.ts","../../../node_modules/.pnpm/vite-node@2.1.9_@types+node@22.19.17/node_modules/vite-node/dist/index-z0r8hvru.d.ts","../../../node_modules/.pnpm/vite-node@2.1.9_@types+node@22.19.17/node_modules/vite-node/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/source-map.d.ts","../../../node_modules/.pnpm/vite-node@2.1.9_@types+node@22.19.17/node_modules/vite-node/dist/client.d.ts","../../../node_modules/.pnpm/vite-node@2.1.9_@types+node@22.19.17/node_modules/vite-node/dist/server.d.ts","../../../node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/utils.d.ts","../../../node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/benchmark.geerunq4.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@2.1.9/node_modules/@vitest/snapshot/dist/manager.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/reporters.nr4dxcka.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/worker.tn5kgiih.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/worker.b9fxpcac.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/vite.czkp4x9w.d.ts","../../../node_modules/.pnpm/@vitest+expect@2.1.9/node_modules/@vitest/expect/dist/chai.d.cts","../../../node_modules/.pnpm/@vitest+expect@2.1.9/node_modules/@vitest/expect/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+expect@2.1.9/node_modules/@vitest/expect/index.d.ts","../../../node_modules/.pnpm/@vitest+spy@2.1.9/node_modules/@vitest/spy/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+mocker@2.1.9_vite@5.4.21_@types+node@22.19.17_/node_modules/@vitest/mocker/dist/types-dzoqtgin.d.ts","../../../node_modules/.pnpm/@vitest+mocker@2.1.9_vite@5.4.21_@types+node@22.19.17_/node_modules/@vitest/mocker/dist/index.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/mocker.crtm890j.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/suite.b2jumifp.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/index.d.ts","./src/loader.ts","./src/loader.test.ts","../../../node_modules/.pnpm/@types+react@18.3.28/node_modules/@types/react/global.d.ts","../../../node_modules/.pnpm/csstype@3.2.3/node_modules/csstype/index.d.ts","../../../node_modules/.pnpm/@types+prop-types@15.7.15/node_modules/@types/prop-types/index.d.ts","../../../node_modules/.pnpm/@types+react@18.3.28/node_modules/@types/react/index.d.ts","../../../node_modules/.pnpm/@types+react-dom@18.3.7_@types+react@18.3.28/node_modules/@types/react-dom/index.d.ts"],"fileIdsList":[[66,115,132,133,230,231],[66,115,132,133],[66,112,113,115,132,133],[66,114,115,132,133],[115,132,133],[66,115,120,132,133,150],[66,115,116,121,126,132,133,135,147,158],[66,115,116,117,126,132,133,135],[61,62,63,66,115,132,133],[66,115,118,132,133,159],[66,115,119,120,127,132,133,136],[66,115,120,132,133,147,155],[66,115,121,123,126,132,133,135],[66,114,115,122,132,133],[66,115,123,124,132,133],[66,115,125,126,132,133],[66,114,115,126,132,133],[66,115,126,127,128,132,133,147,158],[66,115,126,127,128,132,133,142,147,150],[66,108,115,123,126,129,132,133,135,147,158],[66,115,126,127,129,130,132,133,135,147,155,158],[66,115,129,131,132,133,147,155,158],[64,65,66,67,68,69,70,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164],[66,115,126,132,133],[66,115,132,133,134,158],[66,115,123,126,132,133,135,147],[66,115,132,133,136],[66,115,132,133,137],[66,114,115,132,133,138],[66,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164],[66,115,132,133,140],[66,115,132,133,141],[66,115,126,132,133,142,143],[66,115,132,133,142,144,159,161],[66,115,127,132,133],[66,115,126,132,133,147,148,150],[66,115,132,133,149,150],[66,115,132,133,147,148],[66,115,132,133,150],[66,115,132,133,151],[66,112,115,132,133,147,152,158],[66,115,126,132,133,153,154],[66,115,132,133,153,154],[66,115,120,132,133,135,147,155],[66,115,132,133,156],[66,115,132,133,135,157],[66,115,129,132,133,141,158],[66,115,120,132,133,159],[66,115,132,133,147,160],[66,115,132,133,134,161],[66,115,132,133,162],[66,108,115,132,133],[66,108,115,126,128,132,133,138,147,150,158,160,161,163],[66,115,132,133,147,164],[66,115,132,133,236],[66,115,132,133,233,234,235],[52,53,56,66,115,132,133],[66,115,132,133,218],[66,115,132,133,221],[53,54,56,57,58,66,115,132,133],[53,66,115,132,133],[53,54,56,66,115,132,133],[53,54,66,115,132,133],[66,115,132,133,198],[48,66,115,132,133,198,199],[48,66,115,132,133,198],[48,55,66,115,132,133],[49,66,115,132,133],[48,49,50,52,66,115,132,133],[48,66,115,132,133],[66,115,132,133,225,226],[66,115,132,133,225,226,227,228],[66,115,132,133,225,227],[66,115,132,133,225],[66,115,132,133,189],[66,115,132,133,187,189],[66,115,132,133,178,186,187,188,190,192],[66,115,132,133,176],[66,115,132,133,179,184,189,192],[66,115,132,133,175,192],[66,115,132,133,179,180,183,184,185,192],[66,115,132,133,179,180,181,183,184,192],[66,115,132,133,176,177,178,179,180,184,185,186,188,189,190,192],[66,115,132,133,192],[66,115,132,133,174,176,177,178,179,180,181,183,184,185,186,187,188,189,190,191],[66,115,132,133,174,192],[66,115,132,133,179,181,182,184,185,192],[66,115,132,133,183,192],[66,115,132,133,184,185,189,192],[66,115,132,133,177,187],[66,115,132,133,167,196],[66,115,132,133,166,167],[51,66,115,132,133],[66,80,84,115,132,133,158],[66,80,115,132,133,147,158],[66,75,115,132,133],[66,77,80,115,132,133,155,158],[66,115,132,133,135,155],[66,115,132,133,165],[66,75,115,132,133,165],[66,77,80,115,132,133,135,158],[66,72,73,76,79,115,126,132,133,147,158],[66,80,87,115,132,133],[66,72,78,115,132,133],[66,80,101,102,115,132,133],[66,76,80,115,132,133,150,158,165],[66,101,115,132,133,165],[66,74,75,115,132,133,165],[66,80,115,132,133],[66,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,102,103,104,105,106,107,115,132,133],[66,80,95,115,132,133],[66,80,87,88,115,132,133],[66,78,80,88,89,115,132,133],[66,79,115,132,133],[66,72,75,80,115,132,133],[66,80,84,88,89,115,132,133],[66,84,115,132,133],[66,78,80,83,115,132,133,158],[66,72,77,80,87,115,132,133],[66,115,132,133,147],[66,75,80,101,115,132,133,163,165],[66,115,132,133,203,204],[66,115,132,133,203],[66,115,132,133,197,203,204,216],[66,115,126,127,129,130,131,132,133,135,147,155,158,164,165,167,168,169,170,171,172,173,193,194,195,196],[66,115,132,133,169,170,171,172],[66,115,132,133,169,170,171],[66,115,132,133,169],[66,115,132,133,170],[66,115,132,133,167],[59,66,115,132,133,209,210,230],[48,59,66,115,132,133,200,201,230],[66,115,132,133,222],[48,53,59,60,66,115,127,132,133,147,197,200,202,205,206,207,208,211,212,216,217,230],[59,66,115,132,133,209,210,211,230],[66,115,132,133,197,213],[66,115,132,133,163,214],[59,60,66,115,132,133,200,202,205,230],[48,53,56,59,60,66,115,127,132,133,147,163,197,200,201,202,205,206,207,208,209,210,211,212,213,214,215,216,217,219,220,222,223,224,229,230]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"d2e64a6f25013b099e83bfadb2c388d7bef3e8f3fdb25528225bbc841e7e7e3a","impliedFormat":99},{"version":"369ba5259e66ca8c7d35e3234f7a2a0863a770fdb8266505747c65cf346a0804","impliedFormat":99},{"version":"64d984f55025daf604f670b7dfd090ea765f2098aee871174ef2ee3e94479098","impliedFormat":99},{"version":"f147b6710441cf3ec3234adf63b0593ce5e8c9b692959d21d3babc8454bcf743","impliedFormat":99},{"version":"e96d5373a66c2cfbbc7e6642cf274055aa2c7ff6bd37be7480c66faf9804db6d","impliedFormat":99},{"version":"02bcdd7a76c5c1c485cbf05626d24c86ac8f9a1d8dc31f8924108bbaa4cf3ba9","impliedFormat":99},{"version":"c874ab6feac6e0fdf9142727c9a876065777a5392f14b0bbcf869b1e69eb46b5","impliedFormat":99},{"version":"7c553fc9e34773ddbaabe0fa1367d4b109101d0868a008f11042bee24b5a925d","impliedFormat":99},{"version":"9962ce696fbdce2421d883ca4b062a54f982496625437ae4d3633376c5ad4a80","impliedFormat":99},{"version":"e3ea467c4a7f743f3548c9ed61300591965b1d12c08c8bb9aaff8a002ba95fce","impliedFormat":99},{"version":"4c17183a07a63bea2653fbfc0a942b027160ddbee823024789a415f9589de327","impliedFormat":99},{"version":"3e2203c892297ea44b87470fde51b3d48cfe3eeb6901995de429539462894464","impliedFormat":99},{"version":"c84bf7a4abc5e7fdf45971a71b25b0e0d34ccd5e720a866dd78bb71d60d41a3f","impliedFormat":99},{"version":"6c7176368037af28cb72f2392010fa1cef295d6d6744bca8cfb54985f3a18c3e","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"437e20f2ba32abaeb7985e0afe0002de1917bc74e949ba585e49feba65da6ca1","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"3af97acf03cc97de58a3a4bc91f8f616408099bc4233f6d0852e72a8ffb91ac9","affectsGlobalScope":true,"impliedFormat":1},{"version":"808069bba06b6768b62fd22429b53362e7af342da4a236ed2d2e1c89fcca3b4a","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"4967529644e391115ca5592184d4b63980569adf60ee685f968fd59ab1557188","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"f9501cc13ce624c72b61f12b3963e84fad210fbdf0ffbc4590e08460a3f04eba","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0fa06ada475b910e2106c98c68b10483dc8811d0c14a8a8dd36efb2672485b29","impliedFormat":1},{"version":"33e5e9aba62c3193d10d1d33ae1fa75c46a1171cf76fef750777377d53b0303f","impliedFormat":1},{"version":"2b06b93fd01bcd49d1a6bd1f9b65ddcae6480b9a86e9061634d6f8e354c1468f","impliedFormat":1},{"version":"6a0cd27e5dc2cfbe039e731cf879d12b0e2dded06d1b1dedad07f7712de0d7f4","affectsGlobalScope":true,"impliedFormat":1},{"version":"13f5c844119c43e51ce777c509267f14d6aaf31eafb2c2b002ca35584cd13b29","impliedFormat":1},{"version":"e60477649d6ad21542bd2dc7e3d9ff6853d0797ba9f689ba2f6653818999c264","impliedFormat":1},{"version":"c2510f124c0293ab80b1777c44d80f812b75612f297b9857406468c0f4dafe29","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"4c829ab315f57c5442c6667b53769975acbf92003a66aef19bce151987675bd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"b2ade7657e2db96d18315694789eff2ddd3d8aea7215b181f8a0b303277cc579","impliedFormat":1},{"version":"9855e02d837744303391e5623a531734443a5f8e6e8755e018c41d63ad797db2","impliedFormat":1},{"version":"4d631b81fa2f07a0e63a9a143d6a82c25c5f051298651a9b69176ba28930756d","impliedFormat":1},{"version":"836a356aae992ff3c28a0212e3eabcb76dd4b0cc06bcb9607aeef560661b860d","impliedFormat":1},{"version":"1e0d1f8b0adfa0b0330e028c7941b5a98c08b600efe7f14d2d2a00854fb2f393","impliedFormat":1},{"version":"41670ee38943d9cbb4924e436f56fc19ee94232bc96108562de1a734af20dc2c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c906fb15bd2aabc9ed1e3f44eb6a8661199d6c320b3aa196b826121552cb3695","impliedFormat":1},{"version":"22295e8103f1d6d8ea4b5d6211e43421fe4564e34d0dd8e09e520e452d89e659","impliedFormat":1},{"version":"58647d85d0f722a1ce9de50955df60a7489f0593bf1a7015521efe901c06d770","impliedFormat":1},{"version":"6b4e081d55ac24fc8a4631d5dd77fe249fa25900abd7d046abb87d90e3b45645","impliedFormat":1},{"version":"a10f0e1854f3316d7ee437b79649e5a6ae3ae14ffe6322b02d4987071a95362e","impliedFormat":1},{"version":"e208f73ef6a980104304b0d2ca5f6bf1b85de6009d2c7e404028b875020fa8f2","impliedFormat":1},{"version":"d163b6bc2372b4f07260747cbc6c0a6405ab3fbcea3852305e98ac43ca59f5bc","impliedFormat":1},{"version":"e6fa9ad47c5f71ff733744a029d1dc472c618de53804eae08ffc243b936f87ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"a6f137d651076822d4fe884287e68fd61785a0d3d1fdb250a5059b691fa897db","impliedFormat":1},{"version":"24826ed94a78d5c64bd857570fdbd96229ad41b5cb654c08d75a9845e3ab7dde","impliedFormat":1},{"version":"8b479a130ccb62e98f11f136d3ac80f2984fdc07616516d29881f3061f2dd472","impliedFormat":1},{"version":"928af3d90454bf656a52a48679f199f64c1435247d6189d1caf4c68f2eaf921f","affectsGlobalScope":true,"impliedFormat":1},{"version":"bceb58df66ab8fb00170df20cd813978c5ab84be1d285710c4eb005d8e9d8efb","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f16a7e4deafa527ed9995a772bb380eb7d3c2c0fd4ae178c5263ed18394db2c","impliedFormat":1},{"version":"933921f0bb0ec12ef45d1062a1fc0f27635318f4d294e4d99de9a5493e618ca2","impliedFormat":1},{"version":"71a0f3ad612c123b57239a7749770017ecfe6b66411488000aba83e4546fde25","impliedFormat":1},{"version":"77fbe5eecb6fac4b6242bbf6eebfc43e98ce5ccba8fa44e0ef6a95c945ff4d98","impliedFormat":1},{"version":"4f9d8ca0c417b67b69eeb54c7ca1bedd7b56034bb9bfd27c5d4f3bc4692daca7","impliedFormat":1},{"version":"814118df420c4e38fe5ae1b9a3bafb6e9c2aa40838e528cde908381867be6466","impliedFormat":1},{"version":"a3fc63c0d7b031693f665f5494412ba4b551fe644ededccc0ab5922401079c95","impliedFormat":1},{"version":"80523c00b8544a2000ae0143e4a90a00b47f99823eb7926c1e03c494216fc363","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"746911b62b329587939560deb5c036aca48aece03147b021fa680223255d5183","affectsGlobalScope":true,"impliedFormat":1},{"version":"18fd40412d102c5564136f29735e5d1c3b455b8a37f920da79561f1fde068208","impliedFormat":1},{"version":"c8d3e5a18ba35629954e48c4cc8f11dc88224650067a172685c736b27a34a4dc","impliedFormat":1},{"version":"f0be1b8078cd549d91f37c30c222c2a187ac1cf981d994fb476a1adc61387b14","affectsGlobalScope":true,"impliedFormat":1},{"version":"0aaed1d72199b01234152f7a60046bc947f1f37d78d182e9ae09c4289e06a592","impliedFormat":1},{"version":"2b55d426ff2b9087485e52ac4bc7cfafe1dc420fc76dad926cd46526567c501a","impliedFormat":1},{"version":"66ba1b2c3e3a3644a1011cd530fb444a96b1b2dfe2f5e837a002d41a1a799e60","impliedFormat":1},{"version":"7e514f5b852fdbc166b539fdd1f4e9114f29911592a5eb10a94bb3a13ccac3c4","impliedFormat":1},{"version":"5b7aa3c4c1a5d81b411e8cb302b45507fea9358d3569196b27eb1a27ae3a90ef","affectsGlobalScope":true,"impliedFormat":1},{"version":"5987a903da92c7462e0b35704ce7da94d7fdc4b89a984871c0e2b87a8aae9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"ea08a0345023ade2b47fbff5a76d0d0ed8bff10bc9d22b83f40858a8e941501c","impliedFormat":1},{"version":"47613031a5a31510831304405af561b0ffaedb734437c595256bb61a90f9311b","impliedFormat":1},{"version":"ae062ce7d9510060c5d7e7952ae379224fb3f8f2dd74e88959878af2057c143b","impliedFormat":1},{"version":"8a1a0d0a4a06a8d278947fcb66bf684f117bf147f89b06e50662d79a53be3e9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"358765d5ea8afd285d4fd1532e78b88273f18cb3f87403a9b16fef61ac9fdcfe","impliedFormat":1},{"version":"9f55299850d4f0921e79b6bf344b47c420ce0f507b9dcf593e532b09ea7eeea1","impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"ee70b8037ecdf0de6c04f35277f253663a536d7e38f1539d270e4e916d225a3f","affectsGlobalScope":true,"impliedFormat":1},{"version":"a660aa95476042d3fdcc1343cf6bb8fdf24772d31712b1db321c5a4dcc325434","impliedFormat":1},{"version":"282f98006ed7fa9bb2cd9bdbe2524595cfc4bcd58a0bb3232e4519f2138df811","impliedFormat":1},{"version":"6222e987b58abfe92597e1273ad7233626285bc2d78409d4a7b113d81a83496b","impliedFormat":1},{"version":"cbe726263ae9a7bf32352380f7e8ab66ee25b3457137e316929269c19e18a2be","impliedFormat":1},{"version":"8b96046bf5fb0a815cba6b0880d9f97b7f3a93cf187e8dcfe8e2792e97f38f87","impliedFormat":99},{"version":"bacf2c84cf448b2cd02c717ad46c3d7fd530e0c91282888c923ad64810a4d511","affectsGlobalScope":true,"impliedFormat":1},{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","impliedFormat":1},{"version":"52dcc257df5119fb66d864625112ce5033ac51a4c2afe376a0b299d2f7f76e4a","impliedFormat":1},{"version":"e5bab5f871ef708d52d47b3e5d0aa72a08ee7a152f33931d9a60809711a2a9a3","impliedFormat":1},{"version":"e16dc2a81595736024a206c7d5c8a39bfe2e6039208ef29981d0d95434ba8fcf","impliedFormat":1},{"version":"cc4a4903fb698ca1d961d4c10dce658aa3a479faf40509d526f122b044eaf6a4","impliedFormat":1},{"version":"19ee8416e6473ed6c7adb868fa796b5653cf0fa2a337658e677eaa0d134388c3","impliedFormat":1},{"version":"1328ab4e442614b28cdb3d4b414cf68325c0da0dca07287a338d0654b7a00261","impliedFormat":1},{"version":"a039dc21f045919f3cbee2ec13812cc6cc3eebc99dae4be00973230f468d19a6","impliedFormat":1},{"version":"3fbe57af01460e49dcd29df55d6931e1672bc6f1be0fb073d11410bc16f9037d","impliedFormat":1},{"version":"f760be449e8562ec5c09bb5187e8e1eabf3c113c0c58cddda53ef8c69f3e2131","impliedFormat":1},{"version":"44325ed13294fce6ab825b82947bbeed2611db7dad9d9135260192f375e5a189","impliedFormat":1},{"version":"e392e8fb5b514eafc585601c1d781485aa6dd6a320e75daf1064a4c6918a1b45","impliedFormat":1},{"version":"46e4a36e8ddbdfb4e7330e11c81c970dc8b218611df9183d39c41c5f8c653b55","impliedFormat":1},{"version":"370bde134aa8c2abc926d0e99d3a4d5d5dba65c6ee65459137e4f02670cbf841","impliedFormat":1},{"version":"6332f565867cf4a740a70e30f31cefba37ef7cebcf74f22eab8d744fde6d193e","impliedFormat":1},{"version":"2977b7884aedc895a1d0c9c210c7cf3272c29d6959a08a6fa3ff71e0aff08175","impliedFormat":1},{"version":"17f2922d41ddd032830a91371c948cd9ce903b35c95adca72271a54584f19b0b","impliedFormat":1},{"version":"3eed76ede2a1a14d7c9bb0a642041282dcc264811139d3dd275c9fe14efc9840","impliedFormat":1},{"version":"00cf4001e0d9c6e5e036bc545b9d73e2b8b84cddb02e61ad05bab3752b1d4522","impliedFormat":1},{"version":"8d369483f0c2b9ee388129cfdb6a43bc8112b377e86a41884bd06e19ce04f4c1","impliedFormat":99},{"version":"82e687ebd99518bc63ea04b0c3810fb6e50aa6942decd0ca6f7a56d9b9a212a6","impliedFormat":99},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","impliedFormat":1},{"version":"8f07f2b6514744ac96e51d7cb8518c0f4de319471237ea10cf688b8d0e9d0225","impliedFormat":1},{"version":"257b83faa134d971c738a6b9e4c47e59bb7b23274719d92197580dd662bfafc3","impliedFormat":99},{"version":"e01ea380015ed698c3c0e2ccd0db72f3fc3ef1abc4519f122aa1c1a8d419a505","impliedFormat":99},{"version":"5ada1f8a9580c0f7478fe03ae3e07e958f0b79bdfb9dd50eeb98c1324f40011b","impliedFormat":99},{"version":"a8301dc90b4bd9fba333226ee0f1681aeeff1bd90233a8f647e687cb4b7d3521","impliedFormat":99},{"version":"e3225dc0bec183183509d290f641786245e6652bc3dce755f7ef404060693c35","impliedFormat":99},{"version":"09a03870ed8c55d7453bc9ad684df88965f2f770f987481ca71b8a09be5205bc","impliedFormat":99},{"version":"e6233e1c976265e85aa8ad76c3881febe6264cb06ae3136f0257e1eab4a6cc5a","impliedFormat":99},{"version":"2cdd50ddc49e2d608ee848fc4ab0db9a2716624fabb4209c7c683d87e54d79c5","impliedFormat":99},{"version":"e431d664338b8470abb1750d699c7dfcebb1a25434559ef85bb96f1e82de5972","impliedFormat":99},{"version":"2c4254139d037c3caca66ce291c1308c1b5092cfcb151eb25980db932dd3b01a","impliedFormat":99},{"version":"970ae00ed018cb96352dc3f37355ef9c2d9f8aa94d7174ccd6d0ed855e462097","impliedFormat":99},{"version":"d2f8dee457ef7660b604226d471d55d927c3051766bdd80353553837492635c3","impliedFormat":99},{"version":"110a503289a2ef76141ffff3ffceb9a1c3662c32748eb9f6777a2bd0866d6fb1","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":99},{"version":"310e6b62c493ce991624169a1c1904015769d947be88dc67e00adc7ebebcfa87","impliedFormat":99},{"version":"62fefda288160bf6e435b21cc03d3fbac11193d8d3bd0e82d86623cca7691c29","impliedFormat":99},{"version":"fcc46a8bcbf9bef21023bba1995160a25f0bc590ca3563ec44c315b4f4c1b18a","impliedFormat":99},{"version":"0309a01650023994ed96edbd675ea4fdc3779a823ce716ad876cc77afb792b62","impliedFormat":99},{"version":"f13d7beeea58e219daef3a40e0dc4f2bd7d9581ac04cedec236102a12dfd2090","impliedFormat":99},{"version":"669573548930fb7d0a0761b827e203dc623581e21febf0be80fb02414f217d74","impliedFormat":99},{"version":"48c411efce1848d1ed55de41d7deb93cbf7c04080912fd87aa517ed25ef42639","affectsGlobalScope":true,"impliedFormat":1},{"version":"a094636c05f3e75cb072684dd42cd25a4c1324bec4a866706c85c04cecd49613","affectsGlobalScope":true,"impliedFormat":99},{"version":"fe2d63fcfdde197391b6b70daf7be8c02a60afa90754a5f4a04bdc367f62793d","impliedFormat":99},{"version":"9a3e2c85ec1ab7a0874a19814cc73c691b716282cb727914093089c5a8475955","impliedFormat":99},{"version":"cbdc781d2429935c9c42acd680f2a53a9f633e8de03290ec6ea818e4f7bff19a","impliedFormat":99},{"version":"9f6d9f5dd710922f82f69abf9a324e28122b5f31ae6f6ce78427716db30a377e","impliedFormat":99},{"version":"ac2414a284bdecfd6ab7b87578744ab056cd04dd574b17853cd76830ef5b72f2","impliedFormat":99},{"version":"c3f921bbc9d2e65bd503a56fbc66da910e68467baedb0b9db0cc939e1876c0d7","impliedFormat":99},{"version":"c30a41267fc04c6518b17e55dcb2b810f267af4314b0b6d7df1c33a76ce1b330","impliedFormat":1},{"version":"72422d0bac4076912385d0c10911b82e4694fc106e2d70added091f88f0824ba","impliedFormat":1},{"version":"da251b82c25bee1d93f9fd80c5a61d945da4f708ca21285541d7aff83ecb8200","impliedFormat":1},{"version":"64db14db2bf37ac089766fdb3c7e1160fabc10e9929bc2deeede7237e4419fc8","impliedFormat":1},{"version":"98b94085c9f78eba36d3d2314affe973e8994f99864b8708122750788825c771","impliedFormat":1},{"version":"0cc99fbb161d78729d71fad66c6c363e3095862d6277160f29fa960744b785c6","affectsGlobalScope":true,"impliedFormat":99},{"version":"a2e86112e3e501ef59dffdf99d65ac80dd56d69d449eb9ab2f044c1fed072185","signature":"3991ccd7beebcb1a08025ad7788e362eb83658ebd5f7baf0544b128f1d625812"},{"version":"061105ca1edc6732569dd3e8edf3611f7b8a1b8495baa1fd699d662f11d9da4a","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"eb5b19b86227ace1d29ea4cf81387279d04bb34051e944bc53df69f58914b788","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"87d9d29dbc745f182683f63187bf3d53fd8673e5fca38ad5eaab69798ed29fbc","impliedFormat":1},{"version":"035312d4945d13efa134ae482f6dc56a1a9346f7ac3be7ccbad5741058ce87f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"17ed71200119e86ccef2d96b73b02ce8854b76ad6bd21b5021d4269bec527b5f","impliedFormat":1}],"root":[231,232],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":99,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":6},"referencedMap":[[232,1],[231,2],[166,2],[112,3],[113,3],[114,4],[66,5],[115,6],[116,7],[117,8],[61,2],[64,9],[62,2],[63,2],[118,10],[119,11],[120,12],[121,13],[122,14],[123,15],[124,15],[125,16],[126,17],[127,18],[128,19],[67,2],[65,2],[129,20],[130,21],[131,22],[165,23],[132,24],[133,2],[134,25],[135,26],[136,27],[137,28],[138,29],[139,30],[140,31],[141,32],[142,33],[143,33],[144,34],[145,2],[146,35],[147,36],[149,37],[148,38],[150,39],[151,40],[152,41],[153,42],[154,43],[155,44],[156,45],[157,46],[158,47],[159,48],[160,49],[161,50],[162,51],[68,2],[69,2],[70,2],[109,52],[110,2],[111,2],[163,53],[164,54],[235,2],[237,55],[233,2],[236,56],[217,2],[218,57],[219,58],[222,59],[221,2],[48,2],[59,60],[54,61],[57,62],[209,63],[198,2],[201,64],[200,65],[212,65],[199,66],[220,2],[56,67],[58,67],[50,68],[53,69],[206,68],[55,70],[49,2],[71,2],[234,2],[173,2],[227,71],[229,72],[228,73],[226,74],[225,2],[190,75],[188,76],[189,77],[177,78],[178,76],[185,79],[176,80],[181,81],[191,2],[182,82],[187,83],[193,84],[192,85],[175,86],[183,87],[184,88],[179,89],[186,75],[180,90],[168,91],[167,92],[174,2],[210,2],[51,2],[52,93],[46,2],[47,2],[8,2],[9,2],[11,2],[10,2],[2,2],[12,2],[13,2],[14,2],[15,2],[16,2],[17,2],[18,2],[19,2],[3,2],[20,2],[21,2],[4,2],[22,2],[26,2],[23,2],[24,2],[25,2],[27,2],[28,2],[29,2],[5,2],[30,2],[31,2],[32,2],[33,2],[6,2],[37,2],[34,2],[35,2],[36,2],[38,2],[7,2],[39,2],[44,2],[45,2],[40,2],[41,2],[42,2],[43,2],[1,2],[87,94],[97,95],[86,94],[107,96],[78,97],[77,98],[106,99],[100,100],[105,101],[80,102],[94,103],[79,104],[103,105],[75,106],[74,99],[104,107],[76,108],[81,109],[82,2],[85,109],[72,2],[108,110],[98,111],[89,112],[90,113],[92,114],[88,115],[91,116],[101,99],[83,117],[84,118],[93,119],[73,120],[96,111],[95,109],[99,2],[102,121],[207,122],[204,123],[205,122],[208,124],[203,2],[197,125],[194,126],[172,127],[170,128],[169,2],[171,129],[195,2],[196,130],[211,131],[202,132],[60,2],[223,133],[213,134],[224,135],[216,136],[215,137],[214,138],[230,139]],"latestChangedDtsFile":"./dist/loader.d.ts","version":"5.9.3"} \ No newline at end of file +{"fileNames":["../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../node_modules/.pnpm/@vitest+pretty-format@2.1.9/node_modules/@vitest/pretty-format/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/types.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/helpers.d.ts","../../../node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/index-c1cfc5e9.d.ts","../../../node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/node.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/tasks-3znpj1lr.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/types-bxe-2udy.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/diff.d.ts","../../../node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/types.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/error.d.ts","../../../node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/environment.looobwuu.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/compatibility/disposable.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/compatibility/indexable.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/compatibility/iterators.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/compatibility/index.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/globals.typedarray.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/buffer.buffer.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/globals.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/abortcontroller.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/domexception.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/events.d.ts","../../../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/header.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/readable.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/file.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/fetch.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/formdata.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/connector.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/client.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/errors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/dispatcher.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/global-dispatcher.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/global-origin.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/pool-stats.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/handlers.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/balanced-pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-interceptor.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-client.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-errors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/env-http-proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/retry-handler.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/retry-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/api.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/interceptors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/util.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/cookies.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/patch.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/websocket.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/eventsource.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/filereader.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/diagnostics-channel.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/content-type.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/cache.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/index.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/fetch.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/navigator.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/web-globals/storage.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/assert.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/assert/strict.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/async_hooks.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/buffer.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/child_process.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/cluster.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/console.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/constants.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/crypto.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/dgram.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/dns.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/dns/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/domain.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/events.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/fs.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/fs/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/http.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/http2.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/https.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/inspector.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/inspector.generated.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/module.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/net.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/os.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/path.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/process.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/punycode.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/querystring.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/readline.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/readline/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/repl.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/sea.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/sqlite.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/stream.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/stream/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/stream/web.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/string_decoder.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/test.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/timers.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/timers/promises.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/tls.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/trace_events.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/tty.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/url.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/util.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/v8.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/vm.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/wasi.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/worker_threads.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/zlib.d.ts","../../../node_modules/.pnpm/@types+node@22.19.17/node_modules/@types/node/index.d.ts","../../../node_modules/.pnpm/@types+estree@1.0.8/node_modules/@types/estree/index.d.ts","../../../node_modules/.pnpm/rollup@4.60.2/node_modules/rollup/dist/rollup.d.ts","../../../node_modules/.pnpm/rollup@4.60.2/node_modules/rollup/dist/parseast.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/types/hmrpayload.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/types/customevent.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/types/hot.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/dist/node/types.d-agj9qkwt.d.ts","../../../node_modules/.pnpm/esbuild@0.21.5/node_modules/esbuild/lib/main.d.ts","../../../node_modules/.pnpm/source-map-js@1.2.1/node_modules/source-map-js/source-map.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/previous-map.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/input.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/css-syntax-error.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/declaration.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/root.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/warning.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/lazy-result.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/no-work-result.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/processor.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/result.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/document.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/rule.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/node.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/comment.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/container.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/at-rule.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/list.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/postcss.d.ts","../../../node_modules/.pnpm/postcss@8.5.10/node_modules/postcss/lib/postcss.d.mts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/dist/node/runtime.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/types/importglob.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/types/metadata.d.ts","../../../node_modules/.pnpm/vite@5.4.21_@types+node@22.19.17/node_modules/vite/dist/node/index.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@2.1.9/node_modules/@vitest/snapshot/dist/environment-ddx0edty.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@2.1.9/node_modules/@vitest/snapshot/dist/rawsnapshot-cpnkto81.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@2.1.9/node_modules/@vitest/snapshot/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@2.1.9/node_modules/@vitest/snapshot/dist/environment.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/config.cy0c388z.d.ts","../../../node_modules/.pnpm/vite-node@2.1.9_@types+node@22.19.17/node_modules/vite-node/dist/trace-mapping.d-dlvdeqop.d.ts","../../../node_modules/.pnpm/vite-node@2.1.9_@types+node@22.19.17/node_modules/vite-node/dist/index-z0r8hvru.d.ts","../../../node_modules/.pnpm/vite-node@2.1.9_@types+node@22.19.17/node_modules/vite-node/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+utils@2.1.9/node_modules/@vitest/utils/dist/source-map.d.ts","../../../node_modules/.pnpm/vite-node@2.1.9_@types+node@22.19.17/node_modules/vite-node/dist/client.d.ts","../../../node_modules/.pnpm/vite-node@2.1.9_@types+node@22.19.17/node_modules/vite-node/dist/server.d.ts","../../../node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/utils.d.ts","../../../node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/benchmark.geerunq4.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@2.1.9/node_modules/@vitest/snapshot/dist/manager.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/reporters.nr4dxcka.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/worker.tn5kgiih.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/worker.b9fxpcac.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/vite.czkp4x9w.d.ts","../../../node_modules/.pnpm/@vitest+expect@2.1.9/node_modules/@vitest/expect/dist/chai.d.cts","../../../node_modules/.pnpm/@vitest+expect@2.1.9/node_modules/@vitest/expect/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+expect@2.1.9/node_modules/@vitest/expect/index.d.ts","../../../node_modules/.pnpm/@vitest+spy@2.1.9/node_modules/@vitest/spy/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+mocker@2.1.9_vite@5.4.21_@types+node@22.19.17_/node_modules/@vitest/mocker/dist/types-dzoqtgin.d.ts","../../../node_modules/.pnpm/@vitest+mocker@2.1.9_vite@5.4.21_@types+node@22.19.17_/node_modules/@vitest/mocker/dist/index.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/mocker.crtm890j.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/chunks/suite.b2jumifp.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.d.ts","../../../node_modules/.pnpm/vitest@2.1.9_@types+node@22.19.17_jsdom@25.0.1/node_modules/vitest/dist/index.d.ts","./src/loader.ts","./src/loader.test.ts","../../../node_modules/.pnpm/@types+react@18.3.28/node_modules/@types/react/global.d.ts","../../../node_modules/.pnpm/csstype@3.2.3/node_modules/csstype/index.d.ts","../../../node_modules/.pnpm/@types+prop-types@15.7.15/node_modules/@types/prop-types/index.d.ts","../../../node_modules/.pnpm/@types+react@18.3.28/node_modules/@types/react/index.d.ts","../../../node_modules/.pnpm/@types+react-dom@18.3.7_@types+react@18.3.28/node_modules/@types/react-dom/index.d.ts"],"fileIdsList":[[66,115,132,133,230,231],[66,115,132,133],[66,112,113,115,132,133],[66,114,115,132,133],[115,132,133],[66,115,120,132,133,150],[66,115,116,121,126,132,133,135,147,158],[66,115,116,117,126,132,133,135],[61,62,63,66,115,132,133],[66,115,118,132,133,159],[66,115,119,120,127,132,133,136],[66,115,120,132,133,147,155],[66,115,121,123,126,132,133,135],[66,114,115,122,132,133],[66,115,123,124,132,133],[66,115,125,126,132,133],[66,114,115,126,132,133],[66,115,126,127,128,132,133,147,158],[66,115,126,127,128,132,133,142,147,150],[66,108,115,123,126,129,132,133,135,147,158],[66,115,126,127,129,130,132,133,135,147,155,158],[66,115,129,131,132,133,147,155,158],[64,65,66,67,68,69,70,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164],[66,115,126,132,133],[66,115,132,133,134,158],[66,115,123,126,132,133,135,147],[66,115,132,133,136],[66,115,132,133,137],[66,114,115,132,133,138],[66,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164],[66,115,132,133,140],[66,115,132,133,141],[66,115,126,132,133,142,143],[66,115,132,133,142,144,159,161],[66,115,127,132,133],[66,115,126,132,133,147,148,150],[66,115,132,133,149,150],[66,115,132,133,147,148],[66,115,132,133,150],[66,115,132,133,151],[66,112,115,132,133,147,152,158],[66,115,126,132,133,153,154],[66,115,132,133,153,154],[66,115,120,132,133,135,147,155],[66,115,132,133,156],[66,115,132,133,135,157],[66,115,129,132,133,141,158],[66,115,120,132,133,159],[66,115,132,133,147,160],[66,115,132,133,134,161],[66,115,132,133,162],[66,108,115,132,133],[66,108,115,126,128,132,133,138,147,150,158,160,161,163],[66,115,132,133,147,164],[66,115,132,133,236],[66,115,132,133,233,234,235],[52,53,56,66,115,132,133],[66,115,132,133,218],[66,115,132,133,221],[53,54,56,57,58,66,115,132,133],[53,66,115,132,133],[53,54,56,66,115,132,133],[53,54,66,115,132,133],[66,115,132,133,198],[48,66,115,132,133,198,199],[48,66,115,132,133,198],[48,55,66,115,132,133],[49,66,115,132,133],[48,49,50,52,66,115,132,133],[48,66,115,132,133],[66,115,132,133,225,226],[66,115,132,133,225,226,227,228],[66,115,132,133,225,227],[66,115,132,133,225],[66,115,132,133,189],[66,115,132,133,187,189],[66,115,132,133,178,186,187,188,190,192],[66,115,132,133,176],[66,115,132,133,179,184,189,192],[66,115,132,133,175,192],[66,115,132,133,179,180,183,184,185,192],[66,115,132,133,179,180,181,183,184,192],[66,115,132,133,176,177,178,179,180,184,185,186,188,189,190,192],[66,115,132,133,192],[66,115,132,133,174,176,177,178,179,180,181,183,184,185,186,187,188,189,190,191],[66,115,132,133,174,192],[66,115,132,133,179,181,182,184,185,192],[66,115,132,133,183,192],[66,115,132,133,184,185,189,192],[66,115,132,133,177,187],[66,115,132,133,167,196],[66,115,132,133,166,167],[51,66,115,132,133],[66,80,84,115,132,133,158],[66,80,115,132,133,147,158],[66,75,115,132,133],[66,77,80,115,132,133,155,158],[66,115,132,133,135,155],[66,115,132,133,165],[66,75,115,132,133,165],[66,77,80,115,132,133,135,158],[66,72,73,76,79,115,126,132,133,147,158],[66,80,87,115,132,133],[66,72,78,115,132,133],[66,80,101,102,115,132,133],[66,76,80,115,132,133,150,158,165],[66,101,115,132,133,165],[66,74,75,115,132,133,165],[66,80,115,132,133],[66,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,102,103,104,105,106,107,115,132,133],[66,80,95,115,132,133],[66,80,87,88,115,132,133],[66,78,80,88,89,115,132,133],[66,79,115,132,133],[66,72,75,80,115,132,133],[66,80,84,88,89,115,132,133],[66,84,115,132,133],[66,78,80,83,115,132,133,158],[66,72,77,80,87,115,132,133],[66,115,132,133,147],[66,75,80,101,115,132,133,163,165],[66,115,132,133,203,204],[66,115,132,133,203],[66,115,132,133,197,203,204,216],[66,115,126,127,129,130,131,132,133,135,147,155,158,164,165,167,168,169,170,171,172,173,193,194,195,196],[66,115,132,133,169,170,171,172],[66,115,132,133,169,170,171],[66,115,132,133,169],[66,115,132,133,170],[66,115,132,133,167],[59,66,115,132,133,209,210,230],[48,59,66,115,132,133,200,201,230],[66,115,132,133,222],[48,53,59,60,66,115,127,132,133,147,197,200,202,205,206,207,208,211,212,216,217,230],[59,66,115,132,133,209,210,211,230],[66,115,132,133,197,213],[66,115,132,133,163,214],[59,60,66,115,132,133,200,202,205,230],[48,53,56,59,60,66,115,127,132,133,147,163,197,200,201,202,205,206,207,208,209,210,211,212,213,214,215,216,217,219,220,222,223,224,229,230]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"d2e64a6f25013b099e83bfadb2c388d7bef3e8f3fdb25528225bbc841e7e7e3a","impliedFormat":99},{"version":"369ba5259e66ca8c7d35e3234f7a2a0863a770fdb8266505747c65cf346a0804","impliedFormat":99},{"version":"64d984f55025daf604f670b7dfd090ea765f2098aee871174ef2ee3e94479098","impliedFormat":99},{"version":"f147b6710441cf3ec3234adf63b0593ce5e8c9b692959d21d3babc8454bcf743","impliedFormat":99},{"version":"e96d5373a66c2cfbbc7e6642cf274055aa2c7ff6bd37be7480c66faf9804db6d","impliedFormat":99},{"version":"02bcdd7a76c5c1c485cbf05626d24c86ac8f9a1d8dc31f8924108bbaa4cf3ba9","impliedFormat":99},{"version":"c874ab6feac6e0fdf9142727c9a876065777a5392f14b0bbcf869b1e69eb46b5","impliedFormat":99},{"version":"7c553fc9e34773ddbaabe0fa1367d4b109101d0868a008f11042bee24b5a925d","impliedFormat":99},{"version":"9962ce696fbdce2421d883ca4b062a54f982496625437ae4d3633376c5ad4a80","impliedFormat":99},{"version":"e3ea467c4a7f743f3548c9ed61300591965b1d12c08c8bb9aaff8a002ba95fce","impliedFormat":99},{"version":"4c17183a07a63bea2653fbfc0a942b027160ddbee823024789a415f9589de327","impliedFormat":99},{"version":"3e2203c892297ea44b87470fde51b3d48cfe3eeb6901995de429539462894464","impliedFormat":99},{"version":"c84bf7a4abc5e7fdf45971a71b25b0e0d34ccd5e720a866dd78bb71d60d41a3f","impliedFormat":99},{"version":"6c7176368037af28cb72f2392010fa1cef295d6d6744bca8cfb54985f3a18c3e","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"437e20f2ba32abaeb7985e0afe0002de1917bc74e949ba585e49feba65da6ca1","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"3af97acf03cc97de58a3a4bc91f8f616408099bc4233f6d0852e72a8ffb91ac9","affectsGlobalScope":true,"impliedFormat":1},{"version":"808069bba06b6768b62fd22429b53362e7af342da4a236ed2d2e1c89fcca3b4a","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"4967529644e391115ca5592184d4b63980569adf60ee685f968fd59ab1557188","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"f9501cc13ce624c72b61f12b3963e84fad210fbdf0ffbc4590e08460a3f04eba","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0fa06ada475b910e2106c98c68b10483dc8811d0c14a8a8dd36efb2672485b29","impliedFormat":1},{"version":"33e5e9aba62c3193d10d1d33ae1fa75c46a1171cf76fef750777377d53b0303f","impliedFormat":1},{"version":"2b06b93fd01bcd49d1a6bd1f9b65ddcae6480b9a86e9061634d6f8e354c1468f","impliedFormat":1},{"version":"6a0cd27e5dc2cfbe039e731cf879d12b0e2dded06d1b1dedad07f7712de0d7f4","affectsGlobalScope":true,"impliedFormat":1},{"version":"13f5c844119c43e51ce777c509267f14d6aaf31eafb2c2b002ca35584cd13b29","impliedFormat":1},{"version":"e60477649d6ad21542bd2dc7e3d9ff6853d0797ba9f689ba2f6653818999c264","impliedFormat":1},{"version":"c2510f124c0293ab80b1777c44d80f812b75612f297b9857406468c0f4dafe29","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"4c829ab315f57c5442c6667b53769975acbf92003a66aef19bce151987675bd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"b2ade7657e2db96d18315694789eff2ddd3d8aea7215b181f8a0b303277cc579","impliedFormat":1},{"version":"9855e02d837744303391e5623a531734443a5f8e6e8755e018c41d63ad797db2","impliedFormat":1},{"version":"4d631b81fa2f07a0e63a9a143d6a82c25c5f051298651a9b69176ba28930756d","impliedFormat":1},{"version":"836a356aae992ff3c28a0212e3eabcb76dd4b0cc06bcb9607aeef560661b860d","impliedFormat":1},{"version":"1e0d1f8b0adfa0b0330e028c7941b5a98c08b600efe7f14d2d2a00854fb2f393","impliedFormat":1},{"version":"41670ee38943d9cbb4924e436f56fc19ee94232bc96108562de1a734af20dc2c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c906fb15bd2aabc9ed1e3f44eb6a8661199d6c320b3aa196b826121552cb3695","impliedFormat":1},{"version":"22295e8103f1d6d8ea4b5d6211e43421fe4564e34d0dd8e09e520e452d89e659","impliedFormat":1},{"version":"58647d85d0f722a1ce9de50955df60a7489f0593bf1a7015521efe901c06d770","impliedFormat":1},{"version":"6b4e081d55ac24fc8a4631d5dd77fe249fa25900abd7d046abb87d90e3b45645","impliedFormat":1},{"version":"a10f0e1854f3316d7ee437b79649e5a6ae3ae14ffe6322b02d4987071a95362e","impliedFormat":1},{"version":"e208f73ef6a980104304b0d2ca5f6bf1b85de6009d2c7e404028b875020fa8f2","impliedFormat":1},{"version":"d163b6bc2372b4f07260747cbc6c0a6405ab3fbcea3852305e98ac43ca59f5bc","impliedFormat":1},{"version":"e6fa9ad47c5f71ff733744a029d1dc472c618de53804eae08ffc243b936f87ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"a6f137d651076822d4fe884287e68fd61785a0d3d1fdb250a5059b691fa897db","impliedFormat":1},{"version":"24826ed94a78d5c64bd857570fdbd96229ad41b5cb654c08d75a9845e3ab7dde","impliedFormat":1},{"version":"8b479a130ccb62e98f11f136d3ac80f2984fdc07616516d29881f3061f2dd472","impliedFormat":1},{"version":"928af3d90454bf656a52a48679f199f64c1435247d6189d1caf4c68f2eaf921f","affectsGlobalScope":true,"impliedFormat":1},{"version":"bceb58df66ab8fb00170df20cd813978c5ab84be1d285710c4eb005d8e9d8efb","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f16a7e4deafa527ed9995a772bb380eb7d3c2c0fd4ae178c5263ed18394db2c","impliedFormat":1},{"version":"933921f0bb0ec12ef45d1062a1fc0f27635318f4d294e4d99de9a5493e618ca2","impliedFormat":1},{"version":"71a0f3ad612c123b57239a7749770017ecfe6b66411488000aba83e4546fde25","impliedFormat":1},{"version":"77fbe5eecb6fac4b6242bbf6eebfc43e98ce5ccba8fa44e0ef6a95c945ff4d98","impliedFormat":1},{"version":"4f9d8ca0c417b67b69eeb54c7ca1bedd7b56034bb9bfd27c5d4f3bc4692daca7","impliedFormat":1},{"version":"814118df420c4e38fe5ae1b9a3bafb6e9c2aa40838e528cde908381867be6466","impliedFormat":1},{"version":"a3fc63c0d7b031693f665f5494412ba4b551fe644ededccc0ab5922401079c95","impliedFormat":1},{"version":"80523c00b8544a2000ae0143e4a90a00b47f99823eb7926c1e03c494216fc363","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"746911b62b329587939560deb5c036aca48aece03147b021fa680223255d5183","affectsGlobalScope":true,"impliedFormat":1},{"version":"18fd40412d102c5564136f29735e5d1c3b455b8a37f920da79561f1fde068208","impliedFormat":1},{"version":"c8d3e5a18ba35629954e48c4cc8f11dc88224650067a172685c736b27a34a4dc","impliedFormat":1},{"version":"f0be1b8078cd549d91f37c30c222c2a187ac1cf981d994fb476a1adc61387b14","affectsGlobalScope":true,"impliedFormat":1},{"version":"0aaed1d72199b01234152f7a60046bc947f1f37d78d182e9ae09c4289e06a592","impliedFormat":1},{"version":"2b55d426ff2b9087485e52ac4bc7cfafe1dc420fc76dad926cd46526567c501a","impliedFormat":1},{"version":"66ba1b2c3e3a3644a1011cd530fb444a96b1b2dfe2f5e837a002d41a1a799e60","impliedFormat":1},{"version":"7e514f5b852fdbc166b539fdd1f4e9114f29911592a5eb10a94bb3a13ccac3c4","impliedFormat":1},{"version":"5b7aa3c4c1a5d81b411e8cb302b45507fea9358d3569196b27eb1a27ae3a90ef","affectsGlobalScope":true,"impliedFormat":1},{"version":"5987a903da92c7462e0b35704ce7da94d7fdc4b89a984871c0e2b87a8aae9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"ea08a0345023ade2b47fbff5a76d0d0ed8bff10bc9d22b83f40858a8e941501c","impliedFormat":1},{"version":"47613031a5a31510831304405af561b0ffaedb734437c595256bb61a90f9311b","impliedFormat":1},{"version":"ae062ce7d9510060c5d7e7952ae379224fb3f8f2dd74e88959878af2057c143b","impliedFormat":1},{"version":"8a1a0d0a4a06a8d278947fcb66bf684f117bf147f89b06e50662d79a53be3e9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"358765d5ea8afd285d4fd1532e78b88273f18cb3f87403a9b16fef61ac9fdcfe","impliedFormat":1},{"version":"9f55299850d4f0921e79b6bf344b47c420ce0f507b9dcf593e532b09ea7eeea1","impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"ee70b8037ecdf0de6c04f35277f253663a536d7e38f1539d270e4e916d225a3f","affectsGlobalScope":true,"impliedFormat":1},{"version":"a660aa95476042d3fdcc1343cf6bb8fdf24772d31712b1db321c5a4dcc325434","impliedFormat":1},{"version":"282f98006ed7fa9bb2cd9bdbe2524595cfc4bcd58a0bb3232e4519f2138df811","impliedFormat":1},{"version":"6222e987b58abfe92597e1273ad7233626285bc2d78409d4a7b113d81a83496b","impliedFormat":1},{"version":"cbe726263ae9a7bf32352380f7e8ab66ee25b3457137e316929269c19e18a2be","impliedFormat":1},{"version":"8b96046bf5fb0a815cba6b0880d9f97b7f3a93cf187e8dcfe8e2792e97f38f87","impliedFormat":99},{"version":"bacf2c84cf448b2cd02c717ad46c3d7fd530e0c91282888c923ad64810a4d511","affectsGlobalScope":true,"impliedFormat":1},{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","impliedFormat":1},{"version":"52dcc257df5119fb66d864625112ce5033ac51a4c2afe376a0b299d2f7f76e4a","impliedFormat":1},{"version":"e5bab5f871ef708d52d47b3e5d0aa72a08ee7a152f33931d9a60809711a2a9a3","impliedFormat":1},{"version":"e16dc2a81595736024a206c7d5c8a39bfe2e6039208ef29981d0d95434ba8fcf","impliedFormat":1},{"version":"cc4a4903fb698ca1d961d4c10dce658aa3a479faf40509d526f122b044eaf6a4","impliedFormat":1},{"version":"19ee8416e6473ed6c7adb868fa796b5653cf0fa2a337658e677eaa0d134388c3","impliedFormat":1},{"version":"1328ab4e442614b28cdb3d4b414cf68325c0da0dca07287a338d0654b7a00261","impliedFormat":1},{"version":"a039dc21f045919f3cbee2ec13812cc6cc3eebc99dae4be00973230f468d19a6","impliedFormat":1},{"version":"3fbe57af01460e49dcd29df55d6931e1672bc6f1be0fb073d11410bc16f9037d","impliedFormat":1},{"version":"f760be449e8562ec5c09bb5187e8e1eabf3c113c0c58cddda53ef8c69f3e2131","impliedFormat":1},{"version":"44325ed13294fce6ab825b82947bbeed2611db7dad9d9135260192f375e5a189","impliedFormat":1},{"version":"e392e8fb5b514eafc585601c1d781485aa6dd6a320e75daf1064a4c6918a1b45","impliedFormat":1},{"version":"46e4a36e8ddbdfb4e7330e11c81c970dc8b218611df9183d39c41c5f8c653b55","impliedFormat":1},{"version":"370bde134aa8c2abc926d0e99d3a4d5d5dba65c6ee65459137e4f02670cbf841","impliedFormat":1},{"version":"6332f565867cf4a740a70e30f31cefba37ef7cebcf74f22eab8d744fde6d193e","impliedFormat":1},{"version":"2977b7884aedc895a1d0c9c210c7cf3272c29d6959a08a6fa3ff71e0aff08175","impliedFormat":1},{"version":"17f2922d41ddd032830a91371c948cd9ce903b35c95adca72271a54584f19b0b","impliedFormat":1},{"version":"3eed76ede2a1a14d7c9bb0a642041282dcc264811139d3dd275c9fe14efc9840","impliedFormat":1},{"version":"00cf4001e0d9c6e5e036bc545b9d73e2b8b84cddb02e61ad05bab3752b1d4522","impliedFormat":1},{"version":"8d369483f0c2b9ee388129cfdb6a43bc8112b377e86a41884bd06e19ce04f4c1","impliedFormat":99},{"version":"82e687ebd99518bc63ea04b0c3810fb6e50aa6942decd0ca6f7a56d9b9a212a6","impliedFormat":99},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","impliedFormat":1},{"version":"8f07f2b6514744ac96e51d7cb8518c0f4de319471237ea10cf688b8d0e9d0225","impliedFormat":1},{"version":"257b83faa134d971c738a6b9e4c47e59bb7b23274719d92197580dd662bfafc3","impliedFormat":99},{"version":"e01ea380015ed698c3c0e2ccd0db72f3fc3ef1abc4519f122aa1c1a8d419a505","impliedFormat":99},{"version":"5ada1f8a9580c0f7478fe03ae3e07e958f0b79bdfb9dd50eeb98c1324f40011b","impliedFormat":99},{"version":"a8301dc90b4bd9fba333226ee0f1681aeeff1bd90233a8f647e687cb4b7d3521","impliedFormat":99},{"version":"e3225dc0bec183183509d290f641786245e6652bc3dce755f7ef404060693c35","impliedFormat":99},{"version":"09a03870ed8c55d7453bc9ad684df88965f2f770f987481ca71b8a09be5205bc","impliedFormat":99},{"version":"e6233e1c976265e85aa8ad76c3881febe6264cb06ae3136f0257e1eab4a6cc5a","impliedFormat":99},{"version":"2cdd50ddc49e2d608ee848fc4ab0db9a2716624fabb4209c7c683d87e54d79c5","impliedFormat":99},{"version":"e431d664338b8470abb1750d699c7dfcebb1a25434559ef85bb96f1e82de5972","impliedFormat":99},{"version":"2c4254139d037c3caca66ce291c1308c1b5092cfcb151eb25980db932dd3b01a","impliedFormat":99},{"version":"970ae00ed018cb96352dc3f37355ef9c2d9f8aa94d7174ccd6d0ed855e462097","impliedFormat":99},{"version":"d2f8dee457ef7660b604226d471d55d927c3051766bdd80353553837492635c3","impliedFormat":99},{"version":"110a503289a2ef76141ffff3ffceb9a1c3662c32748eb9f6777a2bd0866d6fb1","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":99},{"version":"310e6b62c493ce991624169a1c1904015769d947be88dc67e00adc7ebebcfa87","impliedFormat":99},{"version":"62fefda288160bf6e435b21cc03d3fbac11193d8d3bd0e82d86623cca7691c29","impliedFormat":99},{"version":"fcc46a8bcbf9bef21023bba1995160a25f0bc590ca3563ec44c315b4f4c1b18a","impliedFormat":99},{"version":"0309a01650023994ed96edbd675ea4fdc3779a823ce716ad876cc77afb792b62","impliedFormat":99},{"version":"f13d7beeea58e219daef3a40e0dc4f2bd7d9581ac04cedec236102a12dfd2090","impliedFormat":99},{"version":"669573548930fb7d0a0761b827e203dc623581e21febf0be80fb02414f217d74","impliedFormat":99},{"version":"48c411efce1848d1ed55de41d7deb93cbf7c04080912fd87aa517ed25ef42639","affectsGlobalScope":true,"impliedFormat":1},{"version":"a094636c05f3e75cb072684dd42cd25a4c1324bec4a866706c85c04cecd49613","affectsGlobalScope":true,"impliedFormat":99},{"version":"fe2d63fcfdde197391b6b70daf7be8c02a60afa90754a5f4a04bdc367f62793d","impliedFormat":99},{"version":"9a3e2c85ec1ab7a0874a19814cc73c691b716282cb727914093089c5a8475955","impliedFormat":99},{"version":"cbdc781d2429935c9c42acd680f2a53a9f633e8de03290ec6ea818e4f7bff19a","impliedFormat":99},{"version":"9f6d9f5dd710922f82f69abf9a324e28122b5f31ae6f6ce78427716db30a377e","impliedFormat":99},{"version":"ac2414a284bdecfd6ab7b87578744ab056cd04dd574b17853cd76830ef5b72f2","impliedFormat":99},{"version":"c3f921bbc9d2e65bd503a56fbc66da910e68467baedb0b9db0cc939e1876c0d7","impliedFormat":99},{"version":"c30a41267fc04c6518b17e55dcb2b810f267af4314b0b6d7df1c33a76ce1b330","impliedFormat":1},{"version":"72422d0bac4076912385d0c10911b82e4694fc106e2d70added091f88f0824ba","impliedFormat":1},{"version":"da251b82c25bee1d93f9fd80c5a61d945da4f708ca21285541d7aff83ecb8200","impliedFormat":1},{"version":"64db14db2bf37ac089766fdb3c7e1160fabc10e9929bc2deeede7237e4419fc8","impliedFormat":1},{"version":"98b94085c9f78eba36d3d2314affe973e8994f99864b8708122750788825c771","impliedFormat":1},{"version":"0cc99fbb161d78729d71fad66c6c363e3095862d6277160f29fa960744b785c6","affectsGlobalScope":true,"impliedFormat":99},{"version":"cf7ba2ce6c7f2c24b273c412fa1ca3aaaa680b007224ed037121d396b2627580","signature":"4ad21336942db591f6dc4fcc3768829bc4fb2b1727265947c96e7a6446945106"},{"version":"850ffc2ae5e969f4262328ad587259e1ad27db917b0a6566e7a98b1be799b383","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"eb5b19b86227ace1d29ea4cf81387279d04bb34051e944bc53df69f58914b788","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"87d9d29dbc745f182683f63187bf3d53fd8673e5fca38ad5eaab69798ed29fbc","impliedFormat":1},{"version":"035312d4945d13efa134ae482f6dc56a1a9346f7ac3be7ccbad5741058ce87f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"17ed71200119e86ccef2d96b73b02ce8854b76ad6bd21b5021d4269bec527b5f","impliedFormat":1}],"root":[231,232],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":99,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":6},"referencedMap":[[232,1],[231,2],[166,2],[112,3],[113,3],[114,4],[66,5],[115,6],[116,7],[117,8],[61,2],[64,9],[62,2],[63,2],[118,10],[119,11],[120,12],[121,13],[122,14],[123,15],[124,15],[125,16],[126,17],[127,18],[128,19],[67,2],[65,2],[129,20],[130,21],[131,22],[165,23],[132,24],[133,2],[134,25],[135,26],[136,27],[137,28],[138,29],[139,30],[140,31],[141,32],[142,33],[143,33],[144,34],[145,2],[146,35],[147,36],[149,37],[148,38],[150,39],[151,40],[152,41],[153,42],[154,43],[155,44],[156,45],[157,46],[158,47],[159,48],[160,49],[161,50],[162,51],[68,2],[69,2],[70,2],[109,52],[110,2],[111,2],[163,53],[164,54],[235,2],[237,55],[233,2],[236,56],[217,2],[218,57],[219,58],[222,59],[221,2],[48,2],[59,60],[54,61],[57,62],[209,63],[198,2],[201,64],[200,65],[212,65],[199,66],[220,2],[56,67],[58,67],[50,68],[53,69],[206,68],[55,70],[49,2],[71,2],[234,2],[173,2],[227,71],[229,72],[228,73],[226,74],[225,2],[190,75],[188,76],[189,77],[177,78],[178,76],[185,79],[176,80],[181,81],[191,2],[182,82],[187,83],[193,84],[192,85],[175,86],[183,87],[184,88],[179,89],[186,75],[180,90],[168,91],[167,92],[174,2],[210,2],[51,2],[52,93],[46,2],[47,2],[8,2],[9,2],[11,2],[10,2],[2,2],[12,2],[13,2],[14,2],[15,2],[16,2],[17,2],[18,2],[19,2],[3,2],[20,2],[21,2],[4,2],[22,2],[26,2],[23,2],[24,2],[25,2],[27,2],[28,2],[29,2],[5,2],[30,2],[31,2],[32,2],[33,2],[6,2],[37,2],[34,2],[35,2],[36,2],[38,2],[7,2],[39,2],[44,2],[45,2],[40,2],[41,2],[42,2],[43,2],[1,2],[87,94],[97,95],[86,94],[107,96],[78,97],[77,98],[106,99],[100,100],[105,101],[80,102],[94,103],[79,104],[103,105],[75,106],[74,99],[104,107],[76,108],[81,109],[82,2],[85,109],[72,2],[108,110],[98,111],[89,112],[90,113],[92,114],[88,115],[91,116],[101,99],[83,117],[84,118],[93,119],[73,120],[96,111],[95,109],[99,2],[102,121],[207,122],[204,123],[205,122],[208,124],[203,2],[197,125],[194,126],[172,127],[170,128],[169,2],[171,129],[195,2],[196,130],[211,131],[202,132],[60,2],[223,133],[213,134],[224,135],[216,136],[215,137],[214,138],[230,139]],"latestChangedDtsFile":"./dist/loader.d.ts","version":"5.9.3"} \ No newline at end of file diff --git a/demo/host.html b/demo/host.html index bd89f6a..93db360 100644 --- a/demo/host.html +++ b/demo/host.html @@ -3,7 +3,7 @@ - Host Page Simulation + AI Support Engineer · test host
-

Host Page Simulation

+ SDK · test host +

AI Support Engineer

- This page simulates a real product embedding the AI Support widget. - In production, the <script> tag below lives inside - the app, here it's inline so we can smoke test the widget E2E. + This is a minimal, neutral host page used to verify the chat widget + loads and the agent pipeline works end-to-end. Real product + integrations live in their own repos and pass their own + data-product + data-suggestions when + embedding the loader.

-
- Session dashboard at - http://localhost:5174. + +
+

What you should see

+
    +
  • Chat avatar in the bottom-right of this page
  • +
  • + Click it → a session opens against + http://localhost:8080 +
  • +
  • + Send any message → the pipeline streams phase events and returns + a response +
  • +
  • + Visit the dashboard at + http://localhost:5174 to replay sessions +
  • +
+
+ +
+

Embedding in your own product

+

+ Drop one <script> tag into the host page. + Suggestions are optional — leave the attribute off and the empty + state shows just the welcome. +

+
<script
+  src="https://api.your-deployment/widget/loader.js"
+  data-api-base="https://api.your-deployment"
+  data-product="your-product-slug"
+  data-suggestions='[
+    {"label":"Common question A","query":"how do I do X?"},
+    {"label":"Common question B","query":"why is Y not working?"}
+  ]'
+></script>
- + diff --git a/fixtures/mock-responses/basket-push-empty.json b/fixtures/mock-responses/basket-push-empty.json deleted file mode 100644 index fabe5ba..0000000 --- a/fixtures/mock-responses/basket-push-empty.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "slug": "basket-push-empty", - "keywords": [ - "basket is empty", - "nothing in basket", - "empty basket", - "pushed but empty", - "tesco is empty", - "asda is empty", - "basket push", - "items not in tesco", - "nothing there" - ], - "router": { - "escalate": true, - "rationale": "Docs describe the symptom but the 'push succeeds with 200 but drops items' behavior is a specific bug we've located in the retailer client code.", - "confidence": "high" - }, - "codeInvestigation": { - "rootCause": "The retailer push client in src/retailers/tesco.ts treats any 2xx response as a success, but Tesco's API returns HTTP 200 with an empty body when the session cookie has expired. Items are silently dropped. ASDA exhibits the same pattern.", - "affectedFiles": [ - "src/retailers/tesco.ts", - "src/retailers/asda.ts", - "src/retailers/sessionStatus.ts" - ], - "workaround": "Go to Settings → Supermarkets and click Reconnect on the retailer, then re-run the push. The new session will populate the basket correctly.", - "confidence": "high" - }, - "resolution": { - "explanation": "This is a bug in how we handle expired retailer sessions during basket push. Tesco and ASDA's APIs return HTTP 200 with an empty response body when the session cookie has expired, but our code treats any 2xx status as a successful push and discards the items. The fix is to detect the empty-items response and surface it as an expired-session error instead of a silent success.", - "workaround": "Open Settings → Supermarkets, click Reconnect next to Tesco or ASDA, and run the push again. The basket should populate within a few seconds.", - "confidence": "high", - "citations": [ - "known-issues.md", - "troubleshooting.md", - "accounts-and-auth.md" - ] - }, - "ticket": { - "title": "Retailer: treat 200-with-empty-body as expired session, not success", - "body": "**Problem**\nUsers report that pushing a basket to Tesco or ASDA shows a success toast in SnapBasket, but the retailer site is empty when they switch to complete checkout.\n\n**Root cause**\n`src/retailers/tesco.ts` and `src/retailers/asda.ts` treat any 2xx response as a successful push. Both retailers return HTTP 200 with an empty body when the session cookie has expired, so items are silently dropped.\n\n**Suggested fix**\n1. In the retailer clients, check the response body for an `items: []` (or equivalently empty payload) and treat that as a session-expired signal.\n2. Route that signal through `sessionStatus.ts` so the UI surfaces the 'Reconnect ' banner and the push is aborted before the success toast.\n3. Add integration tests for both retailers that mock a 200-empty response and assert an expired-session error is raised.\n\n**Affected files**\n- src/retailers/tesco.ts\n- src/retailers/asda.ts\n- src/retailers/sessionStatus.ts\n\n**Severity**: high — silent data loss from the user's perspective." - }, - "pr": { - "branch": "fix/retailer-expired-session-detection", - "title": "fix(retailers): detect expired session on 200-empty response", - "summary": "Tesco and ASDA return HTTP 200 with an empty body on expired session cookies; previously we treated that as a successful push. This PR checks the response body and raises an ExpiredSessionError, which propagates to the UI as a 'Reconnect' banner." - } -} diff --git a/fixtures/mock-responses/heic-rotation.json b/fixtures/mock-responses/heic-rotation.json deleted file mode 100644 index 6405ead..0000000 --- a/fixtures/mock-responses/heic-rotation.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "slug": "heic-rotation", - "keywords": [ - "rotated", - "rotation", - "sideways", - "upside down", - "heic", - "iphone photo", - "photo is rotated" - ], - "router": { - "escalate": false, - "rationale": "Docs describe this known behavior and a clear workaround; no code investigation needed.", - "confidence": "high", - "draftAnswer": "Rotated iPhone photos are a known HEIC → JPEG conversion issue. The simplest fix is to rotate the photo on your phone before uploading, or export it as PNG from the Photos app. A permanent fix to preserve EXIF orientation is in progress." - }, - "resolution": { - "explanation": "This is a known issue with our HEIC image converter: iPhone photos taken in portrait mode occasionally lose their EXIF orientation metadata during conversion and render rotated. It does not affect OCR accuracy, but the preview is misleading.", - "workaround": "Rotate the image on your phone (Photos app → Edit → Rotate) before uploading, or export the image as PNG first. The OCR will read the rotated version correctly.", - "confidence": "high", - "citations": ["known-issues.md", "troubleshooting.md"] - } -} diff --git a/fixtures/mock-responses/quantity-ocr.json b/fixtures/mock-responses/quantity-ocr.json deleted file mode 100644 index a446ee8..0000000 --- a/fixtures/mock-responses/quantity-ocr.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "slug": "quantity-ocr", - "keywords": [ - "6 eggs", - "quantity wrong", - "wrong quantity", - "only added 1", - "said 6 but", - "quantity is 1", - "quantities are wrong", - "handwritten digit" - ], - "router": { - "escalate": true, - "rationale": "Docs mention this class of issue but the specific digit-to-letter misread pattern needs code inspection to confirm the parser behavior.", - "confidence": "medium" - }, - "codeInvestigation": { - "rootCause": "The quantity parser in ocr/parseQuantity.ts discards any token that contains a non-numeric character, which silently drops misread digits like '6' read as 'b'. The fallback path then defaults the quantity to 1 without surfacing that the token was rejected.", - "affectedFiles": [ - "src/ocr/parseQuantity.ts", - "src/ocr/confidence.ts", - "src/ui/ReviewTable.svelte" - ], - "workaround": "Edit the quantity inline in the review table before pushing the basket — cells become editable on click.", - "confidence": "medium" - }, - "resolution": { - "explanation": "When a handwritten digit is misread by the OCR as a letter (commonly 6→b, 7→1), our quantity parser rejects the mixed token and silently falls back to a default of 1. The underlying OCR confidence signal exists but isn't surfaced on the review row, so it looks like a successful parse. The fix would be to (a) detect likely-digit-letter confusions and retry, and (b) mark the row as low-confidence so users are prompted to check it.", - "workaround": "Every row in the review table is editable on click — adjust the quantity manually before pushing the basket to Tesco or ASDA.", - "confidence": "medium", - "citations": [ - "known-issues.md", - "ocr-and-items.md", - "troubleshooting.md" - ] - }, - "ticket": { - "title": "OCR: handwritten quantity digits silently default to 1 on digit-letter misreads", - "body": "**Problem**\nUsers report that handwritten quantities like \"6 eggs\" land in the review table as quantity 1 with no indication that the digit was misread.\n\n**Probable root cause**\n`src/ocr/parseQuantity.ts` discards any token containing a non-numeric character. When the OCR pass misreads `6` as `b`, the token is rejected and the fallback default of 1 is used, without downgrading the row's confidence badge.\n\n**Suggested fix**\n1. In `parseQuantity.ts`, detect common digit-letter confusions (`b↔6`, `l↔1`, `O↔0`, `S↔5`) and retry the parse against the digit-interpretation.\n2. When the parser falls back to the default, emit a `quantityFallback: true` flag on the row so `confidence.ts` can downgrade it to Low.\n3. In `ReviewTable.svelte`, render a small warning badge on rows with `quantityFallback`.\n\n**Affected files**\n- src/ocr/parseQuantity.ts\n- src/ocr/confidence.ts\n- src/ui/ReviewTable.svelte\n\n**Severity**: medium — user-facing but with an obvious workaround (edit inline)." - } -} diff --git a/package.json b/package.json index c70ef2f..c17f499 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "pnpm": { "onlyBuiltDependencies": [ "@biomejs/biome", + "better-sqlite3", "esbuild", "onnxruntime-node", "protobufjs", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e311187..606a2cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: '@xenova/transformers': specifier: ^2.17.2 version: 2.17.2 + better-sqlite3: + specifier: ^11.5.0 + version: 11.10.0 cors: specifier: ^2.8.5 version: 2.8.6 @@ -45,6 +48,9 @@ importers: specifier: ^3.23.8 version: 3.25.76 devDependencies: + '@types/better-sqlite3': + specifier: ^7.6.12 + version: 7.6.13 '@types/cors': specifier: ^2.8.17 version: 2.8.19 @@ -925,6 +931,9 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/better-sqlite3@7.6.13': + resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} + '@types/body-parser@1.19.6': resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} @@ -1147,10 +1156,16 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + better-sqlite3@11.10.0: + resolution: {integrity: sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -1485,6 +1500,9 @@ packages: picomatch: optional: true + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -3031,6 +3049,10 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@types/better-sqlite3@7.6.13': + dependencies: + '@types/node': 22.19.17 + '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 @@ -3262,8 +3284,17 @@ snapshots: baseline-browser-mapping@2.10.20: {} + better-sqlite3@11.10.0: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.3 + binary-extensions@2.3.0: {} + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -3651,6 +3682,8 @@ snapshots: optionalDependencies: picomatch: 4.0.4 + file-uri-to-path@1.0.0: {} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 From 5b0140e2da8569987e70c8287c7ed8f13fd3a1c9 Mon Sep 17 00:00:00 2001 From: Cash-Codes Date: Sat, 2 May 2026 08:36:30 +0100 Subject: [PATCH 4/4] chore: tidy up for rollout --- .dockerignore | 31 +- .env.example | 32 +- Dockerfile | 90 + LICENSE | 38 + README.md | 576 ++++- .../http-ok-despite-content-match-fail.json | 48 + .../fixtures/ssl-tls-unreachable.json | 25 + .../fixtures/timing-fields-zero.json | 27 + apps/api/package.json | 2 + apps/api/src/app.ts | 63 +- apps/api/src/clients/claude.mock.test.ts | 4 +- apps/api/src/clients/claude.mock.ts | 4 +- apps/api/src/clients/claude.ts | 16 +- apps/api/src/clients/claude/prompts.ts | 14 +- apps/api/src/clients/claude/spawn.ts | 28 +- apps/api/src/clients/github.ts | 4 +- apps/api/src/clients/shortcut.mock.ts | 20 +- apps/api/src/clients/shortcut.ts | 6 +- apps/api/src/config.ts | 37 +- apps/api/src/fixtures/fixtures.test.ts | 2 +- apps/api/src/fixtures/index.ts | 21 +- .../api/src/orchestrator/codeInvestigation.ts | 4 +- apps/api/src/orchestrator/composeTicket.ts | 4 +- apps/api/src/orchestrator/docsRetrieval.ts | 2 +- apps/api/src/orchestrator/index.test.ts | 2 +- apps/api/src/orchestrator/openFixPR/index.ts | 9 +- .../api/src/orchestrator/openFixPR/prompts.ts | 4 +- .../orchestrator/openFixPR/worktree.test.ts | 2 +- .../src/orchestrator/openFixPR/worktree.ts | 6 +- apps/api/src/orchestrator/resolution.ts | 2 +- apps/api/src/orchestrator/router.ts | 2 +- apps/api/src/orchestrator/ticketing.ts | 2 +- apps/api/src/productRepo/bootstrap.ts | 6 +- apps/api/src/rag/indexer.test.ts | 4 +- apps/api/src/rag/indexer.ts | 4 +- apps/api/src/routes/chat.ts | 25 +- apps/api/src/routes/dashboard.ts | 48 + apps/api/src/routes/health.ts | 21 +- apps/api/src/routes/routes.test.ts | 4 +- apps/api/src/routes/session.ts | 4 +- apps/api/src/routes/widget.ts | 6 +- apps/api/src/server.ts | 127 +- apps/api/src/sessions/sqliteStore.test.ts | 4 +- apps/api/src/sessions/sqliteStore.ts | 2 +- apps/api/src/sessions/store.test.ts | 2 +- apps/api/src/sessions/store.ts | 2 +- .../src/components/PhaseTimeline.tsx | 2 +- apps/dashboard/src/components/SessionRow.tsx | 2 +- .../dashboard/src/components/SystemHeader.tsx | 31 +- apps/dashboard/src/index.css | 4 +- apps/dashboard/src/lib/api.ts | 15 + apps/dashboard/src/main.tsx | 2 +- apps/dashboard/src/routes/SessionViewer.tsx | 2 +- apps/dashboard/tsconfig.json | 2 +- apps/dashboard/vite.config.ts | 9 +- .../app/src/components/ChatWindow.test.tsx | 2 +- apps/widget/app/src/lib/api.ts | 2 +- apps/widget/loader/src/loader.ts | 4 +- demo.gif | Bin 0 -> 12539826 bytes demo/host.html | 2 +- package.json | 2 +- screenshots/dashboard.png | Bin 0 -> 237345 bytes screenshots/github_pr.png | Bin 0 -> 366024 bytes screenshots/main.png | Bin 0 -> 206675 bytes screenshots/shortcut_ticket.png | Bin 0 -> 486302 bytes scripts/deploy-cloud-run.sh | 105 + scripts/dev.sh | 52 +- scripts/snapshot-demo-assets.sh | 62 + technical_guide.md | 1923 +++++++++++++++++ 69 files changed, 3422 insertions(+), 187 deletions(-) create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 apps/api/demo-assets/fixtures/http-ok-despite-content-match-fail.json create mode 100644 apps/api/demo-assets/fixtures/ssl-tls-unreachable.json create mode 100644 apps/api/demo-assets/fixtures/timing-fields-zero.json create mode 100644 apps/api/src/routes/dashboard.ts create mode 100644 demo.gif create mode 100644 screenshots/dashboard.png create mode 100644 screenshots/github_pr.png create mode 100644 screenshots/main.png create mode 100644 screenshots/shortcut_ticket.png create mode 100755 scripts/deploy-cloud-run.sh create mode 100755 scripts/snapshot-demo-assets.sh create mode 100644 technical_guide.md diff --git a/.dockerignore b/.dockerignore index 84139f4..9cc0358 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,16 +1,37 @@ +# Don't ship local artifacts into the build context. node_modules **/node_modules dist **/dist -coverage data -.git -.gitignore .env -.env.local +.env.* *.log -.DS_Store + +# Source-control + editor noise +.git +.gitignore +.github +.husky .vscode .idea +.DS_Store + +# Tests / coverage +coverage +**/coverage +**/*.test.ts +**/*.test.tsx +**/__tests__ + +# Credentials, never bake into images claude-credentials.json +*.credentials.json + +# Local docs that aren't needed inside the image (the demo-assets snapshot +# lives under apps/api/demo-assets and is included implicitly). docs/superpowers +README.md + +# pnpm artifacts that get re-derived inside the image +.pnpm-store diff --git a/.env.example b/.env.example index 45d0f2d..8cff8a5 100644 --- a/.env.example +++ b/.env.example @@ -11,26 +11,44 @@ ENABLE_PR_FLOW=false # investigation) and /docs/*.md (for RAG). # Prod: leave PRODUCT_REPO_PATH empty and set PRODUCT_REPO_URL; # the entrypoint clones the repo at boot. -PRODUCT_REPO_PATH=/Users/jen/projects/ai_support_agents_product +PRODUCT_REPO_PATH= PRODUCT_REPO_URL= +# Base branch the openFixPR worktree forks from when proposing a fix. +# Defaults to "main". Override when the trunk lives on a non-default +# branch (common during early development). PRs target this branch too. +PRODUCT_REPO_BASE_BRANCH=main -# RAG overrides — leave unset to use /docs + data/rag-index.json +# RAG overrides - leave unset to use /docs + data/rag-index.json DOCS_DIR= RAG_CACHE_PATH= +# SQLite session store. Defaults to data/sessions.db (next to data/rag-index.json). +# Sessions persist across api restarts. Set to ":memory:" for ephemeral mode. +DATABASE_PATH= + +# Demo fixtures dir. Empty = no canned demo responses; the agent's mock +# fallback returns a generic "running in demo mode" reply. Cloud-Run +# deploys point this at a product-specific fixtures folder so visitors see +# the full pipeline flow without burning live LLM tokens. +FIXTURES_DIR= + # CORS WIDGET_ALLOWED_ORIGINS= DASHBOARD_ORIGIN= -# Shortcut — if SHORTCUT_API_TOKEN is unset, the api uses the mock client. +# Shortcut - if SHORTCUT_API_TOKEN is unset, the api uses the mock client. # Get a token at https://app.shortcut.com/settings/account/api-tokens -# SHORTCUT_WORKFLOW_STATE_ID is the numeric id of the workflow state new bug -# tickets should land in (often "Ready for Dev"). Find it via: +# SHORTCUT_WORKSPACE_SLUG is the workspace identifier in the user-facing +# URL (e.g. https://app.shortcut.com//...). The mock client uses it +# to render realistic ticket URLs in screencasts. +# SHORTCUT_WORKFLOW_STATE_ID is the numeric id of the workflow state new +# bug tickets should land in (often "Ready for Dev"). Find it via: # GET https://api.app.shortcut.com/api/v3/workflows SHORTCUT_API_TOKEN= -SHORTCUT_WORKSPACE= +SHORTCUT_BASE_URL=https://api.app.shortcut.com/api/v3 +SHORTCUT_WORKSPACE_SLUG= SHORTCUT_WORKFLOW_STATE_ID= -# GitHub — if unset OR ENABLE_PR_FLOW=false, uses mock PR client +# GitHub - if unset OR ENABLE_PR_FLOW=false, uses mock PR client GITHUB_TOKEN= GITHUB_REPO= diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..14e6547 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,90 @@ +# AI Support Engineer - Cloud Run image (mock-mode demo). +# +# Two stages: build everything in the workspace, then copy only what the +# api needs into a slim runtime. The widget's loader + iframe SPA are +# emitted to repo-root /dist/widget/ at build time and served as static +# assets by the api. + +# ──────────────────────────────────────────────────────────────────── +# Stage 1 - builder +# ──────────────────────────────────────────────────────────────────── +FROM node:22-slim AS builder + +# better-sqlite3 + onnxruntime + transformers compile native bindings. +RUN apt-get update && apt-get install -y --no-install-recommends \ + python3 \ + make \ + g++ \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Enable pnpm via corepack and pin to the workspace's declared version. +RUN corepack enable +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ +COPY packages/shared/package.json packages/shared/ +COPY apps/api/package.json apps/api/ +COPY apps/dashboard/package.json apps/dashboard/ +COPY apps/widget/package.json apps/widget/ + +RUN pnpm install --frozen-lockfile + +# Source - kept after install so dep changes don't bust the source layer. +COPY tsconfig.base.json biome.json ./ +COPY packages packages +COPY apps apps + +# Build order: shared → api (consumes shared) → widget (loader + app SPA) +# → dashboard (the bundled session-replay UI served at /dashboard/). +RUN pnpm --filter @ai-support/shared build \ + && pnpm --filter @ai-support/api build \ + && pnpm --filter @ai-support/widget build \ + && pnpm --filter @ai-support/dashboard build + +# ──────────────────────────────────────────────────────────────────── +# Stage 2 - runtime +# ──────────────────────────────────────────────────────────────────── +FROM node:22-slim AS runtime + +WORKDIR /app +ENV NODE_ENV=production \ + PORT=8080 + +# Copy the workspace metadata so node module resolution works against +# pnpm's symlinked node_modules tree. +COPY --from=builder /app/package.json /app/pnpm-workspace.yaml ./ +COPY --from=builder /app/node_modules ./node_modules + +# Built workspace packages. The per-workspace node_modules dirs are +# pnpm symlink farms pointing into /app/node_modules/.pnpm - they're +# tiny but required for module resolution at runtime. +COPY --from=builder /app/packages/shared/dist packages/shared/dist +COPY --from=builder /app/packages/shared/package.json packages/shared/package.json +COPY --from=builder /app/packages/shared/node_modules packages/shared/node_modules + +# Built api. +COPY --from=builder /app/apps/api/dist apps/api/dist +COPY --from=builder /app/apps/api/package.json apps/api/package.json +COPY --from=builder /app/apps/api/node_modules apps/api/node_modules + +# Demo assets (docs + fixtures snapshot from the product repo). +COPY --from=builder /app/apps/api/demo-assets apps/api/demo-assets + +# Built widget assets (loader.js + iframe SPA), served by the api at +# /widget/loader.js and /widget/* respectively. +COPY --from=builder /app/dist/widget dist/widget + +# Built dashboard SPA, served by the api at /dashboard/*. +COPY --from=builder /app/dist/dashboard dist/dashboard + +EXPOSE 8080 + +# Default DOCS_DIR + FIXTURES_DIR point at the bundled snapshot. Override +# in deploys that ship against a different product. WIDGET_ALLOWED_ORIGINS +# is set per-deployment via Cloud Run env vars (not baked). +ENV DOCS_DIR=/app/apps/api/demo-assets/docs \ + FIXTURES_DIR=/app/apps/api/demo-assets/fixtures \ + DATABASE_PATH=:memory: \ + DEMO_MODE=true + +CMD ["node", "apps/api/dist/server.js"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..001a517 --- /dev/null +++ b/LICENSE @@ -0,0 +1,38 @@ +MIT License + +Copyright (c) 2026 Cash-Codes + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +"Commons Clause" License Condition v1.0 + +The Software is provided to you by the Licensor under the License, as defined +below, subject to the following condition. + +Without limiting other conditions in the License, the grant of rights under +the License will not include, and the License does not grant to you, the +right to Sell the Software. + +For purposes of the foregoing, "Sell" means practicing any or all of the +rights granted to you under the License to provide to third parties, for a +fee or other consideration (including without limitation fees for hosting or +consulting/support services related to the Software), a product or service +whose value derives, entirely or substantially, from the functionality of the +Software. Any license notice or attribution required by the License must also +include this Commons Clause License Condition notice. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 0b99bc3..b17449a 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,575 @@ # AI Support Engineer -Agentic support system. User sends a bug report → docs RAG → optional code investigation → explanation + workaround → Shortcut ticket → optional fix PR. +An embeddable AI support agent that reads your product docs, investigates your codebase when docs aren't enough, drafts a workaround for the user and - when the issue is a confirmed bug - opens a Shortcut ticket and a GitHub PR with the fix. Drop one ` +``` + +The loader injects a floating chat avatar + sandboxed iframe. The iframe is served from the api's origin (so its fetches to `/session/init`, `/chat`, etc. are same-origin and need no extra CORS). The host page's CORS is governed by `WIDGET_ALLOWED_ORIGINS` - make sure your host's origin is in the CSV. + +`data-suggestions` is optional. When present, the empty-state shows clickable chips that pre-fill the message. When absent, the empty-state shows just the welcome text. + +### 7. Trigger your first run + +Visit `http://localhost:5175` (Pulsefile dev) or whichever host you embedded into. Click the chat avatar, click a chip - or type a question. Watch the api logs: + +``` +[20:42:42] phase completed { phase: "intake", durationMs: 0 } +[20:42:42] phase completed { phase: "docsRetrieval", durationMs: 12 } +[20:42:42] claude-cli: spawning { tag: "router" } +[20:43:09] claude-cli: completed { tag: "router", stdoutBytes: 1449 } +[20:43:09] claude-cli: spawning { tag: "investigate" } +[20:43:44] claude-cli: completed { tag: "investigate", stdoutBytes: 1585 } +[20:43:55] claude-cli: completed { tag: "synthesize", stdoutBytes: 862 } +[20:43:56] shortcut: story created { ticketId: 76, ticketUrl: "https://..." } +[20:43:56] worktree: created { branch: "support/...", baseBranch: "main" } +[20:45:17] claude-cli: completed { tag: "fix-agent", stdoutBytes: 853 } +[20:45:17] github: PR opened { branch: "support/...", prUrl: "https://..." } +``` + +Replay the session at `http://localhost:5174/dashboard/`. Each phase is timed and traceable; ticket and PR URLs are linked. + +### 8. Manual smoke test (no UI) + +```bash +# 1. Create a session +SESSION=$(curl -s -X POST http://localhost:8080/session/init \ + -H "Content-Type: application/json" \ + -d '{"product":"pulsefile"}' | jq -r .sessionId) + +# 2. Stream a question (SSE - Ctrl-C to stop) +curl -N -X POST http://localhost:8080/chat \ + -H "Content-Type: application/json" \ + -d "{\"sessionId\":\"${SESSION}\",\"message\":\"My HTTP check shows ok but content-match is failing - is that intended?\"}" + +# 3. Read the persisted session +curl -s http://localhost:8080/sessions/${SESSION} | jq . +``` + +## Docker (local testing) + +The same image is what deploys to Cloud Run. + +### Build + +```bash +docker build -t agent-api:local . +``` + +The Dockerfile is a multi-stage build on `node:22-slim`: + +- **builder** - installs `python3 / make / g++` (for `better-sqlite3` + `onnxruntime` native bindings), runs `pnpm install --frozen-lockfile`, then builds shared → api → widget → dashboard in order. +- **runtime** - copies only `node_modules`, the built `dist/` of each workspace and the demo-assets snapshot. No build toolchain in the runtime image. + +### Run + +```bash +docker run --rm -p 8080:8080 \ + -e PRODUCT_REPO_PATH= \ + -e DEMO_MODE=true \ + -e DATABASE_PATH=:memory: \ + agent-api:local +``` + +Mock mode kicks in (no Claude credentials mounted, no Shortcut / GitHub tokens). Hit `http://localhost:8080/widget/`, `http://localhost:8080/dashboard/`, `http://localhost:8080/health`. + +To exercise live Claude inside Docker, mount your credentials in: + +```bash +# (macOS) Extract from Keychain to a flat file once +security find-generic-password -s "Claude Code-credentials" -w \ + > /tmp/claude-credentials-content +mkdir -p /tmp/claude-creds +echo '{"claudeAiOauth":'"$(cat /tmp/claude-credentials-content)"'}' \ + > /tmp/claude-creds/.credentials.json + +docker run --rm -p 8080:8080 \ + -v /tmp/claude-creds/.credentials.json:/root/.claude/.credentials.json:ro \ + -v /Users/you/projects/pulsefile:/repos/pulsefile \ + -e PRODUCT_REPO_PATH=/repos/pulsefile \ + agent-api:local +``` + +## Cloud Run Deployment + +Mock-mode deploy - bundles the demo-assets snapshot, runs without Claude / Shortcut / GitHub credentials. Public, scale-to-zero, ~£0/month at idle. + +### One-shot + +```bash +./scripts/deploy-cloud-run.sh +``` + +The script: + +1. Re-snapshots `/docs` + `fixtures/mock-responses` into `apps/api/demo-assets/` so the image always matches the current product repo state. +2. Enables required APIs (`artifactregistry`, `cloudbuild`, `run`) idempotently. +3. Creates the Artifact Registry repo if missing. +4. `gcloud builds submit` - remote linux/amd64 build, ~3-5 min. +5. `gcloud run deploy` with the env vars below. + +### Environment overrides + +```bash +PROJECT_ID=ai-support-engineer \ +REGION=us-central1 \ +SERVICE_NAME=agent-api \ +ALLOWED_ORIGINS="https://your-host.example.com,http://localhost:5175" \ +./scripts/deploy-cloud-run.sh +``` + +`ALLOWED_ORIGINS` becomes `WIDGET_ALLOWED_ORIGINS` on the deployed service. The script uses `^@^` as the gcloud env-var delimiter so a CSV value like `https://a,http://b` survives parsing intact. + +### Tightening CORS after the host product deploys + +The agent allows any origin when `WIDGET_ALLOWED_ORIGINS` is empty (dev default). Once your host product has a public URL, restrict the allow-list: + +```bash +ALLOWED_ORIGINS="https://your-host.example.com" \ +SKIP_SNAPSHOT=1 \ +./scripts/deploy-cloud-run.sh +``` + +The agent's own origin is **always** allowed automatically (the iframe at `/widget/` makes same-origin asset requests with `