-
-`)
- }))
- },
-})
diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css
deleted file mode 100644
index df0ee30..0000000
--- a/docs/.vitepress/theme/custom.css
+++ /dev/null
@@ -1,35 +0,0 @@
-:root {
- --vp-c-brand-1: #806000;
- --vp-c-brand-2: #967000;
- --vp-c-brand-3: #a47b00;
- --vp-c-brand-soft: rgba(242, 183, 5, 0.14);
- --vp-button-brand-text: #242117;
- --vp-button-brand-bg: #f2c438;
- --vp-button-brand-hover-text: #242117;
- --vp-button-brand-hover-bg: #f7d361;
- --vp-button-brand-active-text: #242117;
- --vp-button-brand-active-bg: #e6b824;
-}
-
-.dark {
- --vp-c-brand-1: #f2cb57;
- --vp-c-brand-2: #e7bd3b;
- --vp-c-brand-3: #d5a926;
- --vp-c-brand-soft: rgba(242, 183, 5, 0.16);
-}
-
-.VPHero .image-src {
- max-width: 240px;
- max-height: 240px;
- border-radius: 32px;
-}
-
-.VPNavBarTitle .logo {
- border-radius: 6px;
-}
-
-.VPHome .vp-doc img {
- border: 1px solid var(--vp-c-divider);
- border-radius: 12px;
- margin: 24px auto;
-}
diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts
deleted file mode 100644
index 42fe9a9..0000000
--- a/docs/.vitepress/theme/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import DefaultTheme from 'vitepress/theme'
-import './custom.css'
-
-export default DefaultTheme
diff --git a/docs/analysis-app.md b/docs/analysis-app.md
deleted file mode 100644
index b23bfdf..0000000
--- a/docs/analysis-app.md
+++ /dev/null
@@ -1,288 +0,0 @@
-# Analysis apps (JavaScript)
-
-**[中文](zh/analysis-app.md)** · [Docs](index.md)
-
-An analysis app is a workspace tab whose contents are a JavaScript application you
-wrote. JavaScript is the declaration: the app's `render` function is the description of
-the interface, and the range controls, chips, KPI cards, charts and tables are all yours
-to compose. An analysis app reads the database the window already has open — the same
-tables, views and attached files — through the host functions below.
-
-This is for building a view over your data: a dashboard, a purpose-built browser for one
-table, a report you run every morning. An analysis app opens and closes like a query, and
-sits beside your SQL tabs.
-
-## Open an app
-
-Any of these opens one, and each loads the folder immediately:
-
-- the **+** at the end of the tab strip, then **Open app…**;
-- drag an app folder onto the window;
-- name it on the command line: `ducklocal examples/analysis_app`.
-
-A folder that cannot be an app — a file, a path that is gone, or a folder with no
-`main.js` — is refused **inside the tab**, naming the folder and what is missing. An app
-that is already working is never thrown away by a folder you cancelled out of or named by
-mistake.
-
-Apps close with the tab's close button and rename like a query tab. The app folders you
-have open are remembered: they reopen at the next launch, and one that has been moved or
-deleted is reported by name rather than silently forgotten.
-
-Apps run on their own DuckDB connection to the database the main window has open, so an
-app and the SQL editor see the same tables, views and attached files without waiting on
-each other: a dashboard refreshing half a dozen statements no longer freezes the editor.
-What a second connection does not carry is connection-local state — a `TEMP` table or a
-`SET` made in the SQL editor is not there for an app, and the other way round. All apps
-share that one connection, so they still queue behind each other.
-
-## View definition
-
-**View definition** in the app's header shows the folder and the entry file's source,
-read-only. An app is an ordinary directory of JavaScript files, so that is the whole
-definition — there is no second, hidden form of the app to inspect.
-
-## Reload
-
-Save a `.js` or `.mjs` file in the app's folder and the app reloads. The host polls the
-folder every 250 ms and waits 200 ms for writes to settle, so saving six files at once is
-one reload. Dotfiles, `node_modules/` and `target/` are ignored. Only the folder currently
-shown is watched.
-
-**Reload** in the app's header does the same thing on demand.
-
-A reload that fails **keeps the last app that loaded** and reports the error above it,
-inside the tab. A load that fails on an app that has never loaded shows the error as the
-tab's whole body instead.
-
-A reload restarts the app's JavaScript, not its connection. The app connection is one
-long-lived connection shared by every app, so state an app made on it — an `ATTACH`, a
-`SET`, a `TEMP` table — is still there after the reload. Write an app's setup so that
-running it twice is safe (`ATTACH IF NOT EXISTS …`, `CREATE OR REPLACE TEMP TABLE …`)
-rather than assuming a clean connection on every load.
-
-## Host functions
-
-Import them from the `ducklocal` module:
-
-```js
-import { catalog, query, appDir, sqlLiteral, sqlIdentifier } from "ducklocal";
-```
-
-They all run against the app connection — the same database the main window is on — and
-they throw JavaScript `Error`s on failure. Everything but `appDir` may be called at any
-time; `appDir` answers during the app's load.
-
-### `catalog()`
-
-```ts
-catalog(): Promise
-
-interface CatalogEntry {
- database: string; // e.g. "memory"
- schema: string; // e.g. "main"
- name: string; // e.g. "orders"
- kind: "table" | "view";
- estimated_rows: number | null;
- comment: string | null;
- columns: { name: string; type: string }[]; // type is DuckDB's, e.g. "DECIMAL(38,10)"
-}
-```
-
-Every table and view of every database on the connection — the one the window opened and
-anything `ATTACH`ed, by the window or by the app itself — except DuckDB's own catalogs
-(`information_schema`, `pg_catalog`, `system`). `entry.database` says which database an
-entry belongs to; use it when you qualify a name. Tables come before views. DuckDB resolves
-identifiers case-insensitively and keeps tables and views in one namespace, so qualify a
-name when you build SQL from it, and quote it with `sqlIdentifier`.
-
-### `query(sql, limit?)`
-
-```ts
-query(sql: string, limit?: number): Promise
-
-interface QueryResult {
- columns: { name: string; type: string }[];
- rows: any[][]; // one array per row, one entry per column
- row_count: number; // rows actually returned
- truncated: boolean; // true when the row limit stopped the result early
- elapsed_ms: number;
-}
-```
-
-- `limit` defaults to **1000**; a value below 1 is refused and anything above 100000 is
- clamped. A 2,000,000-cell budget applies
- as well, so a very wide result returns fewer rows than `limit`. **Read `truncated`.**
-- `type` is the Arrow type as rendered by DuckLocal, e.g. `Int64`, `Utf8`,
- `Decimal(38, 10)`, `Timestamp(Microsecond, None)`.
-- The statement is prepared and executed as given; `query()` does not split or validate
- multi-statement SQL.
-
-### `appDir()`
-
-```ts
-appDir(): string // the app's own folder, absolute
-```
-
-An app cannot read the filesystem, so this is how it addresses data that ships beside it —
-`query("SELECT * FROM " + sqlLiteral(appDir() + "/orders.csv"))` works with nothing
-attached and nothing open in the window. It answers while the app loads: call it in `init()`
-and keep the result.
-
-`panelDir()` is the deprecated alias from before apps were called apps; it keeps working,
-but new code should use `appDir()`.
-
-### `sqlLiteral(value)`
-
-```ts
-sqlLiteral(value: string): string // e.g. "O'Brien" -> 'O''Brien'
-```
-
-Quotes and escapes a string as a SQL string literal. Use it for any value that comes from
-your app's own state — a filter, a channel id, a date — instead of templating it into SQL
-by hand. A `NUL` byte is refused, because a SQL literal cannot carry one.
-
-### `sqlIdentifier(name)`
-
-```ts
-sqlIdentifier(name: string): string // e.g. "my table" -> "my table"
-```
-
-The same job for the other half of a statement: a table, view or column **name**, quoted so
-it is read as one name and matched exactly as written. A name is not a string literal, and
-the names an app builds SQL from are rarely its own — `catalog()` answers with whatever the
-database holds, so `my table`, `Order`, and a name holding a `"` all turn up. An empty name
-and a `NUL` byte are refused; neither names anything, and quoting them would only hide that.
-
-```js
-const entry = (await catalog()).find((table) => table.name === "orders");
-const from = `${sqlIdentifier(entry.schema)}.${sqlIdentifier(entry.name)}`;
-const rows = await query(`SELECT count(*) FROM ${from}`);
-```
-
-### Cell encodings
-
-A cell is plain JSON **when that loses nothing** — `null`, booleans, strings, and numbers
-that fit an IEEE double exactly. Anything else arrives as an object with an `encoding`
-field, the same encoding the `ducklocal query` CLI prints, so no digit is silently dropped:
-
-| Value | What arrives |
-| --- | --- |
-| `NULL` | `null` |
-| `BOOLEAN` | `true` / `false` |
-| integers within ±2^53−1 | number |
-| larger integers (`HUGEINT`, `UBIGINT`, …) | `{ "encoding": "integer", "value": "170141183460469231731687303715884105727" }` |
-| `DECIMAL` | `{ "encoding": "decimal", "value": "12345678901234567890.1234567890" }` |
-| non-finite `FLOAT`/`DOUBLE` | `{ "encoding": "float", "value": "inf" }` |
-| `DATE` | `{ "encoding": "date", "unit": "Day", "value": "19783" }` |
-| `TIMESTAMP` | `{ "encoding": "timestamp", "unit": "Microsecond", "value": "1709296496789000" }` |
-| `TIME` | `{ "encoding": "time", "unit": "Microsecond", "value": "45296789000" }` |
-| `INTERVAL` | `{ "encoding": "interval", "months": 0, "days": 1, "nanos": "0" }` |
-| `BLOB`, `GEOMETRY` | `{ "encoding": "hex", "value": "00ff" }` |
-| `LIST` / `ARRAY` | array |
-| `STRUCT` | `{ "encoding": "struct", "fields": [["name", ], …] }` |
-| `MAP` | `{ "encoding": "map", "entries": [[, ], …] }` |
-| `UNION` | `{ "encoding": "union-value", "value": }` |
-
-`DATE` value `19783` is days since 1970-01-01; `TIMESTAMP` and `TIME` values are counts of
-`unit` since the epoch or midnight. These are the storage values, not formatted text:
-format them yourself, or `CAST` the column to `VARCHAR` in SQL if you want the string form.
-
-## Components
-
-An app draws with the same component catalog the shell ships, imported from
-`gpui-component`: `GroupBox` (a titled card), `Progress` (a bar), `Toggle`, `Badge`, `Tag`,
-`Alert`, `Empty`, `Collapsible`, `DescriptionList`, `DataTable` with `DataTableState`, the
-`Table` family, `Sidebar`, `Resizable`, `Scroll`, `DescriptionList`, and the charts —
-`BarChart`, `LineChart`, `AreaChart`, `PieChart`, `RadarChart`. Layout primitives
-(`div`, `h_flex`, `v_flex`, `Button`) come from `gpui-kit` and `gpui-base`.
-
-There is no `ToggleGroup`: compose a segmented control or a row of chips from several
-`Toggle`s. The example app at
-[`examples/analysis_app`](https://github.com/JetSquirrel/DuckLocal/tree/main/examples/analysis_app)
-is a full dashboard built from exactly these, and it is the best thing to copy from.
-
-Every app folder ships a `jsconfig.json` and a generated `gpui-kit.d.ts`, so check the
-app against the API the runtime will actually give it before you save:
-
-```sh
-npx --yes -p typescript tsc -p /jsconfig.json --noImplicitAny false
-```
-
-That reports a property that does not exist on a catalog component — the kind of mistake
-the runtime otherwise refuses only at render, inside the app's own error surface, which
-is not written to the app log. Its blind spot is the `gpui-base` primitives (`div`,
-`h_flex`, `v_flex`, `Button.new`): they are loosely typed, so a wrong method on one of
-those is not caught here and still only shows up at render.
-
-## SQL is not sandboxed
-
-`query()` runs on DuckLocal's own database, **with DuckLocal's privileges and the user's**.
-An app can read and write anything the SQL editor can, including `COPY` to files, `ATTACH`
-of other databases, `INSTALL`/`LOAD` of extensions, and queries against S3 views whose
-credentials are already configured. Treat an app's JavaScript as code you are choosing to
-run, exactly as you would a shell script.
-
-So the choice is asked for. The first time a folder opens as an app — from the command line,
-a drop, the picker, or a tab restored at launch — its tab says what the app's SQL can do and
-waits: **View source** shows the entry file without running it, **Trust and run** runs it.
-The answer is remembered per folder, so later launches and every reload after a save run
-without asking again. `ducklocal export --html` runs the app you name on the command line
-and does not ask.
-
-What an app does **not** get is anything else the process could do:
-
-- **No filesystem, network, process, or environment module.** `fs`, `net`, `process` and
- friends are not available to a script unless the host grants them; DuckLocal grants none.
-- **No S3 credentials.** The S3 browser's keys live in DuckLocal's own Rust state and are
- used by DuckLocal's signing client; they are never written into the DuckDB connection, and
- the host module cannot reach them. An app can still run SQL that uses httpfs if the user's
- own connection is configured for it.
-- **The host module is the whole surface.** Only the functions above cross into Rust.
-
-## Export an app as HTML
-
-`ducklocal export --html ` runs an app once and writes what it asked the database into one self-contained HTML file, for sending an app's numbers to someone who does not have DuckLocal. The command, its options and its exit codes are in [the CLI guide](cli.md#export-an-app-as-a-static-html-file). The capture ends when the app has gone quiet, or at `--timeout` seconds (default 15), whichever comes first; in the deadline case the JSON's `stop_reason` is `deadline` and the report carries a visible warning that it may be incomplete.
-
-The report is the app's data, not its interface. Only what `query()` returned is exported, in call order, one section per distinct statement — an identical statement run again collapses into its section, marked as run that many times — and every call is captured, including statements that are not `SELECT`, such as `ATTACH`. A `catalog()` call becomes an appendix of tables and columns rather than a numbered statement. A leading `-- title: …` comment on the statement's first line names its section ("Statement N — title"); the SQL itself shows verbatim. Each result shows as a table, with an inline bar chart above it when the result is a label and a number per row: exactly two columns, at most 25 rows, and a non-negative numeric second column (the first column labels the bars). Anything else is only a table.
-
-What the report does **not** hold is anything the app drew: KPI cards, charts, and tables built from JavaScript constants never reach the file, because the export records queries, not the render — an app draws native components and their contents are decided while they are laid out, so nothing describes a chart's bars well enough to reproduce them. Constants a report must show can be sent through SQL instead: `SELECT * FROM (VALUES ('Q1', 120), ('Q2', 95)) AS t(quarter, total)`.
-
-Because it is the loading state, a statement an app only runs on a click is not in the report, and neither is anything after a reload. The app's JavaScript runs with the same privileges as always: exporting is running the app, exactly as opening it in a tab is.
-
-## Dashboard specs (.dash)
-
-A `.dash` file is a dashboard declared as data — query and plot blocks, no JavaScript — for the common case of standard plots over saved queries. The file format and `ducklocal check` validation are in [the CLI guide](cli.md#check-a-dashboard-spec).
-
-Open one like an app: choose **Open dashboard…** from the tab strip's `+` menu, name it on the command line (`ducklocal dashboard.dash`), or drag the file onto the window, and it opens as a dashboard tab beside your queries and apps. The tab runs the spec's queries on the window's own connection — so a dashboard sees connection-local state such as `TEMP` tables, and queues with the editor's queries — and renders each plot as one panel of a vertical stack whose dividers drag to resize. Only read-only statements run: a query that could write (DDL, DML, `COPY`, `ATTACH`, …) is refused before it reaches the connection, so opening a `.dash` file someone sent you cannot change your data. A plot whose query fails shows the reason in its own panel; the rest of the dashboard still draws. The toolbar's reload re-reads the file and re-runs everything, and a reload that fails validation never replaces a working dashboard — the reason appears above it instead. Open dashboards are remembered between launches, exactly like apps.
-
-The tab is also an editor: its source view edits the file with syntax highlighting — the SQL in heredocs coloured as it is in the SQL editor — completion and diagnostics, and writes back with the save button or ⌘S — a save whose spec no longer validates keeps the last working dashboard up and says why. Outside the GUI, `ducklocal lsp` serves the same completion, diagnostics, hover and go-to-definition to any LSP-capable editor (see [the CLI guide](cli.md#edit-a-dashboard-spec-with-lsp)).
-
-## Known limits
-
-- **An app in a tab has no window-level overlay.** The shell's dialogs, sheets, toasts and
- tooltip layer are found only when the shell's own root view is the window's first view. In
- a tab DuckLocal's root holds that place — it has to, or DuckLocal's own dialogs would break — so
- `window.open_dialog`, `window.open_sheet` and `window.push_toast` throw a `TypeError`
- reading *needs a ShellRoot as the window's first view*, which surfaces the way any other
- error from your code does. A tooltip is the exception, and the one silent one: it is
- attached by a hover listener, which has nothing to throw into, so a tooltip in an app
- simply never appears. Build app UI that stays inside its own bounds — an expanded region
- rather than a modal.
-- **Reload is implemented by DuckLocal, not by the shell's watcher.** gpui-shell's hot reload
- hangs off `runtime.watch` / `runtime.refresh`, which only work for a `ShellRoot` the runtime
- built itself; that path is not reachable from an embedding host, so DuckLocal watches the
- folder itself and reloads through `load_application` / `mount_application`. The consequence:
- reload watches `.js`/`.mjs` files only. Any other file an app reads is not watched.
-- **A reload compiles on the UI thread.** The script runtime is not sendable, so mounting an
- app happens on the main thread; a very large module graph will make the window stutter
- while it loads. The first load is deferred until after the tab's first frame, so the tab
- appears immediately either way.
-- **One connection for all apps, and no cancellation.** Apps do not block the main
- window, but they do block each other: they share one connection behind one lock, so a long
- query in one app delays every other app's. One connection each is not available — a
- host function is handed arguments, not a caller, so nothing at the moment `query()` runs
- says which app asked. Cancelling a query in flight is not exposed either; keep an app's
- statements bounded rather than counting on stopping one.
-- **`row_count` is what came back, not what matched.** With `truncated: true`, the rows that
- would have followed are not available; aggregate in SQL rather than counting in JavaScript.
diff --git a/docs/assets/intro.jpg b/docs/assets/intro.jpg
deleted file mode 100644
index f5bde47..0000000
Binary files a/docs/assets/intro.jpg and /dev/null differ
diff --git a/docs/assets/logo.png b/docs/assets/logo.png
deleted file mode 100644
index 485b984..0000000
Binary files a/docs/assets/logo.png and /dev/null differ
diff --git a/docs/cli.md b/docs/cli.md
deleted file mode 100644
index 37fc2f3..0000000
--- a/docs/cli.md
+++ /dev/null
@@ -1,260 +0,0 @@
-# AI CLI and official skill
-
-**[中文](zh/cli.md)** · [Docs](index.md)
-
-## Run without a window
-
-`ducklocal query` executes SQL without initializing the GUI, history, registered files, language settings, or the GUI's global connection. Each invocation owns a new connection. With no command (or file, directory, and glob arguments), the existing GUI still opens. To open a GUI path named `query`, `profile`, `export`, `check` or `dash`, use `./query`, `./profile`, `./export`, `./check`, `./dash`.
-
-`ducklocal export` is the one subcommand that starts the window platform, because an analysis app renders and rendering needs a window: it opens one hidden window, draws one frame, and exits when the app has stopped asking the database. Nothing appears on screen.
-
-The supported release target remains **macOS 12+, Apple silicon**. There is no separate DuckDB CLI dependency. A build containing this CLI can be invoked directly inside its app bundle:
-
-```bash
-/Applications/DuckLocal.app/Contents/MacOS/ducklocal --help
-/Applications/DuckLocal.app/Contents/MacOS/ducklocal --version
-```
-
-Alternatively, build this checkout with `cargo build --locked` and use `./target/debug/ducklocal`. The examples below assume that binary is available as `ducklocal` on your shell's PATH. Older releases may not have `query`; check help first. JSON and Parquet support are bundled, not downloaded at query time.
-
-## Query options
-
-```bash
-ducklocal --help
-ducklocal --version
-ducklocal query --help
-ducklocal query --sql "SELECT 1 AS n"
-ducklocal query --sql "SELECT 1 AS n" --format md
-ducklocal query --sql-file analysis.sql --limit 100
-ducklocal query --sql-file - < analysis.sql
-ducklocal query --database warehouse.duckdb --sql "SHOW TABLES"
-```
-
-- Exactly one of `--sql SQL` and `--sql-file FILE` is required. Files must be UTF-8; `-` reads stdin. SQL must contain exactly one statement. DuckDB's parser validates this before opening the target database or executing anything; comments, quoted semicolons, and trailing semicolons work. Scripts are rejected, not partially executed.
-- `--database PATH` opens an **existing file, read-only by default**. Omit it for a fresh in-memory database. `--read-write` requires `--database` and explicitly permits writes and creating a database (not parent directories). Database errors never fall back to memory.
-- `--limit N` is a positive integer, defaults to 1000, and limits returned rows. A 2,000,000-cell budget also applies; an extra row is read to determine `truncated`. Neither limit constrains query computation or DuckDB's result buffering. Large individual cells can still be large.
-- `--format json` (the default) is the contract below. `--format md` renders the same result as a Markdown table, for a document or an agent reading it. Nothing else changes: the same SQL, the same limits, the same errors.
-- Repeated/unknown flags, missing values, empty SQL, and invalid limits are errors. Options use separate values, not `--flag=value`. Relative paths resolve against the process working directory, not the SQL file directory. Quote shell paths; inside SQL, double apostrophes (`'O''Brien.csv'`). SQL identifiers use double quotes.
-
-### Markdown output
-
-`--format md` is a rendering, not a second contract: the values are the ones the JSON holds, written the way the results grid shows them.
-
-| Value | Rendered as |
-| --- | --- |
-| `NULL` | `NULL` |
-| integer, decimal, float | the digits the value carries, exactly — a `DECIMAL(38,10)` keeps its scale, `NaN`/`inf`/`-inf` are spelled out |
-| `DATE` | `YYYY-MM-DD` |
-| `TIMESTAMP` | `YYYY-MM-DD HH:MM:SS[.ffffff]`, with the fraction only when the value has one. No timezone is appended; `--format json` keeps the raw count |
-| `TIME` | `HH:MM:SS[.ffffff]` |
-| `INTERVAL` | `1 months 2 days 3000 ns` |
-| `BLOB`, `GEOMETRY` | `0x00ff`, elided with `…` when long |
-| `LIST`, `STRUCT`, `MAP` | `[1, 2]`, `{x: 1}`, elided with `…` past 120 characters |
-
-A `|` in a cell is escaped and a newline becomes ` `, so a value cannot break the table it is in. A result with no rows is followed by `_0 rows._`, and a result that was cut short by `--limit` or the cell budget by `_Truncated at N rows: …_` — a preview should not read like a complete answer. Errors are unchanged: JSON on stderr, empty stdout.
-
-**Read-only is not a filesystem or network sandbox.** SQL such as `COPY` can write files even when the database is read-only. Authorize output paths, overwrites, database mutations, extension installation, and external access before execution. DuckLocal does not automatically install extensions or retry operations. Explicit `INSTALL`/`LOAD` SQL remains possible with authorization; installed extensions may autoload. A failed command can already have performed side effects (for example before an output failure); inspect the destination before retrying.
-
-## Explore and convert files
-
-After confirming the actual file exists:
-
-```bash
-ducklocal query --sql "DESCRIBE SELECT * FROM 'sales.csv'"
-ducklocal query --sql "SELECT * FROM 'sales.csv'" --limit 20
-ducklocal query --sql "SELECT sum(amount) AS total FROM 'sales.csv'"
-# Only after authorizing this output path:
-ducklocal query --sql "COPY (SELECT * FROM 'sales.csv') TO 'sales.parquet' (FORMAT PARQUET)"
-ducklocal query --sql "SELECT count(*), sum(amount) FROM 'sales.parquet'"
-ducklocal query --sql "DESCRIBE SELECT * FROM 'events.json'"
-```
-
-Do not guess `amount` exists: inspect DESCRIBE first. Compute full aggregates in SQL rather than summing a truncated preview. CLI calls do not share the GUI's registered views or each other's in-memory tables. Persist explicitly when needed:
-
-```bash
-# These are separate statements and separate invocations, with explicit write permission.
-ducklocal query --database warehouse.duckdb --read-write --sql "CREATE TABLE sales AS SELECT * FROM 'sales.csv'"
-ducklocal query --database warehouse.duckdb --sql "SELECT count(*) FROM sales"
-```
-
-A database lock conflict is an error. Close the other writer (including the GUI), or use an authorized copy; never delete lock files or silently create a different database.
-
-## JSONL and nested JSON
-
-`read_ndjson_objects` is the reader for newline-delimited JSON (one object per line, `.jsonl`/`.ndjson`); `read_json`/`read_json_auto` read JSON documents (an array or a single object). Name the reader explicitly for a JSONL file rather than relying on auto-detection. `json_extract_string(col, '$.a.b[0].c')` walks a nested path — object keys and array indexes — and answers VARCHAR:
-
-```bash
-ducklocal query --sql "SELECT json_extract_string(event, '$.payload.items[0].sku') AS sku, count(*) AS n FROM read_ndjson_objects('events.jsonl') GROUP BY 1 ORDER BY n DESC"
-```
-
-Use `json_extract` instead when the leaf is not a string and you want it as JSON.
-
-## Profile a relation
-
-`ducklocal profile` answers the questions that decide a chart, a scale and a number format, before anything is built on them. `DESCRIBE` says a column is a `DOUBLE`; a profile says it uses two decimals, that its largest value is a thousand times its median, and that its dates skip eleven days in the middle.
-
-```bash
-ducklocal profile sales.csv
-ducklocal profile orders.parquet
-ducklocal profile "my orders" --database warehouse.duckdb
-```
-
-TARGET is a data file — `csv`, `tsv`, `txt`, `parquet`, `json`, `ndjson`, `jsonl` — or a workbook (`xlsx`, `xls`, `xlsb`, `ods`; its first sheet is imported as a TEMP table and profiled), or, with `--database`, a table or view name. A dotted name is read as `schema.table` and each part is quoted, so a name with a space or a capital letter works as written. A target that names nothing is an argument error (exit 2), not a SQL one.
-
-One JSON object comes back: `target`, `relation` (the SQL the statistics ran against), `row_count`, `elapsed_ms`, and `columns` in the relation's own order. Per column:
-
-| Field | Meaning |
-| --- | --- |
-| `name`, `type` | as `DESCRIBE` reports them |
-| `nulls` | rows where the column is `NULL` |
-| `distinct` | exact, not estimated |
-| `unique` | present and `true` when `distinct` equals `row_count` |
-| `min`, `max` | as text, so a `DECIMAL` keeps its digits |
-| `decimals` | digits after the point the column **actually uses**, which is not its declared scale |
-| `median` | a value the column holds, not an interpolation between two of them |
-| `max_over_median` | how many times the middle value the largest one is — the number that decides a linear axis from a logarithmic one |
-| `covered_days`, `span_days`, `missing_days` | days the column names, days between its ends, and the difference: `0` is a continuous series, anything else is holes a line would draw over |
-
-`decimals`, `median` and `max_over_median` appear on numeric columns; the day fields on dates and timestamps. `LIST`, `STRUCT`, `MAP` and `UNION` columns report `nulls` only — `min` and `max` are not defined on them.
-
-Statistics are exact and read the whole relation, so a profile costs a full scan. `--limit` does not apply: a profile of a sample is not a profile.
-
-## Export an app as a static HTML file
-
-`ducklocal export` answers "what was that app showing?" for someone who does not have DuckLocal. It runs the app once — the same runtime, the same host module, the same database rules as `query` — and writes the statements its `query()` calls issued, with their results, into one self-contained HTML file.
-
-```bash
-ducklocal export --html examples/analysis_app
-ducklocal export --html --out report.html --database warehouse.duckdb apps/sales
-```
-
-- `--html` is required, and is the only format there is. APP is an app folder (one holding `main.js`) or its `main.js`, resolved the way the GUI resolves it; a path that names neither is an argument error (exit 2).
-- `--out FILE` names the destination and defaults to `./.html` in the working directory. An existing file is refused unless `--force` is given — checked before the app runs, so a refusal costs nothing.
-- `--database PATH` and `--read-write` mean exactly what they mean for `query`: an existing file, read-only unless asked otherwise, in memory when omitted. The app runs on that connection, so an app that writes needs `--read-write`.
-- `--timeout SECONDS` is a positive integer, default 15: the capture stops when the app has stopped asking the database for a moment, or at the deadline, whichever comes first.
-- The command starts the window platform, because an app renders and rendering needs a window. The window is hidden and never appears.
-
-One JSON object goes to stdout:
-
-```json
-{"html":"/abs/report.html","app":"/abs/app","queries":2,"rows":212,"app_errors":0,"captured_ms":630,"stop_reason":"settled"}
-```
-
-`queries` counts the captured statements, `rows` the rows across those that succeeded, and `app_errors` what the app logged as an error while it ran. `stop_reason` is `settled` when the app went quiet on its own, `deadline` when `--timeout` cut the capture short — then the report may be missing statements, and the HTML shows a visible warning saying so.
-
-The report holds the app folder, the database it ran against, the export time, and one section per statement: the SQL, its columns and their Arrow types, the result as a table, and a bar chart when a result is a name and a number per row. A `catalog()` call becomes an appendix of tables, views and columns. Statements an app runs more than once appear once, with the last result.
-
-The report does **not** hold the app's own layout or its charts. An app draws native components, and a chart's bars are decided while it is laid out, not described anywhere that can be read out — so the export shows the data the app was built from, not the interface it built. Filters, toggles and later refreshes are not represented either, and there is no JavaScript in the file. It is a snapshot of the app's loading state, and it says so at the top.
-
-The app's JavaScript runs with the same privileges it always has: `query()` can `COPY`, `ATTACH` and write files. The export is not a sandbox.
-
-Exit codes: **0** with the file written; **2** for a bad command line, an app path that names nothing, or a destination that already exists; **1** when the app could not be loaded (nothing is written) or when it loaded and then failed (the report is written anyway, with the error in it, and the message names the file). An app failure reports the error kind `app`.
-
-## Check a dashboard spec
-
-A `.dash` file declares a dashboard the way Terraform declares infrastructure — queries and plots as blocks, references between them — rather than scripting one as an analysis app. The two formats coexist: the spec covers query + standard plot and is easy for a person or an agent to diff; an app stays for bespoke layout and interaction.
-
-```hcl
-query "latency" {
- sql = < 'NULL'`.
-
-The two fixes compose: `try_cast(NULLIF(amount, 'NULL') AS DOUBLE)`.
-
-## Database files
-
-Any path that **exists** and is not a data file is opened as a DuckDB database
-instead of being attached as a view. The extension does not matter: a `.db`,
-`.duckdb`, or even a `.md` path is treated as a database, and DuckDB decides
-whether it can actually be opened.
-
-Two consequences are worth knowing:
-
-- **You cannot create a new database by naming one.** A path that does not
- exist is reported as not found. Open an existing database file, or start
- in-memory.
-- If the file cannot be opened as DuckDB, DuckLocal falls back to an in-memory
- workspace and reports the error, rather than failing to start.
-
-Attaching data files while a database file is open **writes those views into
-that database file** — they persist there, not merely in the session.
-
-## Naming
-
-A file's view is named after its file stem, cleaned up into a valid identifier.
-When that name is already taken in the connection, DuckLocal appends a counter:
-`events`, then `events_2`, `events_3`. Two files with the same stem in
-different directories therefore get distinct views.
-
-Duplicate detection is by the path text as written, so `./a.csv` and `a.csv`
-are treated as two different files.
-
-## Limits
-
-- **256 data files per open request.** The cap covers all the paths in one
- request together, not each folder separately — it exists so that dropping a
- home directory by accident does not tie up the connection for minutes. When
- it bites, DuckLocal says so and attaches the first 256 files.
-- Files re-attached at startup from the previous session are not subject to
- that cap.
-
-## Managing registered sources
-
-Registered files appear in the sidebar's **Local files** group, each with its
-view name, file name, and row count. Selecting a file generates a `SELECT`
-statement for it.
-
-The **×** on a file row removes it, after a confirmation dialog. Removal drops
-the view and forgets the registration; **the underlying file is untouched.**
-
-**Refresh schema** reloads the catalog and the registered files.
-
-## What is remembered
-
-The list of registered files — their paths, view names, and kinds — is stored
-in DuckLocal's own history database and re-attached on the next launch, so the
-workspace you left is the workspace you get back. The database file itself is
-*not* remembered: each launch starts in memory unless you name a database.
-
-See [Settings and app data](settings-and-data.md) for the on-disk locations.
diff --git a/docs/development.md b/docs/development.md
deleted file mode 100644
index 1a1c509..0000000
--- a/docs/development.md
+++ /dev/null
@@ -1,178 +0,0 @@
-# Development
-
-**[中文](zh/development.md)** · [Docs](index.md)
-
-## Build and run
-
-```bash
-cargo run # empty in-memory workspace
-cargo run -- ./data/logs/ # open something straight away
-cargo test # run the test suite
-```
-
-DuckDB is built from the vendored sources, so the first build is long and
-needs a few gigabytes of disk. Dev-profile dependencies are compiled at
-`opt-level = 3`, which makes that first build slower still but keeps the
-development loop usable — only `ducklocal` itself recompiles afterwards.
-
-**Toolchain.** There is no `rust-toolchain.toml` and no `rust-version` key, so
-the effective floor is set by dependencies: `1.85.1`, required by `duckdb`.
-CI uses plain stable.
-
-## The pinned toolkit
-
-The UI toolkit, the script runtime that analysis apps run on, and the
-component catalog they draw from are three crates out of one repository,
-`longbridge/gpui-kit`, and `rquickjs` is patched to the same one. All four are
-pinned to a single revision on purpose: two revisions put two copies of
-`gpui-base`, or of `rquickjs`, in the build, and that fails as a wall of trait
-mismatches naming neither cause.
-
-```bash
-./scripts/check-deps.sh
-```
-
-It checks the three things Cargo will not: one revision across the
-dependencies and the `[patch]`, a `Cargo.lock` that agrees with it, and no
-crate in the build twice — once from the repository and once from crates.io.
-It reads the two manifests and nothing else, so it is offline and immediate.
-CI runs it before the tests. To move to a newer toolkit, change every `rev` in
-`Cargo.toml` together, run `cargo update`, and run the script.
-
-Pinning by revision is also why this crate is not publishable to crates.io: a
-git dependency and a `[patch]` are both refused there. Distribution is the
-signed macOS bundle below.
-
-## Bundle a macOS app
-
-```bash
-./scripts/bundle.sh
-# produces target/release/DuckLocal.app
-```
-
-That assembles the bundle — binary at `Contents/MacOS/ducklocal`, plus
-`assets/Info.plist` and `assets/AppIcon.icns` — but **does not sign it**. The
-result runs on your machine and will be refused by Gatekeeper anywhere else.
-
-## Package, sign, and notarize
-
-```bash
-scripts/package-macos.sh
-```
-
-Run it from the repository root; it writes `DuckLocal.app` and `dmg-root` into
-the working directory and the dmg next to them. The script refuses to run
-without credentials — an unnotarized artifact is not something a user can open
-on current macOS, so it fails fast rather than producing one by accident.
-
-Required:
-
-| Variable | Meaning |
-| --- | --- |
-| `NOTARY_KEY` | Path to an App Store Connect API key (`.p8`) |
-| `NOTARY_KEY_ID` | That key's Key ID |
-| `NOTARY_ISSUER` | The issuer UUID the key belongs to |
-| a Developer ID Application identity | Auto-detected when exactly one is in the keychain, otherwise set `MACOS_SIGN_IDENTITY` |
-
-The script builds the bundle with the version stamped from the argument, signs
-the inner executable and the app with `--options runtime --timestamp` and
-`scripts/entitlements.plist`, builds a UDZO dmg with an `/Applications`
-symlink, **signs the dmg itself**, submits it with `notarytool submit --wait
---timeout 300m`, staples the ticket, and finishes with `stapler validate` plus
-two `spctl --assess` checks.
-
-Two things to know before using it:
-
-- The five-hour timeout is a client-side wait, not a cancellation. If it
- expires, the submission keeps processing on Apple's side, and the ticket can
- be collected later — but **a ticket binds to the exact bytes submitted**, so
- do not rebuild; staple the file you submitted.
-- Only the dmg is notarized, so the inner `.app` carries no stapled ticket. A
- first launch from a just-mounted image needs network to check in with Apple.
-
-The `com.apple.security.cs.disable-library-validation` entitlement is required,
-because DuckDB `dlopen`s its extensions — `httpfs` among them.
-
-## CI and releases
-
-| Workflow | Trigger | What it does |
-| --- | --- | --- |
-| `ci.yml` | Push to `main`, any pull request | `scripts/check-deps.sh`, then `cargo test --locked`, on `macos-latest` |
-| `release.yml` | Tag matching `v*`, or manual dispatch with a version | Builds `aarch64-apple-darwin`, imports the signing certificate into a throwaway keychain, runs `package-macos.sh`, uploads `ducklocal-macos-arm64.dmg`, then creates the GitHub release with generated notes |
-| `gh-pages.yml` | Push to `main` touching `docs/` or the workflow, or manual dispatch | Builds the documentation site with Node.js 24 and deploys it to GitHub Pages |
-
-The release build needs these repository secrets: `MACOS_CERTIFICATE`,
-`MACOS_CERTIFICATE_PWD`, `NOTARY_KEY_BASE64`, `NOTARY_KEY_ID`, and
-`NOTARY_ISSUER`.
-
-## Platform support
-
-macOS on Apple silicon is the only supported target, and deliberately so: the
-packaging path is `.app` plus dmg, there is no Windows or Linux artifact, and
-the release workflow says as much. There is no `cfg(target_os)` anywhere in
-`src/`, and the windowing layer builds with X11 and Wayland features, so a
-Linux build is plausible — but nothing in CI exercises it, and it is not
-tested.
-
-## The documentation site
-
-The guides in `docs/` are also published as a site, built with
-[VitePress](https://vitepress.dev/). Use Node.js 22 or newer; **Node.js 24 LTS
-is recommended** and used by the documentation workflow. Run these commands
-from the repository root:
-
-```bash
-npm --prefix docs ci # install the locked documentation dependencies
-npm --prefix docs run dev # http://localhost:5173/DuckLocal/
-npm --prefix docs run build # output lands in target/docs-site
-npm --prefix docs run preview # http://localhost:4173/DuckLocal/
-```
-
-English pages live directly in `docs/`, and Chinese pages in `docs/zh/`.
-These are the same Markdown files linked from the README and rendered on GitHub;
-there are no generated source-page copies. `docs/.vitepress/config.mts` defines
-both locales, their navigation and sidebars, local search, and the
-`/DuckLocal/` GitHub Pages base path. It also generates redirects for the old
-Chinese `.zh-CN.html` URLs, preserving query strings and anchors.
-`docs/.vitepress/theme/` extends the native default theme with a small brand
-stylesheet, `docs/assets/` holds the images, and `docs/public/` holds the favicon.
-
-The documentation package pins stable VitePress 1.6.4. Its transitive development
-tooling currently has npm audit advisories; keep development and preview servers
-local, and do not expose them to untrusted networks. The published site is static.
-
-`.github/workflows/gh-pages.yml` builds and deploys the site on pushes to `main`
-that touch `docs/` or the workflow itself, and can also be run manually.
-**GitHub Pages has to be switched on once**, in Settings → Pages, with Source
-set to “GitHub Actions”.
-
-## Project layout
-
-| Path | Contents |
-| --- | --- |
-| `src/main.rs` | Entry point, early CLI dispatch, GUI window setup |
-| `src/cli.rs` | Headless arguments, DuckDB parser validation, isolated connections, JSON errors |
-| `tests/cli.rs` | Real executable integration tests; scratch data under `target/cli-tests` |
-| `skills/ducklocal/` | Official schema-first SQL agent skill and CLI reference |
-| `src/sources.rs` | Resolving paths into files to attach and databases to open |
-| `src/db.rs` | The DuckDB connection, attaching files, server info |
-| `src/query.rs` | Query execution, result serialization, export |
-| `src/profile.rs` | Column profiling behind `ducklocal profile` |
-| `src/schema.rs` | Catalog introspection for the sidebar |
-| `src/analysis/` | JavaScript analysis apps: the script runtime, the `ducklocal` host module, the app tab, the reload watcher |
-| `src/app_export/` | `ducklocal export`: running an app headless and writing its statements and results as one standalone HTML file |
-| `src/history.rs` | The app's own database: history, registered files, settings |
-| `src/s3.rs` | SigV4 signing and S3 listing |
-| `src/i18n.rs` | The string table and language selection |
-| `src/state.rs` | Application state shared across views |
-| `src/ui/` | Editor, results grid, charts, sidebar, dialogs, title and status bars |
-| `src/perf_probe.rs` | Test-only performance probe harness: wall time, allocation count, and bytes for paths that scale with data size |
-| `docs/` | English guides, Chinese guides in `zh/`, and the VitePress package, config, and theme |
-| `assets/` | Icon, `Info.plist`, the diagram the README and docs use |
-| `scripts/` | `bundle.sh`, `package-macos.sh`, `check-deps.sh`, entitlements |
-
-## Testing notes
-
-The test suite is `cargo test`. Query execution tests exercise DuckDB through
-an in-memory connection; the export tests cover both CSV and Parquet, the
-latter by reading the written file back with `read_parquet`.
diff --git a/docs/getting-started.md b/docs/getting-started.md
deleted file mode 100644
index 2b0dff7..0000000
--- a/docs/getting-started.md
+++ /dev/null
@@ -1,107 +0,0 @@
-# Getting started
-
-**[中文](zh/getting-started.md)** · [Docs](index.md)
-
-DuckLocal is a desktop app for asking questions of the data files on your
-machine with SQL. There is no server to run, no connection to configure, and
-no account — you point it at files and start querying. This page takes you
-from download to your first result in about five minutes.
-
-## 1. Install {#install}
-
-You need **macOS 12 or later on Apple silicon** (M1 or newer).
-
-1. Download [`ducklocal-macos-arm64.dmg`](https://github.com/JetSquirrel/DuckLocal/releases/latest)
- from the latest release.
-2. Open it and drag **DuckLocal** into **Applications**.
-3. Launch DuckLocal from Applications or Spotlight.
-
-The disk image is signed and notarized by Apple, so it opens without any
-Gatekeeper workaround.
-
-::: details Building from source instead
-You need Rust stable 1.85.1 or newer and a C++ toolchain (Xcode Command Line
-Tools). DuckDB is compiled from vendored sources, so the first build takes
-several minutes and a few gigabytes of disk.
-
-```bash
-git clone https://github.com/JetSquirrel/DuckLocal
-cd DuckLocal
-cargo build --release
-./target/release/ducklocal
-```
-
-The binary is `./target/release/ducklocal`; use it wherever this guide says
-`ducklocal`. See [Development](development.md) for bundling a `.app`.
-:::
-
-## 2. Add the `ducklocal` command (optional) {#add-command}
-
-Everything in the app works without a terminal. If you also want to open data
-from the command line — or let an AI agent run queries with the
-[CLI](cli.md) — link the binary inside the app onto your `PATH`:
-
-```bash
-sudo mkdir -p /usr/local/bin
-sudo ln -sf /Applications/DuckLocal.app/Contents/MacOS/ducklocal /usr/local/bin/ducklocal
-ducklocal --version
-```
-
-The link follows the app, so updating DuckLocal in Applications updates the
-command too. To remove it: `sudo rm /usr/local/bin/ducklocal`.
-
-## 3. Open some data
-
-The first launch opens on a screen titled **Drop your data in**. From here,
-any of these gets data in:
-
-- **Drag** CSV, TSV, Parquet, JSON or Excel files — or a whole folder — onto
- the window.
-- Click **Open files…** or **Open folder…**.
-- From a terminal, name the paths:
-
- ```bash
- ducklocal ./sales.csv # one file
- ducklocal ./logs/ # every data file under a folder, recursively
- ducklocal './data/*.parquet' # a pattern — quote it so the shell leaves it alone
- ducklocal warehouse.duckdb # an existing DuckDB database
- ```
-
-Each file becomes a view named after the file — `sales.csv` becomes `sales` —
-and shows up under **Local files** in the sidebar with its columns and row
-count. DuckLocal reads the files where they are; nothing is copied or
-uploaded.
-
-Files you open are remembered, so the next launch starts with the same
-workspace. [Data sources](data-sources.md) has the details on formats,
-folders, patterns and databases.
-
-::: tip No data handy?
-The [first-10-minutes tutorial](tutorial.md) walks through a small sample
-file step by step.
-:::
-
-## 4. Run a query
-
-Click **New query** (or open some data — the editor appears on its own). Type
-SQL and press **⌘↵** (Cmd+Enter):
-
-```sql
-SELECT * FROM sales LIMIT 20;
-```
-
-The result appears in the panel under the editor. Switch it to **Chart** for a
-quick picture, or export it as CSV or Parquet. The toolbar above the editor
-has **Run**, **Format** and **EXPLAIN**.
-
-A shortcut worth knowing: in the sidebar, click the play button beside a
-table to get a ready-made `SELECT * … LIMIT 100`, or a column name to select
-just that column.
-
-## Where to go next
-
-- [Your first 10 minutes](tutorial.md) — a guided tour with sample data
-- [Data sources](data-sources.md) — formats, folders, patterns, databases
-- [SQL editor](sql-editor.md) — tabs, shortcuts, autocompletion, EXPLAIN
-- [Results and charts](results-and-charts.md) — filtering, export, charts
-- [Troubleshooting](troubleshooting.md) — when something does not behave
diff --git a/docs/index.md b/docs/index.md
deleted file mode 100644
index 0d2202f..0000000
--- a/docs/index.md
+++ /dev/null
@@ -1,83 +0,0 @@
----
-layout: home
-hero:
- name: DuckLocal
- text: SQL on your files, right on your Mac.
- tagline: Drop in CSV, Parquet, JSON or Excel and query it with DuckDB. No server, no setup, no upload.
- image:
- src: /assets/logo.png
- alt: DuckLocal
- actions:
- - theme: brand
- text: Get started
- link: /getting-started
- - theme: alt
- text: Try the 10-minute tutorial
- link: /tutorial
- - theme: alt
- text: Download for macOS
- link: https://github.com/JetSquirrel/DuckLocal/releases/latest
-features:
- - title: Query files where they are
- details: A file, a folder, a glob or a .duckdb database becomes queryable the moment you open it — and stays there next launch.
- link: /data-sources
- linkText: Data sources
- - title: Nothing leaves your machine
- details: No account, no telemetry, no cloud. Files are read in place and never copied or uploaded.
- link: /settings-and-data
- linkText: What is stored, and where
- - title: A focused SQL workspace
- details: Query tabs, autocompletion from your own tables, one-click formatting and EXPLAIN.
- link: /sql-editor
- linkText: The SQL editor
- - title: From rows to a picture
- details: Filter the grid, chart the result, and export it as CSV or Parquet.
- link: /results-and-charts
- linkText: Results and charts
- - title: Built for AI agents
- details: A headless CLI with a precise JSON contract, plus an official agent skill for schema-first analysis.
- link: /cli
- linkText: CLI and skill
- - title: Dashboards as files
- details: Declare queries and plots in a .dash file, or script a custom view and export it as one HTML page to share.
- link: /analysis-app
- linkText: Apps and dashboards
----
-
-
中文文档 · macOS 12+ on Apple silicon · Free and open source (Apache-2.0)
-
-## Up and running in three steps
-
-1. **[Download](https://github.com/JetSquirrel/DuckLocal/releases/latest)**
- the disk image and drag DuckLocal to Applications.
-2. **Drop a data file** — or a whole folder — onto the window. Each file
- becomes a view named after it.
-3. **Press ⌘↵** on a query:
-
-```sql
-SELECT channel, sum(revenue) AS revenue
-FROM sales
-GROUP BY channel
-ORDER BY revenue DESC;
-```
-
-New here? [Getting started](getting-started.md) covers installation and the
-first launch; [Your first 10 minutes](tutorial.md) is a guided tour with a
-sample file.
-
-
-
-## Find your way
-
-| I want to… | Read |
-| --- | --- |
-| Install DuckLocal and run a first query | [Getting started](getting-started.md) |
-| Learn by doing, with sample data | [Your first 10 minutes](tutorial.md) |
-| Open folders, globs, Excel or a `.duckdb` file | [Data sources](data-sources.md) |
-| Query objects in S3 or a compatible store | [S3 and httpfs](s3.md) |
-| Get more out of the editor | [SQL editor](sql-editor.md) · [Schema and history](schema-and-history.md) |
-| Chart or export a result | [Results and charts](results-and-charts.md) |
-| Let an AI agent query my data | [CLI and agent skill](cli.md) |
-| Build a dashboard | [Apps and dashboards](analysis-app.md) |
-| Fix something that is not working | [Troubleshooting](troubleshooting.md) |
-| Build DuckLocal from source or contribute | [Development](development.md) |
diff --git a/docs/package-lock.json b/docs/package-lock.json
deleted file mode 100644
index 12a1cce..0000000
--- a/docs/package-lock.json
+++ /dev/null
@@ -1,2564 +0,0 @@
-{
- "name": "ducklocal-docs",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "ducklocal-docs",
- "devDependencies": {
- "vitepress": "1.6.4"
- },
- "engines": {
- "node": ">=22"
- }
- },
- "node_modules/@algolia/abtesting": {
- "version": "1.25.0",
- "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.25.0.tgz",
- "integrity": "sha512-rSTin9Uta23uaewYVQEp8XI9T3iA/zrg0/1G2vhf8oFFDxFL5vybnZ5IQwsVAg4JpKxPX4/WYNKdcfWrZymk7w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/autocomplete-core": {
- "version": "1.17.7",
- "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz",
- "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/autocomplete-plugin-algolia-insights": "1.17.7",
- "@algolia/autocomplete-shared": "1.17.7"
- }
- },
- "node_modules/@algolia/autocomplete-plugin-algolia-insights": {
- "version": "1.17.7",
- "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz",
- "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/autocomplete-shared": "1.17.7"
- },
- "peerDependencies": {
- "search-insights": ">= 1 < 3"
- }
- },
- "node_modules/@algolia/autocomplete-preset-algolia": {
- "version": "1.17.7",
- "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz",
- "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/autocomplete-shared": "1.17.7"
- },
- "peerDependencies": {
- "@algolia/client-search": ">= 4.9.1 < 6",
- "algoliasearch": ">= 4.9.1 < 6"
- }
- },
- "node_modules/@algolia/autocomplete-shared": {
- "version": "1.17.7",
- "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz",
- "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "@algolia/client-search": ">= 4.9.1 < 6",
- "algoliasearch": ">= 4.9.1 < 6"
- }
- },
- "node_modules/@algolia/client-abtesting": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.59.0.tgz",
- "integrity": "sha512-bm2XN0hCSMYwStSsCBT0/PUB2BDxoyR1Lnub3c392HMEy9bi8PUSW8vR6zltVEKWG2t4PQFWMD5C07bmJxGgPg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/client-analytics": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.59.0.tgz",
- "integrity": "sha512-XOFPOTa69WuqHR6c5tMgnUUwwqQgNSzMpxmhrgA9KmxRf8WIqEa0cokHJvohk5CYb7CZx0xeSL6Bk2IUJ7Lv7Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/client-common": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.59.0.tgz",
- "integrity": "sha512-PC8ipLOYFKRTfIUY1J3FJxS6ryzWziaXmIX9/sNMoUR8L+XhF7hX2QAeUI87YVl5zujvlYTSOb+HAIqKXDjyHQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/client-insights": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.59.0.tgz",
- "integrity": "sha512-yFNcCMM5fHiyoR0HuxMrzy+VjDcmhFUZTm2IJ2DHwGsVH3B5SEob4zTmeEZ3j/AZqNnmrJOCKl/tJnBg7+84bA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/client-personalization": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.59.0.tgz",
- "integrity": "sha512-GYja6HkDt2VrQhWmB2cLx3Z5fDwI9no7q+xwCWcFrTPm5CLH9QZvK0XLO9co1FcNIDxxkMaP3AXM39/XcecEOg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/client-query-suggestions": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.59.0.tgz",
- "integrity": "sha512-Wofg7bMpWh8N5qDDZs0wy6whc+KMmdNsxgrIGp9Ug2s1Bka0uq7AjyckdxReKPHLA0Q1qH8X/SNh0wn2t2X2Lw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/client-search": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.59.0.tgz",
- "integrity": "sha512-fHnALZfbEnODczGk14Y/1YBRApp6UEpZUTexGcMUPzY7RDc7q4HN2Y6jh0KUG8Jo9B+q+wOoQEc3ziR0ErbuFg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/ingestion": {
- "version": "1.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.59.0.tgz",
- "integrity": "sha512-Fa38s1mHgoaLCT117sfJ6P78rtxUt93CYxBYpq1VOIcslaF+cH+1h5uikAPsKfxLnsuEDZHiBiaI6eNPTsQMRA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/monitoring": {
- "version": "1.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.59.0.tgz",
- "integrity": "sha512-NyNsRSqM2tF1MX7ZGw/j4rduoEJiQ5wfvbSo/CFVdEzYCjyxbGFRPOZyS/GETJG9rk1TdHOq8NZqKqk/u1fm4g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/recommend": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.59.0.tgz",
- "integrity": "sha512-nXBK2uygWtvbCOffMWqqfjjcEtp9enDKY5/2Pw/Hhw8VVaOyK2ThbGK04bNX/Le+qoK1VHYkodWGVTKfw0Otkw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/requester-browser-xhr": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.59.0.tgz",
- "integrity": "sha512-yb+4afX/zja8QwX0KmV4/ae2kyYkRknsE79CRusYS2U5D8qwn2wq0cn1x12f3tm3F3+5FgmDdbuGdQTuCLSKMQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/requester-fetch": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.59.0.tgz",
- "integrity": "sha512-Lp52TmpA1QtNmdHzs505Xwf4tgII7RAapkDSF9AAtWIBETcGaTIaXci4Rd9nS6SdaWK1BWTSqAPp5wzh6UN3Ag==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@algolia/requester-node-http": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.59.0.tgz",
- "integrity": "sha512-YYHLEs5rC6oRTFwT7bJaKBR9NSFzikeVHGAT1ffATmUQzR8XqyhHXjoieAUoR7fBU6I5cfy1FVeh5GoRgriuzA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/client-common": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/@babel/helper-string-parser": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
- "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
- "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/parser": {
- "version": "7.29.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
- "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.29.8"
- },
- "bin": {
- "parser": "bin/babel-parser.js"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/types": {
- "version": "7.29.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
- "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-string-parser": "^7.29.7",
- "@babel/helper-validator-identifier": "^7.29.7"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@docsearch/css": {
- "version": "3.8.2",
- "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz",
- "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@docsearch/js": {
- "version": "3.8.2",
- "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz",
- "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@docsearch/react": "3.8.2",
- "preact": "^10.0.0"
- }
- },
- "node_modules/@docsearch/react": {
- "version": "3.8.2",
- "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz",
- "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/autocomplete-core": "1.17.7",
- "@algolia/autocomplete-preset-algolia": "1.17.7",
- "@docsearch/css": "3.8.2",
- "algoliasearch": "^5.14.2"
- },
- "peerDependencies": {
- "@types/react": ">= 16.8.0 < 19.0.0",
- "react": ">= 16.8.0 < 19.0.0",
- "react-dom": ">= 16.8.0 < 19.0.0",
- "search-insights": ">= 1 < 3"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "react": {
- "optional": true
- },
- "react-dom": {
- "optional": true
- },
- "search-insights": {
- "optional": true
- }
- }
- },
- "node_modules/@esbuild/aix-ppc64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
- "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "aix"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-arm": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
- "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
- "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
- "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
- "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
- "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
- "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
- "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
- "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
- "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ia32": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
- "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-loong64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
- "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-mips64el": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
- "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ppc64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
- "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-riscv64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
- "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-s390x": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
- "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
- "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/netbsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
- "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/openbsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
- "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/sunos-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
- "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
- "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-ia32": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
- "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
- "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@iconify-json/simple-icons": {
- "version": "1.2.96",
- "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.96.tgz",
- "integrity": "sha512-/FmCYo/H5rIywTLV/P6OYsr0rg/31vuc8jYq0QnkOZl6m7PWIs+h5oAnSTT2cqRhOsMaKqbXcdkka6tnZ1WiUA==",
- "dev": true,
- "license": "CC0-1.0",
- "dependencies": {
- "@iconify/types": "*"
- }
- },
- "node_modules/@iconify/types": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
- "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz",
- "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@napi-rs/lzma-linux-x64-gnu": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz",
- "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": "^22.20 || ^24.12 || >=25"
- }
- },
- "node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.3.tgz",
- "integrity": "sha512-w3Jnvi1ocaVm/c7yVPpfB98XeSRBMyzp6njL5MVVbGyXjpmUkN+s6Hp4t0PqhGCCaI1ZHMKXt/w0lA1RCaLVcw==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ]
- },
- "node_modules/@rollup/rollup-android-arm64": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.3.tgz",
- "integrity": "sha512-uI/ESiaIbbRYAEhzy8PCUWDp1hB0bjAqM06mW9flOoNO4Q8DQpeoREhBR5Hegfl+wpXiguyJv6XSPzEN7OxyHQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ]
- },
- "node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.3.tgz",
- "integrity": "sha512-oxhrd1jmXLwWZ83eQYDXxuqRdkqkzrjR3JobKeuUyfdNZo11FuQIvqEOZhyIT7OBHxXoGslDDjN0cQcM6T0TqQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.3.tgz",
- "integrity": "sha512-7/YiIMghVE8DrxKvNdorAaJVdriOFgOIpdStnPx8ppx5zfTwC3jBCSEAIzB7JD5404m65THl6H93UTTVUvypmg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.3.tgz",
- "integrity": "sha512-GXFZRRoMAytaI5z6N3Zhfw0WL18Q0M8r95D5hlC4GqE/lGk8pbSJNUBoOWDfbm6dTciqHj2nU87tI5f6XhQiOg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ]
- },
- "node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.3.tgz",
- "integrity": "sha512-77W+8X3ddYgPxUpB8nZFQs2Mq+wc4HVlcSRtApXLjYBcnPMkttrSnU8VwKQjeWYhMsITHFs5cWBQ8vz1Q+5RHQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.3.tgz",
- "integrity": "sha512-FVkwK+iUC+mq+GipVK46rRVticfAPtvPUNlqlGXUDxdVk/UGjQiiiUVPUrEXdSpU2ufU0XxLGyTqDtBidDOVmg==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.3.tgz",
- "integrity": "sha512-+aGU1t3398yQOVj1Bz8o3e+KtswxAPvO+mtxtNdfXYMkXIHu7XhhkCD7/DEH9q8tF8uhDnMWvfpUKI8y1sZJsg==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "libc": [
- "musl"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.3.tgz",
- "integrity": "sha512-cR0kjpRXR2KJ2oQK8E2KTPtphs+b9hZ8IhTZubNryt/RsqgdOZBQ2Zq0q5UedtiIi0rs3jVhJh55RE1ZHUVGUA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.3.tgz",
- "integrity": "sha512-y1RYi4Q3/9ByVWSSt9kX2ustE0B7kFYbJ6zZdVZVyqopZs3yhCTwRfrjIX4vezUJInma/Gs6BOFDJg7yZmJ0IQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "libc": [
- "musl"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-loong64-gnu": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.3.tgz",
- "integrity": "sha512-DNhEA5viIj3Z5bZLE4z4oV8N5ozWqDwyt7T6KG7VdLDJ0nW+rNOYlphBl4/3HQkK75qipPLsVOfStHHOwN9WSg==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-loong64-musl": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.3.tgz",
- "integrity": "sha512-17gQCqrIpXBX2Cmi9/TygnVOqGbzsba/iaqcYSL8FY7lNugg+7AiYNs5c5nKWD+NRQha36Sa0CqkJqH4XVHwnQ==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "libc": [
- "musl"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-ppc64-gnu": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.3.tgz",
- "integrity": "sha512-6LwVnZRIyINpdku/yOcI8Tm9YqLmhHK5emmlOOnW9tO0SYEm1FmKPcsSAGp0NBlqR2P04xaND4jvN6sTHqhq8A==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-ppc64-musl": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.3.tgz",
- "integrity": "sha512-xMUqkTXlEUtI/p5AAukMwBRr1enU3efsTeF+bskeFfk8t1C9rcC8sLREcZXmTfAXEbvRdJVSonVJez3TMlbR3w==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "libc": [
- "musl"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.3.tgz",
- "integrity": "sha512-S3E94co9F9WRRqEaUoQZ38K1gCz6KiM+nL7/3ijq7fDGF3OznjS5TasgYITlvl27GQKtu4lOAOsr5MFwkijvOA==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.3.tgz",
- "integrity": "sha512-1QtRDwG42x5BJI3s9mxu5rEjDnfbSnk20HQ9/ylTAYnSwYwxMVb+Vgu34wzzTQ7ogqBybebgQNUDAvZVQ38DbA==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "libc": [
- "musl"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.3.tgz",
- "integrity": "sha512-BQhejF6ZXOpxbngiNTP12GCGQeaDVL2QXGeBVViKIYzFHM5RKxTxwUMB1fr1BeNFphFMpnRqC5QSXFSa4z6UQw==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.3.tgz",
- "integrity": "sha512-SXagRwnI2Wlwlitllu59UK/nGVbD1CKPcNqDplHwIC4BqJcpXFjD32d1R/RbuISa95HdQrZM3/7v4bKiowFaLA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.3.tgz",
- "integrity": "sha512-2IPozoEALRCziGqE8O9KMK60PMu5TS1huv4fwoeCexj+WjmcwFtX9CTOVbfXCUqcELAubEwRFPYlzb/WvwY2HQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "libc": [
- "musl"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-openbsd-x64": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.3.tgz",
- "integrity": "sha512-AoxqosUHT9IX54hFn2TiN6A7d6ZKTtE6pd2bqWtqkkNJ6HJGaU6FRouGX8L1O7R/ZwsnCnpQrHzb4pDEx+UHRQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ]
- },
- "node_modules/@rollup/rollup-openharmony-arm64": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.3.tgz",
- "integrity": "sha512-d+CaftKgmkFBzCwezMqqy1d0QNNYugqLCMcYVQWBy5SS2YfeMP8Q8ripkgx9O8IyBXXLHrJ+aaCV4U96usv6Yg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openharmony"
- ]
- },
- "node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.3.tgz",
- "integrity": "sha512-xXlDF6nR1eOuXbdDy5Hl5fmtY7teUDevF/k0O7IPoZe4Tpmdv+lgdE5JRsnhQtt37ql9P0VF2kAN9a0OCZdo+Q==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.3.tgz",
- "integrity": "sha512-YtXAgLN+JP7Ay6qG3eWhc7IHMQPzLc8r3uvhAvlJIoCz/4Q32+Bl9Fmnywidh8v1GOIMmymjovfqY9ETAtysvA==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-x64-gnu": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.3.tgz",
- "integrity": "sha512-WuWtSJRNo549vzcfZyEgfqb6zeSgn1F+UE5kQ+BCjzz0W4MGCjntUHkZVc1VRuAM7+ULaSyhiPxD1spyewFvkQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.3.tgz",
- "integrity": "sha512-+lIKX7O0+IGe7WuhATaAMMeT7B76vfhXH/l9wLQL+nvyhbw2ohYCKIdWL56JfDu75CWt5oKRP4QFH/jkMtBquA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@shikijs/core": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz",
- "integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@shikijs/engine-javascript": "2.5.0",
- "@shikijs/engine-oniguruma": "2.5.0",
- "@shikijs/types": "2.5.0",
- "@shikijs/vscode-textmate": "^10.0.2",
- "@types/hast": "^3.0.4",
- "hast-util-to-html": "^9.0.4"
- }
- },
- "node_modules/@shikijs/engine-javascript": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz",
- "integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@shikijs/types": "2.5.0",
- "@shikijs/vscode-textmate": "^10.0.2",
- "oniguruma-to-es": "^3.1.0"
- }
- },
- "node_modules/@shikijs/engine-oniguruma": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz",
- "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@shikijs/types": "2.5.0",
- "@shikijs/vscode-textmate": "^10.0.2"
- }
- },
- "node_modules/@shikijs/langs": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.5.0.tgz",
- "integrity": "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@shikijs/types": "2.5.0"
- }
- },
- "node_modules/@shikijs/themes": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.5.0.tgz",
- "integrity": "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@shikijs/types": "2.5.0"
- }
- },
- "node_modules/@shikijs/transformers": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-2.5.0.tgz",
- "integrity": "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@shikijs/core": "2.5.0",
- "@shikijs/types": "2.5.0"
- }
- },
- "node_modules/@shikijs/types": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz",
- "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@shikijs/vscode-textmate": "^10.0.2",
- "@types/hast": "^3.0.4"
- }
- },
- "node_modules/@shikijs/vscode-textmate": {
- "version": "10.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
- "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/estree": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
- "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/hast": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz",
- "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "*"
- }
- },
- "node_modules/@types/linkify-it": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
- "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/markdown-it": {
- "version": "14.2.0",
- "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.2.0.tgz",
- "integrity": "sha512-NoQ2yGlLWj4wpxMs+TYmRKk3thDrQ97agr7sFqfLsAlvoS8SNQuTrlObhFqG9iugdTtgOE9jpJ6FNM4ZGsa5xQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/linkify-it": "^5",
- "@types/mdurl": "^2"
- }
- },
- "node_modules/@types/mdast": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
- "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "*"
- }
- },
- "node_modules/@types/mdurl": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
- "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/unist": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
- "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/web-bluetooth": {
- "version": "0.0.21",
- "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
- "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@ungap/structured-clone": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz",
- "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/@vitejs/plugin-vue": {
- "version": "5.2.4",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz",
- "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.0.0 || >=20.0.0"
- },
- "peerDependencies": {
- "vite": "^5.0.0 || ^6.0.0",
- "vue": "^3.2.25"
- }
- },
- "node_modules/@vue/compiler-core": {
- "version": "3.5.42",
- "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.42.tgz",
- "integrity": "sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/parser": "^7.29.8",
- "@vue/shared": "3.5.42",
- "entities": "^7.0.1",
- "estree-walker": "^2.0.2",
- "source-map-js": "^1.2.1"
- }
- },
- "node_modules/@vue/compiler-dom": {
- "version": "3.5.42",
- "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.42.tgz",
- "integrity": "sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vue/compiler-core": "3.5.42",
- "@vue/shared": "3.5.42"
- }
- },
- "node_modules/@vue/compiler-sfc": {
- "version": "3.5.42",
- "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.42.tgz",
- "integrity": "sha512-fkCAFB4okcAANGMThboWnScp/gzWjU0ZSkVnjTIiplmMDq2uq0tIB3j+xVu4rhv5rvOgBySCysudmbMd6xRRqw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/parser": "^7.29.8",
- "@vue/compiler-core": "3.5.42",
- "@vue/compiler-dom": "3.5.42",
- "@vue/compiler-ssr": "3.5.42",
- "@vue/shared": "3.5.42",
- "estree-walker": "^2.0.2",
- "magic-string": "^0.30.21",
- "postcss": "^8.5.19",
- "source-map-js": "^1.2.1"
- }
- },
- "node_modules/@vue/compiler-ssr": {
- "version": "3.5.42",
- "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.42.tgz",
- "integrity": "sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vue/compiler-dom": "3.5.42",
- "@vue/shared": "3.5.42"
- }
- },
- "node_modules/@vue/devtools-api": {
- "version": "7.7.10",
- "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.10.tgz",
- "integrity": "sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vue/devtools-kit": "^7.7.10"
- }
- },
- "node_modules/@vue/devtools-kit": {
- "version": "7.7.10",
- "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.10.tgz",
- "integrity": "sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vue/devtools-shared": "^7.7.10",
- "birpc": "^2.3.0",
- "hookable": "^5.5.3",
- "mitt": "^3.0.1",
- "perfect-debounce": "^1.0.0",
- "speakingurl": "^14.0.1",
- "superjson": "^2.2.2"
- }
- },
- "node_modules/@vue/devtools-shared": {
- "version": "7.7.10",
- "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.10.tgz",
- "integrity": "sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "rfdc": "^1.4.1"
- }
- },
- "node_modules/@vue/reactivity": {
- "version": "3.5.42",
- "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.42.tgz",
- "integrity": "sha512-TzNNfKpb7hDxbQltwAut8VDQA5YP+BuRlxntHUuRjyKwlMvmAPbs3unhCvieijifY6vFfVBwsS7wG/C7uq+bEQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vue/shared": "3.5.42"
- }
- },
- "node_modules/@vue/runtime-core": {
- "version": "3.5.42",
- "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.42.tgz",
- "integrity": "sha512-9uACtuHs7vJGkm5Bp3xu4xRDLFTIYy5DgxpToVjqGIAhAEKwQfsaLvKINhM6nFVp6bZPRFGdDqd1g52MqKsotA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vue/reactivity": "3.5.42",
- "@vue/shared": "3.5.42"
- }
- },
- "node_modules/@vue/runtime-dom": {
- "version": "3.5.42",
- "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.42.tgz",
- "integrity": "sha512-rsCmhiWLaRxGltLwhlCWyYkFn7WAbKRh0q17eZ1A6Dq6eqc2ACQ61IIryxz0LrsvCzHSilLA9JHovVwM8CNE2g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vue/reactivity": "3.5.42",
- "@vue/runtime-core": "3.5.42",
- "@vue/shared": "3.5.42",
- "csstype": "^3.2.3"
- }
- },
- "node_modules/@vue/server-renderer": {
- "version": "3.5.42",
- "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.42.tgz",
- "integrity": "sha512-2++5dUyYS4gvo7xQXSECUDhB7TS0aOl5SeVfC5qSq1Jgfhjvegw1zqhwTIR3imZ+QYPJQw9gfcFvXGAjGZ7ajQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vue/compiler-ssr": "3.5.42",
- "@vue/runtime-dom": "3.5.42",
- "@vue/shared": "3.5.42"
- }
- },
- "node_modules/@vue/shared": {
- "version": "3.5.42",
- "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.42.tgz",
- "integrity": "sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@vueuse/core": {
- "version": "12.8.2",
- "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz",
- "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/web-bluetooth": "^0.0.21",
- "@vueuse/metadata": "12.8.2",
- "@vueuse/shared": "12.8.2",
- "vue": "^3.5.13"
- },
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- }
- },
- "node_modules/@vueuse/integrations": {
- "version": "12.8.2",
- "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.8.2.tgz",
- "integrity": "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vueuse/core": "12.8.2",
- "@vueuse/shared": "12.8.2",
- "vue": "^3.5.13"
- },
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- },
- "peerDependencies": {
- "async-validator": "^4",
- "axios": "^1",
- "change-case": "^5",
- "drauu": "^0.4",
- "focus-trap": "^7",
- "fuse.js": "^7",
- "idb-keyval": "^6",
- "jwt-decode": "^4",
- "nprogress": "^0.2",
- "qrcode": "^1.5",
- "sortablejs": "^1",
- "universal-cookie": "^7"
- },
- "peerDependenciesMeta": {
- "async-validator": {
- "optional": true
- },
- "axios": {
- "optional": true
- },
- "change-case": {
- "optional": true
- },
- "drauu": {
- "optional": true
- },
- "focus-trap": {
- "optional": true
- },
- "fuse.js": {
- "optional": true
- },
- "idb-keyval": {
- "optional": true
- },
- "jwt-decode": {
- "optional": true
- },
- "nprogress": {
- "optional": true
- },
- "qrcode": {
- "optional": true
- },
- "sortablejs": {
- "optional": true
- },
- "universal-cookie": {
- "optional": true
- }
- }
- },
- "node_modules/@vueuse/metadata": {
- "version": "12.8.2",
- "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz",
- "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- }
- },
- "node_modules/@vueuse/shared": {
- "version": "12.8.2",
- "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz",
- "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "vue": "^3.5.13"
- },
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- }
- },
- "node_modules/algoliasearch": {
- "version": "5.59.0",
- "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.59.0.tgz",
- "integrity": "sha512-wUXzaeI7B526W4y1gFg3lcxgDZ67XSgRJIiellYWOas/pLpO7rOtxm9Gr2E/C8aiSDXIgx1q5TdSsvK67Uakqw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@algolia/abtesting": "1.25.0",
- "@algolia/client-abtesting": "5.59.0",
- "@algolia/client-analytics": "5.59.0",
- "@algolia/client-common": "5.59.0",
- "@algolia/client-insights": "5.59.0",
- "@algolia/client-personalization": "5.59.0",
- "@algolia/client-query-suggestions": "5.59.0",
- "@algolia/client-search": "5.59.0",
- "@algolia/ingestion": "1.59.0",
- "@algolia/monitoring": "1.59.0",
- "@algolia/recommend": "5.59.0",
- "@algolia/requester-browser-xhr": "5.59.0",
- "@algolia/requester-fetch": "5.59.0",
- "@algolia/requester-node-http": "5.59.0"
- },
- "engines": {
- "node": ">= 14.0.0"
- }
- },
- "node_modules/birpc": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz",
- "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- }
- },
- "node_modules/ccount": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
- "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/character-entities-html4": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz",
- "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/character-entities-legacy": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
- "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/comma-separated-tokens": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
- "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/copy-anything": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.1.0.tgz",
- "integrity": "sha512-ufbM3smX/Jbnpk5wcQjzd1MgBpzmqfNETUAyZNrGwU9foRlyHoGzMMBBCRzEhQLBjZfFDE1W2ufPXX2vdWkV8Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/mesqueeb"
- }
- },
- "node_modules/csstype": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
- "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/dequal": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
- "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/devlop": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
- "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "dequal": "^2.0.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/emoji-regex-xs": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz",
- "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/entities": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
- "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=0.12"
- },
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
- "node_modules/esbuild": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
- "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=12"
- },
- "optionalDependencies": {
- "@esbuild/aix-ppc64": "0.21.5",
- "@esbuild/android-arm": "0.21.5",
- "@esbuild/android-arm64": "0.21.5",
- "@esbuild/android-x64": "0.21.5",
- "@esbuild/darwin-arm64": "0.21.5",
- "@esbuild/darwin-x64": "0.21.5",
- "@esbuild/freebsd-arm64": "0.21.5",
- "@esbuild/freebsd-x64": "0.21.5",
- "@esbuild/linux-arm": "0.21.5",
- "@esbuild/linux-arm64": "0.21.5",
- "@esbuild/linux-ia32": "0.21.5",
- "@esbuild/linux-loong64": "0.21.5",
- "@esbuild/linux-mips64el": "0.21.5",
- "@esbuild/linux-ppc64": "0.21.5",
- "@esbuild/linux-riscv64": "0.21.5",
- "@esbuild/linux-s390x": "0.21.5",
- "@esbuild/linux-x64": "0.21.5",
- "@esbuild/netbsd-x64": "0.21.5",
- "@esbuild/openbsd-x64": "0.21.5",
- "@esbuild/sunos-x64": "0.21.5",
- "@esbuild/win32-arm64": "0.21.5",
- "@esbuild/win32-ia32": "0.21.5",
- "@esbuild/win32-x64": "0.21.5"
- }
- },
- "node_modules/estree-walker": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
- "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/focus-trap": {
- "version": "7.8.0",
- "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz",
- "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "tabbable": "^6.4.0"
- }
- },
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/hast-util-to-html": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz",
- "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/hast": "^3.0.0",
- "@types/unist": "^3.0.0",
- "ccount": "^2.0.0",
- "comma-separated-tokens": "^2.0.0",
- "hast-util-whitespace": "^3.0.0",
- "html-void-elements": "^3.0.0",
- "mdast-util-to-hast": "^13.0.0",
- "property-information": "^7.0.0",
- "space-separated-tokens": "^2.0.0",
- "stringify-entities": "^4.0.0",
- "zwitch": "^2.0.4"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/hast-util-whitespace": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
- "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/hast": "^3.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/hookable": {
- "version": "5.5.3",
- "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
- "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/html-void-elements": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz",
- "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/magic-string": {
- "version": "0.30.21",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
- "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jridgewell/sourcemap-codec": "^1.5.5"
- }
- },
- "node_modules/mark.js": {
- "version": "8.11.1",
- "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz",
- "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/mdast-util-to-hast": {
- "version": "13.2.1",
- "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
- "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/hast": "^3.0.0",
- "@types/mdast": "^4.0.0",
- "@ungap/structured-clone": "^1.0.0",
- "devlop": "^1.0.0",
- "micromark-util-sanitize-uri": "^2.0.0",
- "trim-lines": "^3.0.0",
- "unist-util-position": "^5.0.0",
- "unist-util-visit": "^5.0.0",
- "vfile": "^6.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/micromark-util-character": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz",
- "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-util-encode": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz",
- "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT"
- },
- "node_modules/micromark-util-sanitize-uri": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
- "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-character": "^2.0.0",
- "micromark-util-encode": "^2.0.0",
- "micromark-util-symbol": "^2.0.0"
- }
- },
- "node_modules/micromark-util-symbol": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz",
- "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT"
- },
- "node_modules/micromark-util-types": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz",
- "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT"
- },
- "node_modules/minisearch": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz",
- "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/mitt": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
- "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/nanoid": {
- "version": "3.3.19",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz",
- "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "license": "MIT",
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/oniguruma-to-es": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-3.1.1.tgz",
- "integrity": "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex-xs": "^1.0.0",
- "regex": "^6.0.1",
- "regex-recursion": "^6.0.2"
- }
- },
- "node_modules/perfect-debounce": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
- "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/picocolors": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
- "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/postcss": {
- "version": "8.5.28",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz",
- "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "nanoid": "^3.3.18",
- "picocolors": "^1.1.1",
- "source-map-js": "^1.2.1"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- }
- },
- "node_modules/preact": {
- "version": "10.29.8",
- "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.8.tgz",
- "integrity": "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/preact"
- },
- "peerDependencies": {
- "preact-render-to-string": ">=5"
- },
- "peerDependenciesMeta": {
- "preact-render-to-string": {
- "optional": true
- }
- }
- },
- "node_modules/property-information": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz",
- "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/regex": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz",
- "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "regex-utilities": "^2.3.0"
- }
- },
- "node_modules/regex-recursion": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz",
- "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "regex-utilities": "^2.3.0"
- }
- },
- "node_modules/regex-utilities": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz",
- "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/rfdc": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
- "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/rollup": {
- "version": "4.63.3",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.63.3.tgz",
- "integrity": "sha512-1i2XreiAoMMXuPGD6Msj2xWrMMkHojNRKivInxGQcg7/1KuPuYlfUutLyh4drnOxUTHX9cHI4wFoat8D/NKaBw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/estree": "1.0.9"
- },
- "bin": {
- "rollup": "dist/bin/rollup"
- },
- "engines": {
- "node": ">=18.0.0",
- "npm": ">=8.0.0"
- },
- "optionalDependencies": {
- "@napi-rs/lzma-linux-x64-gnu": "1.5.1",
- "@rollup/rollup-android-arm-eabi": "4.63.3",
- "@rollup/rollup-android-arm64": "4.63.3",
- "@rollup/rollup-darwin-arm64": "4.63.3",
- "@rollup/rollup-darwin-x64": "4.63.3",
- "@rollup/rollup-freebsd-arm64": "4.63.3",
- "@rollup/rollup-freebsd-x64": "4.63.3",
- "@rollup/rollup-linux-arm-gnueabihf": "4.63.3",
- "@rollup/rollup-linux-arm-musleabihf": "4.63.3",
- "@rollup/rollup-linux-arm64-gnu": "4.63.3",
- "@rollup/rollup-linux-arm64-musl": "4.63.3",
- "@rollup/rollup-linux-loong64-gnu": "4.63.3",
- "@rollup/rollup-linux-loong64-musl": "4.63.3",
- "@rollup/rollup-linux-ppc64-gnu": "4.63.3",
- "@rollup/rollup-linux-ppc64-musl": "4.63.3",
- "@rollup/rollup-linux-riscv64-gnu": "4.63.3",
- "@rollup/rollup-linux-riscv64-musl": "4.63.3",
- "@rollup/rollup-linux-s390x-gnu": "4.63.3",
- "@rollup/rollup-linux-x64-gnu": "4.63.3",
- "@rollup/rollup-linux-x64-musl": "4.63.3",
- "@rollup/rollup-openbsd-x64": "4.63.3",
- "@rollup/rollup-openharmony-arm64": "4.63.3",
- "@rollup/rollup-win32-arm64-msvc": "4.63.3",
- "@rollup/rollup-win32-ia32-msvc": "4.63.3",
- "@rollup/rollup-win32-x64-gnu": "4.63.3",
- "@rollup/rollup-win32-x64-msvc": "4.63.3",
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/search-insights": {
- "version": "2.17.3",
- "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz",
- "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==",
- "dev": true,
- "license": "MIT",
- "peer": true
- },
- "node_modules/shiki": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.5.0.tgz",
- "integrity": "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@shikijs/core": "2.5.0",
- "@shikijs/engine-javascript": "2.5.0",
- "@shikijs/engine-oniguruma": "2.5.0",
- "@shikijs/langs": "2.5.0",
- "@shikijs/themes": "2.5.0",
- "@shikijs/types": "2.5.0",
- "@shikijs/vscode-textmate": "^10.0.2",
- "@types/hast": "^3.0.4"
- }
- },
- "node_modules/source-map-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "dev": true,
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/space-separated-tokens": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz",
- "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/speakingurl": {
- "version": "14.0.1",
- "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
- "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
- "dev": true,
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/stringify-entities": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
- "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "character-entities-html4": "^2.0.0",
- "character-entities-legacy": "^3.0.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/superjson": {
- "version": "2.2.6",
- "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz",
- "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "copy-anything": "^4"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/tabbable": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.5.0.tgz",
- "integrity": "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/trim-lines": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
- "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/unist-util-is": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz",
- "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "^3.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/unist-util-position": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz",
- "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "^3.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/unist-util-stringify-position": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
- "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "^3.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/unist-util-visit": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz",
- "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "^3.0.0",
- "unist-util-is": "^6.0.0",
- "unist-util-visit-parents": "^6.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/unist-util-visit-parents": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz",
- "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "^3.0.0",
- "unist-util-is": "^6.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/vfile": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
- "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "^3.0.0",
- "vfile-message": "^4.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/vfile-message": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz",
- "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "^3.0.0",
- "unist-util-stringify-position": "^4.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/vite": {
- "version": "5.4.21",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
- "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "esbuild": "^0.21.3",
- "postcss": "^8.4.43",
- "rollup": "^4.20.0"
- },
- "bin": {
- "vite": "bin/vite.js"
- },
- "engines": {
- "node": "^18.0.0 || >=20.0.0"
- },
- "funding": {
- "url": "https://github.com/vitejs/vite?sponsor=1"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.3"
- },
- "peerDependencies": {
- "@types/node": "^18.0.0 || >=20.0.0",
- "less": "*",
- "lightningcss": "^1.21.0",
- "sass": "*",
- "sass-embedded": "*",
- "stylus": "*",
- "sugarss": "*",
- "terser": "^5.4.0"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- },
- "less": {
- "optional": true
- },
- "lightningcss": {
- "optional": true
- },
- "sass": {
- "optional": true
- },
- "sass-embedded": {
- "optional": true
- },
- "stylus": {
- "optional": true
- },
- "sugarss": {
- "optional": true
- },
- "terser": {
- "optional": true
- }
- }
- },
- "node_modules/vitepress": {
- "version": "1.6.4",
- "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.6.4.tgz",
- "integrity": "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@docsearch/css": "3.8.2",
- "@docsearch/js": "3.8.2",
- "@iconify-json/simple-icons": "^1.2.21",
- "@shikijs/core": "^2.1.0",
- "@shikijs/transformers": "^2.1.0",
- "@shikijs/types": "^2.1.0",
- "@types/markdown-it": "^14.1.2",
- "@vitejs/plugin-vue": "^5.2.1",
- "@vue/devtools-api": "^7.7.0",
- "@vue/shared": "^3.5.13",
- "@vueuse/core": "^12.4.0",
- "@vueuse/integrations": "^12.4.0",
- "focus-trap": "^7.6.4",
- "mark.js": "8.11.1",
- "minisearch": "^7.1.1",
- "shiki": "^2.1.0",
- "vite": "^5.4.14",
- "vue": "^3.5.13"
- },
- "bin": {
- "vitepress": "bin/vitepress.js"
- },
- "peerDependencies": {
- "markdown-it-mathjax3": "^4",
- "postcss": "^8"
- },
- "peerDependenciesMeta": {
- "markdown-it-mathjax3": {
- "optional": true
- },
- "postcss": {
- "optional": true
- }
- }
- },
- "node_modules/vue": {
- "version": "3.5.42",
- "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.42.tgz",
- "integrity": "sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vue/compiler-dom": "3.5.42",
- "@vue/compiler-sfc": "3.5.42",
- "@vue/runtime-dom": "3.5.42",
- "@vue/server-renderer": "3.5.42",
- "@vue/shared": "3.5.42"
- },
- "peerDependencies": {
- "typescript": "*"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/zwitch": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
- "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- }
- }
-}
diff --git a/docs/package.json b/docs/package.json
deleted file mode 100644
index 6ae6b97..0000000
--- a/docs/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "ducklocal-docs",
- "private": true,
- "type": "module",
- "engines": {
- "node": ">=22"
- },
- "scripts": {
- "dev": "vitepress dev",
- "build": "vitepress build",
- "preview": "vitepress preview"
- },
- "devDependencies": {
- "vitepress": "1.6.4"
- }
-}
diff --git a/docs/public/favicon.png b/docs/public/favicon.png
deleted file mode 100644
index 1115ee9..0000000
Binary files a/docs/public/favicon.png and /dev/null differ
diff --git a/docs/public/samples/sales.csv b/docs/public/samples/sales.csv
deleted file mode 100644
index 04503b7..0000000
--- a/docs/public/samples/sales.csv
+++ /dev/null
@@ -1,225 +0,0 @@
-date,channel,region,orders,revenue
-2026-09-01,Mobile app,East,72,4181.04
-2026-09-01,Mobile app,North,92,6169.52
-2026-09-01,Mobile app,South,84,5012.28
-2026-09-01,Mobile app,West,68,4052.8
-2026-09-01,Phone,East,43,2186.98
-2026-09-01,Phone,North,31,1352.53
-2026-09-01,Phone,South,15,678.9
-2026-09-01,Phone,West,15,601.95
-2026-09-01,Store,East,42,4276.02
-2026-09-01,Store,North,38,3637.36
-2026-09-01,Store,South,22,2496.78
-2026-09-01,Store,West,54,6003.72
-2026-09-01,Web,East,81,7195.23
-2026-09-01,Web,North,61,5410.7
-2026-09-01,Web,South,69,5477.91
-2026-09-01,Web,West,53,3864.76
-2026-09-02,Mobile app,East,74,4582.08
-2026-09-02,Mobile app,North,78,5551.26
-2026-09-02,Mobile app,South,86,4802.24
-2026-09-02,Mobile app,West,70,4955.3
-2026-09-02,Phone,East,49,2129.05
-2026-09-02,Phone,North,45,2136.6
-2026-09-02,Phone,South,21,872.13
-2026-09-02,Phone,West,37,2128.98
-2026-09-02,Store,East,56,5820.64
-2026-09-02,Store,North,20,2072.6
-2026-09-02,Store,South,44,4369.2
-2026-09-02,Store,West,20,2099.4
-2026-09-02,Web,East,75,5667.0
-2026-09-02,Web,North,47,3519.83
-2026-09-02,Web,South,55,3979.8
-2026-09-02,Web,West,47,3298.93
-2026-09-03,Mobile app,East,83,4711.91
-2026-09-03,Mobile app,North,95,6247.2
-2026-09-03,Mobile app,South,87,4897.23
-2026-09-03,Mobile app,West,95,5283.9
-2026-09-03,Phone,East,16,731.52
-2026-09-03,Phone,North,44,2291.96
-2026-09-03,Phone,South,28,1356.32
-2026-09-03,Phone,West,12,633.48
-2026-09-03,Store,East,53,5880.35
-2026-09-03,Store,North,57,5621.34
-2026-09-03,Store,South,33,3307.59
-2026-09-03,Store,West,33,3578.52
-2026-09-03,Web,East,68,5310.12
-2026-09-03,Web,North,48,3657.6
-2026-09-03,Web,South,64,4516.48
-2026-09-03,Web,West,80,5796.8
-2026-09-04,Mobile app,East,81,5357.34
-2026-09-04,Mobile app,North,77,5404.63
-2026-09-04,Mobile app,South,77,5302.22
-2026-09-04,Mobile app,West,61,4158.37
-2026-09-04,Phone,East,26,1249.82
-2026-09-04,Phone,North,38,1934.2
-2026-09-04,Phone,South,30,1638.9
-2026-09-04,Phone,West,30,1436.4
-2026-09-04,Store,East,55,6034.6
-2026-09-04,Store,North,59,6747.83
-2026-09-04,Store,South,51,5293.8
-2026-09-04,Store,West,35,3608.85
-2026-09-04,Web,East,66,4832.52
-2026-09-04,Web,North,70,5554.5
-2026-09-04,Web,South,46,3279.8
-2026-09-04,Web,West,54,4763.34
-2026-09-05,Mobile app,East,73,5418.79
-2026-09-05,Mobile app,North,93,6013.38
-2026-09-05,Mobile app,South,69,3907.47
-2026-09-05,Mobile app,West,85,6031.6
-2026-09-05,Phone,East,42,1726.2
-2026-09-05,Phone,North,14,604.1
-2026-09-05,Phone,South,30,1746.6
-2026-09-05,Phone,West,38,1920.14
-2026-09-05,Store,East,39,4457.31
-2026-09-05,Store,North,27,3059.64
-2026-09-05,Store,South,59,5836.87
-2026-09-05,Store,West,51,5417.22
-2026-09-05,Web,East,74,5448.62
-2026-09-05,Web,North,70,5996.2
-2026-09-05,Web,South,78,6978.66
-2026-09-05,Web,West,70,5709.2
-2026-09-06,Mobile app,East,76,5447.68
-2026-09-06,Mobile app,North,88,5925.04
-2026-09-06,Mobile app,South,96,6958.08
-2026-09-06,Mobile app,West,80,5599.2
-2026-09-06,Phone,East,39,2287.35
-2026-09-06,Phone,North,27,1281.96
-2026-09-06,Phone,South,35,2013.55
-2026-09-06,Phone,West,43,1882.54
-2026-09-06,Store,East,38,3627.48
-2026-09-06,Store,North,50,5333.5
-2026-09-06,Store,South,42,4701.48
-2026-09-06,Store,West,42,4334.82
-2026-09-06,Web,East,77,5929.0
-2026-09-06,Web,North,49,3685.29
-2026-09-06,Web,South,81,5887.08
-2026-09-06,Web,West,65,4801.55
-2026-09-07,Mobile app,East,94,6196.48
-2026-09-07,Mobile app,North,74,4816.66
-2026-09-07,Mobile app,South,90,5544.0
-2026-09-07,Mobile app,West,82,4623.98
-2026-09-07,Phone,East,45,1926.45
-2026-09-07,Phone,North,17,915.96
-2026-09-07,Phone,South,33,1909.05
-2026-09-07,Phone,West,25,1378.5
-2026-09-07,Store,East,44,4763.44
-2026-09-07,Store,North,48,5143.2
-2026-09-07,Store,South,40,4189.6
-2026-09-07,Store,West,40,3981.2
-2026-09-07,Web,East,47,4055.16
-2026-09-07,Web,North,67,5360.67
-2026-09-07,Web,South,59,4259.8
-2026-09-07,Web,West,83,5892.17
-2026-09-08,Mobile app,East,91,6604.78
-2026-09-08,Mobile app,North,79,4871.93
-2026-09-08,Mobile app,South,95,5770.3
-2026-09-08,Mobile app,West,79,5142.11
-2026-09-08,Phone,East,40,1774.0
-2026-09-08,Phone,North,28,1399.44
-2026-09-08,Phone,South,20,1085.4
-2026-09-08,Phone,West,28,1209.6
-2026-09-08,Store,East,53,5707.04
-2026-09-08,Store,North,41,4316.89
-2026-09-08,Store,South,25,2580.0
-2026-09-08,Store,West,49,5187.63
-2026-09-08,Web,East,84,7511.28
-2026-09-08,Web,North,72,5986.8
-2026-09-08,Web,South,64,4893.44
-2026-09-08,Web,West,56,5036.08
-2026-09-09,Mobile app,East,69,4767.21
-2026-09-09,Mobile app,North,89,6023.52
-2026-09-09,Mobile app,South,97,7213.89
-2026-09-09,Mobile app,West,73,5391.78
-2026-09-09,Phone,East,30,1472.4
-2026-09-09,Phone,North,26,1308.58
-2026-09-09,Phone,South,34,1848.24
-2026-09-09,Phone,West,34,1996.14
-2026-09-09,Store,East,43,4254.85
-2026-09-09,Store,North,23,2323.46
-2026-09-09,Store,South,39,3759.21
-2026-09-09,Store,West,55,5753.0
-2026-09-09,Web,East,62,5238.38
-2026-09-09,Web,North,82,6930.64
-2026-09-09,Web,South,58,4538.5
-2026-09-09,Web,West,74,5942.2
-2026-09-10,Mobile app,East,76,5609.56
-2026-09-10,Mobile app,North,72,4371.84
-2026-09-10,Mobile app,South,80,4496.8
-2026-09-10,Mobile app,West,96,6099.84
-2026-09-10,Phone,East,47,2220.28
-2026-09-10,Phone,North,11,522.83
-2026-09-10,Phone,South,11,595.32
-2026-09-10,Phone,West,11,440.77
-2026-09-10,Store,East,22,2203.3
-2026-09-10,Store,North,26,2674.36
-2026-09-10,Store,South,42,4454.94
-2026-09-10,Store,West,34,3499.28
-2026-09-10,Web,East,77,5477.01
-2026-09-10,Web,North,49,3949.4
-2026-09-10,Web,South,57,3990.57
-2026-09-10,Web,West,81,6433.02
-2026-09-11,Mobile app,East,68,4282.64
-2026-09-11,Mobile app,North,64,3875.2
-2026-09-11,Mobile app,South,72,4880.16
-2026-09-11,Mobile app,West,72,4214.16
-2026-09-11,Phone,East,15,614.85
-2026-09-11,Phone,North,11,549.78
-2026-09-11,Phone,South,11,616.33
-2026-09-11,Phone,West,43,2160.32
-2026-09-11,Store,East,54,5685.12
-2026-09-11,Store,North,34,3677.78
-2026-09-11,Store,South,58,5697.92
-2026-09-11,Store,West,50,5717.5
-2026-09-11,Web,East,61,5454.62
-2026-09-11,Web,North,73,6291.87
-2026-09-11,Web,South,81,6530.22
-2026-09-11,Web,West,65,4909.45
-2026-09-12,Mobile app,East,67,4927.18
-2026-09-12,Mobile app,North,79,5074.17
-2026-09-12,Mobile app,South,63,3725.82
-2026-09-12,Mobile app,West,95,5423.55
-2026-09-12,Phone,East,40,2183.6
-2026-09-12,Phone,North,12,509.52
-2026-09-12,Phone,South,36,1544.76
-2026-09-12,Phone,West,36,1946.88
-2026-09-12,Store,East,37,3587.52
-2026-09-12,Store,North,49,5245.45
-2026-09-12,Store,South,33,3136.32
-2026-09-12,Store,West,57,5906.91
-2026-09-12,Web,East,68,4894.64
-2026-09-12,Web,North,80,6690.4
-2026-09-12,Web,South,48,4146.24
-2026-09-12,Web,West,64,4608.64
-2026-09-13,Mobile app,East,80,5264.0
-2026-09-13,Mobile app,North,60,3672.6
-2026-09-13,Mobile app,South,60,3516.0
-2026-09-13,Mobile app,West,84,6225.24
-2026-09-13,Phone,East,27,1422.63
-2026-09-13,Phone,North,31,1716.16
-2026-09-13,Phone,South,31,1266.35
-2026-09-13,Phone,West,23,1112.74
-2026-09-13,Store,East,26,2620.28
-2026-09-13,Store,North,30,3148.5
-2026-09-13,Store,South,38,4030.28
-2026-09-13,Store,West,30,3279.9
-2026-09-13,Web,East,73,5390.32
-2026-09-13,Web,North,45,3339.45
-2026-09-13,Web,South,53,4159.44
-2026-09-13,Web,West,61,4942.83
-2026-09-14,Mobile app,East,94,6103.42
-2026-09-14,Mobile app,North,82,4736.32
-2026-09-14,Mobile app,South,82,5849.06
-2026-09-14,Mobile app,West,90,5265.0
-2026-09-14,Phone,East,37,1845.56
-2026-09-14,Phone,North,49,2920.89
-2026-09-14,Phone,South,41,2195.96
-2026-09-14,Phone,West,25,1079.75
-2026-09-14,Store,East,20,2027.0
-2026-09-14,Store,North,56,5881.12
-2026-09-14,Store,South,24,2536.08
-2026-09-14,Store,West,48,5481.6
-2026-09-14,Web,East,47,4151.51
-2026-09-14,Web,North,67,5384.12
-2026-09-14,Web,South,83,7172.03
-2026-09-14,Web,West,67,5422.98
diff --git a/docs/results-and-charts.md b/docs/results-and-charts.md
deleted file mode 100644
index 184f3bd..0000000
--- a/docs/results-and-charts.md
+++ /dev/null
@@ -1,98 +0,0 @@
-# Results and charts
-
-**[中文](zh/results-and-charts.md)** · [Docs](index.md)
-
-The panel under the editor has two tabs: **Results** and **Chart**.
-
-## The results grid
-
-The grid shows a leading `#` row-number column, then your columns. Numeric
-columns are right-aligned, and column widths can be dragged. The `#` column
-cannot be resized.
-
-**There is no sorting.** Clicking a header does nothing — sort in SQL with
-`ORDER BY` instead.
-
-### Cell rendering
-
-| Value | Shown as |
-| --- | --- |
-| `NULL` | the literal `NULL`, in a muted color |
-| BLOB | `` |
-| GEOMETRY | `` |
-| Integral float | `3.0` |
-| Timestamp | `2026-09-17 04:21:09` — **in UTC, not local time** |
-| List / struct / map | pretty-printed |
-
-The UTC rendering is worth remembering if you are eyeballing timestamps rather
-than comparing them in SQL.
-
-### Filtering
-
-The filter box does a case-insensitive substring match **across all cells** of
-the loaded rows. It is client-side: it never queries the database, and it
-counts against the rows that were loaded, not the true result size.
-
-The filter applies when you press Enter or clear the box, not on every
-keystroke. Beside it, the grid reports `visible / total rows`.
-
-## Row limits
-
-Results are truncated at whichever of these binds first:
-
-- **100,000 rows**
-- **2,000,000 cells** — so a 400-column result materializes only about 5,000
- rows
-
-The cell budget exists because a row cap alone does not bound the work: a
-`PIVOT` over a high-cardinality column returns one column per distinct value,
-and formatting tens of millions of cells would look like a hang.
-
-Truncation is reported in a banner that quotes the real number of rows that
-were materialized. There is **no pagination and no "load more"** — narrow the
-query instead.
-
-## Copying
-
-Hovering a cell reveals a copy button that puts that cell's text on the
-clipboard. That is the only copy affordance: there is no row copy, no range
-selection, no "copy as SQL", and no context menu.
-
-## Export
-
-`Export CSV` and `Export Parquet` open a small dialog with a path field,
-pre-filled with `~/Desktop/export.csv` or `~/Desktop/export.parquet`.
-
-Two things to know:
-
-- The export **re-runs the SQL that produced the current rows**, so the file
- holds the query's full result set — not the filtered view, and not the
- truncated grid.
-- There is no file picker and no overwrite prompt. Type a path, and it is
- written.
-
-## Charts
-
-Charts are derived from the rows already in the grid, in the order the query
-returned them. **No aggregation is applied** — these are not `GROUP BY` charts.
-
-The chart type is chosen for you, based on the first column:
-
-| First column | Chart |
-| --- | --- |
-| Temporal (date / timestamp) | Area chart; x is column 0, one series per numeric column |
-| Anything else | Bar chart; column 0 is the label, the first numeric column is the value |
-
-Rows whose value cells are not numeric — `NULL`, for instance — are dropped
-before plotting.
-
-Limits, all announced in a notice line under the chart title:
-
-| Limit | Behaviour |
-| --- | --- |
-| 12 series | Extra numeric columns are dropped |
-| 1,500 points | The series is bucketed and **averaged** within each bucket |
-| 200 bars | Surplus bars are truncated, not merged |
-
-The title always reports how many points were plotted, so check it before
-trusting the shape of a curve.
diff --git a/docs/s3.md b/docs/s3.md
deleted file mode 100644
index 05f6d49..0000000
--- a/docs/s3.md
+++ /dev/null
@@ -1,95 +0,0 @@
-# S3 and httpfs
-
-**[中文](zh/s3.md)** · [Docs](index.md)
-
-DuckLocal can read objects from S3 and S3-compatible storage through DuckDB's
-`httpfs` extension. Configure it from the **S3** button in the title bar.
-
-## Configure credentials
-
-The dialog has four fields:
-
-| Field | Default | Notes |
-| --- | --- | --- |
-| Endpoint | `s3.amazonaws.com` | `http://` is honored; otherwise HTTPS is used |
-| Region | `us-east-1` | Sent as typed |
-| Access Key ID | — | Required |
-| Secret Access Key | — | Required, masked, with a reveal toggle |
-
-Confirming runs the equivalent of:
-
-```sql
-INSTALL httpfs; LOAD httpfs;
-CREATE OR REPLACE SECRET ducklocal_s3 (
- TYPE s3, PROVIDER config,
- KEY_ID '…', SECRET '…',
- REGION '…', ENDPOINT '…'
-);
-```
-
-**Credentials are session-only.** Nothing is written to disk, and they are
-dropped when you open or switch a database — reconfigure afterwards. There is
-no way to clear them other than reconfiguring.
-
-## Browse
-
-Once configured, an **S3** root appears in the sidebar. It loads lazily:
-expanding the root lists buckets, and expanding a bucket or prefix lists its
-objects. Buckets and prefixes are sorted, and objects show a human-readable
-size. A refresh button reloads a level, and also serves as the retry after an
-error.
-
-Listing is capped at **1,000 entries per level**, even when the response says
-more are available. There is no deeper paging, no prefix filter box, and no
-search — a bucket with more than a thousand objects at one level will appear
-complete when it is not.
-
-## Query objects
-
-Clicking an object whose key has a data-file extension fills the active editor
-with:
-
-```sql
-SELECT *
-FROM 's3://bucket/key'
-LIMIT 100;
-```
-
-That is an ordinary query: the read goes through `httpfs`, so DuckDB's
-`read_parquet` / `read_csv_auto` behaviour, and its pushdown, apply. The query
-replaces whatever the active tab held.
-
-Keys that are not recognized as data files are not clickable.
-
-## Limitations
-
-- **Browsing is read-only.** The browser has no upload, download-to-file,
- delete, copy, or bucket-creation action. Queries still download remote data.
-- **No session tokens.** The `X-Amz-Security-Token` header is never sent, so
- temporary STS credentials will not work — use long-lived keys, or an
- endpoint that accepts key/secret alone.
-- **Endpoint style is mostly automatic.** Virtual-hosted addressing is used
- when the host contains `amazonaws.com`, path style otherwise. For
- self-hosted gateways this is usually what you want; for one that needs the
- other style, there is no override.
-- A wrong region is retried once, using the region DuckDB reports back. If
- that fails too, the error is shown as-is.
-- Network is required: `INSTALL httpfs` fetches the extension on first use.
- Browsing sends HTTP or HTTPS requests to the configured endpoint (`http://`
- selects HTTP; otherwise HTTPS is used). These requests send metadata such
- as bucket names and key prefixes, plus authentication information in signed
- headers; browsing does not upload local database files or query results.
- Queries on remote objects download data to your machine through `httpfs`.
-
-## Troubleshooting
-
-| Symptom | Likely cause |
-| --- | --- |
-| Browsing fails immediately after configuring | Region or endpoint wrong; check the message shown in the sidebar |
-| Errors on a self-hosted endpoint | Wrong addressing style, or an endpoint that requires a session token |
-| `httpfs` installation error | No network, or a proxy that blocks the extension download |
-| Credentials seem forgotten | A database was opened or switched, which clears them by design |
-
-When DuckLocal is packaged as a signed app, loading the `httpfs` extension
-needs the `com.apple.security.cs.disable-library-validation` entitlement; the
-shipped packaging script already includes it.
diff --git a/docs/schema-and-history.md b/docs/schema-and-history.md
deleted file mode 100644
index e759342..0000000
--- a/docs/schema-and-history.md
+++ /dev/null
@@ -1,84 +0,0 @@
-# Schema browser and history
-
-**[中文](zh/schema-and-history.md)** · [Docs](index.md)
-
-The sidebar has two tabs: **Schema** and **History** (**表结构** and **查询历史** in Chinese). Beside them, the collapse button (or **⌘B**) hides the sidebar; the button at the left of the title bar, or ⌘B again, brings it back. Whether it is hidden is remembered.
-
-## The schema tree
-
-The tree shows, from the top:
-
-- **Local files** — the data files you have registered, each named by its
- view, with its row count. The file name appears beside the view name only
- when the two differ (`sales_2` from `sales.csv`), and the folder when two
- files share a view name; hover a row for the full path. Its children are the
- view's columns.
-- **Apps** / **Dashboards** — the analysis apps and `.dash` dashboards you
- have opened recently, sorted by name so a row stays put when you click it.
- Click one to reopen it as a tab, the way you would a file; the × on hover
- takes it off the list, leaving its files and any open tab alone. An entry
- whose path no longer exists is dropped from the list.
-- **S3** — present once [S3 is configured](s3.md). Loads lazily.
-- Each database, then its schemas, then tables and views, then columns.
-
-Tables show an estimated row count; views show none. Column rows show the
-DuckDB data type. The system database and the `information_schema`,
-`pg_catalog`, and `system` schemas are hidden.
-
-**Refresh schema** reloads the catalog and re-attaches the registered files.
-
-## Generating a SELECT
-
-Three things fill the active editor when clicked:
-
-| Click | Generated SQL |
-| --- | --- |
-| A table's play button | `SELECT * FROM db.schema.table LIMIT 100;` |
-| A table's column name | `SELECT col FROM db.schema.table LIMIT 100;` |
-| An S3 object that is a data file | `SELECT * FROM 's3://bucket/key' LIMIT 100;` |
-
-Names are fully qualified as `database.schema.table`, and double-quoted only
-when they are not plain identifiers.
-
-Note that all three **replace the entire buffer** of the active tab — they do
-not insert at the cursor. The same is true of clicking a history entry. Save
-anything you care about before clicking around.
-
-## Altering a column type
-
-A column row offers a type action (not available on view columns, so attached
-CSV and Parquet columns cannot be retyped). It opens a free-text dialog
-pre-filled with the current type and runs:
-
-```sql
-ALTER TABLE db.schema.table ALTER COLUMN "col" SET DATA TYPE ;
-```
-
-There is no picker and no validation list — any DuckDB type string works,
-including parameterised ones like `DECIMAL(10,2)`. An invalid type comes back
-as an error notification. Success reloads the catalog.
-
-Renaming and dropping columns, and editing column comments, are not available.
-
-## Removing a registered file
-
-The **×** on a file row asks for confirmation, then drops the view and forgets
-the registration. **The file on disk is not touched.**
-
-## Query history
-
-Every run is recorded — successes and failures alike — with a local-time
-timestamp, duration in milliseconds, row count (or affected-row count for
-DML), and the error text if it failed. Failed entries are shown in red with a
-*Failed* tag.
-
-The list shows the newest **200** entries. Clicking a row refills the active
-editor with that SQL and focuses it, replacing whatever was there.
-
-There is no retention policy and no pruning: the history table grows without
-bound, and the UI simply shows the most recent 200. There is also no search,
-no filter, no export, and no way to delete an entry from the interface.
-
-History is stored in DuckLocal's own database file, not in the database you
-have open, so it survives switching databases and losing your workspace. See
-[Settings and app data](settings-and-data.md) for where it lives.
diff --git a/docs/settings-and-data.md b/docs/settings-and-data.md
deleted file mode 100644
index 9cbbbf1..0000000
--- a/docs/settings-and-data.md
+++ /dev/null
@@ -1,104 +0,0 @@
-# Settings and app data
-
-**[中文](zh/settings-and-data.md)** · [Docs](index.md)
-
-DuckLocal keeps one file on disk. Everything else lives in memory for the
-duration of a session.
-
-## Where things are stored
-
-| Platform | Path |
-| --- | --- |
-| macOS | `~/Library/Application Support/DuckLocal/history.duckdb` |
-| Linux (if built there) | `~/.local/share/ducklocal/history.duckdb` |
-
-That single DuckDB file holds three tables: the query history, the registered
-data files, and a small key/value settings table — the interface language, the
-open app and dashboard tabs, the recent-documents list, and the app folders
-you have trusted. It lives beside a `.wal`
-while the app is running.
-
-Your data is never copied into it. Registered files are referenced by path and
-re-attached on launch.
-
-## What survives a restart
-
-| Remembered | Where |
-| --- | --- |
-| Registered data files — path, view name, kind | app data file |
-| Query history, including failures | app data file |
-| Interface language | app data file |
-| Interface size | app data file |
-| Whether the sidebar is hidden | app data file |
-| Open app and dashboard tabs, with their titles | app data file |
-| Recently opened apps and dashboards (the sidebar's **Apps** / **Dashboards**) | app data file |
-| App folders you chose to trust | app data file |
-
-| Not remembered | Notes |
-| --- | --- |
-| Open query tabs and their SQL | in memory only — past queries are in **History** |
-| The results panel contents | in memory only |
-| Which database file is open | each launch starts in memory unless you name one |
-| Window size and position | fixed at 1440×900, minimum 960×600 |
-| Sidebar and results panel sizes | fixed per launch |
-| The results filter | in memory only |
-| **The theme** | always starts light — see below |
-| S3 credentials | session-only by design |
-
-The theme is the odd one out: the language toggle persists, the theme toggle
-does not, and every launch begins in light mode.
-
-## Language
-
-The `EN` / `中` button in the title bar switches the interface language
-immediately and records the choice.
-
-On first run — before any setting is stored — the language is taken from the
-system locale: `LC_ALL` or `LANG` containing `zh` selects Chinese, anything
-else selects English. An unrecognized stored value falls back to Chinese.
-
-A few strings are deliberately not translated: `DuckLocal`, the `S3` and
-`EXPLAIN` button labels, the `EN` / `中` toggle, and the credential placeholders.
-Engine and network error messages are surfaced verbatim and are always in
-English, whatever the interface language is.
-
-## Themes
-
-The sun/moon button toggles between the light and dark theme. There is no
-theme picker and no theme file to edit — the two modes are what you get.
-
-## Interface size {#interface-size}
-
-Text, icons and controls scale together, in four steps:
-
-| Size | Base text | Editor text |
-| --- | --- | --- |
-| Small | 13px | 12px |
-| Default | 14px | 13px |
-| Large | 16px | 15px |
-| Extra large | 18px | 17px |
-
-Choose one from the **Aa** button in the title bar, or step through them with
-**⌘+** (larger), **⌘−** (smaller) and **⌘0** (back to default) — these work
-wherever the focus is, the SQL editor included. The choice is remembered, and
-survives switching between light and dark.
-
-Panel sizes you dragged, and the height of a dashboard's plots, stay in pixels:
-they are yours to adjust, not the interface's.
-
-## Resetting
-
-To start over — clearing history, registered files, remembered tabs, trusted
-app folders and the language setting —
-quit DuckLocal and remove its app data directory:
-
-```bash
-rm -rf ~/Library/Application\ Support/DuckLocal
-```
-
-The next launch creates it fresh. **Your data files are never affected by
-this**, only DuckLocal's own records.
-
-## Troubleshooting
-
-Symptoms, causes and fixes are collected on the [Troubleshooting](troubleshooting.md) page.
diff --git a/docs/sql-editor.md b/docs/sql-editor.md
deleted file mode 100644
index aaf5e23..0000000
--- a/docs/sql-editor.md
+++ /dev/null
@@ -1,93 +0,0 @@
-# SQL editor
-
-**[中文](zh/sql-editor.md)** · [Docs](index.md)
-
-Each query tab holds its own editor buffer. The editor highlights real SQL via
-tree-sitter, indents with 2 spaces, and shows line numbers.
-
-## Tabs
-
-| Control | What it does |
-| --- | --- |
-| `+` | Appends a new query tab and focuses it |
-| Click a tab | Switches to it |
-| `×` | Closes a tab — hidden while only one tab remains, so the last one cannot be closed |
-| Rename (toolbar) | Opens a dialog to retitle the active tab; an empty name falls back to `Query N` |
-
-Tabs live in memory only. Their SQL is not saved, so quitting loses every tab
-except the fact that you get one fresh tab next launch.
-
-## Running SQL
-
-Press **⌘↵** (Cmd+Enter) with the editor focused, or use the `Run` button.
-
-While a query is running, pressing run again does nothing: there is **no
-cancel and no timeout**. Long queries run as long as DuckDB needs, and other
-database work queues behind them. If something appears hung, that is why —
-check the status bar, or quit and restart.
-
-How a statement is treated depends on its leading keyword. `SELECT`, `WITH`,
-`SHOW`, `DESCRIBE`, `EXPLAIN`, `PRAGMA`, `SUMMARIZE`, `VALUES`, `FROM`,
-`TABLE`, `PIVOT`, and `CALL` produce a result set. Anything else (DDL, DML)
-reports `Done · N rows affected · took …` instead of a grid. Leading `--`
-comments are skipped when deciding; block comments are not.
-
-## Errors
-
-A failed statement shows an alert titled *Query failed* with DuckDB's message
-verbatim. The message comes from the engine and is always in English,
-whatever the interface language is. Nothing is written to the grid, and the
-attempt is still recorded in [history](schema-and-history.md) with a failure
-marker.
-
-## Format
-
-`Format` runs the buffer through `sqlformat` with a 2-space indent and
-uppercased keywords, then replaces the entire buffer. It is a no-op on an
-empty buffer.
-
-## EXPLAIN
-
-`EXPLAIN` runs `EXPLAIN ` and shows the plan as plain monospace text
-with the elapsed time, switching the results panel back to the Results tab.
-
-## Autocompletion
-
-The completion menu is catalog-aware. Candidates are ranked:
-
-1. Tables and columns from the schema (up to 35 entries)
-2. DuckDB function names
-3. SQL keywords
-
-At most 50 items are offered. Matching is a case-insensitive **prefix** match
-on the identifier immediately to the left of the cursor, so `sel` completes to
-`SELECT` but `elect` completes to nothing. A function inserts its name and an
-opening parenthesis; identifiers that are not plain are inserted double-quoted.
-
-The keyword and function lists are a curated subset — not every DuckDB
-function will appear.
-
-## Keyboard shortcuts
-
-DuckLocal defines a handful of shortcuts itself; everything else comes from
-the editor and table components, and behaves as it does in any macOS text
-field:
-
-| Shortcut | Action |
-| --- | --- |
-| ⌘↵ | Run the query |
-| ⌘S | Save a dashboard's source, in its source view |
-| ⌘+ / ⌘− / ⌘0 | Make the interface larger / smaller / default size — see [Interface size](settings-and-data.md#interface-size) |
-| ⌘B | Hide or show the sidebar |
-| ⌘F / ⇧⌘F | Find / replace in the editor |
-| ⌘Z / ⇧⌘Z | Undo / redo |
-| ⌘A | Select all |
-| ⌘C / ⌘X / ⌘V | Copy / cut / paste |
-| ⌥⌘↑ / ⌥⌘↓ | Add a cursor above / below |
-| ⌘← / ⌘→ / ⌥← / ⌥→ | Move by line / word |
-| ⌘↑ / ⌘↓ | Move to start / end of document |
-| ⌘⌫ / ⌥⌫ | Delete to start of line / previous word |
-
-There is no menu bar and no command palette. Every other action is a button:
-in the toolbar above the editor, in the tab bar, in the sidebar, and in the
-title bar.
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
deleted file mode 100644
index 5107b7e..0000000
--- a/docs/troubleshooting.md
+++ /dev/null
@@ -1,78 +0,0 @@
-# Troubleshooting
-
-**[中文](zh/troubleshooting.md)** · [Docs](index.md)
-
-Find the symptom, read the cause, apply the fix. If yours is not here,
-[open an issue](https://github.com/JetSquirrel/DuckLocal/issues) with what you
-did and what you saw.
-
-## Installing and launching
-
-| Symptom | Cause and fix |
-| --- | --- |
-| The app will not open on an Intel Mac | Releases are built for Apple silicon only. [Build from source](getting-started.md#install) on Intel |
-| `ducklocal: command not found` | The disk image installs the app, not a command. [Link the binary onto your PATH](getting-started.md#add-command) |
-| The terminal is busy while the window is open | Opening the GUI from a terminal runs it in the foreground. Launch from Applications instead, or leave that terminal to it |
-| History, settings or remembered files stop being saved | A second DuckLocal is running and holds the app-data file. Quit the other one and relaunch |
-
-## Opening data
-
-| Symptom | Cause and fix |
-| --- | --- |
-| `File not found` on a path you named | The path does not exist, or is relative to a different directory than you think. Use an absolute path to be sure |
-| A folder reports no data files | Nothing under it matched `.csv`, `.tsv`, `.txt`, `.parquet`, `.json`, `.ndjson`, `.jsonl`, `.xlsx`, `.xls`, `.xlsb` or `.ods` |
-| A folder produced fewer files than expected | Hidden entries and symlinks are skipped, and one open request attaches at most 256 files. Open subfolders separately |
-| A path opened as a database unexpectedly | Any existing file that is not a data file is treated as a DuckDB database. If it will not open, DuckLocal falls back to memory and shows the error |
-| **Not attached …: the database already has a table or view named …** | The open database has its own relation with the name a remembered file uses. DuckLocal never replaces it. Rename or drop one of the two, or remove the file from **Local files** and open it again to get a new name |
-| **Cannot restore relative path …** | A file was remembered by a relative path, which cannot be resolved in a new session. Remove it from **Local files** and open it again |
-| A view shows `sales_2` instead of `sales` | Another file or table already had that name, so the new one got a suffix |
-| A file's view is stale | Views read the file on every query. If a CSV's columns changed shape, use **Refresh schema** in the sidebar |
-
-## Running queries
-
-| Symptom | Cause and fix |
-| --- | --- |
-| **Run** does nothing | A query is already running. There is no cancel and no timeout; quitting and relaunching is the only way to abandon one |
-| **⌘↵** shows the editor instead of running | On the first-run screen, ⌘↵ means "give me an editor". Press it again to run |
-| Results stop early with a truncation notice | The 100,000-row or 2,000,000-cell cap was reached. Narrow the query; there is no pagination |
-| Timestamps look shifted | The grid renders timestamps in UTC, not local time |
-| Clicking a header does not sort | There is no client-side sorting. Use `ORDER BY` |
-| Clicking a table or history entry wiped my SQL | Those clicks replace the whole editor buffer. Use a new query tab for scratch work |
-| An export silently replaced a file | Export writes to the path you give without asking. Choose a new name |
-
-## S3
-
-| Symptom | Cause and fix |
-| --- | --- |
-| S3 credentials were forgotten | They are session-only by design, and opening or switching a database clears them. Configure S3 again |
-| Configuring S3 fails offline | The first use runs `INSTALL httpfs`, which downloads the extension. Connect once, then it is cached |
-| Temporary (STS) credentials are rejected | No session token is sent. Use long-lived keys — see [S3 and httpfs](s3.md#limitations) |
-| A bucket looks smaller than it is | Listing stops at 1,000 entries per level. Query with a glob such as `'s3://bucket/prefix/*.parquet'` instead |
-
-## Apps and dashboards
-
-| Symptom | Cause and fix |
-| --- | --- |
-| An app tab asks **Run this app?** | The first time a folder opens as an app, DuckLocal asks before running its code, because an app's SQL can read and write anything the SQL editor can. **View source** first if you did not write it; **Trust and run** is remembered for that folder |
-| A dashboard plot says a query must be read-only | A `.dash` query tried to write (DDL, DML, `COPY`, `ATTACH`, …). Dashboards only run read-only statements; move the setup into the SQL editor |
-| A `PIVOT` in a dashboard is rejected | Without an explicit `IN (…)` list, DuckDB splits `PIVOT` into more than one statement. List the values: `PIVOT t ON channel IN ('Web', 'Store') USING sum(revenue)` |
-
-## Appearance
-
-| Symptom | Cause and fix |
-| --- | --- |
-| The theme resets to light on every launch | The theme is not persisted; the language is |
-| Text or icons are too small or too large | Use the **Aa** button in the title bar, or ⌘+ / ⌘− / ⌘0. See [Interface size](settings-and-data.md#interface-size) |
-| The interface is in the wrong language | Use the `EN` / `中` button in the title bar; the choice is remembered |
-
-## Starting over
-
-To clear history, remembered files, open tabs and settings, quit DuckLocal and
-remove its app-data directory:
-
-```bash
-rm -rf ~/Library/Application\ Support/DuckLocal
-```
-
-Your data files are never touched — only DuckLocal's own records. See
-[Settings and app data](settings-and-data.md) for what lives there.
diff --git a/docs/tutorial.md b/docs/tutorial.md
deleted file mode 100644
index a589852..0000000
--- a/docs/tutorial.md
+++ /dev/null
@@ -1,133 +0,0 @@
-# Your first 10 minutes
-
-**[中文](zh/tutorial.md)** · [Docs](index.md)
-
-A guided tour: open a small sales file, ask it a few questions, chart the
-answers, and export one. It assumes DuckLocal is installed — if not, start
-with [Getting started](getting-started.md).
-
-## 1. Get the sample file
-
-Download [sales.csv](/samples/sales.csv) — two weeks of made-up orders, 224
-rows. Or from a terminal:
-
-```bash
-curl -LO https://jetsquirrel.github.io/DuckLocal/samples/sales.csv
-```
-
-It has five columns:
-
-| Column | Type | Example |
-| --- | --- | --- |
-| `date` | DATE | `2026-09-01` |
-| `channel` | VARCHAR | `Web`, `Mobile app`, `Store`, `Phone` |
-| `region` | VARCHAR | `North`, `South`, `East`, `West` |
-| `orders` | BIGINT | `72` |
-| `revenue` | DOUBLE | `4181.04` |
-
-You did not have to tell DuckLocal any of that: DuckDB reads the header and
-infers the types on its own.
-
-## 2. Open it
-
-Drag `sales.csv` onto the DuckLocal window. (Or click **Open files…**, or run
-`ducklocal sales.csv` if you [added the command](getting-started.md#add-command).)
-
-A notification confirms **Created view sales.** In the sidebar, **Local
-files** now lists `sales` with its 224 rows; expand it to see the columns and
-their types.
-
-## 3. Look at the rows
-
-In the sidebar, click the play button beside `sales`. The editor fills with a
-`SELECT * … LIMIT 100` for it — press **⌘↵** to run it.
-
-The grid under the editor shows the rows. Try the filter box above it: type
-`Store` and press Enter to keep only the rows that mention it. The filter
-works on the rows already loaded and never re-queries.
-
-## 4. Ask a question
-
-Replace the SQL with this and press **⌘↵**:
-
-```sql
-SELECT channel, round(sum(revenue), 2) AS revenue
-FROM sales
-GROUP BY channel
-ORDER BY revenue DESC;
-```
-
-| channel | revenue |
-| --- | --- |
-| Mobile app | 290549.76 |
-| Web | 289544.8 |
-| Store | 240067.6 |
-| Phone | 82511.2 |
-
-Now switch the results panel from **Results** to **Chart**. Because the first
-column is text, you get a bar per channel, sized by the first numeric column.
-
-::: tip Autocompletion
-While you type, the editor offers table and column names from the sidebar
-first, then DuckDB functions and SQL keywords — type `rev` and `revenue` is
-the first suggestion.
-:::
-
-## 5. Chart a trend
-
-Charts are drawn from the rows exactly as the query returns them, so shape
-the result the way you want it plotted. One column per channel gives one line
-per channel:
-
-```sql
-SELECT
- date,
- round(sum(revenue) FILTER (WHERE channel = 'Web'), 2) AS web,
- round(sum(revenue) FILTER (WHERE channel = 'Mobile app'), 2) AS mobile,
- round(sum(revenue) FILTER (WHERE channel = 'Store'), 2) AS store
-FROM sales
-GROUP BY date
-ORDER BY date;
-```
-
-With a date in the first column, **Chart** draws an area chart over time,
-one series per numeric column. [Results and charts](results-and-charts.md)
-covers the rules and limits.
-
-## 6. Export the answer
-
-With the trend still in the results panel, click **Export CSV**. The dialog
-suggests `~/Desktop/export.csv`; change the path if you like and confirm.
-
-Export re-runs the query, so the file holds the full result — not just what
-is visible in the grid. **It overwrites an existing file without asking.**
-
-## 7. Find it again tomorrow
-
-Open the **History** tab in the sidebar: every query you ran is there, the
-failed ones included. Click one to put it back in the editor — note that this
-replaces what the editor holds.
-
-Quit DuckLocal and launch it again. `sales` is still under **Local files**:
-opened files are remembered by path and re-read on every launch, so an edit
-to the CSV shows up the next time you query it.
-
-## 8. Bonus: the same question from a terminal
-
-If you added the `ducklocal` command, the CLI answers without opening a
-window — handy for scripts and for AI agents:
-
-```bash
-ducklocal query --format md --sql "
- SELECT channel, round(sum(revenue), 2) AS revenue
- FROM 'sales.csv' GROUP BY channel ORDER BY revenue DESC"
-```
-
-Leave out `--format md` for structured JSON. The [CLI guide](cli.md) and the
-official agent skill are the place to start.
-
-## Next
-
-- Point DuckLocal at your own files or folders — see [Data sources](data-sources.md)
-- Query files in S3-compatible storage — see [S3 and httpfs](s3.md)
-- Build a dashboard of saved queries — see [Analysis apps and dashboards](analysis-app.md#dashboard-specs-dash)
diff --git a/docs/zh/analysis-app.md b/docs/zh/analysis-app.md
deleted file mode 100644
index f44c959..0000000
--- a/docs/zh/analysis-app.md
+++ /dev/null
@@ -1,250 +0,0 @@
-# 分析应用(JavaScript)
-
-**[English](../analysis-app.md)** · [文档](index.md)
-
-分析应用是工作区里的一个标签页,内容是你自己写的 JavaScript 应用。JavaScript 就是声明本身:
-应用的 `render` 函数即界面描述,时间范围控件、多选 chips、KPI 卡片、图表与表格都由你组合。
-分析应用通过下面的 host 函数读取窗口已经打开的数据库——同样的表、视图与已附加文件。
-
-它适合为数据做一个专门的界面:看板、只针对某张表的浏览器、每天早上跑一次的报表。分析应用像查询一样
-开合,和 SQL 标签并列。
-
-## 打开应用
-
-以下任一种方式都会立刻加载目录:
-
-- 标签条末尾的 **+**,然后选 **打开应用…**;
-- 把应用目录拖到窗口上;
-- 在命令行里指定:`ducklocal examples/analysis_app`。
-
-无法作为应用的目录——文件、已不存在的路径、或没有 `main.js` 的文件夹——会在**标签页内**被拒绝,
-并说明是哪个目录、缺了什么。取消选择或选错目录都不会丢掉正在工作的应用。
-
-应用用标签自带的关闭按钮关闭,也能像查询标签一样重命名。已打开的应用目录会被记住:下次启动自动
-恢复;如果某个目录已被移走或删除,会按名字报告出来,而不是悄悄忘记。
-
-应用在自己的 DuckDB 连接上运行,连的是主窗口已经打开的那个数据库:两边看到同样的表、视图与已附加
-文件,但互不等待——一个看板刷新六条语句,不会再把 SQL 编辑器冻住。第二个连接带不过来的是连接级状态:
-SQL 编辑器里建的 `TEMP` 表、设的 `SET`,应用看不到,反之亦然。所有应用共用这一个连接,因此应用之间
-仍然会互相排队。
-
-## 查看定义
-
-应用头部的 **查看定义** 会显示该目录与入口文件的源码(只读)。应用就是一个普通的 JavaScript
-目录,这就是它的全部定义——没有第二份隐藏形式需要查看。
-
-## 重新加载
-
-保存应用目录下的 `.js` 或 `.mjs` 文件,应用就会重新加载。宿主每 250 毫秒扫描一次目录,并在最后一次
-变更后等待 200 毫秒,因此一次保存多个文件只会触发一次重载。以点开头的文件、`node_modules/` 与
-`target/` 会被跳过。只有当前显示的目录会被监控。
-
-应用头部的 **重新加载** 可以随时手动触发同样的流程。
-
-重载失败时,**上一个成功加载的应用会保留**,错误信息显示在它上方、就在这个标签页里。如果应用从未
-成功加载过,错误信息会占据标签页主体。
-
-重载重启的是应用的 JavaScript,不是它的连接。应用连接是一个所有应用共用的长连接,所以应用在连接上
-留下的状态——一次 `ATTACH`、一个 `SET`、一张 `TEMP` 表——在重载之后仍然存在。请把应用的初始化写得
-可以安全地执行两遍(`ATTACH IF NOT EXISTS …`、`CREATE OR REPLACE TEMP TABLE …`),而不是假设每次
-加载都面对一个干净的连接。
-
-## Host 函数
-
-从 `ducklocal` 模块导入:
-
-```js
-import { catalog, query, appDir, sqlLiteral, sqlIdentifier } from "ducklocal";
-```
-
-它们都在应用连接上执行——和主窗口同一个数据库——出错时抛出 JavaScript `Error`。除 `appDir` 之外
-都可以在任何时刻调用;`appDir` 在应用加载期间作答。
-
-### `catalog()`
-
-```ts
-catalog(): Promise
-
-interface CatalogEntry {
- database: string; // 例如 "memory"
- schema: string; // 例如 "main"
- name: string; // 例如 "orders"
- kind: "table" | "view";
- estimated_rows: number | null;
- comment: string | null;
- columns: { name: string; type: string }[]; // type 为 DuckDB 类型,如 "DECIMAL(38,10)"
-}
-```
-
-连接上每个数据库里的所有表与视图——窗口打开的那个数据库,以及任何被 `ATTACH` 的数据库(无论由窗口
-还是应用自己附加)——但不包括 DuckDB 自身的 catalog(`information_schema`、`pg_catalog`、`system`)。
-`entry.database` 标明该条目属于哪个数据库,限定名字时请用上它。表排在视图之前。DuckDB 的标识符
-不区分大小写,且表与视图共用一个命名空间,所以用它拼 SQL 时请带上 schema 限定。
-
-### `query(sql, limit?)`
-
-```ts
-query(sql: string, limit?: number): Promise
-
-interface QueryResult {
- columns: { name: string; type: string }[];
- rows: any[][]; // 每行一个数组,每个元素对应一列
- row_count: number; // 实际返回的行数
- truncated: boolean; // 行数上限提前截断时为 true
- elapsed_ms: number;
-}
-```
-
-- `limit` 默认为 **1000**;小于 1 会被拒绝,超过 100000 会被截断到该上限。此外还有 2,000,000 个
- 单元格的预算,因此很宽的结果返回的行数会少于 `limit`。**请务必读取 `truncated`。**
-- `type` 是 DuckLocal 渲染的 Arrow 类型,例如 `Int64`、`Utf8`、`Decimal(38, 10)`、
- `Timestamp(Microsecond, None)`。
-- 语句按原样 prepare 并执行;`query()` 不会拆分或校验多语句 SQL。
-
-### `appDir()`
-
-```ts
-appDir(): string // 应用自己的目录,绝对路径
-```
-
-应用不能读文件系统,所以这是它引用随应用一起分发的数据的方式——
-`query("SELECT * FROM " + sqlLiteral(appDir() + "/orders.csv"))` 不需要用户附加任何文件、
-也不需要窗口里打开任何东西。它在应用加载期间作答:请在 `init()` 里调用一次并保存结果。
-
-`panelDir()` 是改名之前留下的旧别名,仍然可用;新代码请使用 `appDir()`。
-
-### `sqlLiteral(value)`
-
-```ts
-sqlLiteral(value: string): string // 例如 "O'Brien" -> 'O''Brien'
-```
-
-把字符串转义并加引号成 SQL 字符串字面量。凡是来自应用自身状态的值——筛选条件、渠道 id、日期——
-都应该用它,而不是手工拼进 SQL。包含 `NUL` 字节会被拒绝,因为 SQL 字面量无法承载它。
-
-### `sqlIdentifier(name)`
-
-```ts
-sqlIdentifier(name: string): string // 例如 "my table" -> "my table"
-```
-
-同一件事的另一半:表名、视图名、列名**这类标识符**,加上双引号,让它被当作一个名字读取,并且严格按
-写法匹配。标识符不是字符串字面量,而应用用来拼 SQL 的名字往往不是自己起的——`catalog()` 返回的是数据库
-里实际有的东西,`my table`、`Order`、名字里带 `"` 的都会出现。空名字和含 `NUL` 字节的名字会被拒绝:
-它们都不指向任何东西,加上引号只会把这件事掩盖掉。
-
-```js
-const entry = (await catalog()).find((table) => table.name === "orders");
-const from = `${sqlIdentifier(entry.schema)}.${sqlIdentifier(entry.name)}`;
-const rows = await query(`SELECT count(*) FROM ${from}`);
-```
-
-### 单元格编码
-
-当“不丢信息”时,单元格就是普通 JSON——`null`、布尔、字符串,以及能被 IEEE double 精确表示的数值。
-其余情况一律以带 `encoding` 字段的对象返回,与 `ducklocal query` 命令行的编码完全一致,因此不会有
-数字被悄悄截断:
-
-| 值 | 传入 JavaScript 的形式 |
-| --- | --- |
-| `NULL` | `null` |
-| `BOOLEAN` | `true` / `false` |
-| ±2^53−1 以内的整数 | number |
-| 更大的整数(`HUGEINT`、`UBIGINT` 等) | `{ "encoding": "integer", "value": "170141183460469231731687303715884105727" }` |
-| `DECIMAL` | `{ "encoding": "decimal", "value": "12345678901234567890.1234567890" }` |
-| 非有限 `FLOAT`/`DOUBLE` | `{ "encoding": "float", "value": "inf" }` |
-| `DATE` | `{ "encoding": "date", "unit": "Day", "value": "19783" }` |
-| `TIMESTAMP` | `{ "encoding": "timestamp", "unit": "Microsecond", "value": "1709296496789000" }` |
-| `TIME` | `{ "encoding": "time", "unit": "Microsecond", "value": "45296789000" }` |
-| `INTERVAL` | `{ "encoding": "interval", "months": 0, "days": 1, "nanos": "0" }` |
-| `BLOB`、`GEOMETRY` | `{ "encoding": "hex", "value": "00ff" }` |
-| `LIST` / `ARRAY` | 数组 |
-| `STRUCT` | `{ "encoding": "struct", "fields": [["name", ], …] }` |
-| `MAP` | `{ "encoding": "map", "entries": [[, ], …] }` |
-| `UNION` | `{ "encoding": "union-value", "value": }` |
-
-`DATE` 的 `19783` 是自 1970-01-01 起的天数;`TIMESTAMP` 与 `TIME` 是按 `unit` 计的纪元或当日零点
-以来的计数。这些是存储值而非格式化文本:请自行格式化,若想要字符串形式,请在 SQL 中把列
-`CAST` 成 `VARCHAR`。
-
-## 可用组件
-
-应用使用与 shell 相同的组件目录,从 `gpui-component` 导入:`GroupBox`(带标题的卡片)、
-`Progress`(条)、`Toggle`、`Badge`、`Tag`、`Alert`、`Empty`、`Collapsible`、
-`DescriptionList`、`DataTable` 与 `DataTableState`、`Table` 家族、`Sidebar`、`Resizable`、
-`Scroll`,以及图表 `BarChart`、`LineChart`、`AreaChart`、`PieChart`、`RadarChart`。
-布局原语(`div`、`h_flex`、`v_flex`、`Button`)来自 `gpui-kit` 与 `gpui-base`。
-
-没有 `ToggleGroup`:分段控件或多选 chips 用一组 `Toggle` 组合而成。仓库里的
-[`examples/analysis_app`](https://github.com/JetSquirrel/DuckLocal/tree/main/examples/analysis_app)
-就是完全用这些搭出来的一份完整看板,最适合拿来照抄。
-
-每个应用目录都带一份 `jsconfig.json` 和生成的 `gpui-kit.d.ts`。保存之前,先按运行时真正
-会给它的 API 检查一遍:
-
-```sh
-npx --yes -p typescript tsc -p <应用目录>/jsconfig.json --noImplicitAny false
-```
-
-它会报出组件上并不存在的方法——这类错误运行时只会在渲染时、在应用自己的错误区域里拒绝,
-而那里不会写进 DuckLocal 的日志。它也有盲区:`gpui-base` 的原语(`div`、`h_flex`、`v_flex`、
-`Button.new`)类型很松,写错方法这里查不出来,仍然只能在渲染时才暴露。
-
-## SQL 没有沙箱
-
-`query()` 在 DuckLocal 自己的数据库上执行,**拥有 DuckLocal 与用户的权限**。应用能做的事和 SQL 编辑器完全一样,
-包括 `COPY` 写文件、`ATTACH` 其他数据库、`INSTALL`/`LOAD` 扩展,以及查询已配置好的 S3 视图。请把应用
-里的 JavaScript 当作你主动选择运行的代码,就像对待一个 shell 脚本那样。
-
-因此这个选择会明确征求你的同意。一个文件夹第一次作为应用打开时——无论来自命令行、拖放、选择器,还是启动时恢复的
-标签页——标签页会先说明应用的 SQL 能做什么并等待:**先看源码**只显示入口文件、不运行,**信任并运行**才会运行。
-同意按文件夹记住,之后的启动以及保存后的每次重新加载都不再询问。`ducklocal export --html` 运行的是你在命令行
-上点名的应用,不会询问。
-
-应用拿不到的,是进程的其他能力:
-
-- **没有文件系统、网络、进程与环境变量模块。** 除非宿主授予,否则脚本无法使用 `fs`、`net`、
- `process` 等模块;DuckLocal 一律不授予。
-- **拿不到 S3 凭据。** S3 浏览器的密钥保存在 DuckLocal 自己的 Rust 状态里,由 DuckLocal 的签名客户端使用,
- 从不会写入 DuckDB 连接,host 模块也无法访问。不过,如果用户自己的连接配置了 httpfs,应用依然可以
- 执行使用它的 SQL。
-- **host 模块就是全部接口。** 只有上面几个函数会跨到 Rust 一侧。
-
-## 导出为 HTML
-
-`ducklocal export --html <目录>` 把应用跑一次,并把它向数据库询问的内容写进一个自包含 HTML 文件,用来把应用里的数字发给没有 DuckLocal 的人。命令、选项和退出码见 [CLI 指南](cli.md#把应用导出为独立-html)。捕获在应用安静下来时结束,或到达 `--timeout` 秒数(默认 15)时结束,以先到者为准;若是超时结束,JSON 里的 `stop_reason` 为 `deadline`,报告中会出现明显的警告,说明内容可能不完整。
-
-报告给的是应用的数据,不是它的界面:导出的只有 `query()` 返回的内容,按调用顺序、每条不同的语句一节——同一条语句重复执行会并入同一节,并标注执行了多少次——而且每次调用都会被捕获,包括非 `SELECT` 的语句(如 `ATTACH`)。`catalog()` 调用会成为一节表与列的清单,不占语句编号。语句第一行若以 `-- title: …` 注释开头,该注释会成为这一节的名字(「Statement N — title」);SQL 本身按原文展示。每个结果都以表格呈现;当结果恰好是两列、不超过 25 行、且第二列为非负数值时(第一列作为柱子的标签),表格上方还会附一张内联柱状图,其他情况下只有表格。
-
-报告**不包含**应用画出的任何东西:KPI 卡片、图表、以及由 JavaScript 常量拼出来的表格都不会进入文件——导出记录的是查询,不是渲染;应用画的是原生组件,内容在布局时才确定,没有任何可读出并复现图表柱子的描述。报告里必须出现的常量,可以改从 SQL 里送出:`SELECT * FROM (VALUES ('Q1', 120), ('Q2', 95)) AS t(quarter, total)`。
-
-因为它是加载状态,只在点击时才执行的语句不在报告里,重新加载之后的内容也不在。应用的 JavaScript 权限始终如一:导出就是运行应用,和把它开在标签页里完全一样。
-
-## Dashboard 规格文件(.dash) {#dashboard-specs-dash}
-
-`.dash` 文件把 dashboard 声明为数据——query 与 plot block,没有 JavaScript——适合「已保存查询 + 标准图表」的常见场景。文件格式与 `ducklocal check` 校验见 [CLI 指南](cli.md#校验-dashboard-规格文件)。
-
-打开方式与应用相同:在标签栏的 `+` 菜单里选 **打开 Dashboard…**,在命令行指定(`ducklocal dashboard.dash`),或把文件拖到窗口上,就会以 dashboard 标签页的形式打开,与查询、应用并列。标签页在窗口自己的连接上执行规格里的查询——因此能看到 `TEMP` 表等连接级状态,也会与编辑器的查询排队——并把每个 plot 画成竖直堆叠中的一格,分隔条可拖动调整高度。只有只读语句会被执行:可能写入的查询(DDL、DML、`COPY`、`ATTACH` 等)在到达连接之前就被拒绝,因此打开别人发来的 `.dash` 文件不会改动你的数据。某个 plot 的查询失败时,原因显示在它自己的格子里,其余部分照常绘制。工具栏的重新加载会重读文件并重跑所有查询;重载后的规格若不再通过校验,不会替换掉仍在工作的 dashboard,而是在上方显示原因。已打开的 dashboard 会像应用一样被记住,下次启动自动恢复。
-
-标签页同时也是编辑器:源码视图可以直接修改文件,带语法高亮(heredoc 里的 SQL 与 SQL 编辑器同样着色)、补全和诊断,用保存按钮或 ⌘S 写回——保存后的规格若不再通过校验,仍在工作的 dashboard 不会被替换,并会显示原因。在 GUI 之外,`ducklocal lsp` 把同样的补全、诊断、悬停和跳转定义提供给任何支持 LSP 的编辑器(见 [CLI 指南](cli.md#用-lsp-编辑-dashboard-规格文件))。
-
-## 已知限制
-
-- **标签页里的应用没有窗口级浮层。** shell 的对话框、面板、toast 与 tooltip 浮层,只有在 shell 自己的
- 根视图是窗口首视图时才能被找到。而在标签页里,这个位置由 DuckLocal 的根视图占据——否则 DuckLocal 自己的对话框
- 会出问题——因此 `window.open_dialog`、`window.open_sheet`、`window.push_toast` 会抛出
- `TypeError`,内容是 *needs a ShellRoot as the window's first view*,和你自己代码里的其他错误一样会
- 显示出来。tooltip 是例外,也是唯一静默的一个:它由 hover 监听器挂上,那里没有地方抛错,所以应用里的
- tooltip 只是永远不出现。请把应用界面设计在自身范围内——用展开区域代替模态框。
-- **重新加载由 DuckLocal 自己实现,而不是 shell 的 watcher。** gpui-shell 的热重载依赖
- `runtime.watch` / `runtime.refresh`,它们只对运行时自己创建的 `ShellRoot` 生效;嵌入宿主走不到这条
- 路径,因此 DuckLocal 自己监控目录,并通过 `load_application` / `mount_application` 重载。代价是:
- 只监控 `.js`/`.mjs` 文件,应用读取的其他文件不会被监控。
-- **重载在主线程上编译。** 脚本运行时不可跨线程传递,因此应用的挂载发生在主线程;模块图很大时,
- 加载期间窗口会卡顿。首次加载会推迟到标签页的第一帧之后,所以无论哪种情况标签页都会立刻出现。
-- **所有应用共用一个连接,且不能取消。** 应用不再阻塞主窗口,但仍然互相阻塞:它们共用一个连接、
- 一把锁,所以一个应用里的长查询会拖住其他应用。做不到一个应用一个连接——host 函数拿到的是参数,
- 不是调用者,`query()` 执行的那一刻没有任何东西能说明是哪个应用在问。取消执行中的查询同样没有暴露:
- 请把应用的语句写得有界,而不是指望中途叫停。
-- **`row_count` 是返回的行数,不是匹配的行数。** 当 `truncated` 为 `true` 时,后续行不可得;需要计数
- 请在 SQL 里聚合,而不是在 JavaScript 里数。
diff --git a/docs/zh/cli.md b/docs/zh/cli.md
deleted file mode 100644
index 23d865d..0000000
--- a/docs/zh/cli.md
+++ /dev/null
@@ -1,260 +0,0 @@
-# AI CLI 与官方 skill
-
-**[English](../cli.md)** · [文档](index.md)
-
-## 无窗口运行
-
-`ducklocal query` 执行 SQL,不初始化 GUI、历史、注册文件、语言设置或 GUI 全局连接。每次调用创建独立连接。无参数或文件/目录/glob 参数仍打开原有 GUI;名为 `query`、`profile`、`export`、`check`、`dash` 的 GUI 路径请写 `./query`、`./profile`、`./export`、`./check`、`./dash`。
-
-`ducklocal export` 是唯一会启动窗口平台的子命令:分析应用要渲染,渲染需要窗口。它打开一个隐藏窗口、绘制一帧,在应用不再查询后退出,屏幕上不会出现任何东西。
-
-当前发布范围仍是 **macOS 12 及以上、Apple 芯片**,不依赖额外 DuckDB CLI。包含此功能的 app 可直接调用内部二进制:
-
-```bash
-/Applications/DuckLocal.app/Contents/MacOS/ducklocal --help
-/Applications/DuckLocal.app/Contents/MacOS/ducklocal --version
-```
-
-也可从本仓库 `cargo build --locked`,运行 `./target/debug/ducklocal`。以下示例假定该二进制在 PATH 中,名称为 `ducklocal`。旧版可能没有 `query`,先检查 help。JSON 和 Parquet 已编入二进制,不在查询时下载。
-
-## 查询选项
-
-```bash
-ducklocal --help
-ducklocal --version
-ducklocal query --help
-ducklocal query --sql "SELECT 1 AS n"
-ducklocal query --sql "SELECT 1 AS n" --format md
-ducklocal query --sql-file analysis.sql --limit 100
-ducklocal query --sql-file - < analysis.sql
-ducklocal query --database warehouse.duckdb --sql "SHOW TABLES"
-```
-
-- 必须且只能提供 `--sql SQL` 或 `--sql-file FILE`。文件必须为 UTF-8;`-` 从 stdin 读取。每次只允许一条 SQL。打开目标数据库或执行操作前用 DuckDB 的解析器验证;支持注释、引号中的分号、尾部分号,不会只执行脚本的一部分。
-- `--database PATH` 默认以**只读**打开**已有文件**;省略则用新的内存数据库。`--read-write` 必须搭配 `--database`,显式允许写入/创建数据库,不创建父目录。打开失败不回退到内存。
-- `--limit N` 为正整数,默认 1000,限制返回行数;另有 2,000,000 个单元格的预算。额外读取一行判断 `truncated`。这不限制计算量或 DuckDB 内部结果缓冲;单个大单元格仍可能占用很多内存。
-- `--format json`(默认)是下面的契约;`--format md` 把同一份结果渲染成 Markdown 表格,供文档或 agent 阅读。其余行为完全一致:同样的 SQL、同样的限制、同样的错误。
-- 重复/未知参数、缺失值、空 SQL、非法 limit 均报错。参数和值分开,不支持 `--flag=value`。相对路径基于进程工作目录,不是 SQL 文件目录。Shell 路径需引号;SQL 路径中的单引号双写(`'O''Brien.csv'`);SQL 标识符用双引号。
-
-**数据库只读不是文件系统或网络沙箱。** `COPY` 仍可写文件。执行前确认输出路径、覆盖文件、数据库修改、安装扩展和外部访问都符合用户授权。不自动安装扩展,不自动重试;授权后仍可显式执行 `INSTALL`/`LOAD`,已有扩展可能自动加载。失败命令也可能已经产生副作用(例如输出失败前已写入),重试前检查目标。
-
-### Markdown 输出
-
-`--format md` 是一种渲染,不是第二份契约:值就是 JSON 里的那些值,按结果表格展示它们的方式写出。
-
-| 值 | 渲染结果 |
-| --- | --- |
-| `NULL` | `NULL` |
-| 整数、DECIMAL、浮点 | 值本身携带的全部数字——`DECIMAL(38,10)` 保留其标度,`NaN`/`inf`/`-inf` 原样写出 |
-| `DATE` | `YYYY-MM-DD` |
-| `TIMESTAMP` | `YYYY-MM-DD HH:MM:SS[.ffffff]`,只在确有小数时带小数。不附加时区;原始计数在 `--format json` 里 |
-| `TIME` | `HH:MM:SS[.ffffff]` |
-| `INTERVAL` | `1 months 2 days 3000 ns` |
-| `BLOB`、`GEOMETRY` | `0x00ff`,过长时以 `…` 省略 |
-| `LIST`、`STRUCT`、`MAP` | `[1, 2]`、`{x: 1}`,超过 120 字符省略 |
-
-单元格里的 `|` 会被转义、换行变成 ` `,所以值不会破坏所在表格。零行结果后跟 `_0 rows._`;被 `--limit` 或单元格预算截断的结果后跟 `_Truncated at N rows: …_`——预览不该读起来像完整答案。错误行为不变:JSON 写到 stderr,stdout 为空。
-
-## 探查与转换
-
-确认文件实际存在后:
-
-```bash
-ducklocal query --sql "DESCRIBE SELECT * FROM 'sales.csv'"
-ducklocal query --sql "SELECT * FROM 'sales.csv'" --limit 20
-ducklocal query --sql "SELECT sum(amount) AS total FROM 'sales.csv'"
-# 仅在确认此输出路径已获授权后运行:
-ducklocal query --sql "COPY (SELECT * FROM 'sales.csv') TO 'sales.parquet' (FORMAT PARQUET)"
-ducklocal query --sql "SELECT count(*), sum(amount) FROM 'sales.parquet'"
-ducklocal query --sql "DESCRIBE SELECT * FROM 'events.json'"
-```
-
-先 DESCRIBE,不猜 `amount` 等列名。完整统计应在 SQL 内聚合,不能累加截断预览。CLI 不共享 GUI 注册视图,也不共享其他调用的内存表;需要持久化时显式使用数据库:
-
-```bash
-# 分两次调用执行,每次只有一条语句;写入必须获得授权。
-ducklocal query --database warehouse.duckdb --read-write --sql "CREATE TABLE sales AS SELECT * FROM 'sales.csv'"
-ducklocal query --database warehouse.duckdb --sql "SELECT count(*) FROM sales"
-```
-
-数据库锁冲突直接报错。关闭其他写入者(包括 GUI),或使用授权的副本;不要删锁文件、不要偷偷换成别的数据库。
-
-## JSONL 与嵌套 JSON
-
-`read_ndjson_objects` 是换行分隔 JSON(每行一个对象,`.jsonl`/`.ndjson`)的读取函数;`read_json`/`read_json_auto` 读取的是 JSON 文档(一个数组或单个对象)。读 JSONL 文件时请显式写出读取函数,不要依赖自动探测。`json_extract_string(col, '$.a.b[0].c')` 沿嵌套路径——对象键与数组下标——取值并返回 VARCHAR:
-
-```bash
-ducklocal query --sql "SELECT json_extract_string(event, '$.payload.items[0].sku') AS sku, count(*) AS n FROM read_ndjson_objects('events.jsonl') GROUP BY 1 ORDER BY n DESC"
-```
-
-叶子不是字符串、想要 JSON 形式时改用 `json_extract`。
-
-## 数据画像
-
-`ducklocal profile` 回答的是「该画什么图、用什么刻度、怎么格式化数字」这一类在动手之前必须确定的问题。`DESCRIBE` 只告诉你某列是 `DOUBLE`;画像会告诉你它实际只用两位小数、最大值是中位数的一千倍、日期在中间断了十一天。
-
-```bash
-ducklocal profile sales.csv
-ducklocal profile orders.parquet
-ducklocal profile "my orders" --database warehouse.duckdb
-```
-
-TARGET 是数据文件(`csv`、`tsv`、`txt`、`parquet`、`json`、`ndjson`、`jsonl`),或工作簿(`xlsx`、`xls`、`xlsb`、`ods`,其第一个工作表会被导入为 TEMP 表再画像),或者配合 `--database` 时是表名/视图名。带点的名字按 `schema.table` 拆开并逐段加引号,所以带空格或大写的名字可以照原样写。TARGET 指向不存在的东西是参数错误(退出码 2),不是 SQL 错误。
-
-返回一个 JSON 对象:`target`、`relation`(统计实际执行的 SQL 关系)、`row_count`、`elapsed_ms`,以及按关系自身列序排列的 `columns`。每列包含:
-
-| 字段 | 含义 |
-| --- | --- |
-| `name`、`type` | 与 `DESCRIBE` 一致 |
-| `nulls` | 该列为 `NULL` 的行数 |
-| `distinct` | 精确值,不是估算 |
-| `unique` | 当 `distinct` 等于 `row_count` 时出现且为 `true` |
-| `min`、`max` | 以文本给出,`DECIMAL` 因此不丢位数 |
-| `decimals` | 小数点后**实际用到**的位数,不是声明的 scale |
-| `median` | 该列真实存在的一个值,不是两个值之间的插值 |
-| `max_over_median` | 最大值是中位数的多少倍 —— 决定用线性刻度还是对数刻度的那个数 |
-| `covered_days`、`span_days`、`missing_days` | 该列出现过的天数、首尾之间的天数、以及两者之差:`0` 表示连续,非零就是折线会直接画过去的空洞 |
-
-`decimals`、`median`、`max_over_median` 只出现在数值列,日期三项只出现在 DATE/TIMESTAMP 列。`LIST`、`STRUCT`、`MAP`、`UNION` 列只报 `nulls` —— 这些类型没有定义 `min`/`max`。
-
-统计是精确的,会完整扫描整个关系,所以一次画像等于一次全表扫描。`--limit` 对它不适用:对样本做画像不算画像。
-
-## 把应用导出为独立 HTML
-
-`ducklocal export` 回答的是「那个应用当时显示的是什么」,给没有 DuckLocal 的人看。它把应用跑一次——同一套运行时、同一个 host 模块、与 `query` 相同的数据库规则——然后把应用 `query()` 发出的语句和结果写进一个自包含的 HTML 文件。
-
-```bash
-ducklocal export --html examples/analysis_app
-ducklocal export --html --out report.html --database warehouse.duckdb apps/sales
-```
-
-- `--html` 必填,也是目前唯一的格式。APP 是应用目录(其中含 `main.js`)或指向该 `main.js`,按 GUI 的解析方式解析;两者都不是则报参数错误(退出码 2)。
-- `--out FILE` 指定输出路径,默认写到工作目录下的 `./<应用目录名>.html`。目标已存在时必须加 `--force`,且这项检查发生在运行应用之前——拒绝不花任何代价。
-- `--database PATH` 与 `--read-write` 的含义与 `query` 完全一致:已有文件默认只读,省略则为内存库。应用就在这条连接上运行,所以需要写库的应用要加 `--read-write`。
-- `--timeout SECONDS` 为正整数,默认 15:应用停止查询片刻后捕获结束,或到达时限结束,以先到者为准。
-- 该命令会启动窗口平台:应用要渲染,渲染需要窗口。窗口是隐藏的、不会出现。
-
-stdout 为单个 JSON 对象:
-
-```json
-{"html":"/abs/report.html","app":"/abs/app","queries":2,"rows":212,"app_errors":0,"captured_ms":630,"stop_reason":"settled"}
-```
-
-`queries` 是捕获到的语句数,`rows` 是其中成功语句的行数合计,`app_errors` 是应用运行期间记录的报错条数。`stop_reason` 为 `settled` 表示应用自己安静了下来,`deadline` 表示被 `--timeout` 时限截断——此时报告可能缺少语句,HTML 中会出现明显的警告说明这一点。
-
-报告包含:应用目录、所用数据库、导出时间,以及每条语句一节——SQL、列名与 Arrow 类型、结果表格,并在结果是「每行一个名称 + 一个数值」时附一张柱状图。`catalog()` 调用会成为一节表/视图/列清单。同一语句被反复执行只出现一次,展示最后一次结果。
-
-报告**不包含**应用自身的布局与图表。应用画的是原生组件,柱状图的数值是在布局时决定的、没有任何可读出的描述——所以导出给出的是应用所依据的数据,而不是它搭出的界面。筛选、开关和后续刷新同样不在其中,文件里也没有 JavaScript。它是应用加载状态的快照,报告开头就写明了这一点。
-
-应用的 JavaScript 权限与平时完全一样:`query()` 可以 `COPY`、`ATTACH`、写文件。导出不是沙箱。
-
-退出码:**0** 已写出文件;**2** 命令行有误、应用路径指不到东西、目标文件已存在;**1** 应用加载失败(不写文件),或应用加载后失败(仍写出报告,错误记在报告里,stderr 消息会指明文件路径)。应用类失败的错误 kind 为 `app`。
-
-## 校验 dashboard 规格文件
-
-`.dash` 文件以声明的方式描述一个 dashboard——像 Terraform 声明基础设施那样,用 block 写查询和图表,用引用连接它们——而不是像分析应用那样用脚本来画。两种格式并存:规格文件覆盖「查询 + 标准图表」,人和 agent 都容易写、容易 diff;需要定制布局和交互时仍用应用。
-
-```hcl
-query "latency" {
- sql = < 'NULL'`。
-
-两个修法可以合并:`try_cast(NULLIF(amount, 'NULL') AS DOUBLE)`。
-
-## 数据库文件
-
-任何**存在**且不是数据文件的路径,都会被当作 DuckDB 数据库打开,而不是作为视图挂载。扩展名无关紧要:`.db`、`.duckdb` 乃至 `.md` 路径都会被当作数据库,能否真正打开由 DuckDB 决定。
-
-有两点值得了解:
-
-- **无法通过指定名字来新建数据库。** 不存在的路径会被报告为找不到。请打开一个已存在的数据库文件,或者以内存模式启动。
-- 如果文件无法作为 DuckDB 打开,DuckLocal 会回退到内存模式的工作区并报告该错误,而不是启动失败。
-
-在数据库文件已打开的情况下挂载数据文件,会**把这些视图写进那个数据库文件** —— 它们会持久保存在那里,而不只是存在于本次会话中。
-
-## 命名
-
-文件对应的视图以其文件名主干命名,并被整理成合法的标识符。如果该名字在连接中已被占用,DuckLocal 会追加计数:`events`,然后是 `events_2`、`events_3`。因此,位于不同目录、主干同名的两个文件会得到不同的视图。
-
-重复判断依据的是路径文本本身,因此 `./a.csv` 和 `a.csv` 会被当成两个不同的文件。
-
-## 限制
-
-- **每次打开请求最多 256 个数据文件。** 这个上限针对的是一次请求中的所有路径,而不是每个文件夹分别计数 —— 它的存在是为了避免误把整个用户主目录拖进来时,连接被占用好几分钟。触发上限时,DuckLocal 会给出提示,并挂载前 256 个文件。
-- 启动时从上次会话重新挂载的文件不受该上限约束。
-
-## 管理已注册的数据源
-
-已注册的文件出现在侧栏的**本地文件**分组中,每个文件都带有视图名、文件名和行数。选中某个文件会为它生成一条 `SELECT` 语句。
-
-文件行上的 **×** 会在确认对话框之后把它移除。移除会删除视图并忘掉这条注册;**底层文件不会受到任何影响。**
-
-**刷新 Schema** 会重新加载 catalog 和已注册的文件。
-
-## 会被记住的内容
-
-已注册文件的清单 —— 它们的路径、视图名和类型 —— 存放在 DuckLocal 自己的历史数据库中,并在下次启动时重新挂载,因此你离开时的工作区就是你回来时的工作区。数据库文件本身*不会*被记住:除非你指定了某个数据库,否则每次启动都从内存模式开始。
-
-磁盘上的位置参见[设置与应用数据](settings-and-data.md)。
diff --git a/docs/zh/development.md b/docs/zh/development.md
deleted file mode 100644
index ee419f0..0000000
--- a/docs/zh/development.md
+++ /dev/null
@@ -1,138 +0,0 @@
-# 开发
-
-**[English](../development.md)** · [文档](index.md)
-
-## 构建与运行
-
-```bash
-cargo run # 启动空工作区
-cargo run -- ./data/logs/ # 或直接打开数据
-cargo test # 运行测试套件
-```
-
-DuckDB 从随仓库携带的源码构建,因此首次构建耗时很长,还需要几 GB 磁盘空间。dev profile 的依赖以 `opt-level = 3` 编译,这让首次构建更慢,但开发迭代仍然顺畅——之后只有 `ducklocal` 自身会重新编译。
-
-**工具链。** 仓库里既没有 `rust-toolchain.toml`,也没有 `rust-version` 字段,因此实际的版本下限由依赖决定:`duckdb` 要求 `1.85.1`。CI 直接使用 stable。
-
-## 被钉住的工具链
-
-UI 工具包、分析应用所依赖的脚本运行时、应用绘制所用的组件目录,是同一个仓库
-`longbridge/gpui-kit` 里的三个 crate,`rquickjs` 也被 patch 到同一个仓库。四者一起钉在同一个
-revision 是有意为之:两个 revision 会让构建里出现两份 `gpui-base` 或两份 `rquickjs`,报出来的是
-一大片 trait 不匹配,而其中没有一条会说出原因。
-
-```bash
-./scripts/check-deps.sh
-```
-
-它检查 Cargo 不会替你检查的三件事:依赖与 `[patch]` 用的是同一个 revision、`Cargo.lock` 与之一致、
-没有任何 crate 在构建里出现两次(一次来自该仓库,一次来自 crates.io)。它只读这两个清单文件,
-所以离线、即时。CI 会在跑测试之前执行它。要升级工具包,请把 `Cargo.toml` 里所有 `rev` 一起改掉,
-执行 `cargo update`,再跑一次这个脚本。
-
-按 revision 钉依赖,也是这个 crate 无法发布到 crates.io 的原因:git 依赖和 `[patch]` 在那里都不被接受。
-分发走的是下面的 macOS 签名包。
-
-## 打包 macOS 应用
-
-```bash
-./scripts/bundle.sh
-# 生成 target/release/DuckLocal.app
-```
-
-它会组装好应用包——可执行文件位于 `Contents/MacOS/ducklocal`,再加上 `assets/Info.plist` 和 `assets/AppIcon.icns`——但**不做签名**。产物在你自己的机器上可以运行,到了其他机器上会被 Gatekeeper 拒绝。
-
-## 打包、签名与公证
-
-```bash
-scripts/package-macos.sh
-```
-
-请在仓库根目录运行;它会把 `DuckLocal.app` 和 `dmg-root` 写到当前工作目录,dmg 就放在它们旁边。脚本在没有凭据时会拒绝运行——未公证的产物在当前 macOS 上用户根本打不开,所以它宁可快速失败,也不愿意意外产出一个。
-
-需要以下内容:
-
-| 变量 | 含义 |
-| --- | --- |
-| `NOTARY_KEY` | App Store Connect API 密钥(`.p8`)的路径 |
-| `NOTARY_KEY_ID` | 该密钥的 Key ID |
-| `NOTARY_ISSUER` | 该密钥所属的 issuer UUID |
-| Developer ID Application 签名身份 | 当钥匙串中恰好只有一个时自动检测,否则设置 `MACOS_SIGN_IDENTITY` |
-
-脚本会按参数中的版本号给应用包打上版本,用 `--options runtime --timestamp` 和 `scripts/entitlements.plist` 对内部可执行文件和应用本身签名,构建一个带 `/Applications` 符号链接的 UDZO dmg,**对 dmg 本身签名**,用 `notarytool submit --wait --timeout 300m` 提交,把公证票据装订到文件上,最后执行 `stapler validate` 和两次 `spctl --assess` 校验。
-
-使用前需要了解两件事:
-
-- 五小时的超时是客户端等待时间,而不是取消。超时后提交仍会在 Apple 那边继续处理,票据稍后依旧可以领取——但**票据只对提交时的那串字节有效**,所以不要重新构建;请对你提交的那个文件装订票据。
-- 只有 dmg 经过公证,因此内部的 `.app` 上没有装订票据。从刚挂载的镜像中首次启动时需要联网,以便向 Apple 校验。
-
-必须启用 `com.apple.security.cs.disable-library-validation` 授权,因为 DuckDB 会用 `dlopen` 加载它的扩展——`httpfs` 就是其中之一。
-
-## CI 与发布
-
-| 工作流 | 触发条件 | 作用 |
-| --- | --- | --- |
-| `ci.yml` | 推送到 `main`、任意 pull request | 在 `macos-latest` 上先执行 `scripts/check-deps.sh`,再执行 `cargo test --locked` |
-| `release.yml` | 匹配 `v*` 的 tag,或手动指定版本触发 | 构建 `aarch64-apple-darwin`,把签名证书导入临时钥匙串,运行 `package-macos.sh`,上传 `ducklocal-macos-arm64.dmg`,然后用自动生成的说明创建 GitHub 发布 |
-| `gh-pages.yml` | `main` 分支上 `docs/` 或工作流有改动时,或手动触发 | 使用 Node.js 24 构建文档站并部署到 GitHub Pages |
-
-发布构建需要以下仓库密钥:`MACOS_CERTIFICATE`、`MACOS_CERTIFICATE_PWD`、`NOTARY_KEY_BASE64`、`NOTARY_KEY_ID` 和 `NOTARY_ISSUER`。
-
-## 平台支持
-
-Apple 芯片上的 macOS 是唯一受支持的目标平台,而且这是有意为之:打包路径是 `.app` 加 dmg,没有 Windows 或 Linux 产物,发布工作流也是这么写的。`src/` 里没有任何 `cfg(target_os)`,窗口层还带着 X11 和 Wayland feature 一起构建,所以构建出 Linux 版本是可能的——但 CI 里没有任何环节跑它,也没有做过测试。
-
-## 文档站
-
-`docs/` 下的指南同时以站点形式发布,用 [VitePress](https://vitepress.dev/) 构建。
-需要 Node.js 22 或更新版本;**推荐 Node.js 24 LTS**,文档工作流也使用该版本。
-在仓库根目录执行:
-
-```bash
-npm --prefix docs ci # 按锁文件安装文档依赖
-npm --prefix docs run dev # http://localhost:5173/DuckLocal/
-npm --prefix docs run build # 产物在 target/docs-site
-npm --prefix docs run preview # http://localhost:4173/DuckLocal/
-```
-
-英文页面直接位于 `docs/`,中文页面位于 `docs/zh/`。这些就是 README 链接、GitHub 渲染的
-同一批 Markdown,不生成源页面副本。`docs/.vitepress/config.mts` 定义两种语言、各自的
-导航与侧栏、本地搜索,以及 GitHub Pages 的 `/DuckLocal/` 基础路径;还会为旧中文
-`.zh-CN.html` 地址生成保留查询参数和锚点的跳转页。`docs/.vitepress/theme/` 在原生默认
-主题上增加少量品牌样式,`docs/assets/` 存放图片,`docs/public/` 存放 favicon。
-
-文档包固定使用稳定版 VitePress 1.6.4。其间接开发工具依赖目前存在 npm audit 安全告警;
-开发与预览服务器应仅在本机使用,不要暴露给不可信网络。发布的站点是静态文件。
-
-`.github/workflows/gh-pages.yml` 会在 `main` 分支的 `docs/` 或该工作流本身有改动时
-构建并部署,也支持手动触发。**需要先在 Settings → Pages 里把 Source 选为
-“GitHub Actions”**,之后才会自动部署。
-
-## 项目结构
-
-| 路径 | 内容 |
-| --- | --- |
-| `src/main.rs` | 入口点、提前分流 CLI、GUI 窗口设置 |
-| `src/cli.rs` | 无界面参数、DuckDB 解析验证、独立连接、JSON 错误 |
-| `tests/cli.rs` | 真实二进制集成测试,临时数据位于 `target/cli-tests` |
-| `skills/ducklocal/` | 官方 schema 优先 SQL agent skill 与 CLI 参考 |
-| `src/sources.rs` | 把路径解析成要挂载的文件和要打开的数据库 |
-| `src/db.rs` | DuckDB 连接、挂载文件、服务器信息 |
-| `src/query.rs` | 查询执行、结果序列化、导出 |
-| `src/profile.rs` | `ducklocal profile` 背后的列画像 |
-| `src/schema.rs` | 为侧栏做 catalog 内省 |
-| `src/analysis/` | JavaScript 分析应用:脚本运行时、`ducklocal` host 模块、应用标签页、重载监控 |
-| `src/app_export/` | `ducklocal export`:无界面运行应用,把其语句与结果写成一个独立 HTML 文件 |
-| `src/history.rs` | 应用自己的数据库:查询历史、已登记的文件、设置 |
-| `src/s3.rs` | SigV4 签名与 S3 列举 |
-| `src/i18n.rs` | 字符串表和语言选择 |
-| `src/state.rs` | 各视图共享的应用状态 |
-| `src/ui/` | 编辑器、结果表格、图表、侧栏、对话框、标题栏和状态栏 |
-| `src/perf_probe.rs` | 仅测试用的性能探针:为随数据规模增长的路径报告耗时、分配次数与分配字节数 |
-| `docs/` | 英文指南、`zh/` 下的中文指南,以及 VitePress 依赖、配置与主题 |
-| `assets/` | 图标、`Info.plist`、README 与文档使用的示意图 |
-| `scripts/` | `bundle.sh`、`package-macos.sh`、`check-deps.sh`、授权文件 |
-
-## 测试说明
-
-测试套件就是 `cargo test`。查询执行测试通过内存模式的连接来跑 DuckDB;导出测试同时覆盖 CSV 与 Parquet,后者会把写出的文件用 `read_parquet` 读回来验证。
diff --git a/docs/zh/getting-started.md b/docs/zh/getting-started.md
deleted file mode 100644
index a55c25e..0000000
--- a/docs/zh/getting-started.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# 快速上手
-
-**[English](../getting-started.md)** · [文档](index.md)
-
-DuckLocal 是一个桌面应用,让你直接用 SQL 查询本机上的数据文件。不需要启动服务器、不需要配置连接,也不需要注册账号——指向文件,就能开始查询。本页带你从下载走到第一条查询结果,大约五分钟。
-
-## 1. 安装 {#install}
-
-需要 **macOS 12 及以上、Apple silicon 芯片**(M1 或更新)。
-
-1. 从最新版本下载 [`ducklocal-macos-arm64.dmg`](https://github.com/JetSquirrel/DuckLocal/releases/latest)。
-2. 打开磁盘映像,把 **DuckLocal** 拖进“应用程序”。
-3. 从“应用程序”或聚焦搜索启动 DuckLocal。
-
-磁盘映像已经过 Apple 签名和公证,打开时不需要任何绕过 Gatekeeper 的操作。
-
-::: details 改为从源码构建
-需要 Rust stable 1.85.1 或更新版本,以及 C++ 工具链(Xcode Command Line Tools)。DuckDB 由内置源码编译,首次构建需要几分钟,并占用几 GB 磁盘空间。
-
-```bash
-git clone https://github.com/JetSquirrel/DuckLocal
-cd DuckLocal
-cargo build --release
-./target/release/ducklocal
-```
-
-可执行文件是 `./target/release/ducklocal`,本指南中写 `ducklocal` 的地方都可以用它代替。打包 `.app` 的方法见[开发指南](development.md)。
-:::
-
-## 2. 添加 `ducklocal` 命令(可选) {#add-command}
-
-应用里的所有功能都不需要终端。如果你还想从命令行打开数据,或者让 AI agent 通过 [CLI](cli.md) 执行查询,就把应用内的可执行文件链接到 `PATH` 上:
-
-```bash
-sudo mkdir -p /usr/local/bin
-sudo ln -sf /Applications/DuckLocal.app/Contents/MacOS/ducklocal /usr/local/bin/ducklocal
-ducklocal --version
-```
-
-这个链接指向应用本身,所以在“应用程序”里更新 DuckLocal 后,命令也随之更新。要删除它:`sudo rm /usr/local/bin/ducklocal`。
-
-## 3. 打开数据
-
-首次启动会显示一个标题为 **把数据拖进来** 的界面。以下任意一种方式都能导入数据:
-
-- 把 CSV、TSV、Parquet、JSON 或 Excel 文件——或整个文件夹——**拖到窗口上**。
-- 点击 **打开文件…** 或 **打开文件夹…**。
-- 在终端里写出路径:
-
- ```bash
- ducklocal ./sales.csv # 单个文件
- ducklocal ./logs/ # 递归打开文件夹下的所有数据文件
- ducklocal './data/*.parquet' # 通配符——加引号,避免被 shell 提前展开
- ducklocal warehouse.duckdb # 已有的 DuckDB 数据库
- ```
-
-每个文件都会成为一个以文件名命名的视图——`sales.csv` 变成 `sales`——并连同列和行数一起出现在侧边栏的 **本地文件** 下。DuckLocal 在原位置读取文件,不复制,也不上传。
-
-打开过的文件会被记住,下次启动时就是同一个工作区。格式、文件夹、通配符和数据库的细节见[数据源](data-sources.md)。
-
-::: tip 手头没有数据?
-[10 分钟上手教程](tutorial.md)会用一个小样例文件一步步带你走一遍。
-:::
-
-## 4. 运行查询
-
-点击 **新建查询**(或者直接打开数据——编辑器会自动出现)。输入 SQL,按 **⌘↵**(Cmd+Enter):
-
-```sql
-SELECT * FROM sales LIMIT 20;
-```
-
-结果出现在编辑器下方的面板里。切换到 **图表** 可以快速看个大概,也可以导出为 CSV 或 Parquet。编辑器上方的工具栏有 **运行**、**格式化** 和 **EXPLAIN**。
-
-一个值得知道的捷径:在侧边栏里,点击表旁边的播放按钮会生成现成的 `SELECT * … LIMIT 100`,点击列名则只查询这一列。
-
-## 接下来
-
-- [10 分钟上手教程](tutorial.md) —— 用样例数据走一遍
-- [数据源](data-sources.md) —— 格式、文件夹、通配符、数据库
-- [SQL 编辑器](sql-editor.md) —— Tab、快捷键、自动补全、EXPLAIN
-- [结果与图表](results-and-charts.md) —— 过滤、导出、图表
-- [常见问题排查](troubleshooting.md) —— 遇到不对劲的地方时
diff --git a/docs/zh/index.md b/docs/zh/index.md
deleted file mode 100644
index 854f427..0000000
--- a/docs/zh/index.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-layout: home
-hero:
- name: DuckLocal
- text: 在 Mac 上直接用 SQL 查你的文件。
- tagline: 拖入 CSV、Parquet、JSON 或 Excel,用 DuckDB 查询。不用服务器,不用配置,不用上传。
- image:
- src: /assets/logo.png
- alt: DuckLocal
- actions:
- - theme: brand
- text: 快速上手
- link: /zh/getting-started
- - theme: alt
- text: 10 分钟上手教程
- link: /zh/tutorial
- - theme: alt
- text: 下载 macOS 版
- link: https://github.com/JetSquirrel/DuckLocal/releases/latest
-features:
- - title: 文件在哪,就在哪查
- details: 单个文件、文件夹、通配符或 .duckdb 数据库,一打开就能查询——下次启动还在。
- link: /zh/data-sources
- linkText: 数据源
- - title: 数据不离开你的电脑
- details: 没有账号、没有遥测、没有云端。文件原地读取,从不复制或上传。
- link: /zh/settings-and-data
- linkText: 存了什么、存在哪里
- - title: 专注的 SQL 工作区
- details: 多个查询 Tab,基于你自己表结构的自动补全,一键格式化与 EXPLAIN。
- link: /zh/sql-editor
- linkText: SQL 编辑器
- - title: 从数字到图表
- details: 过滤结果表格、把结果画成图,并导出为 CSV 或 Parquet。
- link: /zh/results-and-charts
- linkText: 结果与图表
- - title: 为 AI agent 而生
- details: 无界面 CLI 与严格的 JSON 契约,外加一个官方 agent skill,按先看 schema 再分析的方式工作。
- link: /zh/cli
- linkText: CLI 与 skill
- - title: Dashboard 即文件
- details: 在 .dash 文件里声明查询与图表,或用脚本写一个定制视图,再导出成一个 HTML 页面分享出去。
- link: /zh/analysis-app
- linkText: 分析应用与 Dashboard
----
-
-
English · macOS 12+,Apple silicon · 开源免费(Apache-2.0)
+
+EOF
+}
+
+for name in "${pages[@]}"; do
+ if [ "$name" = index ]; then
+ page index.html "$home" en
+ page zh/index.html "${home}zh/" zh-CN
+ page index.zh-CN.html "${home}zh/" zh-CN
+ else
+ page "$name.html" "$docs$name" en
+ page "zh/$name.html" "${docs}zh/$name" zh-CN
+ # The addresses the first Chinese pages had, before they moved to zh/.
+ page "$name.zh-CN.html" "${docs}zh/$name" zh-CN
+ fi
+done
+
+# Anything else under the old base: the same path on the docs site, without
+# the base and the .html the new site no longer needs.
+cat > "$out/404.html" <
+
+
+
+
+DuckLocal has moved
+
+
+
+
+EOF
+
+echo "Wrote $(find "$out" -name '*.html' | wc -l | tr -d ' ') redirect pages to $out"
diff --git a/skills/ducklocal/SKILL.md b/skills/ducklocal/SKILL.md
index 57989bb..ad6e655 100644
--- a/skills/ducklocal/SKILL.md
+++ b/skills/ducklocal/SKILL.md
@@ -42,7 +42,7 @@ plot "revenue" {
A `query` block holds one `sql` attribute (one read-only statement — SELECT, WITH, FROM, VALUES, SHOW, DESCRIBE, SUMMARIZE or PIVOT — heredoc or string; DDL, DML, COPY, ATTACH and INSTALL are rejected). A `plot` block holds `type` (`line`, `bar`, `area`, `scatter`, `table`), `query` (a `query.name` reference), `x` and `y` (result columns, bare identifiers or quoted strings; `y` optional for `table`), optional `series` and `title`. No functions, conditionals, or interpolation exist. There is a working example at `examples/analysis_app/dashboard.dash`.
-Always validate before handing a spec over: `ducklocal check dashboard.dash`, or `ducklocal check dashboard.dash --database warehouse.duckdb` to also verify every `x`/`y`/`series` against the columns the queries actually return (a non-numeric `y` is an error outside `table`). A spec mistake is exit 2 with kind `spec`, one `file:line: message` per diagnostic — fix all of them, not just the first. To see it rendered, open the file in the GUI (`ducklocal dashboard.dash` or drag it onto the window): it becomes a dashboard tab, a resizable vertical stack of the plots with per-plot inline errors.
+Always validate before handing a spec over: `ducklocal check dashboard.dash`, or `ducklocal check dashboard.dash --database warehouse.duckdb` to also run every query read-only and verify every `x`/`y`/`series` against the columns the queries actually return (a non-numeric `y` is an error outside `table`). A spec mistake is exit 2 with kind `spec`, one `file:line: message` per diagnostic; a query that fails on the database is exit 1 with kind `sql`, one line per failing query — fix all of them, not just the first. Prefer the `--database` form whenever the database exists: without it nothing runs, so errors that appear only at execution (a cast the build cannot perform, a value that will not convert) go unseen. To see it rendered, open the file in the GUI (`ducklocal dashboard.dash` or drag it onto the window): it becomes a dashboard tab, a resizable vertical stack of the plots with per-plot inline errors.
## Authoring an app
diff --git a/src/analysis/mod.rs b/src/analysis/mod.rs
index c992cc1..1345247 100644
--- a/src/analysis/mod.rs
+++ b/src/analysis/mod.rs
@@ -17,7 +17,8 @@
//! src/analysis/watch.rs the host-side reload watcher
//! ```
//!
-//! See `docs/analysis-app.md` for the script-facing description.
+//! See for the script-facing
+//! description.
pub mod apps;
pub mod host;
diff --git a/src/cli.rs b/src/cli.rs
index d0421fb..3144c7f 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -6,7 +6,7 @@ use std::ptr;
use duckdb::{ffi, AccessMode, Config, Connection};
use serde_json::json;
-pub(crate) const HELP: &str = "DuckLocal — local data workspace and headless SQL\n\nUsage:\n ducklocal [PATH ...] Open the GUI (files, folders, globs)\n ducklocal query --sql SQL [OPTIONS] Execute one statement, return JSON\n ducklocal query --sql-file FILE [OPTIONS]\n ducklocal profile TARGET [--database PATH] Per-column statistics, JSON\n ducklocal export --html [OPTIONS] APP App data as a standalone HTML file\n ducklocal check FILE [--database PATH] Validate a .dash dashboard spec\n ducklocal lsp [--database PATH] Language server for .dash files (stdio)\n ducklocal --help\n ducklocal --version\n\nQuery options:\n --sql SQL SQL text; exactly one of --sql and --sql-file is required\n --sql-file FILE UTF-8 SQL file; - reads stdin\n --database PATH File database; must exist, opened read-only by default\n --read-write Allow database writes/creation (requires --database)\n --limit N Maximum returned rows, default 1000; positive integer\n --format FORMAT json (default) or md, a Markdown table to read and quote\n --help Show this help\n\nOutput: one JSON object with columns, rows, row_count, truncated, elapsed_ms.\nColumn types are Arrow debug names, not SQL type names. A 2,000,000-cell\nbudget also applies. Limits constrain output, not computation. --format md\nrenders the same values as readable text: dates and timestamps in ISO form,\nDECIMALs with their digits, NULL as NULL. It is a rendering, not the contract;\nuse JSON where a caller parses the result.\nErrors: JSON on stderr, empty stdout; exit 2 for arguments, 1 for SQL/I/O.\nRead-only is NOT a filesystem/network sandbox: COPY can write files.\nExtensions are not automatically installed. GUI state/history is not used.\nA GUI path named `query`, `profile`, `export`, `check`, `dash` or `lsp` must be written ./query, ./profile, ./export, ./check, ./dash, ./lsp.\n\nProfile: TARGET is a data file (csv/tsv/parquet/json) or a workbook\n(xlsx/xls/xlsb/ods; its first sheet is imported and profiled), or, with\n--database, a table or view name. Per column it reports type, nulls, distinct,\nmin, max; for numbers the decimals actually used, the median and\nmax_over_median; for dates covered_days, span_days and missing_days.\nStatistics are exact and read the whole relation.\n\nExport: APP is an analysis app folder (main.js) or its entry file.\nThe app is run once, in a hidden window, and the statements its query()\ncalls issue are captured with their results. Output is one JSON object naming\nthe written file; the file itself is self-contained HTML with no JavaScript.\nExport options:\n --html Required; the only format\n --out FILE Destination; defaults to ./.html\n --force Replace an existing destination\n --database PATH File database; must exist, opened read-only by default\n --read-write Allow database writes/creation (requires --database)\n --timeout SECONDS Capture time limit, default 15\n\nCheck: FILE is a .dash dashboard spec — query blocks holding SQL heredocs,\nplot blocks with type/query/x/y/series attributes, references like\nquery.latency between them. The check parses the file, resolves every\nreference and attribute, and validates each query's SQL with the real DuckDB\nparser; nothing executes and no table needs to exist. With --database it\nalso describes every query on that database (read-only) and checks each\nplot's x/y/series against the columns the query actually returns.\nOutput: one JSON object with the file's queries and plots; a spec mistake is\nexit 2 with one line per diagnostic, a database or I/O failure is exit 1.\n\nLsp: a Language Server Protocol server for .dash files, over stdio, for\neditors to spawn. Full-document sync; on every open and change it publishes\nthe same parse and semantic diagnostics `check` reports (exit-2 mistakes,\nall severity Error), plus each query's SQL through the real DuckDB parser\nwhen --database is given. Completion offers block, attribute, type and\nquery-name candidates; hover documents blocks, attributes and references;\ngo-to-definition jumps a query.name reference to its query block. Exit 0 on\na clean shutdown, 1 if the client goes away without one, 2 for a bad command\nline or a failed protocol handshake.\n";
+pub(crate) const HELP: &str = "DuckLocal — local data workspace and headless SQL\n\nUsage:\n ducklocal [PATH ...] Open the GUI (files, folders, globs)\n ducklocal query --sql SQL [OPTIONS] Execute one statement, return JSON\n ducklocal query --sql-file FILE [OPTIONS]\n ducklocal profile TARGET [--database PATH] Per-column statistics, JSON\n ducklocal export --html [OPTIONS] APP App data as a standalone HTML file\n ducklocal check FILE [--database PATH] Validate a .dash dashboard spec\n ducklocal lsp [--database PATH] Language server for .dash files (stdio)\n ducklocal --help\n ducklocal --version\n\nQuery options:\n --sql SQL SQL text; exactly one of --sql and --sql-file is required\n --sql-file FILE UTF-8 SQL file; - reads stdin\n --database PATH File database; must exist, opened read-only by default\n --read-write Allow database writes/creation (requires --database)\n --limit N Maximum returned rows, default 1000; positive integer\n --format FORMAT json (default) or md, a Markdown table to read and quote\n --help Show this help\n\nOutput: one JSON object with columns, rows, row_count, truncated, elapsed_ms.\nColumn types are Arrow debug names, not SQL type names. A 2,000,000-cell\nbudget also applies. Limits constrain output, not computation. --format md\nrenders the same values as readable text: dates and timestamps in ISO form,\nDECIMALs with their digits, NULL as NULL. It is a rendering, not the contract;\nuse JSON where a caller parses the result.\nErrors: JSON on stderr, empty stdout; exit 2 for arguments, 1 for SQL/I/O.\nRead-only is NOT a filesystem/network sandbox: COPY can write files.\nExtensions are not automatically installed. GUI state/history is not used.\nA GUI path named `query`, `profile`, `export`, `check`, `dash` or `lsp` must be written ./query, ./profile, ./export, ./check, ./dash, ./lsp.\n\nProfile: TARGET is a data file (csv/tsv/parquet/json) or a workbook\n(xlsx/xls/xlsb/ods; its first sheet is imported and profiled), or, with\n--database, a table or view name. Per column it reports type, nulls, distinct,\nmin, max; for numbers the decimals actually used, the median and\nmax_over_median; for dates covered_days, span_days and missing_days.\nStatistics are exact and read the whole relation.\n\nExport: APP is an analysis app folder (main.js) or its entry file.\nThe app is run once, in a hidden window, and the statements its query()\ncalls issue are captured with their results. Output is one JSON object naming\nthe written file; the file itself is self-contained HTML with no JavaScript.\nExport options:\n --html Required; the only format\n --out FILE Destination; defaults to ./.html\n --force Replace an existing destination\n --database PATH File database; must exist, opened read-only by default\n --read-write Allow database writes/creation (requires --database)\n --timeout SECONDS Capture time limit, default 15\n\nCheck: FILE is a .dash dashboard spec — query blocks holding SQL heredocs,\nplot blocks with type/query/x/y/series attributes, references like\nquery.latency between them. The check parses the file, resolves every\nreference and attribute, and validates each query's SQL with the real DuckDB\nparser; nothing executes and no table needs to exist. With --database it\nalso runs every query on that database (read-only), so an error that only\nshows once rows are read fails the check, and checks each plot's\nx/y/series against the columns the query actually returns.\nOutput: one JSON object with the file's queries and plots; a spec mistake is\nexit 2 with one line per diagnostic, a database or I/O failure is exit 1\n(a failing query is one line each, all of them).\n\nLsp: a Language Server Protocol server for .dash files, over stdio, for\neditors to spawn. Full-document sync; on every open and change it publishes\nthe same parse and semantic diagnostics `check` reports (exit-2 mistakes,\nall severity Error), plus each query's SQL through the real DuckDB parser\nwhen --database is given. Completion offers block, attribute, type and\nquery-name candidates; hover documents blocks, attributes and references;\ngo-to-definition jumps a query.name reference to its query block. Exit 0 on\na clean shutdown, 1 if the client goes away without one, 2 for a bad command\nline or a failed protocol handshake.\n";
#[derive(Debug)]
pub(crate) struct CliError {
diff --git a/src/spec/lsp.rs b/src/spec/lsp.rs
index dd64317..47f2c87 100644
--- a/src/spec/lsp.rs
+++ b/src/spec/lsp.rs
@@ -457,7 +457,7 @@ fn validate(source: &str) -> Option {
}
/// One line of documentation per attribute name — the language rules of
-/// `docs/cli.md`, not localized: like completion details, these read as
+/// , not localized: like completion details, these read as
/// vocabulary, not sentences.
fn attr_doc(name: &str) -> Option<&'static str> {
Some(match name {
diff --git a/src/spec/mod.rs b/src/spec/mod.rs
index 91424ac..5872587 100644
--- a/src/spec/mod.rs
+++ b/src/spec/mod.rs
@@ -20,8 +20,9 @@
//! `ducklocal check FILE` validates a spec without touching a database: parse,
//! references, required attributes, and each query's SQL through the real
//! DuckDB parser (parse-only, nothing executes). With `--database PATH` it
-//! also describes every query on that database and checks each plot's
-//! `x`/`y`/`series` against the columns the query actually returns. The view
+//! also runs every query on that database, read-only — so an error that only
+//! shows once rows are read fails the check, not the dashboard — and checks
+//! each plot's `x`/`y`/`series` against the columns the query returns. The view
//! half runs the same parse and validation before drawing anything, so a file
//! that fails `check` opens as its diagnostics, not as a broken chart.
@@ -98,19 +99,40 @@ pub fn check(args: &[OsString]) -> Result {
})?;
}
- // Column checking needs the queries described, not run: DESCRIBE plans the
- // statement and reports its result columns without reading the data.
+ // Against a database every query is described — its result columns, for
+ // the column check — and then run, the way opening the dashboard runs it.
+ // DESCRIBE only plans: a cast the build cannot perform or a value deep in
+ // the data that will not convert surfaces only once rows are read, and a
+ // check that passes a dashboard the GUI then cannot draw is no check. The
+ // SQL has been shown read-only above and the connection is read-only, so
+ // running it changes nothing; it goes through the view's own `run_of`, so
+ // the two stop at the same row budget and fail on the same statements.
+ // Every failing query is reported, not only the first.
let mut query_columns: Vec